def derive_visa_sm_sk(icc_mk: bytes, atc: bytes) -> bytes: r"""Visa Secure Messaging Session Key Derivation Parameters ---------- icc_mk : bytes Binary ICC Master Key to derive session key from. Has to be a valid DES key. atc : bytes Binary data from tag 9F36 (Application Transaction Counter). Returns ------- sk : bytes Binary 16-byte Session Key. Raises ------ ValueError ICC Master Key must be a double length DES key ATC value must be 2 bytes long Examples -------- >>> from pyemv import kd >>> mk = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> atc = bytes.fromhex("001C") >>> sk = kd.derive_visa_sm_sk(mk, atc) >>> sk.hex().upper() '0123456789ABCDF2FEDCBA987654CDF2' """ if len(icc_mk) != 16: raise ValueError("ICC Master Key must be a double length DES key") if len(atc) != 2: raise ValueError("ATC value must be 2 bytes long") # SK Key A (i.e. first 8 bytes) = r _xor MK Key A r = b"\x00" * 6 + atc sk_a = _xor(r, icc_mk[:8]) # SK Key B (i.e. second 8 bytes) = r _xor MK Key B r = b"\x00" * 6 + _xor(atc, b"\xff\xff") sk_b = _xor(r, icc_mk[8:]) return _adjust_key_parity(sk_a + sk_b)
def derive_icc_mk_a(iss_mk: bytes, pan: bytes, psn: Optional[bytes] = None) -> bytes: r"""ICC Master Key Derivation. EMV Option A. Uses PAN, PAN Sequence Number, MK ISS, Triple DES. Parameters ---------- iss_mk : bytes Binary Issuer Master Key to derive ICC Master Key from. Has to be a valid DES key. pan : bytes ASCII Application Primary Account Number. psn : bytes, optional ASCII 2-digit PAN Sequence Number (default 00). Returns ------- icc_mk : bytes Binary 16-byte ICC Master Key. Notes ----- Derived from Issuer Master Key (iss_mk). Uses EMV Option A - Master Key Derivation method which uses the PAN and PAN sequence number, as defined in EMV Book 2, Annex A. When a card is personalised the issuer will take the 3 iss_mk keys and calculate the 3 icc_mk keys to be stored on the card. - icc_mk_ac - used for the transaction cryptograms (ARQC, TC or AAC) - icc_mk_smi - used for Issuer Script Integrity - icc_mk_smc - used for Issuer Script Confidentiality For further details see also: - EMV 4.3 Book 2 Annex A 1.4 Master Key Derivation - EMV 4.3 Book 2 Annex A 1.4.1 Option A Examples -------- >>> from pyemv import kd >>> iss_mk = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> icc_mk = kd.derive_icc_mk_a(iss_mk, pan=b"12345678901234567", psn=b"01") >>> icc_mk.hex().upper() '73AD54688CEF2934B0979857E3C719F1' """ if psn is None: psn = b"00" # Data A must be at most 16 digits, right-justified, # zero-padded from the left. data_a = _binascii.a2b_hex((pan + psn)[-16:].zfill(16)) # Data B is inverted data A data_b = _xor(data_a, b"\xFF" * len(data_a)) icc_mk = _encrypt_tdes_ecb(iss_mk, data_a + data_b) return _adjust_key_parity(icc_mk)
def generate_arpc_1(sk_ac: bytes, arqc: bytes, arpc_rc: bytes) -> bytes: r"""Generate Authorisation Response Cryptogram (ARPC) using method 1. Method for the generation of an 8-byte ARPC consists of applying the Triple-DES algorithm to: - 8-byte binary ARQC - 2-byte binary Authorisation Response Code (ARPC-RC) Parameters ---------- sk_ac : bytes Binary ICC Session Key for AC. Has to be a valid DES key. arqc : bytes Binary 8-byte Authorisation Request Cryptogram (ARQC). arpc_rc : bytes Binary 2-byte ARPC response code. Returns ------- arpc : bytes Returns binary 8-byte Authorisation Response Cryptogram (ARPC). The resulting issuer authentication data (tag 91) is: 91 || Len || ARPC || ARPC-RC Raises ------ ValueError Session Key must be a double length DES key ARQC must be 8 bytes long ARPC-RC must be 2 bytes long Notes ----- After the host has validated the cryptogram sent by the terminal/reader in the authorisation request it will generate an Authorisation Response cryptogram (ARPC) which will then be returned in the response message along with the ARPC response code and ultimately validated by the card. For further details see also: - EMV 4.3 Book 2 Section 8.2 Issuer Authentication - EMV 4.3 Book 2 Section 8.2.1 ARPC Method 1 Examples -------- >>> from pyemv import ac >>> sk_ac = bytes.fromhex("AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB") >>> arqc = bytes.fromhex("1234567890ABCDEF") >>> arpc_rc = bytes.fromhex("0000") >>> arpc = ac.generate_arpc_1(sk_ac, arqc, arpc_rc) >>> arpc.hex().upper() 'F5E6F44147E2F1B0' """ if len(sk_ac) != 16: raise ValueError("Session Key must be a double length DES key") if len(arqc) != 8: raise ValueError("ARQC must be 8 bytes long") if len(arpc_rc) != 2: raise ValueError("ARPC-RC must be 2 bytes long") return _encrypt_tdes_cbc(sk_ac, b"\x00\x00\x00\x00\x00\x00\x00\x00", _xor(arpc_rc + (b"\00" * 6), arqc))
def derive_icc_mk_b(iss_mk: bytes, pan: bytes, psn: Optional[bytes] = None) -> bytes: r"""ICC Master Key Derivation. EMV Option B. Uses PAN, PAN Sequence Number, MK ISS, Triple DES, SHA-1 and decimalisation of hex digits. Parameters ---------- iss_mk : bytes Binary Issuer Master Key to derive ICC Master Key from. Has to be a valid DES key. pan : bytes ASCII Application Primary Account Number. psn : bytes, optional ASCII 2-digit PAN Sequence Number (default 00). Returns ------- icc_mk : bytes Binary 16-byte ICC Master Key Notes ----- Derived from Issuer Master Key (iss_mk). Uses EMV Option B - Master Key Derivation method which uses the PAN and PAN sequence number, as defined in EMV Book 2, Annex A. When a card is personalised the issuer will take the 3 iss_mk keys and calculate the 3 icc_mk keys to be stored on the card. - icc_mk_ac - used for the transaction cryptograms (ARQC, TC or AAC) - icc_mk_smi - used for Issuer Script Integrity - icc_mk_smc - used for Issuer Script Confidentiality For further details see also: - EMV 4.3 Book 2 Annex A 1.4 Master Key Derivation - EMV 4.3 Book 2 Annex A 1.4.2 Option B Examples -------- >>> from pyemv import kd >>> iss_mk = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> icc_mk = kd.derive_icc_mk_b(iss_mk, pan=b"12345678901234567", psn=b"01") >>> icc_mk.hex().upper() 'AD406D7F6D7570916D75E5DCAB8CF737' """ # For PANs with length of 16 or less method B works as method A if len(pan) <= 16: return derive_icc_mk_a(iss_mk, pan, psn) if psn is None: psn = b"00" # Data A must be an even number of digits, # right-justified, zero-padded from the left. if len(pan) % 2: pan_psn = _binascii.a2b_hex(b"0" + pan + psn) else: pan_psn = _binascii.a2b_hex(pan + psn) # Hash PAN || PAN sequence digest = _hashlib.sha1(pan_psn).hexdigest() # Get first 16 digits out the hash value. result = "".join(filter(str.isdigit, digest))[:16] # If there are not enough digits, substitute # letters using the following decimalization table: # Input a b c d e f # Table 0 1 2 3 4 5 if len(result) < 16: digest = "".join(filter((lambda x: x in ("abcdef")), digest)) digest = digest.translate({ 97: 48, 98: 49, 99: 50, 100: 51, 101: 52, 102: 53 }) result = result + digest[:16 - len(result)] data_a = _binascii.a2b_hex(result) # Data B is inverted data A data_b = _xor(data_a, b"\xFF" * len(data_a)) icc_mk = _encrypt_tdes_ecb(iss_mk, data_a + data_b) return _adjust_key_parity(icc_mk)
def format_vis_pin_block( icc_mk_ac: bytes, pin: bytes, current_pin: Optional[bytes] = None ) -> bytes: r"""Format VIS PIN block with or without the current PIN. Parameters ---------- icc_mk_ac : bytes Binary 16-byte ICC Master Key for Application Cryptogram Has to be a valid DES key. pin : bytes New ASCII Personal Identification Number. current_pin : bytes, optional Current ASCII Personal Identification Number (optional). If present VIS PIN block is generated using current PIN. Returns ------- pin_block : bytes Binary 16-byte VIS PIN block Raises ------ ValueError PIN must be between 4 and 12 digits long Current PIN must be between 4 and 12 digits long ICC Master Key for AC must be a double length DES key Examples -------- >>> from pyemv import sm >>> icc_mk_ac = bytes.fromhex("0123456789ABCDEFFEDCBA9876543210") >>> sm.format_vis_pin_block(icc_mk_ac, b"1234").hex().upper() '041234FF76543210' """ if len(pin) < 4 or len(pin) > 12: raise ValueError("PIN must be between 4 and 12 digits long") if len(icc_mk_ac) != 16: raise ValueError("ICC Master Key for AC must be a double length DES key") # 4 right-most bytes of ICC MK AC Key A padded with 0x00 to form an 8-byte block block_a = b"\x00" * 4 + icc_mk_ac[4:8] # PIN length as 1 byte concatenated with PIN then F-padded to form an 8 byte block block_b = len(pin).to_bytes(1, _sys.byteorder) + _binascii.a2b_hex( pin + b"F" * (14 - len(pin)) ) pin_block = _xor(block_a, block_b) # Generate VIS PIN block using current PIN if current_pin is not None: if len(current_pin) < 4 or len(current_pin) > 12: raise ValueError("Current PIN must be between 4 and 12 digits long") pin_block = _xor( pin_block, _binascii.a2b_hex(current_pin + b"0" * (16 - len(current_pin))) ) return pin_block