def _mac(key, data, ssc=None, dopad=True): if ssc: data = ssc + data if dopad: topad = 8 - len(data) % 8 data = data + "\x80" + ("\x00" * (topad - 1)) a = crypto_utils.cipher(True, "des-cbc", key[:8], data, "\x00" * 8) b = crypto_utils.cipher(False, "des-ecb", key[8:16], a[-8:]) c = crypto_utils.cipher(True, "des-ecb", key[:8], b) return c
def _mac(key, data, ssc = None, dopad=True): if ssc: data = ssc + data if dopad: topad = 8 - len(data) % 8 data = data + "\x80" + ("\x00" * (topad-1)) a = crypto_utils.cipher(True, "des-cbc", key[:8], data) b = crypto_utils.cipher(False, "des-ecb", key[8:16], a[-8:]) c = crypto_utils.cipher(True, "des-ecb", key[:8], b) return c
def encrypt_command(self, tlv_data): config = self.get_config(SE_APDU, TEMPLATE_CT) if config.algorithm is None: ## FIXME: Find out the correct way to determine this return tlv_data result = [] for data in tlv_data: tag, length, value, marks = data if self.MARK_ENCRYPT in marks and tag not in (0xff, 0x00): t = tag & ~(0x01) if t == 0x84: value_ = self.pad(value) if generic_card.DEBUG: print "| Tag 0x%02x, length 0x%02x, encrypting (with ISO padding): " % (tag, length) print "|| " + "\n|| ".join( utils.hexdump( value_ ).splitlines() ) value = crypto_utils.cipher( True, self.get_cipherspec(config), self.get_key(config), value_, self.get_iv(config) ) if generic_card.DEBUG: print "| Encrypted result of length 0x%02x:" % len(value) print "|| " + "\n|| ".join( utils.hexdump(value).splitlines() ) print elif t == 0x86: pi = value[0] value_ = self.pad(value[1:], ord(pi)) if generic_card.DEBUG: print "| Tag 0x%02x, length 0x%02x, encrypting (with padding type %x): " % (tag, length, ord(pi)) print "|| " + "\n|| ".join( utils.hexdump( value_ ).splitlines() ) value = pi + crypto_utils.cipher( True, self.get_cipherspec(config), self.get_key(config), value_, self.get_iv(config) ) if generic_card.DEBUG: print "| Encrypted result of length 0x%02x:" % len(value) print "|| " + "\n|| ".join( utils.hexdump(value).splitlines() ) print result.append( (tag, length, value) ) else: # Ignore result.append(data[:3]) return result
def cmd_enc(self, *args): "Encrypt or decrypt with openssl-like interface" args = list(args) MODE_DECRYPT = "-d" MODE_ENCRYPT = "-e" mode = MODE_ENCRYPT if "-d" in args: mode = MODE_DECRYPT input = None if "-in" in args: i = args.index("-in") input = args[i+1] if "-K" not in args: raise ValueError, "Must specify key with -K" i = args.index("-K") key = args[i+1] key = binascii.a2b_hex("".join(key.split())) iv = None if "-iv" in args: i = args.index("-iv") iv = args[i+1] iv = binascii.a2b_hex("".join(iv.split())) cipher = "des" if args[0][0] != "-": cipher = args[0] text = None if "-text" in args: if input is not None: raise ValueError, "Can't give -in and -text" i = args.index("-text") text = binascii.a2b_hex("".join(args[i+1].split())) if text is None: if input is None: text = self.card.last_result.data else: fp = file(input) text = fp.read() fp.close() result = crypto_utils.cipher(mode == MODE_ENCRYPT, cipher, key, text, iv) self.card.last_result = utils.R_APDU(result+"\x00\x00") print utils.hexdump(result)
def cmd_perform_bac(self, mrz2, verbose=1): "Perform the Basic Acess Control authentication and establishment of session keys" mrz2 = mrz2.upper() Kseed = self.derive_seed(mrz2, verbose) Kenc = self.derive_key(Kseed, 1) Kmac = self.derive_key(Kseed, 2) if verbose: print "Kenc = %s" % hexdump(Kenc) print "Kmac = %s" % hexdump(Kmac) print result = self.send_apdu(self.APDU_GET_RANDOM) if not self.check_sw(result.sw): raise BACError, "SW after GET RANDOM was %02x%02x. Card refused to send rcd_icc. Should NEVER happen." % (result.sw1, result.sw2) rnd_icc = result.data if verbose: print "RND.icc = %s" % hexdump(rnd_icc) rndtmp = self._make_random(8 + 16) rnd_ifd = rndtmp[:8] Kifd = rndtmp[8:] if verbose: print "RND.ifd = %s" % hexdump(rnd_ifd) print "Kifd = %s" % hexdump(Kifd, indent=10) S = rnd_ifd + rnd_icc + Kifd Eifd = crypto_utils.cipher(True, "des3-cbc", Kenc, S) Mifd = self._mac(Kmac, Eifd) if verbose: print "Eifd = %s" % hexdump(Eifd, indent=10) print "Mifd = %s" % hexdump(Mifd) print auth_apdu = C_APDU(self.APDU_MUTUAL_AUTHENTICATE, data = Eifd + Mifd) result = self.send_apdu(auth_apdu) if not self.check_sw(result.sw): raise BACError, "SW after MUTUAL AUTHENTICATE was %02x%02x. Card did not accept our BAC attempt" % (result.sw1, result.sw2) resp_data = result.data Eicc = resp_data[:-8] Micc = self._mac(Kmac, Eicc) if not Micc == resp_data[-8:]: raise ValueError, "Passport authentication failed: Wrong MAC on incoming data during Mutual Authenticate" if verbose: print "Eicc = %s" % hexdump(Eicc, indent=10) print "Micc = %s" % hexdump(Micc) print "Micc verified OK" R = crypto_utils.cipher(False, "des3-cbc", Kenc, Eicc) if verbose: print "R = %s" % hexdump(R, indent=10) if not R[:8] == rnd_icc: raise BACError, "Passport authentication failed: Wrong RND.icc on incoming data during Mutual Authenticate" if not R[8:16] == rnd_ifd: raise BACError, "Passport authentication failed: Wrong RND.ifd on incoming data during Mutual Authenticate" Kicc = R[16:] if verbose: print "Kicc = %s" % hexdump(Kicc) print KSseed = crypto_utils.operation_on_string(Kicc, Kifd, lambda a,b: a^b) self.KSenc = self.derive_key(KSseed, 1) self.KSmac = self.derive_key(KSseed, 2) self.ssc = rnd_icc[-4:] + rnd_ifd[-4:] if False: self.KSenc = binascii.a2b_hex("979EC13B1CBFE9DCD01AB0FED307EAE5") self.KSmac = binascii.a2b_hex("F1CB1F1FB5ADF208806B89DC579DC1F8") self.ssc = binascii.a2b_hex("887022120C06C226") if verbose: print "KSseed = %s" % hexdump(KSseed) print "KSenc = %s" % hexdump(self.KSenc) print "KSmac = %s" % hexdump(self.KSmac) print "ssc = %s" % hexdump(self.ssc) self.se = Passport_Security_Environment(self)
def _mac(self, config, data): return crypto_utils.cipher( True, self.get_cipherspec(config), self.get_key(config), data, self.get_iv(config) )[-8:]
def decrypt_response(self, tlv_data): config = self.get_config(SE_RAPDU, TEMPLATE_CT) if config.algorithm is None: ## FIXME: Find out the correct way to determine this return tlv_data result = [] for data in tlv_data: tag, length, value = data[:3] marks = len(data) > 3 and data[3] or () t = tag & ~(0x01) if t == 0x84: if generic_card.DEBUG: print print "| Tag 0x%02x, length 0x%02x, encrypted (with ISO padding): " % (tag, length) print "|| " + "\n|| ".join( utils.hexdump( value ).splitlines() ) value_ = crypto_utils.cipher( False, self.get_cipherspec(config), self.get_key(config), value, self.get_iv(config) ) if generic_card.DEBUG: print "| Decrypted result of length 0x%02x:" % len(value_) print "|| " + "\n|| ".join( utils.hexdump(value_).splitlines() ) value = self.unpad(value_) if False: print "| Depadded result of length 0x%02x:" % len(value) print "|| " + "\n|| ".join( utils.hexdump(value).splitlines() ) marks = marks + (self.MARK_ENCRYPT,) elif t == 0x86: pi = value[0] if generic_card.DEBUG: print print "| Tag 0x%02x, length 0x%02x, decrypting (with padding type %x): " % (tag, length, ord(pi)) print "|| " + "\n|| ".join( utils.hexdump( value[1:] ).splitlines() ) value_ = crypto_utils.cipher( False, self.get_cipherspec(config), self.get_key(config), value[1:], self.get_iv(config) ) if generic_card.DEBUG: print "| Decrypted result of length 0x%02x:" % len(value_) print "|| " + "\n|| ".join( utils.hexdump(value_).splitlines() ) value = self.unpad(value_, ord(pi)) if False: print "| Depadded result of length 0x%02x:" % len(value) print "|| " + "\n|| ".join( utils.hexdump(value).splitlines() ) value = pi + value marks = marks + (self.MARK_ENCRYPT,) result.append( (tag, length, value, marks) ) return result
def cmd_perform_bac(self, mrz2, verbose=1): "Perform the Basic Acess Control authentication and establishment of session keys" mrz2 = mrz2.upper() Kseed = self.derive_seed(mrz2, verbose) Kenc = self.derive_key(Kseed, 1) Kmac = self.derive_key(Kseed, 2) if verbose: print "Kenc = %s" % hexdump(Kenc) print "Kmac = %s" % hexdump(Kmac) print result = self.send_apdu(self.APDU_GET_RANDOM) if not self.check_sw(result.sw): raise BACError, "SW after GET RANDOM was %02x%02x. Card refused to send rcd_icc. Should NEVER happen." % ( result.sw1, result.sw2) rnd_icc = result.data if verbose: print "RND.icc = %s" % hexdump(rnd_icc) rndtmp = self._make_random(8 + 16) rnd_ifd = rndtmp[:8] Kifd = rndtmp[8:] if verbose: print "RND.ifd = %s" % hexdump(rnd_ifd) print "Kifd = %s" % hexdump(Kifd, indent=10) S = rnd_ifd + rnd_icc + Kifd Eifd = crypto_utils.cipher(True, "des3-cbc", Kenc, S, "\x00" * 8) Mifd = self._mac(Kmac, Eifd) if verbose: print "Eifd = %s" % hexdump(Eifd, indent=10) print "Mifd = %s" % hexdump(Mifd) print auth_apdu = C_APDU(self.APDU_MUTUAL_AUTHENTICATE, data=Eifd + Mifd) result = self.send_apdu(auth_apdu) if not self.check_sw(result.sw): raise BACError, "SW after MUTUAL AUTHENTICATE was %02x%02x. Card did not accept our BAC attempt" % ( result.sw1, result.sw2) resp_data = result.data Eicc = resp_data[:-8] Micc = self._mac(Kmac, Eicc) if not Micc == resp_data[-8:]: raise ValueError, "Passport authentication failed: Wrong MAC on incoming data during Mutual Authenticate" if verbose: print "Eicc = %s" % hexdump(Eicc, indent=10) print "Micc = %s" % hexdump(Micc) print "Micc verified OK" R = crypto_utils.cipher(False, "des3-cbc", Kenc, Eicc, "\x00" * 8) if verbose: print "R = %s" % hexdump(R, indent=10) if not R[:8] == rnd_icc: raise BACError, "Passport authentication failed: Wrong RND.icc on incoming data during Mutual Authenticate" if not R[8:16] == rnd_ifd: raise BACError, "Passport authentication failed: Wrong RND.ifd on incoming data during Mutual Authenticate" Kicc = R[16:] if verbose: print "Kicc = %s" % hexdump(Kicc) print KSseed = crypto_utils.operation_on_string(Kicc, Kifd, lambda a, b: a ^ b) self.KSenc = self.derive_key(KSseed, 1) self.KSmac = self.derive_key(KSseed, 2) self.ssc = rnd_icc[-4:] + rnd_ifd[-4:] if False: self.KSenc = binascii.a2b_hex("979EC13B1CBFE9DCD01AB0FED307EAE5") self.KSmac = binascii.a2b_hex("F1CB1F1FB5ADF208806B89DC579DC1F8") self.ssc = binascii.a2b_hex("887022120C06C226") if verbose: print "KSseed = %s" % hexdump(KSseed) print "KSenc = %s" % hexdump(self.KSenc) print "KSmac = %s" % hexdump(self.KSmac) print "ssc = %s" % hexdump(self.ssc) self.se = Passport_Security_Environment(self)