2025-04-02 12:32:27 +08:00
#!/usr/bin/env python3
2025-08-01 23:12:07 +03:00
import hardnested_utils
from chameleon_cmd import ChameleonCMD
from chameleon_com import ChameleonCom , OpenFailException
2025-04-02 12:32:27 +08:00
import sys
sys . path . append ( '..' )
def test_hardnested_acquire ():
nonces_buffer = bytearray ()
acquire_count = 0
# known key and target block
2025-08-01 23:12:07 +03:00
key = bytes . fromhex ( "FFFFFFFFFFFF" ) # <-- Your known key
2025-04-02 12:32:27 +08:00
block_known = 0x00
type_known = 0x60
2025-04-18 23:53:25 +02:00
block_target = 0x00
2025-04-02 12:32:27 +08:00
type_target = 0x60
# Before acquire start, we need to reset history
hardnested_utils . reset ()
# The nonces file format required by PM3:
# (4byte uid of card) - (block_target 1byte) - (type_target 1byte) - (nonces from device Nbytes)
# ------------------------ open the device ------------------------
try :
cml = ChameleonCom () . open ( 'com19' )
except OpenFailException :
cml = ChameleonCom () . open ( '/dev/ttyACM0' )
cml_cmd = ChameleonCMD ( cml )
2025-08-01 23:12:07 +03:00
# ------------------------ SET DEVICE MODE ------------------------
2025-04-18 23:53:25 +02:00
print ( "Setting device mode to HF Reader..." )
2025-08-09 17:51:57 +03:00
cml_cmd . set_device_reader_mode ()
2025-04-18 23:53:25 +02:00
2025-04-02 12:32:27 +08:00
# ------------------------ append tag info ------------------------
resp = cml_cmd . hf14a_scan ()
if resp is None or len ( resp ) == 0 :
print ( "ISO14443-A Tag no found" )
return
2025-04-18 23:53:25 +02:00
tag_info = resp [ 0 ]
uidbytes = tag_info [ 'uid' ]
2025-04-02 12:32:27 +08:00
uid_len = len ( uidbytes )
if uid_len == 4 :
nonces_buffer . extend ( uidbytes [ 0 : 4 ])
if uid_len == 7 :
nonces_buffer . extend ( uidbytes [ 3 : 7 ])
if uid_len == 10 :
nonces_buffer . extend ( uidbytes [ 6 : 10 ])
nonces_buffer . extend ([ block_target , type_target & 0x01 ])
# ------------------------ append nonces from device ------------------------
while True :
# 1, acquire from device
2025-08-01 23:12:07 +03:00
# slow = 0 to fast acquire...
acquire_datas = cml_cmd . mf1_hard_nested_acquire ( 0 , block_known , type_known , key , block_target , type_target )
2025-04-02 12:32:27 +08:00
if acquire_datas is not None :
acquire_count += 1
print ( f "Acquire success, count: { acquire_count } " )
else :
2025-08-09 17:51:57 +03:00
raise Exception ( "acquire failed" )
2025-04-02 12:32:27 +08:00
# 2. check data
data_check_index = 0
while data_check_index < len ( acquire_datas ):
# Memory Layout: nt_enc1(4byte) - nt_enc2(4byte) - par(1byte)...
# To integer
2025-08-10 14:43:19 +07:00
nt_enc1 = int . from_bytes ( acquire_datas [ data_check_index + 0 : data_check_index + 0 + 4 ], byteorder = 'big' )
nt_enc2 = int . from_bytes ( acquire_datas [ data_check_index + 4 : data_check_index + 4 + 4 ], byteorder = 'big' )
2025-04-02 12:32:27 +08:00
par_enc = acquire_datas [ data_check_index + 8 ]
# check unique and sum
hardnested_utils . check_nonce_unique_sum ( nt_enc1 , par_enc >> 4 )
hardnested_utils . check_nonce_unique_sum ( nt_enc2 , par_enc & 0x0F )
data_check_index += 9 # The two ciphertext random numbers have a total of 8 bytes, and the parity bits corresponding to the two ciphertext random numbers occupy one byte
# 3. store data
nonces_buffer . extend ( acquire_datas )
# 4. After collecting 256 possible different groups, determine whether the collected data is summed correctly. If not, it may not be an EV1 tag.
if hardnested_utils . hardnested_first_byte_num == 256 :
got_match = False
for i in range ( len ( hardnested_utils . hardnested_sums )):
if hardnested_utils . hardnested_first_byte_sum == hardnested_utils . hardnested_sums [ i ]:
got_match = True # Sum matches successfully, and we can try to decrypt it next.
break
if got_match :
print ( f "Acquire finish, save to file [nonces.bin], size is { len ( nonces_buffer ) } bytes" )
break
else :
print (
f "hardnested_first_byte_num exceeds the limit but got_match is false: { hardnested_utils . hardnested_first_byte_sum } " )
else :
continue # Continue acquire
# ------------------------ write nonces to bin ------------------------
with open ( "nonces.bin" , mode = "wb+" ) as fd :
fd . write ( nonces_buffer )
# You can decrypt nonce bin by pm3 client, or any app if support pm3 nonce bin format.
# TODO If CU bin can decrypt, run cmd on here...
2025-04-18 23:53:25 +02:00
2025-08-01 23:12:07 +03:00
2025-04-18 23:53:25 +02:00
if __name__ == "__main__" :
try :
test_hardnested_acquire ()
except Exception as e :
print ( f "An error occurred: { e } " )