Beispiel #1
0
 def __init__(self, respdataPM, respdataApp):
     ind = 0
     self.packages = []
     while len(respdataPM) > ind:
         length = respdataPM[ind]
         pack_aid = l2s(respdataPM[ind + 1:ind + 1 + length])
         ind += length + 1
         lcs = respdataPM[ind]
         priv = respdataPM[ind + 1]
         nmod = respdataPM[ind + 2]
         ind += 3
         mods = []
         for i in xrange(nmod):
             length = respdataPM[ind]
             mods.append(l2s(respdataPM[ind + 1:ind + 1 + length]))
             ind += length + 1
         self.packages.append({
             'pack_aid': pack_aid,
             'lcs': lcs,
             'priv': priv,
             'modules': mods
         })
     ind = 0
     self.insts = []
     while len(respdataApp) > ind:
         length = respdataApp[ind]
         app_aid = l2s(respdataApp[ind + 1:ind + 1 + length])
         ind += length + 1
         lcs = respdataApp[ind]
         priv = respdataApp[ind + 1]
         ind += 2
         self.insts.append({'app_aid': app_aid, 'lcs': lcs, 'priv': priv})
Beispiel #2
0
 def test_Mutauth( self ):
     host_challenge = unhexlify( '0807060504030201' )
     scp = SCP03( **self.scp_par )
     apdu = scp.initUpdate( host_challenge )
     self.assertEqual( l2s( apdu ),
                       unhexlify( '80503000080807060504030201' ))
     # invoke key derivation
     resp = scp.initUpdateResp()
     self.assertEqual( scp.card_challenge,
                       unhexlify( 'A3F5F144D19BE66E' ))
     self.assertEqual( scp.SENC,
                       unhexlify( '852D207B7CC8C880231EDFD5C644CFB1' ))
     self.assertEqual( scp.SMAC,
                       unhexlify( '7131B9369F3D19850E6919CD3321523E' ))
     self.assertEqual( scp.SRMAC,
                       unhexlify( 'B570AA1FDE18F9179B5CBD42D8939D05' ))
     self.assertEqual( scp.card_cryptogram,
                        unhexlify( '72BFCBDF4A14515F' ))
     self.assertEqual( scp.host_cryptogram,
                        unhexlify( 'AEB8DAD1865B85E2' ))
     self.assertEqual( resp,
                       unhexlify( '000050C7606A8CF64800300370' +
                                  'A3F5F144D19BE66E72BFCBDF4A14515F00002A' ))
     # external authenticate
     apdu = scp.extAuth( SL = 1 )
     self.assertEqual( l2s( apdu ),
                       unhexlify( '8482010010AEB8DAD1865B85E2' )
                       + unhexlify( '49FC4CF184E61DCD' ))
     self.assertEqual( scp.MACchain,
                       unhexlify( '49FC4CF184E61DCD4C3928E4C617FBA3' ))
Beispiel #3
0
 def __init__( self, respdataPM, respdataApp ):
     ind = 0
     self.packages = []
     while len( respdataPM ) > ind:
         length = respdataPM[ind]
         pack_aid = l2s( respdataPM[ ind+1: ind+1+length])
         ind += length + 1
         lcs = respdataPM[ ind ]
         priv = respdataPM[ ind+1 ]
         nmod = respdataPM[ ind+2 ]
         ind += 3
         mods = []
         for i in xrange( nmod ):
             length = respdataPM[ind]
             mods.append( l2s( respdataPM[ ind+1: ind+1+length]))
             ind += length + 1
         self.packages.append( { 'pack_aid': pack_aid,
                                 'lcs': lcs,
                                 'priv': priv,
                                 'modules': mods } )
     ind = 0
     self.insts = []
     while len( respdataApp ) > ind:
         length = respdataApp[ind]
         app_aid = l2s( respdataApp[ ind+1: ind+1+length])
         ind += length + 1
         lcs = respdataApp[ ind ]
         priv = respdataApp[ ind+1 ]
         ind += 2
         self.insts.append( { 'app_aid': app_aid,
                              'lcs': lcs,
                              'priv': priv } )
Beispiel #4
0
 def test_Mutauth(self):
     host_challenge = unhexlify('0807060504030201')
     scp = SCP03(**self.scp_par)
     apdu = scp.initUpdate(host_challenge)
     self.assertEqual(l2s(apdu),
                      unhexlify('80503000080807060504030201'))
     # invoke key derivation
     resp = scp.initUpdateResp()
     self.assertEqual(scp.card_challenge,
                      unhexlify('A3F5F144D19BE66E'))
     self.assertEqual(scp.SENC,
                      unhexlify('852D207B7CC8C880231EDFD5C644CFB1'))
     self.assertEqual(scp.SMAC,
                      unhexlify('7131B9369F3D19850E6919CD3321523E'))
     self.assertEqual(scp.SRMAC,
                      unhexlify('B570AA1FDE18F9179B5CBD42D8939D05'))
     self.assertEqual(scp.card_cryptogram,
                      unhexlify('72BFCBDF4A14515F'))
     self.assertEqual(scp.host_cryptogram,
                      unhexlify('AEB8DAD1865B85E2'))
     self.assertEqual(resp,
                      unhexlify('000050C7606A8CF64800300370' +
                                'A3F5F144D19BE66E72BFCBDF4A14515F00002A'))
     # external authenticate
     apdu = scp.extAuth(SL=1)
     self.assertEqual(l2s(apdu),
                      unhexlify('8482010010AEB8DAD1865B85E2') +
                      unhexlify('49FC4CF184E61DCD'))
     self.assertEqual(scp.MACchain,
                      unhexlify('49FC4CF184E61DCD4C3928E4C617FBA3'))
Beispiel #5
0
 def unwrapResp(self, resp, sw1, sw2):
     """ Unwrap response (decipher and check MAC)."""
     sw = (sw1 << 8) + sw2
     if not(sw == 0x9000 or sw1 in (0x62, 0x63)):
         assert len(resp) == 0, "No response data expected"
         return [], sw1, sw2
     dresp = l2s(resp)
     if (self.SL | self.rmacSL) & SL_RMAC:
         assert len(resp) >= 8, "Resp data shorter than 8: %d" % len(resp)
         data2sign = self.MACchain + dresp[:-8] + chr(sw1) + chr(sw2)
         rmac = CMAC(self.SRMAC, data2sign)[:8]
         assert rmac == dresp[-8:], "Wrong R-MAC: %s vs expected: %s" % \
             (hexlify(dresp[-8:]).upper(), hexlify(rmac).upper())
         dresp = dresp[:-8]
     if (self.SL | self.rmacSL) & SL_RENC and len(dresp) > 0:
         assert len(dresp) % 16 == 0, \
             "Length of encrypted data not multiple of 16: %d" % len(dresp)
         k = AES.new(self.SENC, AES.MODE_ECB)
         ICV = k.encrypt(pack(">QQ", 0x8000000000000000L |
                              self.cmdCount / 0x10000000000000000L,
                              self.cmdCount % 0x10000000000000000L))
         k = AES.new(self.SENC, AES.MODE_CBC, IV=ICV)
         ddata = k.decrypt(dresp)
         data = unpad80(ddata, 16)
         assert len(data) > 0, "Empty data encrypted"
     else:
         data = dresp
     return s2l(data), sw1, sw2
Beispiel #6
0
    def wrapAPDU( self, apdu ):
        """ Wrap APDU for SCP02, i.e. calculate MAC and encrypt.
Input APDU and output APDU are list of uint8. """
        lc = len( apdu ) - 5
        assert len( apdu ) >= 5, "Wrong APDU length: %d" % len( apdu )
        assert len( apdu ) == 5 or apdu[4] == lc, \
           "Lc differs from length of data: %d vs %d" % ( apdu[4], lc )

        cla = apdu[0]
        b8 = cla & 0x80
        if cla & 0x03 > 0 or cla & 0x40 != 0:
            # nonzero logical channel in APDU, check that are the same
            assert cla == self.CLA( False, b8 ), "CLA mismatch"
        scla = b8 | 0x04  # CLA without log. ch. but with secure messaging
        sapdu = l2s( apdu )
        # CLA without log. channel can be 80 or 00 only
        if self.isCMAC:
            if self.i & M_CMAC_MODIF: # CMAC on unmodified APDU
                mlc = lc
                clac = chr( b8 )
            else:                     # CMAC on modified APDU
                mlc = lc + 8
                clac = chr( b8 + 0x04 )
            mac = self.calcMAC_1d( clac + sapdu[1:4] + chr(mlc) + sapdu[5:] )
            mac = [ ord(x) for x in mac ]
            if self.isENC:
                k = DES3.new( self.ses_ENC, DES.MODE_CBC, ZERO8 )
                data = [ ord(x) for x in k.encrypt( pad80( sapdu[5:] ))]
                lc = len( data )
            else:
                data = apdu[5:]
            lc += 8
            apdu = [ self.CLA( True, b8 )] + apdu[1:4] + [ lc ] + data + mac
        return apdu
Beispiel #7
0
 def unwrapResp( self, resp, sw1, sw2 ):
     """ Unwrap response (decipher and check MAC)."""
     dresp = l2s( resp )
     if ( self.SL | self.rmacSL ) & SL_RMAC:
         assert len( resp ) >= 8, "Resp data shorter than 8: %d" % len(resp)
         data2sign = self.MACchain + dresp[:-8] + chr(sw1) + chr(sw2)
         rmac = CMAC( self.SRMAC, data2sign )[:8]
         assert rmac == dresp[-8:], "Wrong R-MAC: %s vs expected: %s" % \
             ( hexlify(dresp[-8:]).upper(), hexlify( rmac ).upper())
         dresp = dresp[:-8]
     if ( self.SL | self.rmacSL ) & SL_RENC and len( dresp ) > 0:
         assert len( dresp ) % 16 == 0, \
             "Length of encrypted data not multiple of 16: %d" % len( dresp )
         k = AES.new( self.SENC, AES.MODE_ECB )
         ICV = k.encrypt( pack( ">QQ", 0x8000000000000000L |
                                self.cmdCount / 0x10000000000000000L,
                                self.cmdCount % 0x10000000000000000L ))
         k = AES.new( self.SENC, AES.MODE_CBC, IV = ICV )
         ddata = k.decrypt( dresp )
         m = re_pad80.match( ddata )
         assert m is not None, "Wrong padding"
         data = m.groups()[0]
         assert len( data ) > 0, "Empty data encrypted"
     else:
         data = dresp
     return [ord(x) for x in data ], sw1, sw2
Beispiel #8
0
    def parseInitUpdateResp( self, resp ):
        """ Parse response to Init Update and if correct set diverData,
seqCounter, and card_challenge from it.
resp     - response (list[u8])
Raise exception in case of wrong response. """
        assert len( resp ) in ( 29, 32 ), \
            "Wrong length of response data to Init Update: %d" % len(resp)
        diverData, keyInfo, card_chal, card_cryptogram, seqCounter =\
            partition( l2s( resp ), ( 10, 13, 21, 29 ))
        kv, i = ord( keyInfo[0]), ord( keyInfo[2] )
        assert 0x30 <= kv and kv <= 0x3F, \
            "Wrong key version in resp. to Init Update %02X" % kv
        assert keyInfo[1] == chr( 0x03 ), \
            "Wrong SCP number in resp. to Init Update %02X" % ord(keyInfo[0])
        assert i & ~( M_PSEUDO | M_RMACENC ) == 0 \
            and i != M_RMACENC ^ M_RMAC, "Wrong SCP03 parameter %02X" % i
        self.i, self.keyVer = i, kv

        if self.i & M_PSEUDO:
            assert len( seqCounter ) == 3, "Missing seq. counter"
            self.seqCounter = seqCounter
        else:
            assert len( seqCounter ) == 0, "Seq. counter shall not be present"

        self.deriveKeys( card_chal )
        assert card_cryptogram == self.card_cryptogram, \
            "Recieved and calculated card cryptogram difer: %s vs. %s" % \
            ( hexlify( card_cryptogram ), hexlify( self.card_cryptogram ))
Beispiel #9
0
    def wrapAPDU(self, apdu):
        """ Wrap APDU for SCP02, i.e. calculate MAC and encrypt.
Input APDU and output APDU are list of uint8. """
        lc = len(apdu) - 5
        assert len(apdu) >= 5, "Wrong APDU length: %d" % len(apdu)
        assert len(apdu) == 5 or apdu[4] == lc, \
            "Lc differs from length of data: %d vs %d" % (apdu[4], lc)

        cla = apdu[0]
        b8 = cla & 0x80
        if cla & 0x03 > 0 or cla & 0x40 != 0:
            # nonzero logical channel in APDU, check that are the same
            assert cla == self.CLA(False, b8), "CLA mismatch"
        sapdu = l2s(apdu)
        # CLA without log. channel can be 80 or 00 only
        if self.isCMAC:
            if self.i & M_CMAC_MODIF:  # CMAC on unmodified APDU
                mlc = lc
                clac = chr(b8)
            else:  # CMAC on modified APDU
                mlc = lc + 8
                clac = chr(b8 + 0x04)
            mac = self.calcMAC_1d(clac + sapdu[1:4] + chr(mlc) + sapdu[5:])
            mac = [ord(x) for x in mac]
            if self.isENC:
                k = DES3.new(self.ses_ENC, DES.MODE_CBC, ZERO8)
                data = s2l(k.encrypt(pad80(sapdu[5:], 8)))
                lc = len(data)
            else:
                data = apdu[5:]
            lc += 8
            apdu = [self.CLA(True, b8)] + apdu[1:4] + [lc] + data + mac
        return apdu
Beispiel #10
0
 def parseProactiveCmd(self, resp):
     """ Parse Proactive command from fetched byte array. """
     try:
         res = split2TLV(l2s(resp))
         assert len(res) == 1
         assert res[0][0] == T_PROCMD
     except AssertionError:
         raise ProactiveException("Wrong ProCmd tag / length")
     try:
         tlvs = split2TLV(res[0][1])
     except AssertionError:
         raise ProactiveException("Wrong TLVs in proactive command")
     # parse Command details and Devices TLVs
     tlv = tlvs.pop(0)
     if 0x7F & tlv[0] != T_CMD_DETAILS or len(tlv[1]) != 3 or tlv[1][0] != "\x01":
         raise ProactiveException("ProCmd wrong Command details")
     cmd, qualif = unpack("BB", tlv[1][1:])
     # parse Command details and Devices TLVs
     tlv = tlvs.pop(0)
     if 0x7F & tlv[0] != T_DEVICES or len(tlv[1]) != 2 or tlv[1][0] != chr(DEV_UICC):
         raise ProactiveException("ProCmd wrong Devices")
     dev = ord(tlv[1][1])
     proCmd = ProactiveCommand(cmd, qualif, dev)
     # parse rest of TLVs
     for tlv in tlvs:
         proCmd.TLVs.append(TLV(*tlv))
     return proCmd
Beispiel #11
0
    def parseInitUpdateResp(self, resp):
        """ Parse response to Init Update and if correct set diverData,
seqCounter, and card_challenge from it.
resp     - response (list[u8])
Raise exception in case of wrong response. """
        assert len(resp) in (29, 32), \
            "Wrong length of response data to Init Update: %d" % len(resp)
        diverData, keyInfo, card_chal, card_cryptogram, seqCounter =\
            partition(l2s(resp), (10, 13, 21, 29))
        kv, i = ord(keyInfo[0]), ord(keyInfo[2])
        assert 0x30 <= kv and kv <= 0x3F, \
            "Wrong key version in resp. to Init Update %02X" % kv
        assert keyInfo[1] == chr(0x03), \
            "Wrong SCP number in resp. to Init Update %02X" % ord(keyInfo[0])
        assert i & ~(M_PSEUDO | M_RMACENC) == 0 \
            and i != M_RMACENC ^ M_RMAC, "Wrong SCP03 parameter %02X" % i
        self.i, self.keyVer, self.diverData = i, kv, diverData

        if self.i & M_PSEUDO:
            assert len(seqCounter) == 3, "Missing seq. counter"
            self.seqCounter = s2int(seqCounter)
        else:
            assert len(seqCounter) == 0, "Seq. counter shall not be present"

        self.deriveKeys(card_chal)
        assert card_cryptogram == self.card_cryptogram, \
            "Recieved and calculated card cryptogram difer: %s vs. %s" % \
            (hexlify(card_cryptogram), hexlify(self.card_cryptogram))
Beispiel #12
0
 def parseProactiveCmd(self, resp):
     """ Parse Proactive command from fetched byte array. """
     try:
         res = split2TLV(l2s(resp))
         assert len(res) == 1
         assert res[0][0] == T_PROCMD
     except AssertionError:
         raise ProactiveException("Wrong ProCmd tag / length")
     try:
         tlvs = split2TLV(res[0][1])
     except AssertionError:
         raise ProactiveException("Wrong TLVs in proactive command")
     # parse Command details and Devices TLVs
     tlv = tlvs.pop(0)
     if 0x7F & tlv[0] != T_CMD_DETAILS or len( tlv[1] ) != 3 \
        or tlv[1][0] != '\x01':
         raise ProactiveException("ProCmd wrong Command details")
     cmd, qualif = unpack("BB", tlv[1][1:])
     # parse Command details and Devices TLVs
     tlv = tlvs.pop(0)
     if 0x7F & tlv[0] != T_DEVICES or len( tlv[1] ) != 2 \
        or tlv[1][0] != chr( DEV_UICC ):
         raise ProactiveException("ProCmd wrong Devices")
     dev = ord(tlv[1][1])
     proCmd = ProactiveCommand(cmd, qualif, dev)
     # parse rest of TLVs
     for tlv in tlvs:
         proCmd.TLVs.append(TLV(*tlv))
     return proCmd
Beispiel #13
0
def readBinary(c, le, logCh=0, offset=0):
    """Read Binary on currently selected EF"""
    P1 = (offset >> 8) & 0x7F
    P2 = offset & 0xFF
    apdu = [logCh, INS_READBIN, P1, P2, le]
    resp, sw1, sw2 = c.transmit(apdu)
    sw = (sw1 << 8) + sw2
    if sw != 0x9000:
        raise ISOException(sw)
    return l2s(resp)
Beispiel #14
0
def readBinary( c, le, logCh = 0, offset = 0 ):
    """Read Binary on currently selected EF"""
    P1 = ( offset >> 8 ) & 0x7F
    P2 = offset & 0xFF
    apdu = [ logCh, INS_READBIN, P1, P2, le ]
    resp, sw1, sw2 = c.transmit( apdu )
    sw = ( sw1 << 8 ) + sw2
    if sw != 0x9000:
        raise ISOException( sw )
    return l2s( resp )
Beispiel #15
0
def readRecord( c, recNum, logCh = 0 ):
    """ Read record from currently selected EF"""
    apdu = [ logCh, INS_READREC, recNum, 4, 0 ]
    resp, sw1, sw2 = c.transmit( apdu )
    if sw1 == 0x6C:
        apdu[4] = sw2
        resp, sw1, sw2 = c.transmit( apdu )
    sw = ( sw1 << 8 ) + sw2
    if sw != 0x9000:
        raise ISOException( sw )
    return l2s( resp )
Beispiel #16
0
def getData(c, tag):
    P1 = tag >> 8
    P2 = tag & 0xFF
    apdu = [0x80, INS_GETDATA, P1, P2, 0]
    resp, sw1, sw2 = c.transmit(apdu)
    if sw1 == 0x6C:
        apdu[4] = sw2
        resp, sw1, sw2 = c.transmit(apdu)
    sw = (sw1 << 8) + sw2
    if sw != 0x9000: raise ISOException(sw)
    return l2s(resp)
Beispiel #17
0
def getData( c, tag ):
    P1 = tag >> 8
    P2 = tag & 0xFF
    apdu = [ 0x80, INS_GETDATA, P1, P2, 0 ]
    resp, sw1, sw2 = c.transmit( apdu )
    if sw1 == 0x6C:
        apdu[4] = sw2
        resp, sw1, sw2 = c.transmit( apdu )
    sw = ( sw1 << 8 ) + sw2
    if sw != 0x9000: raise ISOException( sw )
    return l2s( resp )
Beispiel #18
0
def readRecord(c, recNum, logCh=0):
    """ Read record from currently selected EF"""
    apdu = [logCh, INS_READREC, recNum, 4, 0]
    resp, sw1, sw2 = c.transmit(apdu)
    if sw1 == 0x6C:
        apdu[4] = sw2
        resp, sw1, sw2 = c.transmit(apdu)
    sw = (sw1 << 8) + sw2
    if sw != 0x9000:
        raise ISOException(sw)
    return l2s(resp)
Beispiel #19
0
    def parseInitUpdate(self, apdu):
        """ Parse Init Update APDU (list[u8]) and if correct, set
log. channel and host challenge from it. """
        cla = apdu[0]
        assert 0x80 <= cla <= 0x83 or 0xC0 <= cla < 0xCF, "Wrong CLA"
        assert apdu[1] == INS_INIT_UPDATE, "Wrong INS"
        assert apdu[2] == self.keyVer, "Key version changed"
        # ignore P2?
        assert apdu[4] == len(apdu) - 5 == 8, "Wrong Lc/data length"
        self.logCh = logCh(cla)
        self.host_challenge = l2s(apdu[5:])
Beispiel #20
0
    def unwrapAPDU(self, apdu):
        """ Parse MACed/encrypted APDU, decipher and check MAC. """
        lc = self.checkAPDU(apdu)
        if apdu[1] == 0xC0:  # Get Response TPDU
            return apdu
        if 'beginRmaSL' in self.__dict__:
            self.rmacSL = self.beginRmacSL
            del self.beginRmacSL

        self.cmdCount += 1
        cla = apdu[0]
        b8 = cla & 0x80
        assert cla & 0x04, "Secure messaging missing"
        if (cla & 0x40 == 0 and cla & 0x03 > 0) or cla & 0x40 != 0:
            # check logical channels
            assert cla == self.CLA(True, b8), "CLA mismatch"
        scla = b8 | 0x04  # CLA without log. ch. but with secure messaging

        data = l2s(apdu[5:])
        if self.SL & SL_CMAC:    # C-MAC
            assert lc >= 8, "Missing/ too short CMAC"
            sdata = data[:-8]
            data2sign = self.MACchain + chr(scla) + l2s(apdu[1:4])\
                + chr(lc) + sdata
            self.MACchain = CMAC(self.SMAC, data2sign)
            assert data[-8:] == self.MACchain[:8], "Wrong CMAC"
            data = sdata
            lc -= 8
        if self.SL & SL_CENC and lc > 0:  # C-ENC
            assert lc % 16 == 0, "Encoded data length not multiple of BS"
            k = AES.new(self.SENC, AES.MODE_ECB)
            ICV = k.encrypt(pack(">QQ",
                                 self.cmdCount / 0x10000000000000000L,
                                 self.cmdCount % 0x10000000000000000L))
            k = AES.new(self.SENC, AES.MODE_CBC, IV=ICV)
            pdata = k.decrypt(data)
            data = unpad80(pdata, 16)
            assert len(data) > 0, "Empty data encrypted"
            lc = len(data)
        apdu = [self.CLA(False, b8)] + apdu[1:4] + [lc] + s2l(data)
        return apdu
Beispiel #21
0
    def test_Cdecrypt(self):
        host_challenge = unhexlify('0807060504030201')
        scp = SCP03(**self.scp_par)
        apdu = scp.initUpdate(host_challenge)
        apdu = scp.extAuth(SL=3)

        apdu_i4lh = '80E60200150A45786572636973655236000006EF04C602068200'
        apdu_i4l = s2l(unhexlify(apdu_i4lh))
        wapdu = scp.wrapAPDU(apdu_i4l)
        encdata = l2s(wapdu[5:-8])
        self.assertEqual(encdata,
                         unhexlify('DF31907FC027482D5DCB7DC028245F7C108CA4D2AFF12275079768E1EFE9429E'))
Beispiel #22
0
def selectFile( c, path, logCh = 0 ):
    """ Select file by path from MF or MF for empty path """
    if len( path ) > 0:
        apdu = [ logCh, INS_SELECT, 8, 4, len( path )] + [ ord(x) for x in path ]
    else:
        apdu = [ logCh, INS_SELECT, 0, 4, 2, 0x3F, 0x00 ]
    resp, sw1, sw2 = c.transmit( apdu )
    if sw1 == 0x61:
        resp, sw1, sw2 = c.transmit([0, 0xC0, 0, 0, sw2])
    sw = ( sw1 << 8 ) + sw2
    if sw != 0x9000:
        raise ISOException( sw )
    return l2s( resp )
Beispiel #23
0
 def incCounter( self, value = 1 ):
     """ Increment counter by given values (as int, default = 1). """        
     vals = [ ord( x ) for x in self.counter ]
     vals[4] += value
     for i in xrange( 4, 0, -1 ):
         if 0 <= vals[i] and vals[i] < 0x100: break
         vals[i-1] += vals[i] / 0x100
         vals[i] %= 0x100
     self.counter = l2s( vals )
     if 'counter_file' in self.__dict__:
         f = open( self.counter_file, 'w' )
         f.write( hexlify( self.counter ))
         f.close()
Beispiel #24
0
    def wrapAPDU(self, apdu):
        """ Wrap APDU for SCP03, i.e. calculate MAC and encrypt.
Input APDU and output APDU are list of u8. """
        lc = self.checkAPDU(apdu)
        if apdu[1] == 0xC0:  # Get Response TPDU
            return apdu
        if 'beginRmaSL' in self.__dict__:
            self.rmacSL = self.beginRmacSL
            del self.beginRmacSL

        self.cmdCount += 1
        cla = apdu[0]
        b8 = cla & 0x80
        if (cla & 0x40 == 0 and cla & 0x03 > 0) or cla & 0x40 != 0:
            # check logical channels
            assert cla == self.CLA(False, b8), "CLA mismatch"
        scla = b8 | 0x04  # CLA without log. ch. but with secure messaging
        cdata = l2s(apdu[5:])
        if self.SL & SL_CENC and lc > 0:  # C-ENC
            k = AES.new(self.SENC, AES.MODE_ECB)
            ICV = k.encrypt(
                pack(">QQ", self.cmdCount / 0x10000000000000000L,
                     self.cmdCount % 0x10000000000000000L))
            k = AES.new(self.SENC, AES.MODE_CBC, IV=ICV)
            data2enc = pad80(cdata, 16)
            cdata = k.encrypt(data2enc)
            lc = len(cdata)
        if self.SL & SL_CMAC:  # C-MAC
            lc += 8
            data2sign = self.MACchain + chr(scla) + l2s(apdu[1:4])
            if (lc > 0xff):
                data2sign += b'\x00' + chr((lc >> 8) & 0xff) + chr(lc & 0xff)
            else:
                data2sign += chr(lc)
            data2sign += cdata
            self.MACchain = CMAC(self.SMAC, data2sign)
            cdata += self.MACchain[:8]
        apdu = [self.CLA(True, b8)] + apdu[1:4] + [lc] + s2l(cdata)
        return apdu
Beispiel #25
0
def selectFile(c, path, logCh=0):
    """ Select file by path from MF or MF for empty path """
    if len(path) > 0:
        apdu = [logCh, INS_SELECT, 8, 4, len(path)] + [ord(x) for x in path]
    else:
        apdu = [logCh, INS_SELECT, 0, 4, 2, 0x3F, 0x00]
    resp, sw1, sw2 = c.transmit(apdu)
    if sw1 == 0x61:
        resp, sw1, sw2 = c.transmit([0, 0xC0, 0, 0, sw2])
    sw = (sw1 << 8) + sw2
    if sw != 0x9000:
        raise ISOException(sw)
    return l2s(resp)
Beispiel #26
0
 def incCounter(self, value=1):
     """ Increment counter by given values (as int, default = 1). """
     vals = [ord(x) for x in self.counter]
     vals[4] += value
     for i in xrange(4, 0, -1):
         if 0 <= vals[i] < 0x100:
             break
         vals[i - 1] += vals[i] / 0x100
         vals[i] %= 0x100
     self.counter = l2s(vals)
     if 'counter_file' in self.__dict__:
         f = open(self.counter_file, 'w')
         f.write(hexlify(self.counter))
         f.close()
Beispiel #27
0
 def send(self, templ, **kw):
     objects = self.objects.copy()
     objects.update(kw)
     sapdu = GAF(templ).eval(**objects)
     apdu = s2l(sapdu)
     assert 5 <= len(apdu) and len(apdu) <= 260, "Wrong APDU length %d, '%s'" % (len(apdu), hexlify(sapdu))
     resp, sw1, sw2 = CardConnectionDecorator.transmit(self, apdu)
     if sw1 == 0x6C and len(apdu) == 5:
         apdu[4] = sw2
         resp, sw1, sw2 = CardConnectionDecorator.transmit(self, apdu)
     elif sw1 == 0x61:
         apdu = [0, 0xC0, 0, 0, sw2]
         resp, sw1, sw2 = CardConnectionDecorator.transmit(self, apdu)
     sw = (sw1 << 8) + sw2
     return l2s(resp), sw
Beispiel #28
0
 def send( self, templ, **kw ):
     objects = self.objects.copy()
     objects.update( kw )
     sapdu = GAF( templ ).eval( **objects )
     apdu = s2l( sapdu )
     assert 5 <= len( apdu ) and len( apdu ) <= 260,\
         "Wrong APDU length %d, '%s'" % ( len(apdu), hexlify( sapdu ))
     resp, sw1, sw2 = CardConnectionDecorator.transmit( self, apdu )
     if sw1 == 0x6C and len( apdu ) == 5:
         apdu[4] = sw2
         resp, sw1, sw2 = CardConnectionDecorator.transmit( self, apdu )
     elif sw1 == 0x61:
         apdu = [ 0, 0xC0, 0, 0, sw2 ]
         resp, sw1, sw2 = CardConnectionDecorator.transmit( self, apdu )
     sw = ( sw1 << 8 ) + sw2
     return l2s( resp ), sw
Beispiel #29
0
def getExtCardRes( c ):
    """ Issue GET DATA with tag FF21 in order to receive Extended
Card Resources (GP 2.2.1, 11.3 & ETSI TS 102.226, 8.2.1.7).
Returns [ num. of install applets, free NVM, free RAM ]"""
    # CLA = 0x00: return only value
    # CLA = 0x80: return TLV, i.e. 0xFF21 #( value )
    apdu = [ 0x80, INS_GETDATA, 0xFF, 0x21, 0 ] 
    resp, sw1, sw2 = c.transmit( apdu )
    if sw1 == 0x6C:
        apdu[4] = sw2
        resp, sw1, sw2 = c.transmit( apdu )
    sw = ( sw1 << 8 ) + sw2
    if sw != 0x9000: raise ISOException( sw )
    payload = l2s( resp )
    result = [ s2int( findTLValue( payload, ( 0xFF21, tag ))) for
               tag in ( 0x81, 0x82, 0x83 )]
    return result
Beispiel #30
0
def selectApplet( c, AID, logCh = 0 ):
    """ Select applet on a given logical channel or
open new log. channel if logCh is None. """
    if logCh is None:
        logCh = openLogCh( c )
    # select the Applet on the given logical channel
    apdu = [ logCh, INS_SELECT, 4, 0, len( AID ) ] + [ ord( x ) for x in AID ]
    resp, sw1, sw2 = c.transmit( apdu )
    if sw1 == 0x6C and len( AID ) == 0:
        apdu = [ logCh, INS_SELECT, 4, 0, sw2 ]
        resp, sw1, sw2 = c.transmit( apdu )
    if( sw1 == 0x61 ):
        apdu = [ logCh, 0xC0, 0, 0, sw2 ]
        resp, sw1, sw2 = c.transmit( apdu )
    sw = ( sw1 << 8 ) + sw2
    if sw != 0x9000 : raise ISOException( sw )
    respdata = l2s( resp )
    # close channel
    return ( respdata, logCh )
Beispiel #31
0
    def send(self, templ, **kw):
        """ Evaluate GAF and transmit as APDU
templ   - a GAF template to evaluate
kw      - GAF dictionary (updates dictionary from SCP02Connection.__init__)
Return (resp, SW) as (str, int)"""
        objects = self.objects.copy()
        objects.update(kw)
        papdu = s2l(GAF(templ).eval(**objects))
        apdu = self.scp.wrapAPDU(papdu)
        resp, sw1, sw2 = CardConnectionDecorator.transmit(self, apdu)
        if sw1 == 0x6C and len(papdu) == 5:
            papdu[4] = sw2
            apdu = self.scp.wrapAPDU(papdu)
            resp, sw1, sw2 = CardConnectionDecorator.transmit(self, apdu)
        elif sw1 == 0x61:
            resp, sw1, sw2 = self.getResponse(sw2)
        resp, sw1, sw2 = self.scp.unwrapResp(resp, sw1, sw2)
        sw = (sw1 << 8) + sw2
        return l2s(resp), sw
Beispiel #32
0
def selectApplet(c, AID, logCh=0):
    """ Select applet on a given logical channel or
open new log. channel if logCh is None. """
    if logCh is None:
        logCh = openLogCh(c)
    # select the Applet on the given logical channel
    apdu = [logCh, INS_SELECT, 4, 0, len(AID)] + [ord(x) for x in AID]
    resp, sw1, sw2 = c.transmit(apdu)
    if sw1 == 0x6C and len(AID) == 0:
        apdu = [logCh, INS_SELECT, 4, 0, sw2]
        resp, sw1, sw2 = c.transmit(apdu)
    if (sw1 == 0x61):
        apdu = [logCh, 0xC0, 0, 0, sw2]
        resp, sw1, sw2 = c.transmit(apdu)
    sw = (sw1 << 8) + sw2
    if sw != 0x9000: raise ISOException(sw)
    respdata = l2s(resp)
    # close channel
    return (respdata, logCh)
Beispiel #33
0
def getExtCardRes(c):
    """ Issue GET DATA with tag FF21 in order to receive Extended
Card Resources (GP 2.2.1, 11.3 & ETSI TS 102.226, 8.2.1.7).
Returns [ num. of install applets, free NVM, free RAM ]"""
    # CLA = 0x00: return only value
    # CLA = 0x80: return TLV, i.e. 0xFF21 #( value )
    apdu = [0x80, INS_GETDATA, 0xFF, 0x21, 0]
    resp, sw1, sw2 = c.transmit(apdu)
    if sw1 == 0x6C:
        apdu[4] = sw2
        resp, sw1, sw2 = c.transmit(apdu)
    sw = (sw1 << 8) + sw2
    if sw != 0x9000: raise ISOException(sw)
    payload = l2s(resp)
    result = [
        s2int(findTLValue(payload, (0xFF21, tag)))
        for tag in (0x81, 0x82, 0x83)
    ]
    return result
Beispiel #34
0
    def send(self, templ, **kw):
        """ Evaluate GAF and transmit as APDU
templ   - a GAF template to evaluate
kw      - GAF dictionary (updates dictionary from GAFConnection.__init__)
Return ( resp, SW ) as ( str, int )"""
        objects = self.objects.copy()
        objects.update(kw)
        sapdu = GAF(templ).eval(**objects)
        apdu = s2l(sapdu)
        assert 5 <= len( apdu ) and len( apdu ) <= 260,\
            "Wrong APDU length %d, '%s'" % ( len(apdu), hexlify( sapdu ))
        resp, sw1, sw2 = CardConnectionDecorator.transmit(self, apdu)
        if sw1 == 0x6C and len(apdu) == 5:
            apdu[4] = sw2
            resp, sw1, sw2 = CardConnectionDecorator.transmit(self, apdu)
        elif sw1 == 0x61:
            apdu = [0, 0xC0, 0, 0, sw2]
            resp, sw1, sw2 = CardConnectionDecorator.transmit(self, apdu)
        sw = (sw1 << 8) + sw2
        return l2s(resp), sw
Beispiel #35
0
    def parseInitUpdateResp(self, resp):
        """ Parse response to Init Update and if correct set diverData,
seqCounter, and card_challenge from it.
resp     - response (list[u8])
Return received seqCounter if different from the expected one, otherwise None
Raise exception in case of wrong response. """
        assert len(resp) == 28, \
            "Wrong response length to Init Update: %d" % len(resp)
        diverData, keyVer, const02, seqCounter, card_chal, card_cryptogram =\
            partition(l2s(resp), (10, 11, 12, 14, 20))
        assert keyVer == chr(self.keyVer), \
            "Different key version in Init Update response"
        assert const02 == '\x02', "Wrong protocol number"
        self.seqCounter = seqCounter

        self.deriveKeys(card_chal)
        if self.i & M_PSEUDO:
            assert card_chal == self.card_challenge,\
                "Different card challenge"
        assert card_cryptogram == self.card_cryptogram, \
            "Different card cryptogram"
Beispiel #36
0
    def parseInitUpdateResp( self, resp ):
        """ Parse response to Init Update and if correct set diverData,
seqCounter, and card_challenge from it.
resp     - response (list[u8])
Return received seqCounter if different from the expected one, otherwise None
Raise exception in case of wrong response. """
        assert len( resp ) == 28, \
            "Wrong response length to Init Update: %d" % len( resp )
        diverData, keyVer, const02, seqCounter, card_chal, card_cryptogram =\
            partition( l2s( resp ), ( 10, 11, 12, 14, 20 ))
        assert keyVer == chr( self.keyVer ), \
            "Different key version in Init Update response"
        assert const02 == '\x02', "Wrong protocol number"
        self.seqCounter = seqCounter

        self.deriveKeys( card_chal )
        if self.i & M_PSEUDO:
            assert card_chal == self.card_challenge,\
                "Different card challenge"
        assert card_cryptogram == self.card_cryptogram, \
            "Different card cryptogram"
Beispiel #37
0
 def wrapResp(self, resp, sw1, sw2):
     """ Wrap expected response as card would do."""
     sw = (sw1 << 8) + sw2
     if not(sw == 0x9000 or sw1 in (0x62, 0x63)):
         assert len(resp) == 0, "No response data expected"
         return [], sw1, sw2
     dresp = l2s(resp)
     if (self.SL | self.rmacSL) & SL_RENC and len(dresp) > 0:
         assert len(dresp) <= 0xEF, "Data too long for RENC+RMAC"
         k = AES.new(self.SENC, AES.MODE_ECB)
         ICV = k.encrypt(pack(">QQ", 0x8000000000000000L |
                              self.cmdCount / 0x10000000000000000L,
                              self.cmdCount % 0x10000000000000000L))
         k = AES.new(self.SENC, AES.MODE_CBC, IV=ICV)
         dresp = k.encrypt(pad80(dresp, 16))
     if (self.SL | self.rmacSL) & SL_RMAC:
         assert len(dresp) <= 0xF0, "Data too long for RMAC"
         data2sign = self.MACchain + dresp + chr(sw1) + chr(sw2)
         rmac = CMAC(self.SRMAC, data2sign)[:8]
         dresp += rmac
     return s2l(dresp), sw1, sw2
Beispiel #38
0
def cardInfo(c):
    """Deselect, read EF_DIR, EF_ICCID"""
    resetCard(c)
    histBytes = l2s(ATR(c.getATR()).getHistoricalBytes())
    infoMF = selectFile(c, '')
    # read EF_ICCID
    infoICCID = selectFile(c, unhexlify('2FE2'))
    fileSize = s2int(findTLValue(infoICCID, (0x62, 0x80)))
    assert fileSize == 10, "Wrong size of EF_ICCID"
    iccid = swapNibbles(readBinary(c, fileSize))
    # read EF_DIR
    infoDIR = selectFile(c, unhexlify('2F00'))
    # see ETSI 102.221 11.1.1.4.3 for coding
    fileDesc = findTLValue(infoDIR, (0x62, 0x82))
    assert len( fileDesc ) == 5 and \
        fileDesc[:2] == '\x42\x21' # linear EF
    recLen, nRec = unpack(">HB", fileDesc[2:5])
    dirDO = []
    for recNum in xrange(1, nRec + 1):
        try:
            r = readRecord(c, recNum)
            if r == '\xFF' * len(r): continue
            aid = findTLValue(r, (0x61, 0x4F))
            label = findTLValue(r, (0x61, 0x50))
            dirDO.append({'AID': aid, 'label': label})
        except ISOException:
            break
    # select USIM and try to read IMSI
    if len(dirDO) == 1:
        aid_usim = dirDO[0]['AID']
    else:
        aids = [DO['AID'] for DO in dirDO if re.match(DO['label'], 'USIM')]
        if len(aids) == 1:
            aid_usim = aids[0]
        else:
            aid_usim = None
    if aid_usim:
        infoUSIM = selectApplet(c, aid_usim)
        infoIMSI = selectFile(c, unhexlify('7FFF6F07'))
        try:
            bimsi = readBinary(c, 9)
            digits = reduce(
                lambda d, n: d + [ord(n) & 0x0F, ord(n) >> 4],
                bimsi[1:1 + ord(bimsi[0])], [])
            digits.pop(0)  # remove first nibble 8 or 9
            while digits[-1] == 0x0F:
                digits.pop()  # remove trailing F
            imsi = ''.join([chr(ord('0') + i) for i in digits])
        except ISOException:
            imsi = None
    else:
        imsi = None
    # select default applet and get tags 45 and 42
    selectApplet(c, '')
    try:
        cin = findTLValue(getData(c, 0x42), (0x42, ))
    except ISOException:
        cin = None
    try:
        iin = findTLValue(getData(c, 0x45), (0x45, ))
    except ISOException:
        iin = None
    return histBytes, iccid, dirDO, imsi, iin, cin
Beispiel #39
0
def cardInfo( c ):
    """Deselect, read EF_DIR, EF_ICCID"""
    resetCard( c )
    histBytes = l2s( ATR( c.getATR()).getHistoricalBytes())
    infoMF = selectFile( c, '' )
    # read EF_ICCID
    infoICCID = selectFile( c, unhexlify( '2FE2' ))
    fileSize = s2int( findTLValue( infoICCID, ( 0x62, 0x80 )))
    assert fileSize == 10, "Wrong size of EF_ICCID"
    iccid = swapNibbles( readBinary( c, fileSize ))
    # read EF_DIR
    infoDIR = selectFile( c, unhexlify( '2F00' ))
    # see ETSI 102.221 11.1.1.4.3 for coding
    fileDesc = findTLValue( infoDIR, ( 0x62, 0x82 ))
    assert len( fileDesc ) == 5 and \
        fileDesc[:2] == '\x42\x21' # linear EF
    recLen, nRec = unpack( ">HB", fileDesc[2:5] )
    dirDO = []
    for recNum in xrange( 1, nRec+1 ):
        try:
            r = readRecord( c, recNum )
            if r == '\xFF'* len( r ): continue
            aid = findTLValue( r, ( 0x61, 0x4F ))
            label = findTLValue( r, ( 0x61, 0x50 ))
            dirDO.append( { 'AID': aid,
                            'label': label } )
        except ISOException:
            break
    # select USIM and try to read IMSI
    if len( dirDO ) == 1:
        aid_usim = dirDO[0]['AID']
    else:
        aids = [ DO['AID'] for DO in dirDO
                 if re.match( DO['label'], 'USIM' )]
        if len( aids ) == 1:
            aid_usim = aids[0]
        else:
            aid_usim = None
    if aid_usim:
        infoUSIM = selectApplet( c, aid_usim )
        infoIMSI = selectFile( c, unhexlify( '7FFF6F07' ))
        try:
            bimsi = readBinary( c, 9 )
            digits = reduce( lambda d, n: d + [ ord(n) & 0x0F, ord(n) >> 4 ],
                             bimsi[ 1:1+ord(bimsi[0])], [] )
            digits.pop(0)          # remove first nibble 8 or 9
            while digits[-1] == 0x0F: digits.pop() # remove trailing F
            imsi = ''.join( [ chr(ord('0')+i) for i in digits ])
        except ISOException:
            imsi = None
    else: imsi = None
    # select default applet and get tags 45 and 42
    selectApplet( c, '' )
    try:
        cin = findTLValue( getData( c, 0x42 ), ( 0x42, ))
    except ISOException:
        cin = None
    try:
        iin = findTLValue( getData( c, 0x45 ), ( 0x45, ))
    except ISOException:
        iin = None
    return histBytes, iccid, dirDO, imsi, iin, cin