Merge remote-tracking branch 'upstream/main' into pr-merge

This commit is contained in:
GameTec_live committed 2025-04-06 13:28:06 +02:00
commit e99f8dbd0e
12 files changed
+308 -6

No files matched your search

+11
View File
@@ -42,7 +42,18 @@ type_id_SAK_dict = {0x00: "MIFARE Ultralight Classic/C/EV1/Nano | NTAG 2xx",
default_cwd = Path.cwd() / Path(__file__).with_name("bin")
def load_key_file(import_key, keys):
"""
Load key file and append its content to the provided set of keys.
Each key is expected to be on a new line in the file.
"""
with open(import_key.name, 'rb') as file:
keys.update(line.encode('utf-8') for line in file.read().decode('utf-8').splitlines())
return keys
def load_dic_file(import_dic, keys):
return keys
def check_tools():
tools = ['staticnested', 'nested', 'darkside', 'mfkey32v2']
if sys.platform == "win32":
+12
View File
@@ -358,6 +358,18 @@ class ChameleonCMD:
]
}
return resp
@expect_response(Status.HF_TAG_OK)
def mf1_hard_nested_acquire(self, slow, block_known, type_known, key_known, block_target, type_target):
"""
Collect the NT_ENC list for HardNested decryption
:return:
"""
data = struct.pack('!BBB6sBB', slow, type_known, block_known, key_known, type_target, block_target)
resp = self.device.send_cmd_sync(Command.DATA_CMD_MF1_HARDNESTED_ACQUIRE, data)
if resp.status == Status.HF_TAG_OK:
resp.parsed = resp.data # we can return the raw nonces bytes
return resp
@expect_response(Status.LF_TAG_OK)
def em410x_scan(self):
+1
View File
@@ -69,6 +69,7 @@ class Command(enum.IntEnum):
HF14A_RAW = 2010
MF1_MANIPULATE_VALUE_BLOCK = 2011
MF1_CHECK_KEYS_OF_SECTORS = 2012
DATA_CMD_MF1_HARDNESTED_ACQUIRE = 2013
EM410X_SCAN = 3000
EM410X_WRITE_TO_T55XX = 3001
+41
View File
@@ -0,0 +1,41 @@
hardnested_sums = [0, 32, 56, 64, 80, 96, 104, 112, 120, 128, 136, 144, 152, 160, 176, 192, 200, 224, 256]
hardnested_nonces_sum_map = []
hardnested_first_byte_num = 0
hardnested_first_byte_sum = 0
def evenparity32(n):
"""
calc evenparity32, can replace to any fast native impl...
@param n - NT_ENC
"""
ret = 0
for i in range(32):
if (n & (1 << i)) != 0:
ret += 1
return ret % 2
def check_nonce_unique_sum(nt, par):
"""
Check nt_enc is unique and calc first byte sum
Pay attention: thread unsafe!!!
@param nt - NT_ENC
@param par - parity of NT_ENC
"""
global hardnested_first_byte_sum, hardnested_first_byte_num
first_byte = nt >> 24
if not hardnested_nonces_sum_map[first_byte]:
hardnested_first_byte_sum += evenparity32((nt & 0xff000000) | (par & 0x08))
hardnested_nonces_sum_map[first_byte] = True
hardnested_first_byte_num += 1
def reset():
global hardnested_first_byte_sum, hardnested_first_byte_num, hardnested_nonces_sum_map
# clear the history
hardnested_nonces_sum_map = list()
for i in range(256):
hardnested_nonces_sum_map.append(False)
hardnested_first_byte_sum = 0
hardnested_first_byte_num = 0
@@ -0,0 +1,98 @@
#!/usr/bin/env python3
import sys
sys.path.append('..')
from chameleon_com import ChameleonCom, OpenFailException
from chameleon_cmd import ChameleonCMD
import hardnested_utils
def test_hardnested_acquire():
nonces_buffer = bytearray()
acquire_count = 0
# known key and target block
key = bytes.fromhex("????????????")
block_known = 0x00
type_known = 0x60
block_target = 0x07
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)
# ------------------------ append tag info ------------------------
resp = cml_cmd.hf14a_scan()
if resp is None or len(resp) == 0:
print("ISO14443-A Tag no found")
return
uidbytes = bytearray.fromhex(resp['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
acquire_datas = cml_cmd.mf1_hard_nested_acquire(0, block_known, type_known, key, block_target, type_target) # slow = 0 to fast acquire...
if acquire_datas is not None:
acquire_count += 1
print(f"Acquire success, count: {acquire_count}")
else:
raise Exception(f"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])
nt_enc2 = int.from_bytes(acquire_datas[data_check_index + 4: data_check_index + 4 + 4])
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...