pyscard smartcard framework samples — pyscard 1.9.0 documentation

# pyscard smartcard framework samples

pyscard is a python module adding smart cards support to python.

It consists of smartcard.scard, an extension module wrapping Windows smart card base components (also known as PCSC), and smartcard, a python framework library hiding PCSC complexity.

## Display the ATR of inserted cards

    #! /usr/bin/env python
    """
    Sample script that displays the ATR of inserted cards.

    __author__ = "http://www.gemalto.com"

    Copyright 2001-2012 gemalto
    Author: Jean-Daniel Aussel, mailto:jean-daniel.aussel@gemalto.com
    Copyright 2010 Ludovic Rousseau
    Author: Ludovic Rousseau, mailto:ludovic.rousseau@free.fr

    This file is part of pyscard.

    pyscard is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 2.1 of the License, or
    (at your option) any later version.

    pyscard is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with pyscard; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    """
    from __future__ import print_function
    from smartcard.Exceptions import NoCardException
    from smartcard.System import readers
    from smartcard.util import toHexString

    for reader in readers():
        try:
            connection = reader.createConnection()
            connection.connect()
            print(reader, toHexString(connection.getATR()))
        except NoCardException:
            print(reader, 'no card inserted')

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

## Selecting the DF_TELECOM of a card

    #! /usr/bin/env python
    """
    Sample script that tries to select the DF_TELECOM on all inserted cards.

    __author__ = "http://www.gemalto.com"

    Copyright 2001-2012 gemalto
    Author: Jean-Daniel Aussel, mailto:jean-daniel.aussel@gemalto.com
    Copyright 2010 Ludovic Rousseau
    Author: Ludovic Rousseau, mailto:ludovic.rousseau@free.fr

    This file is part of pyscard.

    pyscard is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 2.1 of the License, or
    (at your option) any later version.

    pyscard is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with pyscard; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    """
    from __future__ import print_function
    from smartcard.CardType import AnyCardType
    from smartcard.CardRequest import CardRequest
    from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver
    from smartcard.Exceptions import CardRequestTimeoutException

    # 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()

    try:
        # request card insertion
        print('insert a card (SIM card if possible) within 10s')
        cardrequest = CardRequest(timeout=10, cardType=cardtype)
        cardservice = cardrequest.waitforcard()

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

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

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

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

        else:
            print('no DF_TELECOM')

    except CardRequestTimeoutException:
        print('time-out: no card inserted during last 10s')

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

## A simple apdu tracer and interpreter

    #! /usr/bin/env python
    """
    Sample script that defines a custom card connection observer.

    __author__ = "http://www.gemalto.com"

    Copyright 2001-2012 gemalto
    Author: Jean-Daniel Aussel, mailto:jean-daniel.aussel@gemalto.com

    This file is part of pyscard.

    pyscard is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 2.1 of the License, or
    (at your option) any later version.

    pyscard is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with pyscard; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    """
    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)

## Tracing connection events

    #! /usr/bin/env python
    """
    Sample script that monitors card connection events.

    __author__ = "http://www.gemalto.com"

    Copyright 2001-2012 gemalto
    Author: Jean-Daniel Aussel, mailto:jean-daniel.aussel@gemalto.com

    This file is part of pyscard.

    pyscard is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 2.1 of the License, or
    (at your option) any later version.

    pyscard is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with pyscard; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    """
    from __future__ import print_function
    from smartcard.CardType import AnyCardType
    from smartcard.CardRequest import CardRequest
    from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver

    # 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)

    # connect to the card and perform a few transmits
    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)

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

## Decorating Card Connections to add custom behavior

    #! /usr/bin/env python
    """
    Sample script that illustrates card connection decorators.

    __author__ = "http://www.gemalto.com"

    Copyright 2001-2012 gemalto
    Author: Jean-Daniel Aussel, mailto:jean-daniel.aussel@gemalto.com

    This file is part of pyscard.

    pyscard is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 2.1 of the License, or
    (at your option) any later version.

    pyscard is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with pyscard; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    """
    from __future__ import print_function
    from smartcard.CardType import AnyCardType
    from smartcard.CardRequest import CardRequest
    from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver
    from smartcard.CardConnection import CardConnection
    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)

## Detecting response apdu errors

    #! /usr/bin/env python
    """Sample script for APDU error checking.

    __author__ = "http://www.gemalto.com"

    Copyright 2001-2012 gemalto
    Author: Jean-Daniel Aussel, mailto:jean-daniel.aussel@gemalto.com

    This file is part of pyscard.

    pyscard is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 2.1 of the License, or
    (at your option) any later version.

    pyscard is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with pyscard; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    """

    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)

## Implementing a custom ErrorChecker

    #! /usr/bin/env python
    """Sample script for APDU error checking with a custom error checker.

    __author__ = "http://www.gemalto.com"

    Copyright 2001-2012 gemalto
    Author: Jean-Daniel Aussel, mailto:jean-daniel.aussel@gemalto.com

    This file is part of pyscard.

    pyscard is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 2.1 of the License, or
    (at your option) any later version.

    pyscard is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with pyscard; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    """

    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)

## Implementing a custom card type

    #! /usr/bin/env python
    """
    Sample script that demonstrates how to create a custom CardType.

    __author__ = "http://www.gemalto.com"

    Copyright 2001-2012 gemalto
    Author: Jean-Daniel Aussel, mailto:jean-daniel.aussel@gemalto.com

    This file is part of pyscard.

    pyscard is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 2.1 of the License, or
    (at your option) any later version.

    pyscard is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with pyscard; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    """
    from __future__ import print_function
    from smartcard.CardType import CardType
    from smartcard.CardRequest import CardRequest
    from smartcard.util import toHexString

    class DCCardType(CardType):
    # define our custom CardType
    # this card type defines direct convention card (first atr byte equal to 0x3b)

        def matches(self, atr, reader=None):
            return atr[0] == 0x3B

    # request a direct convention card
    cardtype = DCCardType()
    cardrequest = CardRequest(timeout=1, cardType=cardtype)
    cardservice = cardrequest.waitforcard()

    # connect and print atr and reader
    cardservice.connection.connect()
    print(toHexString(cardservice.connection.getATR()))
    print(cardservice.connection.getReader())

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

## Monitoring smartcard readers

    #! /usr/bin/env python
    """
    Sample script that monitors smartcard readers.

    __author__ = "http://www.gemalto.com"

    Copyright 2001-2012 gemalto
    Author: Jean-Daniel Aussel, mailto:jean-daniel.aussel@gemalto.com

    This file is part of pyscard.

    pyscard is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 2.1 of the License, or
    (at your option) any later version.

    pyscard is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with pyscard; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    """

    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)

## Monitoring smartcard insertion/removal

    #! /usr/bin/env python
    """
    Sample script that monitors smartcard insertion/removal.

    __author__ = "http://www.gemalto.com"

    Copyright 2001-2012 gemalto
    Author: Jean-Daniel Aussel, mailto:jean-daniel.aussel@gemalto.com

    This file is part of pyscard.

    pyscard is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 2.1 of the License, or
    (at your option) any later version.

    pyscard is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with pyscard; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    """

    from __future__ import print_function
    from time import sleep

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

    # 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/ATR byte to string utilities

    #! /usr/bin/env python
    """
    Sample script to illustrate toHexString() utility method

    __author__ = "http://www.gemalto.com"

    Copyright 2001-2012 gemalto
    Author: Jean-Daniel Aussel, mailto:jean-daniel.aussel@gemalto.com

    This file is part of pyscard.

    pyscard is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation; either version 2.1 of the License, or
    (at your option) any later version.

    pyscard is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with pyscard; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    """

    from __future__ import print_function
    from smartcard.util import *

    print(40 * '-')
    bytes = [59, 101, 0, 0, 156, 17, 1, 1, 3]
    print('bytes = [59, 101, 0, 0, 156, 17, 1, 1, 3]')
    print('toHexString(bytes) =', toHexString(bytes))
    print('toHexString(bytes, COMMA) =', toHexString(bytes, COMMA))
    print('toHexString(bytes, PACK) =', toHexString(bytes, PACK))
    print('toHexString(bytes, HEX) =', toHexString(bytes, HEX))
    print('toHexString(bytes, HEX | COMMA) =', toHexString(bytes, HEX | COMMA))
    print('toHexString(bytes, HEX | UPPERCASE) =',
        toHexString(bytes, HEX | UPPERCASE))
    print('toHexString(bytes, HEX | UPPERCASE | COMMA) =',
        toHexString(bytes, HEX | UPPERCASE | COMMA))

    print(40 * '-')
    bytes = [0x3B, 0x65, 0x00, 0x00, 0x9C, 0x11, 0x01, 0x01, 0x03]
    print('bytes = [ 0x3B, 0x65, 0x00, 0x00, 0x9C, 0x11, 0x01, 0x01, 0x03 ]')
    print('toHexString(bytes, COMMA) =', toHexString(bytes, COMMA))
    print('toHexString(bytes) =', toHexString(bytes))
    print('toHexString(bytes, PACK) =', toHexString(bytes, PACK))
    print('toHexString(bytes, HEX) =', toHexString(bytes, HEX))
    print('toHexString(bytes, HEX | COMMA) =', toHexString(bytes, HEX | COMMA))
    print('toHexString(bytes, HEX | UPPERCASE) =',
        toHexString(bytes, HEX | UPPERCASE))
    print('toHexString(bytes, HEX | UPPERCASE | COMMA) =',
        toHexString(bytes, HEX | UPPERCASE | COMMA))

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