def find_hash_name(security_infos: List[bytes]) -> str: """ Return the hashing algorithm for ECC AA from SecurityInfos (DG14) """ for sec_info in security_infos: i = asn1_node_root(sec_info) i = asn1_node_first_child(sec_info, i) # get OID for this SecurityInfo si_oid = asn1_get_all(sec_info, i) if si_oid != encode_oid_string( "2.23.136.1.1.5"): # id-icao-mrtd-security-aaProtocolObject continue i = asn1_node_next(sec_info, i) if asn1_get_value_of_type(sec_info, i, "INTEGER") != b"\x01": raise ValueError("[-] Version mismatch in DG14 AA SecurityInfo!") i = asn1_node_next(sec_info, i) signature_algorithm = asn1_get_all(sec_info, i) if signature_algorithm == encode_oid_string("0.4.0.127.0.7.1.1.4.1.2"): return "sha224" if signature_algorithm == encode_oid_string("0.4.0.127.0.7.1.1.4.1.3"): return "sha256" if signature_algorithm == encode_oid_string("0.4.0.127.0.7.1.1.4.1.4"): return "sha384" if signature_algorithm == encode_oid_string("0.4.0.127.0.7.1.1.4.1.5"): return "sha512" raise ValueError("[-] Unsupported signature algorithm in AA SecurityInfo!")
def find_paceinfos(security_infos: List[bytes]) -> List[Tuple[bytes, int]]: """ From SecurityInfos find Chip Authentication Public Keys and return them as\n list(list(key_id, pub_key))\n If key id doesn't exist, it is an empty bytes b"" """ id_pace = "0.4.0.127.0.7.2.2.4" pace_protocol_dict = { encode_oid_string(id_pace + ".1.1"): "id-PACE-DH-GM-3DES-CBC-CBC", encode_oid_string(id_pace + ".1.2"): "id-PACE-DH-GM-AES-CBC-CMAC-128", encode_oid_string(id_pace + ".1.3"): "id-PACE-DH-GM-AES-CBC-CMAC-192", encode_oid_string(id_pace + ".1.4"): "id-PACE-DH-GM-AES-CBC-CMAC-256", encode_oid_string(id_pace + ".2.1"): "id-PACE-ECDH-GM-3DES-CBC-CBC", encode_oid_string(id_pace + ".2.2"): "id-PACE-ECDH-GM-AES-CBC-CMAC-128", encode_oid_string(id_pace + ".2.3"): "id-PACE-ECDH-GM-AES-CBC-CMAC-192", encode_oid_string(id_pace + ".2.4"): "id-PACE-ECDH-GM-AES-CBC-CMAC-256", encode_oid_string(id_pace + ".3.1"): "id-PACE-DH-IM-3DES-CBC-CBC", encode_oid_string(id_pace + ".3.2"): "id-PACE-DH-IM-AES-CBC-CMAC-128", encode_oid_string(id_pace + ".3.3"): "id-PACE-DH-IM-AES-CBC-CMAC-192", encode_oid_string(id_pace + ".3.4"): "id-PACE-DH-IM-AES-CBC-CMAC-256", encode_oid_string(id_pace + ".4.1"): "id-PACE-ECDH-IM-3DES-CBC-CBC", encode_oid_string(id_pace + ".4.2"): "id-PACE-ECDH-IM-AES-CBC-CMAC-128", encode_oid_string(id_pace + ".4.3"): "id-PACE-ECDH-IM-AES-CBC-CMAC-192", encode_oid_string(id_pace + ".4.4"): "id-PACE-ECDH-IM-AES-CBC-CMAC-256", encode_oid_string(id_pace + ".6.2"): "id-PACE-ECDH-CAM-AES-CBC-CMAC-128", encode_oid_string(id_pace + ".6.3"): "id-PACE-ECDH-CAM-AES-CBC-CMAC-192", encode_oid_string(id_pace + ".6.4"): "id-PACE-ECDH-CAM-AES-CBC-CMAC-256", } supported_pace: List[Tuple[bytes, int]] = [] for sec_info in security_infos: i = asn1_node_root(sec_info) i = asn1_node_first_child(sec_info, i) # get OID for this SecurityInfo si_oid = asn1_get_all(sec_info, i) if si_oid not in pace_protocol_dict: continue i = asn1_node_next(sec_info, i) # get version for this PACEInfo si_ver = asn1_get_value_of_type(sec_info, i, "INTEGER") if si_ver != b"\x02": # Other versions are not supported continue i = asn1_node_next(sec_info, i) # get parameterID for this PACEInfo si_parameter_info = int.from_bytes( asn1_get_value_of_type(sec_info, i, "INTEGER"), byteorder="big" ) supported_pace.append((si_oid, si_parameter_info)) return supported_pace
def extract_certificates(signed_data: bytes) -> List[X509]: """ Return CSCA certificates from Master List """ certs = [] i = asn1_node_root(signed_data) last_byte = i[2] i = asn1_node_first_child(signed_data, i) i = asn1_node_next(signed_data, i) i = asn1_node_first_child(signed_data, i) while True: data = asn1_get_all(signed_data, i) certs.append(load_certificate(FILETYPE_ASN1, data)) if i[2] == last_byte: break i = asn1_node_next(signed_data, i) print(f"\t[+] Extracted {len(certs)} certs") return certs
def parse_efcom(efcom: bytes) -> Dict[bytes, str]: """ Parse EF.COM file and return the files mentioned as a dict """ i = asn1_node_root(efcom) lst = list(i) # LDS Version length is 4 lst[0] = lst[1] lst[1] = lst[0] + 3 lst[2] = lst[1] + 3 i = (lst[0], lst[1], lst[2]) lds_ver = asn1_get_value(efcom, i) print("[+] LDS version: {}.{}".format( *[int(lds_ver[i:i + 2].decode("utf-8")) for i in range(0, 4, 2)])) # Unicode Version number length is 6 lst[0] = lst[2] + 1 lst[1] = lst[0] + 3 lst[2] = lst[1] + 5 i = (lst[0], lst[1], lst[2]) unicode_ver = asn1_get_value(efcom, i) print("[+] Unicode version: {}.{}.{}".format( *[int(unicode_ver[i:i + 2].decode("utf-8")) for i in range(0, 6, 2)])) i = asn1_node_next(efcom, i) rest = asn1_get_value(efcom, i) tag2dg: Dict[int, Tuple[bytes, str]] = { 0x60: (b"\x1E", "EF.COM"), 0x61: (b"\x01", "EF.DG1"), 0x75: (b"\x02", "EF.DG2"), 0x63: (b"\x03", "EF.DG3"), 0x76: (b"\x04", "EF.DG4"), 0x65: (b"\x05", "EF.DG5"), 0x66: (b"\x06", "EF.DG6"), 0x67: (b"\x07", "EF.DG7"), 0x68: (b"\x08", "EF.DG8"), 0x69: (b"\x09", "EF.DG9"), 0x6A: (b"\x0A", "EF.DG10"), 0x6B: (b"\x0B", "EF.DG11"), 0x6C: (b"\x0C", "EF.DG12"), 0x6D: (b"\x0D", "EF.DG13"), 0x6E: (b"\x0E", "EF.DG14"), 0x6F: (b"\x0F", "EF.DG15"), 0x70: (b"\x10", "EF.DG16"), 0x77: (b"\x1D", "EF.SOD"), } dg_list = {tag2dg[byte][0]: tag2dg[byte][1] for byte in rest} return dg_list
def add_seconds_to_certificate(cert: bytes, seconds: int) -> bytes: from datetime import datetime, timedelta i = asn1_node_root(cert) # Certificate i = asn1_node_first_child(cert, i) # tbsCertificate i = asn1_node_first_child(cert, i) # version i = asn1_node_next(cert, i) # serialNumber i = asn1_node_next(cert, i) # signature i = asn1_node_next(cert, i) # issuer i = asn1_node_next(cert, i) # validity i = asn1_node_first_child(cert, i) # notBefore not_before = asn1_get_value(cert, i) if len(not_before) == 13: date_format = "%y%m%d%H%M%SZ" else: date_format = "%Y%m%d%H%M%SZ" date_time_obj = datetime.strptime(not_before.decode("utf-8"), date_format) cert = ( cert[:i[1]] + (date_time_obj + timedelta(seconds=seconds)).strftime(date_format).encode("utf_8") + cert[i[2] + 1:]) i = asn1_node_next(cert, i) # notAfter not_after = asn1_get_value(cert, i) if len(not_after) == 13: date_format = "%y%m%d%H%M%SZ" else: date_format = "%Y%m%d%H%M%SZ" date_time_obj = datetime.strptime(not_after.decode("utf-8"), date_format) cert = ( cert[:i[1]] + (date_time_obj + timedelta(seconds=seconds)).strftime(date_format).encode("utf_8") + cert[i[2] + 1:]) return cert
def assert_dg_hash(dg_file: bytes, data_group_hash_values: bytes, hash_alg: str, dg_number_bytes: bytes) -> bool: """ Calculate the hash over the DG file and compare that in the EF.SOD. """ dg_number = int.from_bytes(dg_number_bytes, byteorder="big") # Only hashes for DG1-DG16 exist if dg_number < 1 and dg_number > 16: raise ValueError("[-] Only hashes for DG1-DG16 exist!") hash_object = hashlib.new(hash_alg) hash_object.update(dg_file) file_hash = hash_object.digest() current = 0 i = asn1_node_root(data_group_hash_values) i = asn1_node_first_child(data_group_hash_values, i) while True: j = asn1_node_first_child(data_group_hash_values, i) current = int.from_bytes( asn1_get_value_of_type(data_group_hash_values, j, "INTEGER"), byteorder="big", ) if current == dg_number: break i = asn1_node_next(data_group_hash_values, i) j = asn1_node_next(data_group_hash_values, j) hash_in_dg = asn1_get_value(data_group_hash_values, j) if not hmac.compare_digest(file_hash, hash_in_dg): print("[-] Potentially cloned document, hashes do not match!") return False print(f"[+] DG {dg_number} hash matches that on the EF.SOD.") return True
def get_dg_numbers(data_group_hash_values: bytes) -> Dict[bytes, str]: """ Get DG numbers from EF.SOD data group hash values. """ dg_list = [] i = asn1_node_root(data_group_hash_values) last = i[2] i = asn1_node_first_child(data_group_hash_values, i) j = asn1_node_first_child(data_group_hash_values, i) dg_list.append(asn1_get_value_of_type(data_group_hash_values, j, "INTEGER")) while i[2] != last: i = asn1_node_next(data_group_hash_values, i) j = asn1_node_first_child(data_group_hash_values, i) dg_list.append( asn1_get_value_of_type(data_group_hash_values, j, "INTEGER")) tag2dg: Dict[bytes, str] = { b"\x1E": "EF.COM", b"\x01": "EF.DG1", b"\x02": "EF.DG2", b"\x03": "EF.DG3", b"\x04": "EF.DG4", b"\x05": "EF.DG5", b"\x06": "EF.DG6", b"\x07": "EF.DG7", b"\x08": "EF.DG8", b"\x09": "EF.DG9", b"\x0A": "EF.DG10", b"\x0B": "EF.DG11", b"\x0C": "EF.DG12", b"\x0D": "EF.DG13", b"\x0E": "EF.DG14", b"\x0F": "EF.DG15", b"\x10": "EF.DG16", b"\x1D": "EF.SOD", } return {byte: tag2dg[byte] for byte in dg_list}
def parse_security_infos(dg14: bytes) -> List[bytes]: """ Return a list of SecurityInfo from SecurityInfos """ i = asn1_node_root(dg14) if dg14[0] == 0x6E: # strip DG14 tag (6E) i = asn1_node_first_child(dg14, i) last_byte = i[2] security_infos = [] i = asn1_node_first_child(dg14, i) security_infos.append(asn1_get_all(dg14, i)) if i[2] != last_byte: while True: i = asn1_node_next(dg14, i) security_infos.append(asn1_get_all(dg14, i)) if i[2] == last_byte: break return security_infos
def passive_auth( efsod: bytes, ee_deviant_doc: bool = False, dump: bool = False ) -> Tuple[str, bytes, bytes, Optional[List[PassiveAuthenticationError]]]: """ Do Passive Authentication :returns: hash_alg that is used to hash DGs, data_group_hash_values """ exceptions: List[PassiveAuthenticationError] = [] # get root node i = asn1_node_root(efsod) # unpack application data 0x77 i = asn1_node_first_child(efsod, i) # unpack sequence i = asn1_node_first_child(efsod, i) # print id-signedData OBJECT IDENTIFIER if dump: print(dump_asn1(asn1_get_all(efsod, i))) # get 2nd item inside (SignedData EXPLICIT tagged) i = asn1_node_next(efsod, i) # unpack SignedData EXPLICIT tag i = asn1_node_first_child(efsod, i) # get 1st item inside (CMSVersion Value = v3) i = asn1_node_first_child(efsod, i) # get 2nd item (DigestAlgorithmIdentifiers) collection of message digest algorithm identifiers. # There MAY be any number of elements in the collection, including zero. i = asn1_node_next(efsod, i) # get 3rd item (EncapsulatedContentInfo) (LDS Document Security Object) i = asn1_node_next(efsod, i) # get 1st item inside (eContentType) # (OID joint-iso-itu-t (2) international(23) icao(136) mrtd(1) security(1) ldsSecurityObject(1)) j = asn1_node_first_child(efsod, i) e_content_type = asn1_get_all(efsod, j) # get the EXPLICIT tagged encoded contents of ldsSecurityObject j = asn1_node_next(efsod, j) # get the encoded contents of ldsSecurityObject j = asn1_node_first_child(efsod, j) # print the value of eContent hash encapsulated_content = asn1_get_value_of_type(efsod, j, "OCTET STRING") del j signer_infos, certificates, crls = None, None, None while signer_infos is None: # https://stackoverflow.com/a/52041365/6077951 # get 4th item i = asn1_node_next(efsod, i) if efsod[i[0]] == 0xA0: # Constructed, Context-Specific 0 certificates = i print("[+] CertificateSet exist") elif efsod[i[0]] == 0xA1: # Constructed, Context-Specific 1 crls = i print("[+] Crls exist") else: signer_infos = i # The inspection system SHALL build and validate a certification path # from a Trust Anchor to the Document Signer Certificate used to # sign the Document Security Object (SOD) according to Doc 9303-11. # store was already built in the first run store = build_store.store doc_sig_cert = asn1_get_value(efsod, certificates) if certificates is not None: if ee_deviant_doc: doc_sig_cert = add_seconds_to_certificate(doc_sig_cert, 43200) CDS = load_certificate(FILETYPE_ASN1, doc_sig_cert) store_ctx = X509StoreContext(store, CDS) try: if store_ctx.verify_certificate() is None: print( "[+] Document Signer Certificate is signed by a CSCA certificate" ) except X509StoreContextError as ex: exceptions.append( PassiveAuthenticationError( "[-] Document Signer Certificate is not signed " "by a CSCA certificate or is invalid!\n" + str(ex))) else: raise PassiveAuthenticationCriticalError( "[-] This application doesn't support this kind of document yet!") # get 1st signerInfo inside signerInfos i = asn1_node_first_child(efsod, signer_infos) # get 1st item inside 1st signerInfo (CMSVersion) i = asn1_node_first_child(efsod, i) signer_info_ver = int.from_bytes(asn1_get_value_of_type( efsod, i, "INTEGER"), byteorder="big") issuer_and_serial_number, subject_key_identifier = None, None # get 2nd item inside 1st signerInfo (SignerIdentifier) i = asn1_node_next(efsod, i) if signer_info_ver == 1: issuer_and_serial_number = i elif signer_info_ver == 3: subject_key_identifier = i if dump: print( dump_asn1( asn1_get_all( efsod, issuer_and_serial_number or subject_key_identifier))) # get 3rd item inside 1st signerInfo (DigestAlgorithmIdentifier) i = asn1_node_next(efsod, i) # get hash algorithm used for encapsulatedContent and SignedAttrs hash_alg = asn1_get_all(efsod, asn1_node_first_child(efsod, i)) try: hash_alg = get_digestalg_name(hash_alg) except ValueError as ex: raise PassiveAuthenticationCriticalError( "[-] Hash algorithm is not recognized.") from ex # get 4th item inside 1st signerInfo ([0] IMPLICIT SignedAttributes) i = asn1_node_next(efsod, i) # use EXPLICIT SET OF tag, rather than of the IMPLICIT [0] tag signed_attrs = asn1_get_all(efsod, i) signed_attrs = b"\x31" + signed_attrs[1:] # get the first Attribute from SignedAttributes j = asn1_node_first_child(efsod, i) content_type, signed_attrs_hash = None, None while content_type is None or signed_attrs_hash is None: # get the content-type and the message-digest k = asn1_node_first_child(efsod, j) # contentType if asn1_get_all(efsod, k) == encode_oid_string("1.2.840.113549.1.9.3"): # then the content-type attribute value MUST match # the SignedData encapContentInfo eContentType value. # checked in line 195 k = asn1_node_next(efsod, k) k = asn1_node_first_child(efsod, k) content_type = asn1_get_all(efsod, k) # messageDigest elif asn1_get_all(efsod, k) == encode_oid_string("1.2.840.113549.1.9.4"): k = asn1_node_next(efsod, k) k = asn1_node_first_child(efsod, k) signed_attrs_hash = asn1_get_value_of_type(efsod, k, "OCTET STRING") j = asn1_node_next(efsod, j) del k, j hash_object = hashlib.new(hash_alg) hash_object.update(encapsulated_content) e_content_hash = hash_object.digest() del hash_object # print("[+] Calculated hash of eContent =", eContent_hash.hex()) # print("[+] Hash of eContent in SignedAttributes =", signedAttrs_hash.hex()) if e_content_type == content_type: print( "[+] Content Type of eContent match with the Content Type in SignedAttributes" ) else: exceptions.append( PassiveAuthenticationError( "[-] Content Type of eContent DOES NOT " "match with the Content Type in SignedAttributes.")) if hmac.compare_digest(signed_attrs_hash, e_content_hash): print("[+] Hash of eContent match with the hash in SignedAttributes") else: exceptions.append( PassiveAuthenticationError( "[+] Hash of eContent DOES NOT match with the hash in SignedAttributes." )) # get 4th item inside 1st signerInfo (SignatureAlgorithmIdentifier) i = asn1_node_next(efsod, i) # get 5th item inside 1st signerInfo (SignatureValue) i = asn1_node_next(efsod, i) signature = asn1_get_value_of_type(efsod, i, "OCTET STRING") # Verify the signature with DS_cert using hash_alg try: if verify(CDS, signature, signed_attrs, hash_alg) is None: print("[+] The signature on EF_SOD is valid.") except ex: exceptions.append( PassiveAuthenticationError( "[-] The signature on EF_SOD is not valid or failed.")) i = asn1_node_root(encapsulated_content) i = asn1_node_first_child(encapsulated_content, i) i = asn1_node_next(encapsulated_content, i) i = asn1_node_next(encapsulated_content, i) data_group_hash_values = asn1_get_all(encapsulated_content, i) if len(exceptions) == 0: return hash_alg, data_group_hash_values, doc_sig_cert, None return hash_alg, data_group_hash_values, doc_sig_cert, exceptions
def process_rapdu(sm_object: SMObject, rapdu: bytes) -> bytes: """ Verify the MAC of the received APDU and return the decrypted data if it exists sm_object -- Necessary secure messaging object (Encryption session key etc.) rapdu -- Received Reply APDU :returns: decrypted_data or None """ if sm_object.enc_alg is None: return rapdu raise ValueError("[-] Encryption algorithm is not set") if sm_object.mac_alg is None: raise ValueError("[-] Mac algorithm is not set") if sm_object.pad_len == 0: raise ValueError("[-] Padding length is 0") if sm_object.ks_enc is None or sm_object.ks_mac is None: raise ValueError("[-] Session keys are not set") if sm_object.ssc is None: raise ValueError("[-] SSC is not set") sm_object.increment_ssc() encrypted_data, decrypted_data = b"", b"" do85, do87, do99 = None, None, None i = asn1_node_root(rapdu) while True: do = asn1_get_all(rapdu, i) if do.startswith(b"\x85"): encrypted_data = asn1_get_value(rapdu, i) do85 = do elif do.startswith(b"\x87"): encrypted_data = asn1_get_value(rapdu, i) do87 = do elif do.startswith(b"\x99"): do99 = do elif do.startswith(b"\x8E"): do8e = asn1_get_value(rapdu, i) if i[2] == len(rapdu) - 1: break i = asn1_node_next(rapdu, i) k = padding_method_2( sm_object.ssc + (do85 or b"") + (do87 or b"") + (do99 or b""), sm_object.pad_len) cc = compute_mac(sm_object.ks_mac, k, sm_object.mac_alg) if cc != do8e: raise ReplyAPDUError("[-] Reply APDU is not valid.") if encrypted_data: # If INS is even, remove the padding indicator (01) if do87 is not None: encrypted_data = encrypted_data[1:] # Decrypt if sm_object.enc_alg == "3DES": decrypted_data = DES3.new(sm_object.ks_enc, DES3.MODE_CBC, iv=bytes([0] * 8)).decrypt(encrypted_data) elif sm_object.enc_alg == "AES": ssc_enc = AES.new(sm_object.ks_enc, AES.MODE_ECB).encrypt(sm_object.ssc) decrypted_data = AES.new(sm_object.ks_enc, AES.MODE_CBC, iv=ssc_enc).decrypt(encrypted_data) # Remove padding decrypted_data = remove_padding(decrypted_data) return decrypted_data
def active_auth(dg15: bytes, sm_object: SMObject, security_infos: List[bytes]): """ Do active authentication with DG15 """ # Generate 8 random bytes rnd_ifd = urandom(8) # exception caught in main program loop data = send( sm_object, APDU(b"\x00", b"\x88", b"\x00", b"\x00", Lc=b"\x08", cdata=rnd_ifd, Le=b"\x00")) if data == b"": raise ActiveAuthenticationError("[-] No reply from card.") i = asn1_node_root(dg15) i = asn1_node_first_child(dg15, i) pub_key = asn1_get_all(dg15, i) i = asn1_node_first_child(dg15, i) i = asn1_node_first_child(dg15, i) if asn1_get_all(dg15, i) == encode_oid_string("1.2.840.10045.2.1"): # ECC r = data[:len(data) // 2] s = data[len(data) // 2:] signature = asn1_sequence(asn1_integer(r) + asn1_integer(s)) ec_pub = EC.pub_key_from_der(pub_key) if ec_pub.check_key() != 1: raise ActiveAuthenticationError( "[-] Active Authentication (AA) failed! Problem in EC Public Key!" ) try: hash_type = find_hash_name(security_infos) except ValueError as ex: raise ActiveAuthenticationError( "[-] Active Authentication (AA) failed! Problem in Security Infos hash type!" ) from ex # for hash_type in ["sha224", "sha256", "sha384", "sha512"]: try: result = ec_pub.verify_dsa_asn1( hashlib.new(hash_type, rnd_ifd).digest(), signature) except EC.ECError as ex: print("[-] Error in EC function " + ex) raise ActiveAuthenticationError( "[-] Error in verify_dsa_asn1 of M2Crypto.EC") from ex if result == 1: print("[+] Active Authentication (AA) completed successfully!") else: raise ActiveAuthenticationError( "[-] Active Authentication (AA) failed!") elif asn1_get_all(dg15, i) == encode_oid_string("1.2.840.113549.1.1.1"): # RSA j = asn1_node_root(pub_key) j = asn1_node_first_child(pub_key, j) j = asn1_node_next(pub_key, j) rsa_pub_key = asn1_get_value_of_type(pub_key, j, "BIT STRING") if rsa_pub_key[0] != 0x00: raise ActiveAuthenticationError( "[-] An issue with the RSA key! Padding 0x00 is expected") rsa_pub_key = rsa_pub_key[1:] j = asn1_node_root(rsa_pub_key) j = asn1_node_first_child(rsa_pub_key, j) n_der = asn1_get_value_of_type(rsa_pub_key, j, "INTEGER") j = asn1_node_next(rsa_pub_key, j) e_der = asn1_get_value_of_type(rsa_pub_key, j, "INTEGER") n = int.from_bytes(n_der, byteorder="big") e = int.from_bytes(e_der, byteorder="big") # rsa_key = RSA.import_key(pub_key) # https://stackoverflow.com/a/60132608/6077951 msg = int.from_bytes(data, byteorder="big") dec = pow(msg, e, n).to_bytes(len(data), byteorder="big") if dec[-1] == 0xCC: if dec[-2] == 0x38: hash_alg = "sha224" elif dec[-2] == 0x34: hash_alg = "sha256" elif dec[-2] == 0x36: hash_alg = "sha384" elif dec[-2] == 0x35: hash_alg = "sha512" t = 2 elif dec[-1] == 0xBC: hash_alg = "sha1" t = 1 else: raise ActiveAuthenticationError( "[-] Error while Active Authentication!") def compare_aa(hash_object): # k = rsa_key.size_in_bits() # Lh = hash_object.digest_size * 8 # Lm1 = (k - Lh - (8 * t) - 4 - 4) // 8 D = dec[-hash_object.digest_size - t:-t] M1 = dec[1:-hash_object.digest_size - t] Mstar = M1 + rnd_ifd hash_object.update(Mstar) Dstar = hash_object.digest() return hmac.compare_digest(D, Dstar) hash_object = hashlib.new(hash_alg) if compare_aa(hash_object): print("[+] Active Authentication (AA) completed successfully!") else: raise ActiveAuthenticationError( "[-] Active Authentication (AA) failed!")