Руководство пользователя pyscard

Carding 4 Carders

Professional
Messages
2,731
Reputation
12
Reaction score
1,352
Points
113
Оглавление
Руководство пользователя pyscard
  • Авторские права
  • Вступление
  • Смарт-карты
  • Быстрый старт
    • Ориентированный на читателя подход
    • Ответ на сброс (ATR)
    • Карточно-ориентированный подход
      • Запрос карты через ATR
      • Запрос любой карты
      • Пользовательские типы карточек
      • Выбор протокола связи карты
    • Объектно-ориентированный подход
  • Отслеживание APDU
    • Грубая сила
    • Использование наблюдателей за подключением карт для отслеживания передачи apdu
      • Полный пример кода
  • Тестирование ошибок передачи APDU
    • Грубая сила для проверки ошибок передачи APDU
    • Проверка ошибок передачи APDU с помощью средств проверки ошибок
      • Средства проверки ошибок
      • Цепочки проверки ошибок
      • Фильтрация исключений
      • Полный пример кода
      • Обнаружение ошибок APDU ответа для подключения карты
      • Написание пользовательского средства проверки ошибок
  • Считыватели смарт-карт
    • Вывод списка устройств чтения смарт-карт
    • Организация считывателей смарт-карт в группы читателей
    • Мониторинг читателей
  • Смарт-карты
    • Мониторинг смарт-карт
    • Отправка APDU на смарт-карту, полученную в результате мониторинга карт
  • Подключения
    • Создание соединения из CardRequest
    • Создание подключения из CardMonitoring
      • Полный пример кода
    • Декораторы подключения карт
      • Эксклюзивный декоратор подключения карт
      • Эксклюзивный декоратор подключения карты передачи
      • Декоратор подключения карты защищенного канала
  • Несколько слов о криптографии
    • Двоичные строки и список байтов
    • Криптография с секретным ключом

Авторские права
Авторские права 2001-2009 Gemalto
Автор: Жан-Даниэль Осель, [email protected]
Этот файл является частью pyscard.
pyscard - бесплатное программное обеспечение; вы можете распространять и / или изменять его в соответствии с условиями Стандартной общественной лицензии ограниченного применения GNU, опубликованной Free Software Foundation; либо версии 2.1 Лицензии, либо (по вашему выбору) любой более поздней версии.
pyscard распространяется в надежде, что он будет полезен, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ; даже без подразумеваемой гарантии ТОВАРНОЙ ПРИГОДНОСТИ или ПРИГОДНОСТИ ДЛЯ КОНКРЕТНОЙ ЦЕЛИ. Подробнее см. Стандартную общественную лицензию ограниченного применения GNU.
Вы должны были получить копию Стандартной общественной лицензии ограниченного применения GNU вместе с pyscard; в противном случае напишите в Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.

Введение
Библиотека смарт-карт pyscard - это платформа для создания приложений с поддержкой смарт-карт на Python. Модуль смарт-карты построен на основе модуля оболочки PCSC API Python.
pyscard поддерживает Windows 2000 и XP с помощью компонентов Microsoft Smart Card Base, а также Linux и Mac OS X с помощью PCSC-lite.

Смарт-карты
Смарт-карты - это пластиковые карты, обычно имеющие размер кредитной карты и содержащие микропроцессор. Смарт-карты взаимодействуют с внешним миром через интерфейс последовательного порта и полудуплексный протокол. Смарт-карты обычно подключаются к специальному терминалу, например терминалу кассового терминала или мобильному телефону. Иногда смарт-карты необходимо сопрягать с персональными компьютерами. Это касается некоторых приложений, таких как безопасный вход, шифрование почты или цифровая подпись, но также и некоторых инструментов смарт-карт на базе ПК, используемых для персонализации или редактирования содержимого смарт-карт. Смарт-карты подключаются к персональному компьютеру с помощью устройства чтения смарт-карт. Устройство чтения смарт-карт подключается с одной стороны к последовательному порту смарт-карты, а с другой стороны - к ПК, часто в настоящее время через порт USB.
Рабочая группа PCSC определила стандартный API для подключения смарт-карт и устройств чтения смарт-карт к ПК. Результирующая эталонная реализация в операционных системах Linux и Mac OS X - PC / SC-lite. Все операционные системы Windows также включают встроенную поддержку смарт-карт, обычно называемую PCSC.
API PCSC реализован на языке C, и для доступа к API PCSC с разных языков, таких как java или Visual Basic, предоставляется несколько мостов. pyscard - это среда Python для разработки приложений для ПК со смарт-картами в Linux, Mac OS X и Windows. Интерфейс нижних уровней pyscard к API PCSC для доступа к смарт-картам и устройствам чтения смарт-карт.

Быстрый старт
В этом разделе мы увидим некоторые варианты того, как отправлять команды APDU на смарт-карту.

Подход, ориентированный на читателя
Приложение ПК взаимодействует с картой, отправляя список байтов, известный как блоки данных протокола приложения (APDU). Формат этих APDU определен в стандарте ISO7816-4. Чтобы отправить APDU на карту, приложение должно сначала подключиться к карте через устройство чтения смарт-карт. Приложения с поддержкой смарт-карт, которые сначала выбирают устройство чтения смарт-карт, а затем подключаются к карте, вставленной в устройство чтения смарт-карт, используют подход, ориентированный на считыватель.
В подходе, ориентированном на считыватель, мы открываем соединение с картой через устройство чтения смарт-карт и отправляем на карту команды APDU, используя соединение:
Code:
>>> from smartcard.System import readers
>>> from smartcard.util import toHexString
>>>
>>> r=readers()
>>> print r
['SchlumbergerSema Reflex USB v.2 0', 'Utimaco CardManUSB 0']
>>> connection = r[0].createConnection()
>>> connection.connect()
>>> SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
>>> DF_TELECOM = [0x7F, 0x10]
>>> data, sw1, sw2 = connection.transmit( SELECT + DF_TELECOM )
>>> print "%x %x" % (sw1, sw2)
9f 1a
>>>

Список доступных читателей можно получить с помощью функции reader (). Мы создаем соединение с первым считывателем (индекс 0 для считывателя 1, 1 для считывателя 2, ...) с помощью вызова r [0] .createConnection () и подключаемся к карте с помощью метода подключения connect (). Затем мы можем отправить команды APDU на карту с помощью метода передачи ().
Однако сценарии, написанные с ориентацией на читателя, имеют следующие недостатки:
  • индекс читателя или имя читателя жестко запрограммированы в скриптах; скрипты необходимо отредактировать, чтобы они соответствовали конфигурации каждого пользователя; например, в предыдущем сценарии нам пришлось бы отредактировать сценарий и изменить r [0] на r [1] для использования второго считывателя
  • нет априорной информации о том, что карта находится в считывателе; чтобы обнаружить вставку карты, мы должны были бы выполнить сценарий и в конечном итоге поймать исключение CardConnectionException, которое указывало бы на то, что в считывающем устройстве нет карты.
  • нет встроенной проверки того, что карта в считывателе относится к ожидаемому типу карты; в предыдущем примере мы могли бы попытаться выбрать DF_TELECOM карты EMV.
Большинство из этих проблем решаются с помощью подхода, ориентированного на карты, на основе методов определения типа карты, таких как использование ответа на сброс (ATR) карты.

Ответ на сброс (ATR)
Первый ответ смарт-карты, вставленной в устройство чтения смарт-карт, - это вызов ATR. Цель ATR - описать поддерживаемые параметры связи. Устройство чтения смарт-карт, драйвер устройства чтения смарт-карт и операционная система будут использовать эти параметры для установления связи с картой. ATR описан в стандарте ISO7816-3. Первые байты ATR описывают соглашение о напряжении (прямое или обратное), за ними следуют байты, описывающие доступные интерфейсы связи и их соответствующие параметры. За этими байтами интерфейса следуют исторические байты, которые не стандартизированы и полезны для передачи служебной информации, такой как тип карты, версия встроенного программного обеспечения или состояние карты. Наконец, за этими байтами истории в конечном итоге следует байт контрольной суммы.
Класс smartcard.ATR - это служебный класс pyscard, который может интерпретировать содержимое ATR:
Code:
#! /usr/bin/env python
"""
Sample script for the smartcard.ATR utility class.

from __future__ import print_function
from smartcard.ATR import ATR
from smartcard.util import toHexString

atr = ATR([0x3B, 0x9E, 0x95, 0x80, 0x1F, 0xC3, 0x80, 0x31, 0xA0, 0x73,
           0xBE, 0x21, 0x13, 0x67, 0x29, 0x02, 0x01, 0x01, 0x81,
           0xCD, 0xB9])

print(atr)
print('historical bytes: ', toHexString(atr.getHistoricalBytes()))
print('checksum: ', "0x%X" % atr.getChecksum())
print('checksum OK: ', atr.checksumOK)
print('T0  supported: ', atr.isT0Supported())
print('T1  supported: ', atr.isT1Supported())
print('T15 supported: ', atr.isT15Supported())

В результате получается следующий результат:
Code:
3B 9E 95 80 1F C3 80 31 A0 73 BE 21 13 67 29 02 01 01 81 CD B9
historical bytes: 80 31 A0 73 BE 21 13 67 29 02 01 01 81 CD
checksum: 0xB9
checksum OK: True
T0 supported: True
T1 supported: False
T15 supported: True

На практике ATR можно использовать для обнаружения конкретной карты, либо пытаясь сопоставить карту с полным ATR, либо сопоставив карту с некоторыми данными в байтах истории. Приложения для ПК с поддержкой смарт-карт, которые обнаруживают смарт-карты на основе содержимого ATR, используют подход, ориентированный на карты, независимо от устройства чтения смарт-карт, в которое вставлена карта.

Карточно-ориентированный подход
В подходе, ориентированном на карты, мы создаем запрос для определенного типа карты и ждем, пока карта, соответствующая запросу, не будет вставлена. Как только соответствующая карта введена, соединение с картой создается автоматически, и мы можем отправлять команды APDU на карту, используя это соединение.

Запрос карты через ATR
Следующие скрипты запрашивают карту с известным ATR:
Code:
>>> from smartcard.CardType import ATRCardType
>>> from smartcard.CardRequest import CardRequest
>>> from smartcard.util import toHexString, toBytes
>>>
>>> cardtype = ATRCardType( toBytes( "3B 16 94 20 02 01 00 00 0D" ) )
>>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
>>> cardservice = cardrequest.waitforcard()
>>>
>>> cardservice.connection.connect()
>>> print toHexString( cardservice.connection.getATR() )
3B 16 94 20 02 01 00 00 0D
>>>
>>> SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
>>> DF_TELECOM = [0x7F, 0x10]
>>> data, sw1, sw2 = cardservice.connection.transmit( SELECT + DF_TELECOM )
>>> print "%x %x" % (sw1, sw2)
9f 1a
>>>

Чтобы запросить карту с известным ATR, вы должны сначала создать объект ATRCardType с желаемым ATR:
Code:
>>> cardtype  =  ATRCardType (  toBytes (  "3B 16 94 20 02 01 00 00 0D"  )  )

А затем создайте CardRequest для этого типа карты. В примере мы запрашиваем тайм-аут в 1 секунду.
Code:
>>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
>>> cardservice = cardrequest.waitforcard()

Функция waitforcard () либо вернется со службой карты, либо с тайм-аутом. Атрибут соединения службы карты может использоваться после этого для передачи команд APDU карте, как и в подходе, ориентированном на считыватель.
Code:
>>> cardservice.connection.connect()
>>> print toHexString( cardservice.connection.getATR() )

При необходимости доступ к считывающему устройству, используемому для подключения, можно получить через объект CardConnection:
Code:
>>> print cardservice.connection.getReader()
SchlumbergerSema Reflex USB v.2 0

ATRCardType также поддерживает маску:
Code:
>>> from smartcard.CardType import ATRCardType
>>> from smartcard.CardRequest import CardRequest
>>> from smartcard.util import toHexString, toBytes
>>>
>>> cardtype = ATRCardType( toBytes( "3B 15 94 20 02 01 00 00 0F" ), toBytes( "00 00 FF FF FF FF FF FF 00" ) )
>>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
>>> cardservice = cardrequest.waitforcard()
>>>
>>> cardservice.connection.connect()
>>> print toHexString( cardservice.connection.getATR() )
3B 16 94 20 02 01 00 00 0D

Доступны другие типы карточек, и можно создавать новые типы карточек, как описано ниже.

Запрос любой карты
AnyCardType полезно для запроса любой карты в любо ридере:
Code:
>>> from smartcard.CardType import AnyCardType
>>> from smartcard.CardRequest import CardRequest
>>> from smartcard.util import toHexString
>>>
>>> cardtype = AnyCardType()
>>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
>>> cardservice = cardrequest.waitforcard()
>>>
>>> cardservice.connection.connect()
>>> print toHexString( cardservice.connection.getATR() )
3B 16 94 20 02 01 00 00 0D
>>> print cardservice.connection.getReader()
SchlumbergerSema Reflex USB v.2 0

Пользовательские типы карточек
Пользовательские типы карт могут быть созданы, например, тип карты, который проверяет ATR и исторические байты карты. Чтобы создать собственный CardType, унаследуйте свой класс CardType от базового класса CardType (или любого другого CardType) и переопределите метод match (). Например, чтобы создать DCCardType, который будет соответствовать картам с прямым соглашением (первый байт ATR равен 0x3b):
Code:
>>> from smartcard.CardType import CardType
>>> from smartcard.CardRequest import CardRequest
>>> from smartcard.util import toHexString
>>>
>>> class DCCardType(CardType):
...      def matches( self, atr, reader=None ):
...          return atr[0]==0x3B
...
>>> cardtype = DCCardType()
>>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
>>> cardservice = cardrequest.waitforcard()
>>>
>>> cardservice.connection.connect()
>>> print toHexString( cardservice.connection.getATR() )
3B 16 94 20 02 01 00 00 0D
>>> print cardservice.connection.getReader()
SchlumbergerSema Reflex USB v.2 0
>>>

Скрипты, написанные с использованием подхода, ориентированного на карты, устраняют проблемы подхода, ориентированного на читателя:
  • нет никаких предположений относительно индекса читателя или имени читателя; желаемая карта поместится в любом считывателе
  • запрос будет заблокирован или истечет время ожидания, если нужный тип карты не вставлен, поскольку мы запрашиваем желаемый тип карты, скрипт не воспроизводится на неизвестной или несовместимой карте
Однако скрипты, написанные с использованием подхода, ориентированного на карты, имеют следующие недостатки:
  • сценарий ограничен конкретным типом карты; мы должны изменить сценарий, если мы хотим выполнить сценарий для другого типа карты. Например, мы должны изменить ATR карты, если мы используем ATRCardType. Тем не менее, это можно частично решить, используя собственный CardType, который соответствует нескольким ATR.
Выбор протокола связи карты
Параметры связи наиболее важны для согласования протокола между устройством чтения смарт-карт и картой. Основными протоколами смарт-карт являются протокол T = 0 и протокол T = 1 для передачи байтов или блоков, соответственно. Требуемый протокол можно указать при подключении карты или передаче карты.
По умолчанию метод connect () объекта CardConnection. Будет пытаться подключиться с использованием протокола T = 0 или T = 1. Чтобы принудительно установить протокол соединения, вы можете передать требуемый протокол методу connect ().
Code:
>>> from smartcard.CardType import AnyCardType
>>> from smartcard.CardConnection import CardConnection
>>> from smartcard.CardRequest import CardRequest
>>> from smartcard.util import toHexString
>>>
>>> cardtype = AnyCardType()
>>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
>>> cardservice = cardrequest.waitforcard()
>>>
>>> cardservice.connection.connect( CardConnection.T1_protocol )
>>> print toHexString( cardservice.connection.getATR() )
3B 16 94 20 02 01 00 00 0D
>>> print cardservice.connection.getReader()
SchlumbergerSema Reflex USB v.2 0

В качестве альтернативы вы можете указать требуемый протокол в методе передачи CardConnection ():
Code:
>>> from smartcard.CardType import AnyCardType
>>> from smartcard.CardConnection import CardConnection
>>> from smartcard.CardRequest import CardRequest
>>> from smartcard.util import toHexString, toBytes
>>>
>>> cardtype = AnyCardType()
>>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
>>> cardservice = cardrequest.waitforcard()
>>>
>>> cardservice.connection.connect()
>>>
>>> SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
>>> DF_TELECOM = [0x7F, 0x10]
>>>
>>> apdu = SELECT+DF_TELECOM
>>> print 'sending ' + toHexString(apdu)
sending A0 A4 00 00 02 7F 10
>>> response, sw1, sw2 = cardservice.connection.transmit( apdu, CardConnection.T1_protocol )
>>> print 'response: ', response, ' status words: ', "%x %x" % (sw1, sw2)
response: [] status words: 9f 1a
>>>
>>> if sw1 == 0x9F:
...     GET_RESPONSE = [0XA0, 0XC0, 00, 00 ]
...     apdu = GET_RESPONSE + [sw2]
...     print 'sending ' + toHexString(apdu)
...     response, sw1, sw2 = cardservice.connection.transmit( apdu )
...     print 'response: ', toHexString(response), ' status words: ', "%x %x" % (sw1, sw2)
...
sending A0 C0 00 00 1A
response: 00 00 00 00 7F 10 02 00 00 00 00 00 0D 13 00 0A 04 00 83 8A 83 8A 00 01 00 00 status words: 90 0
>>>

Объектно-ориентированный подход
В объектно-ориентированном подходе мы связываем объект высокого уровня с набором смарт-карт, поддерживаемых объектом. Например, мы связываем класс загрузчика javacard с набором смарт-карт javacard. Мы создаем запрос для конкретного объекта и ждем, пока не будет вставлена карта, поддерживаемая объектом. После того, как карта, поддерживаемая объектом, вставлена, мы выполняем требуемую функцию, вызывая методы объекта.
Будет написано ...

Отслеживание APDU
Грубая сила

Простой способ отслеживания APDU команд и ответов - это вставить операторы печати вокруг вызовов метода transfer ():
Code:
>>> from smartcard.CardType import ATRCardType
>>> from smartcard.CardRequest import CardRequest
>>> from smartcard.util import toHexString, toBytes
>>>
>>> cardtype = ATRCardType( toBytes( "3B 16 94 20 02 01 00 00 0D" ) )
>>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
>>> cardservice = cardrequest.waitforcard()
>>>
>>> cardservice.connection.connect()
>>>
>>> SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
>>> DF_TELECOM = [0x7F, 0x10]
>>>
>>> apdu = SELECT+DF_TELECOM
>>> print 'sending ' + toHexString(apdu)
sending A0 A4 00 00 02 7F 10
>>> response, sw1, sw2 = cardservice.connection.transmit( apdu )
>>> print 'response: ', response, ' status words: ', "%x %x" % (sw1, sw2)
response: [] status words: 9f 1a
>>>
>>> if sw1 == 0x9F:
...     GET_RESPONSE = [0XA0, 0XC0, 00, 00 ]
...     apdu = GET_RESPONSE + [sw2]
...     print 'sending ' + toHexString(apdu)
...     response, sw1, sw2 = cardservice.connection.transmit( apdu )
...     print 'response: ', toHexString(response), ' status words: ', "%x %x" % (sw1, sw2)
...
sending A0 C0 00 00 1A
response: 00 00 00 00 7F 10 02 00 00 00 00 00 0D 13 00 0A 04 00 83 8A 83 8A 00 01 00 00 status words: 90 0
>>>

Сценарии, написанные таким образом, довольно трудно читать, потому что операторов трассировки больше, чем передает фактический apdu.
Небольшим улучшением видимости будет замена инструкций печати функциями, например:
Code:
>>> from smartcard.CardType import ATRCardType
>>> from smartcard.CardRequest import CardRequest
>>> from smartcard.util import toHexString, toBytes
>>>
>>> cardtype = ATRCardType( toBytes( "3B 16 94 20 02 01 00 00 0D" ) )
>>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
>>> cardservice = cardrequest.waitforcard()
>>>
>>> cardservice.connection.connect()
>>>
>>> SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
>>> DF_TELECOM = [0x7F, 0x10]
>>>
>>> def trace_command(apdu):
...     print 'sending ' + toHexString(apdu)
...
>>> def trace_response( response, sw1, sw2 ):
...     if None==response: response=[]
...     print 'response: ', toHexString(response), ' status words: ', "%x %x" % (sw1, sw2)
...
>>> apdu = SELECT+DF_TELECOM
>>> trace_command(apdu)
sending A0 A4 00 00 02 7F 10
>>> response, sw1, sw2 = cardservice.connection.transmit( apdu )
>>> trace_response( response, sw1, sw2 )
response: status words: 9f 1a
>>>
>>> if sw1 == 0x9F:
...    GET_RESPONSE = [0XA0, 0XC0, 00, 00 ]
...    apdu = GET_RESPONSE + [sw2]
...    trace_command(apdu)
...    response, sw1, sw2 = cardservice.connection.transmit( apdu )
...    trace_response( response, sw1, sw2 )
...
sending A0 C0 00 00 1A
response: 00 00 00 00 7F 10 02 00 00 00 00 00 0D 13 00 0A 04 00 83 8A 83 8A 00 01 00 00 status words: 90 0
>>>

Использование наблюдателей подключения карт для отслеживания передачи apdu
Предпочтительным решением является реализация наблюдателя за подключением карты и регистрация наблюдателя в подключении карты. Затем соединение карты будет уведомлять наблюдателя, когда происходят события подключения карты (например, соединение, отключение, команда apdu или ответ apdu). Это показано в следующем сценарии:
Code:
>>> from smartcard.CardType import AnyCardType
>>> from smartcard.CardRequest import CardRequest
>>> from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver
>>>
>>> GET_RESPONSE = [0XA0, 0XC0, 00, 00 ]
>>> SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
>>> DF_TELECOM = [0x7F, 0x10]
>>>
>>>
>>> cardtype = AnyCardType()
>>> cardrequest = CardRequest( timeout=10, cardType=cardtype )
>>> cardservice = cardrequest.waitforcard()
>>>
>>> observer=ConsoleCardConnectionObserver()
>>> cardservice.connection.addObserver( observer )
>>>
>>> cardservice.connection.connect()
connecting to SchlumbergerSema Reflex USB v.2 0
>>>
>>> apdu = SELECT+DF_TELECOM
>>> response, sw1, sw2 = cardservice.connection.transmit( apdu )
> A0 A4 00 00 02 7F 10
< [] 9F 1A
>>> if sw1 == 0x9F:
...     apdu = GET_RESPONSE + [sw2]
...     response, sw1, sw2 = cardservice.connection.transmit( apdu )
... else:
...     print 'no DF_TELECOM'
...
> A0 C0 00 00 1A
< 00 00 00 00 7F 10 02 00 00 00 00 00 0D 13 00 0A 04 00 83 8A 83 8A 00 01 00 00 90 0
>>>

В этом сценарии ConsoleCardConnectionObserver присоединяется к соединению службы карты после возврата вызова watiforcard ().
Code:
>>> observer=ConsoleCardConnectionObserver()
>>> cardservice.connection.addObserver( observer )

При событиях подключения карты (подключение, отключение, передача команды apdu, получение ответа apdu) подключение карты уведомляет своих наблюдателей с помощью CarConnectionEvent, включая тип события и данные события. ConsoleCardConnectionObserver является простым наблюдателем , который будет печатать на консоли присоединительных карт событий. Определение класса следующее:
Code:
class ConsoleCardConnectionObserver( CardConnectionObserver ):
    def update( self, cardconnection, ccevent ):

        if 'connect'==ccevent.type:
            print 'connecting to ' + cardconnection.getReader()

        elif 'disconnect'==ccevent.type:
            print 'disconnecting from ' + cardconnection.getReader()

        elif 'command'==ccevent.type:
            print '> ', toHexString( ccevent.args[0] )

        elif 'response'==ccevent.type:
            if []==ccevent.args[0]:
                print '< [] ', "%-2X %-2X" % tuple(ccevent.args[-2:])
            else:
        print '< ', toHexString(ccevent.args[0]), "%-2X %-2X" % tuple(ccevent.args[-2:])

Таким образом, обозреватель подключения карты консоли печатает события apdu подключения, отключения, команды и ответа:
Code:
>>> cardservice.connection.connect()
connecting to SchlumbergerSema Reflex USB v.2 0
>>>
>>> apdu = SELECT+DF_TELECOM
>>> response, sw1, sw2 = cardservice.connection.transmit( apdu )
> A0 A4 00 00 02 7F 10
< [] 9F 1A
>>> if sw1 == 0x9F:
...     apdu = GET_RESPONSE + [sw2]
...     response, sw1, sw2 = cardservice.connection.transmit( apdu )
... else:
...     print 'no DF_TELECOM'
...
> A0 C0 00 00 1A
< 00 00 00 00 7F 10 02 00 00 00 00 00 0D 13 00 0A 04 00 83 8A 83 8A 00 01 00 00 90 0

Метод обновления наблюдателя подключения карты вызывается при событии подключения карты с параметром подключения и события подключения. CardConnectionEvent определение класса состоит в следующем:
Code:
class CardConnectionEvent:
    """Base class for card connection events.

   This event is notified by CardConnection objects.

   type: 'connect', 'disconnect', 'command', 'response'
   args: None for 'connect' or 'disconnect'
   command APDU byte list for 'command'
   [response data, sw1, sw2] for 'response'
   type: 'connect' args:"""
   def __init__( self, type, args=None):
       self.type=type
       self.args=args

Вы можете написать свой собственный обозреватель подключения карты, например, для выполнения необычного вывода во фрейме wxWindows или интерпретации apdu. Следующие сценарии определяют небольшой интерпретатор apdu SELECT и GET RESPONSE:
Code:
>>> from smartcard.CardType import AnyCardType
>>> from smartcard.CardRequest import CardRequest
>>> from smartcard.CardConnectionObserver import CardConnectionObserver
>>> from smartcard.util import toHexString
>>>
>>> from string import replace
>>>
>>> class TracerAndSELECTInterpreter( CardConnectionObserver ):
...     def update( self, cardconnection, ccevent ):
...         if 'connect'==ccevent.type:
...             print 'connecting to ' + cardconnection.getReader()
...         elif 'disconnect'==ccevent.type:
...             print 'disconnecting from ' + cardconnection.getReader()
...         elif 'command'==ccevent.type:
...             str=toHexString(ccevent.args[0])
...             str = replace( str , "A0 A4 00 00 02", "SELECT" )
...             str = replace( str , "A0 C0 00 00", "GET RESPONSE" )
...             print '> ', str
...         elif 'response'==ccevent.type:
...             if []==ccevent.args[0]:
...                 print '< [] ', "%-2X %-2X" % tuple(ccevent.args[-2:])
...             else:
...                 print '< ', toHexString(ccevent.args[0]), "%-2X %-2X" % tuple(ccevent.args[-2:])
...
>>>
>>> GET_RESPONSE = [0XA0, 0XC0, 00, 00 ]
>>> SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
>>> DF_TELECOM = [0x7F, 0x10]
>>>
>>>
>>> cardtype = AnyCardType()
>>> cardrequest = CardRequest( timeout=10, cardType=cardtype )
>>> cardservice = cardrequest.waitforcard()
>>>
>>> observer=TracerAndSELECTInterpreter()
>>> cardservice.connection.addObserver( observer )
>>>
>>> cardservice.connection.connect()
connecting to SchlumbergerSema Reflex USB v.2 0
>>>
>>> apdu = SELECT+DF_TELECOM
>>> response, sw1, sw2 = cardservice.connection.transmit( apdu )
> SELECT 7F 10
< [] 9F 1A
>>> if sw1 == 0x9F:
...     apdu = GET_RESPONSE + [sw2]
...     response, sw1, sw2 = cardservice.connection.transmit( apdu )
... else:
...     print 'no DF_TELECOM'
...
> GET RESPONSE 1A
< 00 00 00 00 7F 10 02 00 00 00 00 00 0D 13 00 0A 04 00 83 8A 83 8A 00 01 00 00 90 0
>>>

Полный пример кода
Code:
#! /usr/bin/env python
"""
Sample script that defines a custom card connection observer.
"""
from __future__ import print_function
from smartcard.CardType import AnyCardType
from smartcard.CardRequest import CardRequest
from smartcard.CardConnectionObserver import CardConnectionObserver
from smartcard.util import toHexString


class TracerAndSELECTInterpreter(CardConnectionObserver):
    """This observer will interprer SELECT and GET RESPONSE bytes
    and replace them with a human readable string."""

    def update(self, cardconnection, ccevent):

        if 'connect' == ccevent.type:
            print('connecting to ' + cardconnection.getReader())

        elif 'disconnect' == ccevent.type:
            print('disconnecting from ' + cardconnection.getReader())

        elif 'command' == ccevent.type:
            str = toHexString(ccevent.args[0])
            str = str.replace("A0 A4 00 00 02", "SELECT")
            str = str.replace("A0 C0 00 00", "GET RESPONSE")
            print('>', str)

        elif 'response' == ccevent.type:
            if [] == ccevent.args[0]:
                print('<  []', "%-2X %-2X" % tuple(ccevent.args[-2:]))
            else:
                print('<',
                      toHexString(ccevent.args[0]),
                      "%-2X %-2X" % tuple(ccevent.args[-2:]))


# define the apdus used in this script
GET_RESPONSE = [0XA0, 0XC0, 00, 00]
SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
DF_TELECOM = [0x7F, 0x10]


# we request any type and wait for 10s for card insertion
cardtype = AnyCardType()
cardrequest = CardRequest(timeout=10, cardType=cardtype)
cardservice = cardrequest.waitforcard()

# create an instance of our observer and attach to the connection
observer = TracerAndSELECTInterpreter()
cardservice.connection.addObserver(observer)


# connect and send APDUs
# the observer will trace on the console
cardservice.connection.connect()

apdu = SELECT + DF_TELECOM
response, sw1, sw2 = cardservice.connection.transmit(apdu)
if sw1 == 0x9F:
    apdu = GET_RESPONSE + [sw2]
    response, sw1, sw2 = cardservice.connection.transmit(apdu)
else:
    print('no DF_TELECOM')

import sys
if 'win32' == sys.platform:
    print('press Enter to continue')
    sys.stdin.read(1)

Тестирование ошибок передачи APDU
После передачи и обработки APDU смарт-карта возвращает пару слов состояния, SW1 и SW2, чтобы сообщить о различных кодах успеха или ошибок после необходимой обработки. Некоторые из этих кодов успеха или ошибок стандартизированы, например, в ISO7816-4, ISO7816-8 или ISO7816-9. Другие коды слов состояния стандартизированы органами стандартизации, такими как Open Platform (например, javacard), 3GPP (например, SIM- или USIM-карты) или Eurocard-Mastercard-Visa (EMV) (например, банковские карты). Наконец, любой разработчик приложений для смарт-карт может определить собственные коды, относящиеся к приложению; например, апплет MUSCLE определяет набор частных кодов, связанных с функциями апплета MUSCLE.
Некоторые из этих кодов слов состояния уникальны, но другие имеют разное значение в зависимости от типа карты и поддерживаемых стандартов. Например, ISO7816-4 определяет код ошибки 0x62 0x82 как «Файл недействителен», тогда как в Open Platform 2.1 тот же код ошибки определяется как «Жизненный цикл карты - CARD_LOCKED». В результате список кодов ошибок, которые могут быть возвращены смарт-картой, и их интерпретация зависят от типа карты. Следующее обсуждение описывает возможные стратегии для проверки и сообщения ошибок слова состояния смарт-карты.

Грубая сила для проверки ошибок передачи APDU
Что касается трассировки APDU, простой способ проверки ошибок в ответных APDU во время выполнения скриптов - это вставить тестовые операторы после вызова метода transfer ():
Code:
>>> from smartcard.CardType import AnyCardType
>>> from smartcard.CardRequest import CardRequest
>>> from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver
>>>
>>> GET_RESPONSE = [0XA0, 0XC0, 00, 00 ]
>>> SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
>>> DF_TELECOM = [0x7F, 0x10]
>>>
>>> cardtype = AnyCardType()
>>> cardrequest = CardRequest( timeout=10, cardType=cardtype )
>>> cardservice = cardrequest.waitforcard()
>>>
>>> observer=ConsoleCardConnectionObserver()
>>> cardservice.connection.addObserver( observer )
>>>
>>> cardservice.connection.connect()
connecting to Utimaco CardManUSB 0
>>>
>>> apdu = SELECT+DF_TELECOM
>>> response, sw1, sw2 = cardservice.connection.transmit( apdu )
> A0 A4 00 00 02 7F 10
< [] 6E 0
>>>
>>> if sw1 in range(0x61, 0x6f):
... print "Error: sw1: %x sw2: %x" % (sw1, sw2)
...
Error: sw1: 6e sw2: 0
>>> if sw1 == 0x9F:
... apdu = GET_RESPONSE + [sw2]
... response, sw1, sw2 = cardservice.connection.transmit( apdu )
...
>>> cardservice.connection.disconnect()
disconnecting from Utimaco CardManUSB 0
>>>

Сценарии, написанные таким образом, довольно трудно читать, потому что сообщений об обнаружении ошибок больше, чем передает фактический apdu.
Улучшение видимости заключается в том, чтобы заключить инструкцию передачи внутри функции mytransmit, например:
Code:
>>> from smartcard.CardType import AnyCardType
>>> from smartcard.CardRequest import CardRequest
>>> from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver
>>>
>>> def mytransmit( connection, apdu ):
... response, sw1, sw2 = connection.transmit( apdu )
... if sw1 in range(0x61, 0x6f):
... print "Error: sw1: %x sw2: %x" % (sw1, sw2)
... return response, sw1, sw2
...
>>>
>>> GET_RESPONSE = [0XA0, 0XC0, 00, 00 ]
>>> SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
>>> DF_TELECOM = [0x7F, 0x10]
>>>
>>>
>>> cardtype = AnyCardType()
>>> cardrequest = CardRequest( timeout=10, cardType=cardtype )
>>> cardservice = cardrequest.waitforcard()
>>>
>>> observer=ConsoleCardConnectionObserver()
>>> cardservice.connection.addObserver( observer )
>>>
>>> cardservice.connection.connect()
connecting to Utimaco CardManUSB 0
>>>
>>> apdu = SELECT+DF_TELECOM
>>> response, sw1, sw2 = mytransmit( cardservice.connection, apdu )
> A0 A4 00 00 02 7F 10
< [] 6E 0
Error: sw1: 6e sw2: 0
>>>
>>> if sw1 == 0x9F:
... apdu = GET_RESPONSE + [sw2]
... response, sw1, sw2 = mytransmit( cardservice.connection, apdu )
...
>>> cardservice.connection.disconnect()
disconnecting from Utimaco CardManUSB 0
>>>

Предпочтительным решением для проверки ошибок является использование smarcard.sw.ErrorChecker, как описано в следующем разделе.

Проверка ошибок передачи APDU средствами проверки ошибок
Ошибки слова состояния могут возникать из разных источников. Стандарты ISO7816-4 определяют слова состояния для sw1 в диапазоне от 0x62 до 0x6F и некоторые значения sw2, за исключением 0x66, который зарезервирован для вопросов, связанных с безопасностью. Стандарты ISO7816-8 определяют другие слова состояния, например sw1 = 0x68 и sw2 = 0x83 или 0x84 для ошибок объединения команд. Другие стандарты, такие как Open Platform, определяют дополнительные слова состояния error, например sw1 = 0x94 и sw2 = 0x84.
Предпочтительная стратегия проверки ошибок слова состояния основана на отдельных средствах проверки ошибок (smartcard.sw.ErrorChecker), которые могут быть объединены в цепочку проверки ошибок (smartcars.sw.ErrorCheckingChain).

Средства проверки ошибок
Средство проверки ошибок - это класс, производный от ErrorChecker, который проверяет распознанные условия ошибки sw1, sw2 при вызове и вызывает исключение при обнаружении такого условия. Это показано в следующем примере:
Code:
>>> from smartcard.sw.ISO7816_4ErrorChecker import ISO7816_4ErrorChecker
>>>
>>> errorchecker=ISO7816_4ErrorChecker()
>>> errorchecker( [], 0x90, 0x00 )
>>> errorchecker( [], 0x6A, 0x80 )
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "D:\projects\pyscard-install\factory\python\lib\site-packages\smartcard\sw\ISO7816_4ErrorChecker.py", line 137, in __call__
raise exception( data, sw1, sw2, message )
smartcard.sw.SWExceptions.CheckingErrorException: 'Status word exception: checking error - Incorrect parameters in the data field!'
>>>

Первый вызов средства проверки ошибок не вызывает исключения, поскольку 90 00 не сообщает об ошибках. Однако второй вызов вызывает CheckingErrorException.

Ошибка проверки цепочек
Средства проверки ошибок могут быть объединены в цепочку проверки ошибок. Каждая программа проверки в цепочке вызывается до тех пор, пока не будет выполнено условие ошибки, и в этом случае возникает исключение. Это показано в следующем примере:
Code:
>>> from smartcard.sw.ISO7816_4ErrorChecker import ISO7816_4ErrorChecker
>>> from smartcard.sw.ISO7816_8ErrorChecker import ISO7816_8ErrorChecker
>>> from smartcard.sw.ISO7816_9ErrorChecker import ISO7816_9ErrorChecker
>>>
>>> from smartcard.sw.ErrorCheckingChain import ErrorCheckingChain
>>>
>>> errorchain = []
>>> errorchain=[ ErrorCheckingChain( errorchain, ISO7816_9ErrorChecker() ),
... ErrorCheckingChain( errorchain, ISO7816_8ErrorChecker() ),
... ErrorCheckingChain( errorchain, ISO7816_4ErrorChecker() ) ]
>>>
>>> errorchain[0]( [], 0x90, 0x00 )
>>> errorchain[0]( [], 0x6A, 0x8a )
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "D:\projects\pyscard-install\factory\python\lib\site-packages\smartcard\sw\ErrorCheckingChain.py", line 60,
in __call__
self.strategy( data, sw1, sw2 )
File "D:\projects\pyscard-install\factory\python\lib\site-packages\smartcard\sw\ISO7816_9ErrorChecker.py", line 74, in __call__
raise exception( data, sw1, sw2, message )
smartcard.sw.SWExceptions.CheckingErrorException: 'Status word exception: checking error - DF name already exists!'
>>>

В этом примере создается цепочка проверки ошибок, которая сначала проверяет ошибки iso 7816-9, затем ошибки iso7816-8 и, наконец, ошибки iso7816-4.
Первый вызов цепочки ошибок не вызывает исключения, поскольку 90 00 не сообщает об ошибках. Однако второй вызов вызывает CheckingErrorException, вызванный средством проверки ошибок iso7816-9.

Фильтрация исключений
Вы можете отфильтровать нежелательные исключения в цепочке, добавив отфильтрованное исключение в цепочку проверки ошибок:
Code:
>>> from smartcard.sw.ISO7816_4ErrorChecker import ISO7816_4ErrorChecker
>>> from smartcard.sw.ISO7816_8ErrorChecker import ISO7816_8ErrorChecker
>>> from smartcard.sw.ISO7816_9ErrorChecker import ISO7816_9ErrorChecker
>>>
>>> from smartcard.sw.ErrorCheckingChain import ErrorCheckingChain
>>>
>>> errorchain = []
>>> errorchain=[ ErrorCheckingChain( errorchain, ISO7816_9ErrorChecker() ),
... ErrorCheckingChain( errorchain, ISO7816_8ErrorChecker() ),
... ErrorCheckingChain( errorchain, ISO7816_4ErrorChecker() ) ]
>>>
>>>
>>> errorchain[0]( [], 0x90, 0x00 )
>>> errorchain[0]( [], 0x62, 0x00 )
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "D:\projects\pyscard-install\factory\python\lib\site-packages\smartcard\sw\ErrorCheckingChain.py", line 72, in __call__
return self.next()( data, sw1, sw2 )
File "D:\projects\pyscard-install\factory\python\lib\site-packages\smartcard\sw\ErrorCheckingChain.py", line 72, in __call__
return self.next()( data, sw1, sw2 )
File "D:\projects\pyscard-install\factory\python\lib\site-packages\smartcard\sw\ErrorCheckingChain.py", line 60, in __call__
self.strategy( data, sw1, sw2 )
File "D:\projects\pyscard-install\factory\python\lib\site-packages\smartcard\sw\ISO7816_4ErrorChecker.py", line 137, in __call__
raise exception( data, sw1, sw2, message )
smartcard.sw.SWExceptions.WarningProcessingException: 'Status word exception: warning processing - Response padded/ More APDU commands expected!'
>>>
>>> from smartcard.sw.SWExceptions import WarningProcessingException
>>>
>>> errorchain[0].addFilterException( WarningProcessingException )
>>> errorchain[0]( [], 0x62, 0x00 )
>>>

Первый вызов цепочки ошибок с sw1 sw2 = 62 00 вызывает исключение WarningProcessingException.
Code:
...
>>> errorchain[0]( [], 0x62, 0x00 )
Traceback (most recent call last):
...

После добавления фильтра для WarningProcessingException второй вызов цепочки ошибок с sw1 sw2 = 62 00 не вызывает исключения:
Code:
>>> from smartcard.sw.SWExceptions import WarningProcessingException
>>>
>>> errorchain[0].addFilterException( WarningProcessingException )
>>> errorchain[0]( [], 0x62, 0x00 )
>>>

Полный пример кода
Code:
#! /usr/bin/env python
"""Sample script for APDU error checking.
"""


from __future__ import print_function
from smartcard.CardType import AnyCardType
from smartcard.CardRequest import CardRequest
from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver

from smartcard.sw.ErrorCheckingChain import ErrorCheckingChain
from smartcard.sw.ISO7816_4ErrorChecker import ISO7816_4ErrorChecker
from smartcard.sw.ISO7816_8ErrorChecker import ISO7816_8ErrorChecker
from smartcard.sw.ISO7816_9ErrorChecker import ISO7816_9ErrorChecker
from smartcard.sw.SWExceptions import SWException, WarningProcessingException


# define the apdus used in this script
GET_RESPONSE = [0XA0, 0XC0, 00, 00]
SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
DF_TELECOM = [0x7F, 0x10]


if __name__ == '__main__':

    print('Insert a card within 10 seconds')
    print('Cards without a DF_TELECOM will except')

    # request any card type
    cardtype = AnyCardType()
    cardrequest = CardRequest(timeout=10, cardType=cardtype)
    cardservice = cardrequest.waitforcard()

    # use ISO7816-4 and ISO7816-8 error checking strategy
    # first check iso7816_8 errors, then iso7816_4 errors
    errorchain = []
    errorchain = [ErrorCheckingChain(errorchain, ISO7816_9ErrorChecker())]
    errorchain = [ErrorCheckingChain(errorchain, ISO7816_8ErrorChecker())]
    errorchain = [ErrorCheckingChain(errorchain, ISO7816_4ErrorChecker())]
    cardservice.connection.setErrorCheckingChain(errorchain)

    # filter Warning Processing Exceptions (sw1 = 0x62 or 0x63)
    cardservice.connection.addSWExceptionToFilter(WarningProcessingException)

    # attach the console tracer
    observer = ConsoleCardConnectionObserver()
    cardservice.connection.addObserver(observer)

    # connect to the card and perform a few transmits
    cardservice.connection.connect()

    try:
        apdu = SELECT + DF_TELECOM
        response, sw1, sw2 = cardservice.connection.transmit(apdu)

        if sw1 == 0x9F:
            apdu = GET_RESPONSE + [sw2]
            response, sw1, sw2 = cardservice.connection.transmit(apdu)

    except SWException as e:
        print(str(e))

    cardservice.connection.disconnect()

    import sys
    if 'win32' == sys.platform:
        print('press Enter to continue')
        sys.stdin.read(1)

Обнаружение ошибок APDU ответа для подключения карты
Чтобы обнаружить ошибки ответа APDU во время передачи, просто установите цепочку проверки ошибок соединения, используемого для передачи:
Code:
from smartcard.CardType import AnyCardType
from smartcard.CardRequest import CardRequest
from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver

from smartcard.sw.ErrorCheckingChain import ErrorCheckingChain
from smartcard.sw.ISO7816_4ErrorChecker import ISO7816_4ErrorChecker
from smartcard.sw.ISO7816_8ErrorChecker import ISO7816_8ErrorChecker
from smartcard.sw.SWExceptions import SWException, WarningProcessingException

# request any card
cardtype = AnyCardType()
cardrequest = CardRequest( timeout=10, cardType=cardtype )
cardservice = cardrequest.waitforcard()

# our error checking chain
errorchain=[]
errorchain=[ ErrorCheckingChain( errorchain, ISO7816_8ErrorChecker() ),
             ErrorCheckingChain( errorchain, ISO7816_4ErrorChecker() ) ]
cardservice.connection.setErrorCheckingChain( errorchain )

# a console tracer
observer=ConsoleCardConnectionObserver()
cardservice.connection.addObserver( observer )

# send a few apdus; exceptions will occur upon errors
cardservice.connection.connect()

try:
    SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
    DF_TELECOM = [0x7F, 0x10]
    apdu = SELECT+DF_TELECOM
    response, sw1, sw2 = cardservice.connection.transmit( apdu )
    if sw1 == 0x9F:
        GET_RESPONSE = [0XA0, 0XC0, 00, 00 ]
        apdu = GET_RESPONSE + [sw2]
        response, sw1, sw2 = cardservice.connection.transmit( apdu )
except SWException, e:
    print str(e)

Выполнение предыдущего сценария на SIM-карте приведет к выводу, подобному следующему:
Code:
connecting to SchlumbergerSema Reflex USB v.2 0
> A0 A4 00 00 02 7F 10
< [] 9F 1A
> A0 C0 00 00 1A
< 00 00 00 00 7F 10 02 00 00 00 00 00 0D 13 00 0A 04 00 83 8A 83 8A 00 01 00 00 90 0
disconnecting from SchlumbergerSema Reflex USB v.2 0
disconnecting from SchlumbergerSema Reflex USB v.2 0

тогда как выполнение сценария на не-SIM-карте приведет к:
Code:
connecting to Utimaco CardManUSB 0
> A0 A4 00 00 02 7F 10
< [] 6E 0
'Status word exception: checking error - Class (CLA) not supported!'
disconnecting from Utimaco CardManUSB 0
disconnecting from Utimaco CardManUSB 0

Чтобы реализовать цепочку проверки ошибок, создайте объект ErrorCheckingChain с желаемыми стратегиями проверки ошибок и установите этот объект цепочки как цепочку проверки ошибок подключения карты. Подключение карты будет использовать цепочку для проверки ошибок при получении ответа apdu:

Написание кастомной программы проверки ошибок
Для реализации настраиваемого средства проверки ошибок требуется реализация подкласса op21_ErrorChecker и переопределение метода __call__. Следующая программа проверки ошибок вызывает исключение SecurityRelatedException, когда sw1 = 0x66 и sw2 = 0x00.
Пользовательские средства проверки можно использовать отдельно, как в следующем примере, или связать с другими средствами проверки ошибок.
Code:
#! /usr/bin/env python
"""Sample script for APDU error checking with a custom error checker.
"""

from __future__ import print_function
from smartcard.CardType import AnyCardType
from smartcard.CardRequest import CardRequest
from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver

from smartcard.sw.ErrorCheckingChain import ErrorCheckingChain
from smartcard.sw.ErrorChecker import ErrorChecker
from smartcard.sw.SWExceptions import SWException


class MyErrorChecker(ErrorChecker):
    """Our custom error checker that will except if 0x61<sw1<0x70."""

    def __call__(self, data, sw1, sw2):
        print(sw1, sw2)
        if 0x61 < sw1 and 0x70 > sw1:
            raise SWException(data, sw1, sw2)

# define the apdus used in this script
GET_RESPONSE = [0XA0, 0XC0, 00, 00]
SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
DF_TELECOM = [0x7F, 0x10]

if __name__ == '__main__':

    print('Insert a card within 10 seconds')
    print('Cards without a DF_TELECOM will except')

    # request any card
    cardtype = AnyCardType()
    cardrequest = CardRequest(timeout=10, cardType=cardtype)
    cardservice = cardrequest.waitforcard()

    # our error checking chain
    errorchain = []
    errorchain = [ErrorCheckingChain([], MyErrorChecker())]
    cardservice.connection.setErrorCheckingChain(errorchain)

    # attach the console tracer
    observer = ConsoleCardConnectionObserver()
    cardservice.connection.addObserver(observer)

    # send a few apdus; exceptions will occur upon errors
    cardservice.connection.connect()

    try:
        SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
        DF_TELECOM = [0x7F, 0x10]
        apdu = SELECT + DF_TELECOM
        response, sw1, sw2 = cardservice.connection.transmit(apdu)
        if sw1 == 0x9F:
            GET_RESPONSE = [0XA0, 0XC0, 00, 00]
            apdu = GET_RESPONSE + [sw2]
            response, sw1, sw2 = cardservice.connection.transmit(apdu)
    except SWException as e:
        print(e, "%x %x" % (e.sw1, e.sw2))

        cardservice.connection.disconnect()

    import sys
    if 'win32' == sys.platform:
        print('press Enter to continue')
        sys.stdin.read(1)

Считыватели смарт-карт
Вывод списка устройств чтения смарт-карт

Самый простой способ получить список устройств чтения смарт-карт - это функция smartcard.System.readers ():
Code:
>>> import smartcard.System
>>> print smartcard.System.readers()
['Schlumberger e-gate 0', 'SchlumbergerSema Reflex USB v.2 0', 'Utimaco CardManUSB 0']
>>>

Организация считывателей смарт-карт в группы читателей
Управление группами читателей доступно только в Windows, поскольку PCSC-lite в настоящее время не поддерживает управление группами читателей.
Читатели могут быть организованы в читательские группы. Чтобы получить группы устройств чтения смарт-карт, используйте readergroups ():
Code:
>>> import smartcard.System
>>> print smartcard.System.readergroups()
['SCard$DefaultReaders']
>>>

У объекта readergroups () есть все атрибуты списка. Чтобы добавить группу читателей, просто используйте оператор +, например:
Code:
>>> from smartcard.System import readergroups
>>> g=readergroups()
>>> print g
['SCard$DefaultReaders']
>>> g+='Biometric$Readers'
>>> print g
['SCard$DefaultReaders', 'Biometric$Readers']
>>>

Вы также можете использовать методы добавления и вставки, а также оператор +, например:
Code:
>>> from smartcard.System import readergroups
>>> g=readergroups()
>>> print g
['SCard$DefaultReaders']
>>> g=g+['Biometric$Readers','Pinpad$Readers']
>>> print g
['SCard$DefaultReaders', 'Biometric$Readers', 'Pinpad$Readers']
>>>

или же
Code:
>>> from smartcard.System import readergroups
>>> g=readergroups()
>>> print g
['SCard$DefaultReaders']
>>> g.append('Biometric$Readers')
>>> g.insert(1,'Pinpad$Readers')
>>> print g
['SCard$DefaultReaders', 'Pinpad$Readers', 'Biometric$Readers']
>>>

Группы устройств чтения смарт-карт не сохраняются до тех пор, пока устройство чтения не будет добавлено в группу. Чтобы добавить читателя в группу читателей, используйте addreadertogroups ():
Code:
>>> from smartcard.System import readergroups, addreadertogroups, readers
>>> g=readergroups()
>>> g+='USB$Readers'
>>> addreadertogroups( 'Schlumberger e-gate 0', 'USB$Readers' )
>>> readers( 'USB$Readers')
['Schlumberger e-gate 0']
>>>

Чтобы удалить группу читателей, доступны все операторы списка для управления группами читателей, включая pop () или remove ():
Code:
>>> from smartcard.System import readergroups, addreadertogroups, readers
>>> g=readergroups()
>>> g+='USB$Readers'
>>> print g
['SCard$DefaultReaders', 'USB$Readers']
>>> g.pop(1)
'USB$Readers'
>>> g
['SCard$DefaultReaders']
>>>

или же
Code:
>>> from smartcard.System import readergroups, addreadertogroups, readers
>>> g=readergroups()
>>> g+='USB$Readers'
>>> print g
['SCard$DefaultReaders', 'USB$Readers']
>>> readergroups().remove('USB$Readers')
>>> readergroups()
['SCard$DefaultReaders']
>>>

Мониторинг читателей
Вы можете отслеживать вставку или удаление считывателей с помощью интерфейса ReaderObserver.
Для отслеживания вставки считывателя создайте объект ReaderObserver, реализующий метод update (), который будет вызываться при удалении считывателя / вставки. В следующем примере кода реализуется ReaderObserver, который просто печатает вставленные / удаленные считыватели на стандартный вывод:
Code:
from smartcard.ReaderMonitoring import ReaderObserver

class printobserver( ReaderObserver ):
    """A simple reader observer that is notified
    when readers are added/removed from the system and
    prints the list of readers
    """
    def update( self, observable, (addedreaders, removedreaders) ):
        print "Added readers", addedreaders
        print "Removed readers", removedreaders

Чтобы отслеживать установку / удаление считывателя, просто добавьте наблюдателя в ReaderMonitor:
Code:
#! /usr/bin/env python
"""
Sample script that monitors smartcard readers.
"""

from __future__ import print_function
from time import sleep

from smartcard.ReaderMonitoring import ReaderMonitor, ReaderObserver


class printobserver(ReaderObserver):
    """A simple reader observer that is notified
    when readers are added/removed from the system and
    prints the list of readers
    """

    def update(self, observable, actions):
        (addedreaders, removedreaders) = actions
        print("Added readers", addedreaders)
        print("Removed readers", removedreaders)

if __name__ == '__main__':
    print("Add or remove a smartcard reader to the system.")
    print("This program will exit in 10 seconds")
    print("")
    readermonitor = ReaderMonitor()
    readerobserver = printobserver()
    readermonitor.addObserver(readerobserver)

    sleep(10)

    # don't forget to remove observer, or the
    # monitor will poll forever...
    readermonitor.deleteObserver(readerobserver)

    import sys
    if 'win32' == sys.platform:
        print('press Enter to continue')
        sys.stdin.read(1)


Смарт-карты
Мониторинг смарт-карт

Вы можете контролировать вставку или извлечение карт с помощью интерфейса CardObserver.
Чтобы отслеживать вставку и извлечение карты, создайте объект CardObserver, который реализует метод update (), который будет вызываться при вставке / извлечении карты. В следующем примере кода реализуется CardObserver, который просто печатает вставленные / удаленные карты на стандартный вывод с именем printobserver. Чтобы отслеживать вставку / извлечение карты, просто добавьте обозреватель карты в CardMonitor:
Code:
#! /usr/bin/env python
"""
Sample script that monitors smartcard insertion/removal.
"""

from __future__ import print_function
from time import sleep

from smartcard.CardMonitoring import CardMonitor, CardObserver
from smartcard.util import toHexString


# a simple card observer that prints inserted/removed cards
class PrintObserver(CardObserver):
    """A simple card observer that is notified
    when cards are inserted/removed from the system and
    prints the list of cards
    """

    def update(self, observable, actions):
        (addedcards, removedcards) = actions
        for card in addedcards:
            print("+Inserted: ", toHexString(card.atr))
        for card in removedcards:
            print("-Removed: ", toHexString(card.atr))

if __name__ == '__main__':
    print("Insert or remove a smartcard in the system.")
    print("This program will exit in 10 seconds")
    print("")
    cardmonitor = CardMonitor()
    cardobserver = PrintObserver()
    cardmonitor.addObserver(cardobserver)

    sleep(10)

    # don't forget to remove observer, or the
    # monitor will poll forever...
    cardmonitor.deleteObserver(cardobserver)

    import sys
    if 'win32' == sys.platform:
        print('press Enter to continue')
        sys.stdin.read(1)

Отправка APDU на смарт-карту, полученную в результате мониторинга карты
Метод обновления CardObserver получает два списка объектов Cards: недавно добавленные карты и недавно удаленные карты. Соединение может быть создано с каждым объектом Card из добавленного списка карт для отправки APDUS.
В следующем примере кода реализуется класс CardObserver с именем selectDFTELECOMObserver, который подключается к вставленным картам и передает APDU, в нашем случае SELECT DF_TELECOM.
Чтобы отслеживать вставку карты, подключитесь к вставленным картам и отправьте APDU, создайте экземпляр selectDFTELECOMObserver и добавьте его в CardMonitor:
Code:
#! /usr/bin/env python
"""
Sample script that monitors smartcard insertion/removal and select DF_TELECOM on inserted cards

"""

from __future__ import print_function
from time import sleep

from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver
from smartcard.CardMonitoring import CardMonitor, CardObserver
from smartcard.util import toHexString

# define the apdus used in this script
GET_RESPONSE = [0XA0, 0XC0, 00, 00]
SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
DF_TELECOM = [0x7F, 0x10]


# a simple card observer that tries to select DF_TELECOM on an inserted card
class selectDFTELECOMObserver(CardObserver):
    """A simple card observer that is notified
    when cards are inserted/removed from the system and
    prints the list of cards
    """

    def __init__(self):
        self.observer = ConsoleCardConnectionObserver()

    def update(self, observable, actions):
        (addedcards, removedcards) = actions
        for card in addedcards:
            print("+Inserted: ", toHexString(card.atr))
            card.connection = card.createConnection()
            card.connection.connect()
            card.connection.addObserver(self.observer)
            apdu = SELECT + DF_TELECOM
            response, sw1, sw2 = card.connection.transmit(apdu)
            if sw1 == 0x9F:
                apdu = GET_RESPONSE + [sw2]
                response, sw1, sw2 = card.connection.transmit(apdu)

        for card in removedcards:
            print("-Removed: ", toHexString(card.atr))

if __name__ == '__main__':
    print("Insert or remove a SIM card in the system.")
    print("This program will exit in 60 seconds")
    print("")
    cardmonitor = CardMonitor()
    selectobserver = selectDFTELECOMObserver()
    cardmonitor.addObserver(selectobserver)

    sleep(60)

    # don't forget to remove observer, or the
    # monitor will poll forever...
    cardmonitor.deleteObserver(selectobserver)

    import sys
    if 'win32' == sys.platform:
        print('press Enter to continue')
        sys.stdin.read(1)

Подключения
Подключение к карте и отправка APDU выполняется через объект CardConnection. Объекты CardConnection создаются с помощью CardRequest или CardMonitoring.

Создание соединения из CardRequest
Успешный CardRequest возвращает CardService, соответствующий запрошенной услуге карты для карты, или PassThruCardService, если не требовалась конкретная услуга карты:
Code:
>>> from smartcard.CardType import AnyCardType
>>> from smartcard.CardRequest import CardRequest
>>> from smartcard.util import toHexString
>>>
>>> cardtype = AnyCardType()
>>> cardrequest = CardRequest( timeout=1, cardType=cardtype )
>>> cardservice = cardrequest.waitforcard()
>>>
>>> cardservice.connection.connect()
>>> print toHexString( cardservice.connection.getATR() )
3B 16 94 20 02 01 00 00 0D
>>> print cardservice.connection.getReader()
SchlumbergerSema Reflex USB v.2 0

Каждый CardService имеет атрибут подключения, который является CardConnection для карты.

Создание подключения из CardMonitoring
Метод обновления CardObserver получает кортеж со списком подключенных карт и списком удаленных карт. Чтобы создать CardConnection из объекта карты, используйте метод createConnection () нужной карты:
Code:
class myobserver( CardObserver ):
    def update( self, observable, (addedcards, removedcards) ):
        for card in addedcards:
                print "+Inserted: ", toHexString( card.atr )
                card.connection = card.createConnection()
                card.connection.connect()
                response, sw1, sw2 = card.connection.transmit( SELECT_DF_TELECOM )
                print "%.2x %.2x" % (sw1, sw2)

Полный пример кода
Code:
#! /usr/bin/env python
"""
Sample script that monitors card insertions, connects to cards and transmit an apdu
"""
from __future__ import print_function
from time import sleep

from smartcard.CardMonitoring import CardMonitor, CardObserver
from smartcard.util import *

# replace by your favourite apdu
SELECT_DF_TELECOM = [0xA0, 0xA4, 0x00, 0x00, 0x02, 0x7F, 0x10]


class transmitobserver(CardObserver):
    """A card observer that is notified when cards are inserted/removed
    from the system, connects to cards and SELECT DF_TELECOM """

    def __init__(self):
        self.cards = []

    def update(self, observable, actions):
        (addedcards, removedcards) = actions
        for card in addedcards:
            if card not in self.cards:
                self.cards += [card]
                print("+Inserted: ", toHexString(card.atr))
                card.connection = card.createConnection()
                card.connection.connect()
                response, sw1, sw2 = card.connection.transmit(
                    SELECT_DF_TELECOM)
                print("%.2x %.2x" % (sw1, sw2))

        for card in removedcards:
            print("-Removed: ", toHexString(card.atr))
            if card in self.cards:
                self.cards.remove(card)

if __name__ == '__main__':
    print("Insert or remove a smartcard in the system.")
    print("This program will exit in 100 seconds")
    print("")
    cardmonitor = CardMonitor()
    cardobserver = transmitobserver()
    cardmonitor.addObserver(cardobserver)

    sleep(100)

Декораторы подключения карт
APDU передаются на карту с помощью объекта CardConnection. Иногда бывает полезно прозрачно изменить поведение подключения смарт-карты, например, для автоматического установления безопасного канала или фильтрации и изменения на лету некоторых команд или ответов APDU или ATR смарт-карты. pyscard использует шаблон проектирования декоратора для динамического изменения поведения подключения смарт-карты. CardConnectionDecorator изменяет поведение объекта CardConnection. Например, следующий CardConnectionDecorator перезаписывает метод CardConnection getATR ():
Code:
class FakeATRConnection( CardConnectionDecorator ):
    '''This decorator changes the fist byte of the ATR.'''
    def __init__( self, cardconnection ):
        CardConnectionDecorator.__init__( self, cardconnection )

    def getATR( self ):
        """Replace first BYTE of ATR by 3F"""
        atr = CardConnectionDecorator.getATR( self )
        return [ 0x3f ] + atr [1:]

Чтобы применить декоратор, просто создайте декоратор вокруг экземпляра CardConnection, чтобы обернуть его и использовать декоратор вместо объекта подключения карты:
Code:
# request any card type
cardtype = AnyCardType()
cardrequest = CardRequest( timeout=1.5, cardType=cardtype )
cardservice = cardrequest.waitforcard()

# attach the console tracer
observer=ConsoleCardConnectionObserver()
cardservice.connection.addObserver( observer )

# attach our decorator
cardservice.connection = FakeATRConnection( cardservice.connection )

# connect to the card and perform a few transmits
cardservice.connection.connect()

print 'ATR', toHexString( cardservice.connection.getATR() )

Декораторы могут быть вложенными. Например, чтобы вложить FakeATRConnection в SecureChannelConnection, используйте следующую конструкцию:
Code:
# attach our decorator
FakeATRConnection( SecureChannelConnection( cardservice.connection ) )

# connect to the card and perform a few transmits
cardservice.connection.connect()

print 'ATR', toHexString( cardservice.connection.getATR() )

Полный пример кода:
Code:
#! /usr/bin/env python
"""
Sample script that illustrates card connection decorators.
"""
from __future__ import print_function
from smartcard.CardType import AnyCardType
from smartcard.CardRequest import CardRequest
from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver
from smartcard.CardConnectionDecorator import CardConnectionDecorator
from smartcard.util import toHexString

# define two custom CardConnectionDecorator
# the decorators are very simple, just to illustrate
# shortly how several decorators can be added to the
# card connection


class SecureChannelConnection(CardConnectionDecorator):
    '''This decorator is a mockup of secure channel connection.
    It merely pretends to cypher/uncypher upon apdu transmission.'''

    def __init__(self, cardconnection):
        CardConnectionDecorator.__init__(self, cardconnection)

    def cypher(self, bytes):
        '''Cypher mock-up; you would include the secure channel logics here.'''
        print('cyphering', toHexString(bytes))
        return bytes

    def uncypher(self, data):
        '''Uncypher mock-up;
        you would include the secure channel logics here.'''
        print('uncyphering', toHexString(data))
        return data

    def transmit(self, bytes, protocol=None):
        """Cypher/uncypher APDUs before transmission"""
        cypheredbytes = self.cypher(bytes)
        data, sw1, sw2 = CardConnectionDecorator.transmit(
            self, cypheredbytes, protocol)
        if [] != data:
            data = self.uncypher(data)
        return data, sw1, sw2


class FakeATRConnection(CardConnectionDecorator):
    '''This decorator changes the fist byte of the ATR. This is just an example
    to show that decorators can be nested.'''

    def __init__(self, cardconnection):
        CardConnectionDecorator.__init__(self, cardconnection)

    def getATR(self):
        """Replace first BYTE of ATR by 3F"""
        atr = CardConnectionDecorator.getATR(self)
        return [0x3f] + atr[1:]


# define the apdus used in this script
GET_RESPONSE = [0XA0, 0XC0, 00, 00]
SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
DF_TELECOM = [0x7F, 0x10]


# request any card type
cardtype = AnyCardType()
cardrequest = CardRequest(timeout=1.5, cardType=cardtype)
cardservice = cardrequest.waitforcard()

# attach the console tracer
observer = ConsoleCardConnectionObserver()
cardservice.connection.addObserver(observer)

# attach our decorator
cardservice.connection = FakeATRConnection(
    SecureChannelConnection(cardservice.connection))

# connect to the card and perform a few transmits
cardservice.connection.connect()

print('ATR', toHexString(cardservice.connection.getATR()))

apdu = SELECT + DF_TELECOM
response, sw1, sw2 = cardservice.connection.transmit(apdu)

if sw1 == 0x9F:
    apdu = GET_RESPONSE + [sw2]
    response, sw1, sw2 = cardservice.connection.transmit(apdu)


import sys
if 'win32' == sys.platform:
    print('press Enter to continue')
    sys.stdin.read(1)

Эксклюзивный декоратор подключения карт
Объект ExclusiveConnectCardConnection выполняет монопольное соединение с картой, т.е. никакой другой поток или процесс не сможет подключиться к карте. С помощью считывателей PCSC это делается путем выполнения SCardConnect с атрибутом SCARD_SHARE_EXCLUSIVE.
Code:
from smartcard.CardType import AnyCardType
from smartcard.CardRequest import CardRequest
from smartcard.CardConnection import CardConnection
from smartcard.util import toHexString

from smartcard.ExclusiveConnectCardConnection import ExclusiveConnectCardConnection

# request any card type
cardtype = AnyCardType()
cardrequest = CardRequest( timeout=5, cardType=cardtype )
cardservice = cardrequest.waitforcard()

# attach our decorator
cardservice.connection = ExclusiveConnectCardConnection( cardservice.connection )

# connect to the card and perform a few transmits
cardservice.connection.connect()

print 'ATR', toHexString( cardservice.connection.getATR() )

Эксклюзивный декоратор подключения карты передачи
ExclusiveTransmitCardConnection выполняет эксклюзивную транзакцию с картой, то есть серию передач, которые не могут быть прерваны передачами других потоков. Для этого включите желаемые передачи между вызовами методов lock () и unlock () в ExclusiveTransmitCardConnection:
Code:
#! /usr/bin/env python
"""
Sample script that illustrates exclusive card connection decorators.
"""
from __future__ import print_function
from smartcard.CardType import AnyCardType
from smartcard.CardRequest import CardRequest
from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver
from smartcard.util import toHexString

from smartcard.ExclusiveConnectCardConnection import \
    ExclusiveConnectCardConnection
from smartcard.ExclusiveTransmitCardConnection import \
    ExclusiveTransmitCardConnection


# define the apdus used in this script
GET_RESPONSE = [0XA0, 0XC0, 00, 00]
SELECT = [0xA0, 0xA4, 0x00, 0x00, 0x02]
DF_TELECOM = [0x7F, 0x10]

# request any card type
cardtype = AnyCardType()
cardrequest = CardRequest(timeout=5, cardType=cardtype)
cardservice = cardrequest.waitforcard()

# attach the console tracer
observer = ConsoleCardConnectionObserver()
cardservice.connection.addObserver(observer)

# attach our decorator
cardservice.connection = ExclusiveTransmitCardConnection(
    ExclusiveConnectCardConnection(cardservice.connection))

# connect to the card and perform a few transmits
cardservice.connection.connect()

print('ATR', toHexString(cardservice.connection.getATR()))

try:
    # lock for initiating transaction
    cardservice.connection.lock()

    apdu = SELECT + DF_TELECOM
    response, sw1, sw2 = cardservice.connection.transmit(apdu)

    if sw1 == 0x9F:
        apdu = GET_RESPONSE + [sw2]
        response, sw1, sw2 = cardservice.connection.transmit(apdu)
finally:
    # unlock connection at the end of the transaction
    cardservice.connection.unlock()

import sys
if 'win32' == sys.platform:
    print('press Enter to continue')
    sys.stdin.read(1)

Декоратор подключения карты защищенного канала
Другой пример применения декораторов CardConnection - реализация безопасного канала. Следующий пример представляет собой шаблонный декоратор CardConnection для защищенного канала, где каждый APDU команды зашифрован, а каждый APDU ответа не зашифрован:
Code:
class SecureChannelConnection( CardConnectionDecorator ):
    '''This decorator is a mockup of secure channel connection.
    It merely pretends to cypher/uncypher upon apdu transmission.'''
    def __init__( self, cardconnection ):
        CardConnectionDecorator.__init__( self, cardconnection )

    def cypher( self, bytes ):
        '''Cypher mock-up; you would include the secure channel logics here.'''
        print 'cyphering', toHexString( bytes )
        return bytes

    def uncypher( self, data ):
        '''Uncypher mock-up; you would include the secure channel logics here.'''
        print 'uncyphering', toHexString( data )
        return data

    def transmit
      
      
      
      
            )
        return data, sw1, sw2

Несколько слов о криптографии
Смарт-карты - это защитные устройства. В результате для приложений смарт-карт обычно требуется какая-то криптография, например, для установления безопасного канала со смарт-картой. Одним из эталонных криптографических модулей для Python является pycrypto, набор криптографических инструментов Python. В этом разделе кратко показаны основы pycrypto, чтобы вы могли быстро начать включать криптографию в приложения для смарт-карт Python.

Двоичные строки и список байтов
pycrypto обрабатывает двоичные строки, то есть строки Python, содержащие символы, такие как '01427023', тогда как pyscard обрабатывает APDU как список байтов, например [0x01, 0x42, 0x70, 0x23]. Служебная функция HexListToBinString и BinStringToHexList (и их версии с короткими именами hl2bs и bs2hl) обеспечивают преобразование между двумя типами.
Code:
from smartcard.util import HexListToBinString, BinStringToHexList

test_data = [ 0x01, 0x42, 0x70, 0x23 ]
binstring = HexListToBinString( test_data )
hexlist = BinStringToHexList( binstring )
print binstring, hexlist

pycrypto поддерживает следующие алгоритмы хеширования: SHA-1, MD2, MD4 и MD5. Чтобы хешировать 16 байтов данных с помощью SHA-1:
Code:
from Crypto.Hash import SHA

from smartcard.util import toHexString, PACK

test_data = [ 0x01, 0x42, 0x70, 0x23 ]
binstring = HexListToBinString( test_data )

zhash = SHA.new( binstring )
hash_as_string = zhash.digest()[:16]
hash_as_bytes = BinStringToHexList( hash_as_string )
print hash_as_string, ',', toHexString( hash_as_bytes, PACK )

Чтобы выполнить хеширование MD5, просто замените SHA на MD5 в предыдущем скрипте.

Криптография с секретным ключом
pycrypto поддерживает несколько алгоритмов секретных ключей, таких как DES, тройной DES, AES, blowfish или IDEA. Чтобы выполнить тройное шифрование DES в режиме ECB:
Code:
from Crypto.Cipher import DES3

from smartcard.util import toBytes

key = "31323334353637383132333435363738"
key_as_binstring = HexListToBinString( toBytes( key ) )
zdes = DES3.new( key_as_binstring, DES3.MODE_ECB )

message = "71727374757677787172737475767778"
message_as_binstring = HexListToBinString( toBytes( message ) )

encrypted_as_string = zdes.encrypt( message_as_binstring )
decrypted_as_string = zdes.decrypt( encrypted_as_string )
print message_as_binstring, encrypted_as_string, decrypted_as_string
 

Carder

Professional
Messages
2,619
Reputation
9
Reaction score
1,699
Points
113
Спасибо большое за руководство, очень интересная информация, обязательно буду пробовать.
 
Top