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
def wrapData(self, data, zPad=False): """ Cipher data by DEK. """ if zPad: data = pad80(data) assert len(data) % 8 == 0, "Sensitive data must be BS padded" k = DES3.new(self.ses_DEK, DES.MODE_ECB) return k.encrypt(data)
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
def calcMAC_3d(self, s): """ Pad string and calculate MAC according to B.1.2.1 - Full 3DES """ e = DES3.new(self.ses_ENC, DES.MODE_ECB) s = pad80(s, 8) q = len(s) / 8 h = ZERO8 for i in xrange(q): h = e.encrypt(bxor(h, s[8 * i:8 * (i + 1)])) return h
def calcMAC_3d( self, s ): """ Pad string and calculate MAC according to B.1.2.1 - Full 3DES """ e = DES3.new( self.ses_ENC, DES.MODE_ECB ) s = pad80( s ) q = len( s ) / 8 h = ZERO8 for i in xrange(q): h = e.encrypt( bxor( h, s[8*i:8*(i+1)] )) return h
def calc(self, s): " Pad string and calculate MAC according to B.1.2.2 - " +\ "Single DES plus final 3DES """ s = pad80(s, 8) q = len(s) / 8 h = '\0' * 8 # zero ICV for i in xrange(q): h = self.e.encrypt(bxor(h, s[8 * i:8 * (i + 1)])) h = self.d.decrypt(h) h = self.e.encrypt(h) return h
def calcMAC_1d(self, s, zResetICV=False): " Pad string and calculate MAC according to B.1.2.2 - " +\ "Single DES plus final 3DES """ e = DES.new(self.ses_C_MAC[:8], DES.MODE_ECB) d = DES.new(self.ses_C_MAC[8:], DES.MODE_ECB) s = pad80(s, 8) q = len(s) / 8 h = zResetICV and ZERO8 or self.icv for i in xrange(q): h = e.encrypt(bxor(h, s[8 * i:8 * (i + 1)])) h = d.decrypt(h) h = e.encrypt(h) self.icv = (self.i & M_ICV_ENC) and self.k_icv.encrypt(h) or h return h
def calcMAC_1d( self, s, zResetICV = False ): " Pad string and calculate MAC according to B.1.2.2 - " +\ "Single DES plus final 3DES """ e = DES.new( self.ses_C_MAC[:8], DES.MODE_ECB ) d = DES.new( self.ses_C_MAC[8:], DES.MODE_ECB ) s = pad80( s ) q = len( s ) / 8 h = zResetICV and ZERO8 or self.icv for i in xrange(q): h = e.encrypt( bxor( h, s[8*i:8*(i+1)] )) h = d.decrypt( h ) h = e.encrypt( h ) self.icv = ( self.i & M_ICV_ENC ) and self.k_icv.encrypt( h ) or h return h
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
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
def wrapData( self, data, zPad = False ): """ Cipher data by DEK. """ if zPad: data = pad80( data ) assert len( data ) % 8 == 0, "Sensitive data must be BS padded" k = DES3.new( self.ses_DEK, DES.MODE_ECB ) return k.encrypt( data )