mirror of
https://github.com/RfidResearchGroup/ChameleonUltra.git
synced 2026-03-30 14:55:42 +00:00
110 lines
4.3 KiB
Python
110 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
import hardnested_utils
|
|
from chameleon_cmd import ChameleonCMD
|
|
from chameleon_com import ChameleonCom, OpenFailException
|
|
import sys
|
|
sys.path.append('..')
|
|
|
|
|
|
def test_hardnested_acquire():
|
|
nonces_buffer = bytearray()
|
|
acquire_count = 0
|
|
|
|
# known key and target block
|
|
key = bytes.fromhex("FFFFFFFFFFFF") # <-- Your known key
|
|
block_known = 0x00
|
|
type_known = 0x60
|
|
block_target = 0x00
|
|
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)
|
|
|
|
# ------------------------ SET DEVICE MODE ------------------------
|
|
print("Setting device mode to HF Reader...")
|
|
cml_cmd.set_device_reader_mode()
|
|
|
|
# ------------------------ append tag info ------------------------
|
|
|
|
resp = cml_cmd.hf14a_scan()
|
|
if resp is None or len(resp) == 0:
|
|
print("ISO14443-A Tag no found")
|
|
return
|
|
|
|
tag_info = resp[0]
|
|
uidbytes = tag_info['uid']
|
|
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
|
|
# slow = 0 to fast acquire...
|
|
acquire_datas = cml_cmd.mf1_hard_nested_acquire(0, block_known, type_known, key, block_target, type_target)
|
|
if acquire_datas is not None:
|
|
acquire_count += 1
|
|
print(f"Acquire success, count: {acquire_count}")
|
|
else:
|
|
raise Exception("acquire failed")
|
|
# 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
|
|
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')
|
|
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...
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
test_hardnested_acquire()
|
|
except Exception as e:
|
|
print(f"An error occurred: {e}")
|