Esempio n. 1
0
 def testcase_ATR3(self):
     """Simera 3.13."""
     a = ATR([0x3B, 0x16, 0x18, 0x20, 0x02, 0x01, 0x00, 0x80, 0x0D])
     historicalbytes = [0x20, 0x02, 0x01, 0x00, 0x80, 0x0D]
     self.assertEqual(a.getHistoricalBytes(), historicalbytes)
     self.assertEqual(a.getChecksum(), None)
     self.assertTrue(a.isT0Supported())
     self.assertTrue(not a.isT1Supported())
     self.assertTrue(not a.isT15Supported())
Esempio n. 2
0
 def testcase_ATR2(self):
     """Palmera Protect V2."""
     a = ATR([0x3B, 0x65, 0x00, 0x00, 0x9C, 0x02, 0x02, 0x01, 0x02])
     historicalbytes = [0x9C, 0x02, 0x02, 0x01, 0x02]
     self.assertEquals(a.getHistoricalBytes(), historicalbytes)
     self.assertEquals(a.getChecksum(), None)
     self.assert_(a.isT0Supported())
     self.assert_(not a.isT1Supported())
     self.assert_(not a.isT15Supported())
Esempio n. 3
0
 def testcase_ATR2(self):
     """Palmera Protect V2."""
     a = ATR([0x3B, 0x65, 0x00, 0x00, 0x9C, 0x02, 0x02, 0x01, 0x02])
     historicalbytes = [0x9C, 0x02, 0x02, 0x01, 0x02]
     self.assertEqual(a.getHistoricalBytes(), historicalbytes)
     self.assertEqual(a.getChecksum(), None)
     self.assertTrue(a.isT0Supported())
     self.assertTrue(not a.isT1Supported())
     self.assertTrue(not a.isT15Supported())
Esempio n. 4
0
 def testcase_ATR5(self):
     """Demo Vitale online IGEA340"""
     a = ATR([0x3F, 0x65, 0x25, 0x00, 0x52, 0x09, 0x6A, 0x90, 0x00])
     historicalbytes = [0x52, 0x09, 0x6A, 0x90, 0x00]
     self.assertEqual(a.getHistoricalBytes(), historicalbytes)
     self.assertEqual(a.getChecksum(), None)
     self.assertTrue(a.isT0Supported())
     self.assertTrue(not a.isT1Supported())
     self.assertTrue(not a.isT15Supported())
Esempio n. 5
0
 def testcase_ATR3(self):
     """Simera 3.13."""
     a = ATR([0x3B, 0x16, 0x18, 0x20, 0x02, 0x01, 0x00, 0x80, 0x0D])
     historicalbytes = [0x20, 0x02, 0x01, 0x00, 0x80, 0x0D]
     self.assertEquals(a.getHistoricalBytes(), historicalbytes)
     self.assertEquals(a.getChecksum(), None)
     self.assert_(a.isT0Supported())
     self.assert_(not a.isT1Supported())
     self.assert_(not a.isT15Supported())
Esempio n. 6
0
 def testcase_ATR5(self):
     """Demo Vitale online IGEA340"""
     a = ATR([0x3F, 0x65, 0x25, 0x00, 0x52, 0x09, 0x6A, 0x90, 0x00])
     historicalbytes = [0x52, 0x09, 0x6A, 0x90, 0x00]
     self.assertEquals(a.getHistoricalBytes(), historicalbytes)
     self.assertEquals(a.getChecksum(), None)
     self.assert_(a.isT0Supported())
     self.assert_(not a.isT1Supported())
     self.assert_(not a.isT15Supported())
Esempio n. 7
0
 def testcase_ATR4(self):
     """SIMRock'n Tree"""
     a = ATR([0x3B, 0x77, 0x94, 0x00, 0x00, 0x82, 0x30, 0x00, 0x13,
         0x6C, 0x9F, 0x22])
     historicalbytes = [0x82, 0x30, 0x00, 0x13, 0x6C, 0x9F, 0x22]
     self.assertEquals(a.getHistoricalBytes(), historicalbytes)
     self.assertEquals(a.getChecksum(), None)
     self.assert_(a.isT0Supported())
     self.assert_(not a.isT1Supported())
     self.assert_(not a.isT15Supported())
Esempio n. 8
0
def translate_atr(atr):
	
	atr = ATR(atr)
	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()
Esempio n. 9
0
 def testcase_ATR4(self):
     """SIMRock'n Tree"""
     a = ATR([0x3B, 0x77, 0x94, 0x00, 0x00, 0x82, 0x30, 0x00, 0x13,
         0x6C, 0x9F, 0x22])
     historicalbytes = [0x82, 0x30, 0x00, 0x13, 0x6C, 0x9F, 0x22]
     self.assertEqual(a.getHistoricalBytes(), historicalbytes)
     self.assertEqual(a.getChecksum(), None)
     self.assertTrue(a.isT0Supported())
     self.assertTrue(not a.isT1Supported())
     self.assertTrue(not a.isT15Supported())
Esempio n. 10
0
def getinfo(connection: CardConnectionDecorator) -> dict:
    atr = ATR(connection.getATR())
    hb = toHexString(atr.getHistoricalBytes())
    cardname = hb[-17:-12]
    name = cardnameMap.get(cardname, "Unknown " + str(cardname))
    return {
        "Name": name,
        "T0": atr.isT0Supported(),
        "T1": atr.isT1Supported(),
        "T15": atr.isT15Supported()
    }
Esempio n. 11
0
 def testcase_ATR1(self):
     """Usimera Classic 2."""
     a = ATR([0x3B, 0x9E, 0x95, 0x80, 0x1F, 0xC3, 0x80, 0x31, 0xA0, 0x73,
         0xBE, 0x21, 0x13, 0x67, 0x29, 0x02, 0x01, 0x01, 0x81, 0xCD, 0xB9])
     historicalbytes = [0x80, 0x31, 0xA0, 0x73, 0xBE, 0x21, 0x13, 0x67,
         0x29, 0x02, 0x01, 0x01, 0x81, 0xCD]
     self.assertEqual(a.getHistoricalBytes(), historicalbytes)
     self.assertEqual(a.getChecksum(), 0xB9)
     self.assertTrue(a.checksumOK)
     self.assertTrue(a.isT0Supported())
     self.assertTrue(not a.isT1Supported())
     self.assertTrue(a.isT15Supported())
Esempio n. 12
0
 def testcase_ATR1(self):
     """Usimera Classic 2."""
     a = ATR([0x3B, 0x9E, 0x95, 0x80, 0x1F, 0xC3, 0x80, 0x31, 0xA0, 0x73,
         0xBE, 0x21, 0x13, 0x67, 0x29, 0x02, 0x01, 0x01, 0x81, 0xCD, 0xB9])
     historicalbytes = [0x80, 0x31, 0xA0, 0x73, 0xBE, 0x21, 0x13, 0x67,
         0x29, 0x02, 0x01, 0x01, 0x81, 0xCD]
     self.assertEquals(a.getHistoricalBytes(), historicalbytes)
     self.assertEquals(a.getChecksum(), 0xB9)
     self.assert_(a.checksumOK)
     self.assert_(a.isT0Supported())
     self.assert_(not a.isT1Supported())
     self.assert_(a.isT15Supported())
Esempio n. 13
0
def getATR():

    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())
Esempio n. 14
0
 def testcase_ATR7(self):
     """Protect V3 T=1"""
     a = ATR([0x3B, 0xE5, 0x00, 0x00, 0x81, 0x21, 0x45, 0x9C, 0x10,
         0x01, 0x00, 0x80, 0x0D])
     historicalbytes = [0x9C, 0x10, 0x01, 0x00, 0x80]
     self.assertEqual(a.getHistoricalBytes(), historicalbytes)
     self.assertEqual(a.getChecksum(), 0x0D)
     self.assertTrue(not a.isT0Supported())
     self.assertTrue(a.isT1Supported())
     self.assertTrue(not a.isT15Supported())
     self.assertTrue(a.checksumOK)
     self.assertTrue(a.getTB1() == 0x00)
     self.assertTrue(a.getTC1() == 0x00)
     self.assertTrue(a.getTD1() == 0x81)
     self.assertTrue(a.TD[2 - 1] == 0x21)  # TD2
     self.assertTrue(a.TB[3 - 1] == 0x45)  # TB3
Esempio n. 15
0
 def testcase_ATR7(self):
     """Protect V3 T=1"""
     a = ATR([0x3B, 0xE5, 0x00, 0x00, 0x81, 0x21, 0x45, 0x9C, 0x10,
         0x01, 0x00, 0x80, 0x0D])
     historicalbytes = [0x9C, 0x10, 0x01, 0x00, 0x80]
     self.assertEquals(a.getHistoricalBytes(), historicalbytes)
     self.assertEquals(a.getChecksum(), 0x0D)
     self.assert_(not a.isT0Supported())
     self.assert_(a.isT1Supported())
     self.assert_(not a.isT15Supported())
     self.assert_(a.checksumOK)
     self.assert_(a.getTB1() == 0x00)
     self.assert_(a.getTC1() == 0x00)
     self.assert_(a.getTD1() == 0x81)
     self.assert_(a.TD[2 - 1] == 0x21) # TD2
     self.assert_(a.TB[3 - 1] == 0x45) # TB3
Esempio n. 16
0
def info():
    global connection

    recognized_cards = {
        '00 01': 'MIFARE Classic 1K',
        '00 02': 'MIFARE Classic 4K',
        '00 03': 'MIFARE Ultralight',
        '00 26': 'MIFARE Mini',
        'F0 04': 'Topaz and Jewel',
        'F0 11': 'FeliCa 212K/424K'
    }

    if connection:
        print('[*] Tag Information\n')

        atr = ATR(connection.getATR())
        hb = toHexString(atr.getHistoricalBytes())
        name_key = hb[-17:-12]
        card_name = recognized_cards.get(name_key, 'Unknown')
        print('[+] Card Name:  ', card_name)
        print('[+] T0 Support: ', atr.isT0Supported())
        print('[+] T1 Support: ', atr.isT1Supported())
        print('[+] T15 Support:', atr.isT15Supported())
Esempio n. 17
0
def main():
    global ATRS
    get_smartcards_list()
    cardtype = AnyCardType()
    while True:
        cardrequest = CardRequest(timeout=120, cardType=cardtype)
        cardservice = cardrequest.waitforcard()
        cardservice.connection.connect()
        atrBytes = cardservice.connection.getATR()
        atr = ATR(atrBytes)
        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())
        if (ATRS[toHexString(atrBytes)]):
            print(ATRS[toHexString(atrBytes)])
        print(cardservice.connection)
        send(cardservice.connection)
        sleep(5)
    return 0
Esempio n. 18
0
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 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()
Esempio n. 19
0
from smartcard.CardRequest import CardRequest
from smartcard.util import toHexString
from smartcard.ATR import ATR

card_type = AnyCardType()
card_request = CardRequest(timeout=1, cardType=card_type)
card_service = card_request.waitforcard()

card_service.connection.connect()
atr = ATR(card_service.connection.getATR())
print('------- SMART CARD INFO -------')
print(toHexString(card_service.connection.getATR()))
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())
print('-------------------------------')

GET = [0xFF, 0xCA, 0x00, 0x00, 0x00]
DF_TELECOM = [0xFF, 0xB0, 0x00, 0x04, 0x04]
AUTH_KEY = [0xFF, 0x82, 0x00, 0x00, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]


def trace_command(apdu):
    print('sending ', toHexString(apdu))


def trace_response(response, sw1, sw2):
    if response is None:
Esempio n. 20
0

## Include all library elements:
from smartcard.CardType import ATRCardType
from smartcard.ATR import ATR
from smartcard.CardConnection import CardConnection
from smartcard.CardRequest import CardRequest
from smartcard.util import toHexString, toBytes, toASCIIString, bs2hl
## Import an AES algorithm for checking the results:
import Crypto.Cipher.AES

## Here, we define the card type which we want to
## listen to:
cardtype = ATRCardType( toBytes( "3B 90 11 00" ) )
atr = ATR( toBytes( "3B 90 11 00" ) )
if not atr.isT0Supported():
  print "Error: Card does not support T0 protocol."
#fi

cardrequest = CardRequest( timeout=5, cardType=cardtype )

## Wait for the card to be present:
## In case the card is in the reader, this command will return immediately.
cardservice = cardrequest.waitforcard()

## Connect to the card using T0 protocol.
cardservice.connection.connect( CardConnection.T0_protocol )

## Print the Answer To Reset (ATR), which should be: 3B 90 11 00
print toHexString( cardservice.connection.getATR() )
Esempio n. 21
0
        print "###Tag Info###"
        atr = ATR(connection.getATR())
        hb = toHexString(atr.getHistoricalBytes())
        cardname = hb[-17:-12]
        cardnameMap = {
            "00 01": "MIFARE Classic 1K",
            "00 02": "MIFARE Classic 4K",
            "00 03": "MIFARE Ultralight",
            "00 26": "MIFARE Mini",
            "F0 04": "Topaz and Jewel",
            "F0 11": "FeliCa 212K",
            "F0 11": "FeliCa 424K"
        }
        name = cardnameMap.get(cardname, "unknown")
        print "Card Name: "+ name
        print "T0 supported: ", atr.isT0Supported()
        print "T1 supported: ", atr.isT1Supported()
        print "T15 suppoerted: ", atr.isT15Supported()

    elif COMMAND == "loadkey":
        if (len(sys.argv) < 3):
            print "usage: python nfctool.py loadkey <key>"
            print "ex) python nfctool.py loadkey FFFFFFFFFFFF"
            sys.exit()

        COMMAND = [0xFF, 0x82, 0x00, 0x00, 0x06]
        key = [sys.argv[2][0:2], sys.argv[2][2:4], sys.argv[2][4:6], sys.argv[2][6:8], sys.argv[2][8:10], sys.argv[2][10:12]]
        for i in range(6):
            key[i] = int(key[i], 16)
        COMMAND.extend(key)
Esempio n. 22
0
class AcsReader(PcscReader):
    def __init__(self, reader):
        PcscReader.__init__(self, reader)
        self.pn532 = Pn532(self)

    def open(self):
        PcscReader.open(self)

        # We could pass this into connect, but this is clearer
        self.atr = ATR(self.conn.getATR())
        if DEBUG:
            print 'ATR: %s' % self.atr
            self.atr.dump()

        if not self.atr.isT0Supported():
            self.close()
            raise CardConnectionException('Reader reports T0 protocol not supported')

        if DEBUG:
            print 'Firmware version %s' % self.firmware_version()

        self.pn532.set_retries(0, 0, 0)

    def send(self, apdu):
        resp, sw1, sw2 = self.conn.transmit(list(apdu))
        return resp, sw1, sw2


    def firmware_version(self):
        apdu = APDU(0xff, 0, 0x48)
        resp, sw1, sw2 = self.send(apdu)
        return toASCIIString(resp + [sw1, sw2])


    def led_buzzer(self, red=None, green=None, blink=None, buzzer=None):
        led_ctl = 0
        if red is not None:
            led_ctl |= 0x4
            if not isinstance(red, (list, tuple)):
                red = False, False, red

            initial_led, blink_led, final_led = red
            led_ctl |= 0x1 if final_led else 0
            led_ctl |= 0x10 if initial_led else 0
            led_ctl |= 0x40 if blink_led else 0
            
        if green is not None:
            led_ctl |= 0x8
            if not isinstance(green, (list, tuple)):
                green = False, False, green

            initial_led, blink_led, final_led = green
            led_ctl |= 0x2 if final_led else 0
            led_ctl |= 0x20 if initial_led else 0
            led_ctl |= 0x80 if blink_led else 0
        
        initial_delay, blink_delay, blink_count = 0, 0, 0
        if blink:
            initial_delay, blink_delay, blink_count = blink
            initial_delay = initial_delay / 100
            blink_delay = blink_delay / 100

        buzz_ctl = 0
        if buzzer:
            initial_buzz, blink_buzz = buzzer
            buzz_ctl = 0
            buzz_ctl |= 0x1 if initial_buzz else 0
            buzz_ctl |= 0x2 if blink_buzz else 0

        extra = [initial_delay, blink_delay, blink_count, buzz_ctl]

        apdu = APDU(0xff, 0, 0x40, led_ctl, data=extra)
        resp, sw1, sw2 = self.send(apdu)
        if sw1 != 0x90:
            raise ReaderException('Error setting LEDs %02x%02x' % (sw1, sw2))

        red, green = map(bool, [sw2 & 0x1, sw2 & 0x2])
        return red, green


    def red_on(self):
        self.led_buzzer(red=True)

    def red_off(self):
        self.led_buzzer(red=False)

    def green_on(self):
        self.led_buzzer(green=True)

    def green_off(self):
        self.led_buzzer(green=False)

    def denied(self):
        self.led_buzzer(
            red=[True, False, False],
            green=[True, True, False],
            blink=[500, 300, 3],
            buzzer=[True, False]
        )


    def send_to_pn532(self, apdu):
        apdu = APDU(0xff, 0, 0, data=apdu)
        resp, sw1, sw2 = self.send(apdu)

        if sw1 != 0x61:
            raise ReaderException('Error communicating with PN532: %02x%02x' % (sw1, sw2))

        apdu = APDU(0xff, 0xc0, lc=sw2)
        resp, sw1, sw2 = self.send(apdu)

        return resp, sw1, sw2

    def send_to_sam(self, p1, p2, lc):
        if (self.atr.TS, self.atr.T0) == (0x3b, 0):
            raise SAMException('SAM not reported present')

        resp, sw1, sw2 = self.send(APDU(0x80, 0x14, p1, p2, lc))
        if (sw1, sw2) != (0x90, 0):
            raise ReaderException('Error communicating with SAM: %02x%02x' % (sw1, sw2))

        return resp

    def sam_serial(self):
        return self.send_to_sam(0, 0, 8)

    def sam_id(self):
        return self.send_to_sam(4, 0, 6)

    def sam_os(self):
        resp = self.send_to_sam(6, 0, 8)
        os = resp[:4]
        rest = resp[4:]
        return toASCIIString(os), rest
Esempio n. 23
0
class AcsReader(PcscReader):
    def __init__(self, reader):
        PcscReader.__init__(self, reader)
        self.pn532 = Pn532(self)

    def open(self):
        PcscReader.open(self)

        # We could pass this into connect, but this is clearer
        self.atr = ATR(self.conn.getATR())
        if DEBUG:
            print('ATR: %s' % self.atr)
            self.atr.dump()

        if not self.atr.isT0Supported():
            self.close()
            raise CardConnectionException('Reader reports T0 protocol not supported')

        if DEBUG:
            print('Firmware version %s' % self.firmware_version())

        self.pn532.set_retries(0, 0, 0)

    def send(self, apdu):
        resp, sw1, sw2 = self.conn.transmit(list(apdu))
        return resp, sw1, sw2

    @property
    def tags(self):
        return self.pn532.scan()


    def firmware_version(self):
        apdu = APDU(0xff, 0, 0x48)
        resp, sw1, sw2 = self.send(apdu)
        return toASCIIString(resp + [sw1, sw2])


    def led_buzzer(self, red=None, green=None, blink=None, buzzer=None):
        led_ctl = 0
        if red is not None:
            led_ctl |= 0x4
            if not isinstance(red, (list, tuple)):
                red = False, False, red

            initial_led, blink_led, final_led = red
            led_ctl |= 0x1 if final_led else 0
            led_ctl |= 0x10 if initial_led else 0
            led_ctl |= 0x40 if blink_led else 0
            
        if green is not None:
            led_ctl |= 0x8
            if not isinstance(green, (list, tuple)):
                green = False, False, green

            initial_led, blink_led, final_led = green
            led_ctl |= 0x2 if final_led else 0
            led_ctl |= 0x20 if initial_led else 0
            led_ctl |= 0x80 if blink_led else 0
        
        initial_delay, blink_delay, blink_count = 0, 0, 0
        if blink:
            initial_delay, blink_delay, blink_count = blink
            initial_delay = initial_delay / 100
            blink_delay = blink_delay / 100

        buzz_ctl = 0
        if buzzer:
            initial_buzz, blink_buzz = buzzer
            buzz_ctl = 0
            buzz_ctl |= 0x1 if initial_buzz else 0
            buzz_ctl |= 0x2 if blink_buzz else 0

        extra = [initial_delay, blink_delay, blink_count, buzz_ctl]

        apdu = APDU(0xff, 0, 0x40, led_ctl, data=extra)
        resp, sw1, sw2 = self.send(apdu)
        if sw1 != 0x90:
            raise ReaderException('Error setting LEDs %02x%02x' % (sw1, sw2))

        red, green = list(map(bool, [sw2 & 0x1, sw2 & 0x2]))
        return red, green


    def red_on(self):
        self.led_buzzer(red=True)

    def red_off(self):
        self.led_buzzer(red=False)

    def green_on(self):
        self.led_buzzer(green=True)

    def green_off(self):
        self.led_buzzer(green=False)

    def leds_off(self):
        self.led_buzzer(red=False, green=False)

    def denied(self):
        self.led_buzzer(
            red=[True, False, False],
            green=[True, True, False],
            blink=[500, 300, 3],
            buzzer=[True, False]
        )


    def send_to_pn532(self, apdu):
        apdu = APDU(0xff, 0, 0, data=apdu)
        resp, sw1, sw2 = self.send(apdu)

        if sw1 != 0x61:
            raise ReaderException('Error communicating with PN532: %02x%02x' % (sw1, sw2))

        apdu = APDU(0xff, 0xc0, lc=sw2)
        resp, sw1, sw2 = self.send(apdu)

        return resp, sw1, sw2

    def send_to_sam(self, p1, p2, lc):
        if (self.atr.TS, self.atr.T0) == (0x3b, 0):
            raise SAMException('SAM not reported present')

        resp, sw1, sw2 = self.send(APDU(0x80, 0x14, p1, p2, lc))
        if (sw1, sw2) != (0x90, 0):
            raise ReaderException('Error communicating with SAM: %02x%02x' % (sw1, sw2))

        return resp

    def sam_serial(self):
        return self.send_to_sam(0, 0, 8)

    def sam_id(self):
        return self.send_to_sam(4, 0, 6)

    def sam_os(self):
        resp = self.send_to_sam(6, 0, 8)
        os = resp[:4]
        rest = resp[4:]
        return toASCIIString(os), rest