from aliro_harness.reader.key_derivation import ( build_salt_volatile, derive_expedited_session_keys, ) def test_salt_volatile_layout_per_spec_8_3_1_13(): salt = build_salt_volatile( reader_long_term_pub_x=b"\x01" * 32, reader_group_id=b"\xaa" * 16, reader_group_sub_id=b"\xbb" * 16, reader_ephem_pub_x=b"\x33" * 32, transaction_id=b"\xcc" * 16, command_parameters=0x00, authentication_policy=0x00, ) p = 0 assert salt[p : p + 32] == b"\x01" * 32 # x(reader_group_identifier_key) p += 32 assert salt[p : p + 12] == b"Volatile****" p += 12 assert salt[p : p + 16] == b"\xaa" * 16 # group_id p += 16 assert salt[p : p + 16] == b"\xbb" * 16 # sub_id p += 16 assert salt[p] == 0x5E # interface_byte = NFC p += 1 assert salt[p : p + 2] == bytes([0x5C, 0x02]) # literal p += 2 assert salt[p : p + 2] == bytes([0x01, 0x00]) # protocol_version p += 2 assert salt[p : p + 32] == b"\x33" * 32 # x(reader_ephem) p += 32 assert salt[p : p + 16] == b"\xcc" * 16 # txn_id p += 16 assert salt[p : p + 2] == bytes([0x00, 0x00]) # flag = cmd_params || auth_policy p += 2 assert salt[p : p + 10] == bytes.fromhex("A50880020000 5C020100".replace(" ", "")) p += 10 # salt_volatile ends at the 0xA5 TLV per spec ยง8.3.1.13. The # credential_long_term_pub_x previously appended here was a misread of # the spec (caused vendor library ACWG_Error_Crypto_EncryptDecrypt). assert len(salt) == p == 141 def test_salt_volatile_threads_flag_bytes_in_correct_order(): """Guards against cmd_params/auth_policy swap.""" salt = build_salt_volatile( reader_long_term_pub_x=b"\x00" * 32, reader_group_id=b"\x00" * 16, reader_group_sub_id=b"\x00" * 16, reader_ephem_pub_x=b"\x00" * 32, transaction_id=b"\x00" * 16, command_parameters=0xAB, authentication_policy=0xCD, ) # flag offset: 32 + 12 + 16 + 16 + 1 + 2 + 2 + 32 + 16 = 129 assert salt[129] == 0xAB assert salt[130] == 0xCD def test_derive_expedited_session_keys_returns_160_bytes_deterministic(): kdh = bytes.fromhex("11" * 32) salt = bytes.fromhex("22" * 141) info = bytes.fromhex("33" * 65) # x(credential_ephem_pub) is 32B in practice; any bytes OK here out1 = derive_expedited_session_keys(kdh, salt, info) out2 = derive_expedited_session_keys(kdh, salt, info) assert len(out1) == 160 assert out1 == out2 def test_derive_expedited_session_keys_changes_with_inputs(): kdh = bytes.fromhex("11" * 32) salt_a = bytes.fromhex("22" * 141) salt_b = bytes.fromhex("23" + "22" * 140) info = bytes.fromhex("33" * 32) assert derive_expedited_session_keys(kdh, salt_a, info) != derive_expedited_session_keys(kdh, salt_b, info)