def mutual_authenticate(self, p1, p2, mutual_challenge): """ Takes an encrypted challenge in the form 'Terminal Challenge | Card Challenge | Card number' and checks it for validity. If the challenge is successful the card encrypts 'Card Challenge | Terminal challenge' and returns this value """ key = self._get_referenced_key(p1, p2) card_number = self.get_card_number() if (key == None): raise SwError(SW["ERR_INCORRECTP1P2"]) if p1 == 0x00: #No information given cipher = get_referenced_cipher(self.cipher) else: cipher = get_referenced_cipher(p1) if (cipher == None): raise SwError(SW["ERR_INCORRECTP1P2"]) plain = vsCrypto.decrypt(cipher, key, mutual_challenge) last_challenge_len = len(self.last_challenge) terminal_challenge = plain[:last_challenge_len-1] card_challenge = plain[last_challenge_len:-len(card_number)-1] serial_number = plain[-len(card_number):] if terminal_challenge != self.last_challenge: raise SwError(SW["WARN_NOINFO63"]) elif serial_number != card_number: raise SwError(SW["WARN_NOINFO63"]) result = card_challenge + terminal_challenge return SW["NORMAL"], vsCrypto.encrypt(cipher, key, result)
def mutual_authenticate(self, p1, p2, mutual_challenge): """ Takes an encrypted challenge in the form 'Terminal Challenge | Card Challenge | Card number' and checks it for validity. If the challenge is successful the card encrypts 'Card Challenge | Terminal challenge' and returns this value """ key = self._get_referenced_key(p1, p2) card_number = self.get_card_number() if (key == None): raise SwError(SW["ERR_INCORRECTP1P2"]) if p1 == 0x00: #No information given cipher = get_referenced_cipher(self.cipher) else: cipher = get_referenced_cipher(p1) if (cipher == None): raise SwError(SW["ERR_INCORRECTP1P2"]) plain = vsCrypto.decrypt(cipher, key, mutual_challenge) last_challenge_len = len(self.last_challenge) terminal_challenge = plain[:last_challenge_len - 1] card_challenge = plain[last_challenge_len:-len(card_number) - 1] serial_number = plain[-len(card_number):] if terminal_challenge != self.last_challenge: raise SwError(SW["WARN_NOINFO63"]) elif serial_number != card_number: raise SwError(SW["WARN_NOINFO63"]) result = card_challenge + terminal_challenge return SW["NORMAL"], vsCrypto.encrypt(cipher, key, result)
def external_authenticate(self, p1, p2, resp_data): """Performs the basic access control protocol as defined in the ICAO MRTD standard""" rnd_icc = self.last_challenge # Receive Mutual Authenticate APDU from terminal # Decrypt data and check MAC Eifd = resp_data[:-8] padded_Eifd = vsCrypto.append_padding(self.current_SE.cct.blocklength, Eifd) Mifd = vsCrypto.crypto_checksum("CC", self.KMac, padded_Eifd) # Check the MAC if not Mifd == resp_data[-8:]: raise SwError(SW["ERR_SECMESSOBJECTSINCORRECT"]) # Decrypt the data plain = vsCrypto.decrypt("DES3-CBC", self.KEnc, resp_data[:-8]) if plain[8:16] != rnd_icc: raise SwError(SW["WARN_NOINFO63"]) # Extract keying material from IFD, generate ICC keying material Kifd = plain[16:] rnd_ifd = plain[:8] Kicc = urandom(16) # Generate Answer data = plain[8:16] + plain[:8] + Kicc Eicc = vsCrypto.encrypt("DES3-CBC", self.KEnc, data) padded_Eicc = vsCrypto.append_padding(self.current_SE.cct.blocklength, Eicc) Micc = vsCrypto.crypto_checksum("CC", self.KMac, padded_Eicc) # Derive the final keys and set the current SE KSseed = vsCrypto.operation_on_string(Kicc, Kifd, lambda a, b: a ^ b) self.current_SE.ct.key = self.derive_key(KSseed, 1) self.current_SE.cct.key = self.derive_key(KSseed, 2) self.current_SE.ssc = stringtoint(rnd_icc[-4:] + rnd_ifd[-4:]) return SW["NORMAL"], Eicc + Micc
def encipher(self, p1, p2, data): """ Encipher data using key, algorithm, IV and Padding specified by the current Security environment. :returns: raw data (no TLV coding). """ algo = self.ct.algorithm key = self.ct.key if key == None or algo == None: raise SwError(SW["ERR_CONDITIONNOTSATISFIED"]) else: padded = vsCrypto.append_padding(vsCrypto.get_cipher_blocklen(algo), data) crypted = vsCrypto.encrypt(algo, key, padded, self.ct.iv) return crypted
def internal_authenticate(self, p1, p2, data): """ Authenticate card to terminal. Encrypt the challenge of the terminal to prove key posession """ if p1 == 0x00: #No information given cipher = get_referenced_cipher(self.cipher) else: cipher = get_referenced_cipher(p1) if cipher == "RSA" or cipher == "DSA": crypted_challenge = self.asym_key.sign(data, "") crypted_challenge = crypted_challenge[0] crypted_challenge = inttostring(crypted_challenge) else: key = self._get_referenced_key(p1, p2) crypted_challenge = vsCrypto.encrypt(cipher, key, data) return SW["NORMAL"], crypted_challenge
def internal_authenticate(self, p1, p2, data): """ Authenticate card to terminal. Encrypt the challenge of the terminal to prove key posession """ if p1 == 0x00: #No information given cipher = get_referenced_cipher(self.cipher) else: cipher = get_referenced_cipher(p1) if cipher == "RSA" or cipher == "DSA": crypted_challenge = self.asym_key.sign(data,"") crypted_challenge = crypted_challenge[0] crypted_challenge = inttostring(crypted_challenge) else: key = self._get_referenced_key(p1, p2) crypted_challenge = vsCrypto.encrypt(cipher, key, data) return SW["NORMAL"], crypted_challenge
def external_authenticate(self, p1, p2, data): """ Authenticate the terminal to the card. Check whether Terminal correctly encrypted the given challenge or not """ if self.last_challenge is None: raise SwError(SW["ERR_CONDITIONNOTSATISFIED"]) key = self._get_referenced_key(p1, p2) if p1 == 0x00: #No information given cipher = get_referenced_cipher(self.cipher) else: cipher = get_referenced_cipher(p1) reference = vsCrypto.append_padding(cipher, self.last_challenge) reference = vsCrypto.encrypt(cipher, key, reference) if(reference == data): #Invalidate last challenge self.last_challenge = None return SW["NORMAL"], "" else: raise SwError(SW["WARN_NOINFO63"])