25
25
from chameleon_enum import Command , Status , SlotNumber , TagSenseType , TagSpecificType
26
26
from chameleon_enum import MifareClassicWriteMode , MifareClassicPrngType , MifareClassicDarksideStatus , MfcKeyType
27
27
from chameleon_enum import AnimationMode , ButtonPressFunction , ButtonType , MfcValueBlockOperator
28
+ from crypto1 import Crypto1
28
29
29
30
# NXP IDs based on https://www.nxp.com/docs/en/application-note/AN10833.pdf
30
31
type_id_SAK_dict = {0x00 : "MIFARE Ultralight Classic/C/EV1/Nano | NTAG 2xx" ,
@@ -1240,32 +1241,34 @@ def _run_mfkey32v2(items):
1240
1241
1241
1242
1242
1243
class ItemGenerator :
1243
- def __init__ (self , rs , i = 0 , j = 1 ):
1244
- self .rs = rs
1244
+ def __init__ (self , rs , uid_found_keys = set ()):
1245
+ self .rs : list = rs
1246
+ self .progress = 0
1245
1247
self .i = 0
1246
1248
self .j = 1
1247
1249
self .found = set ()
1248
1250
self .keys = set ()
1251
+ for known_key in uid_found_keys :
1252
+ self .test_key (known_key )
1249
1253
1250
1254
def __iter__ (self ):
1251
1255
return self
1252
1256
1253
1257
def __next__ (self ):
1254
- try :
1255
- item_i = self .rs [self .i ]
1256
- except IndexError :
1257
- raise StopIteration
1258
- if self .key_from_item (item_i ) in self .found :
1258
+ size = len (self .rs )
1259
+ if self .j >= size :
1259
1260
self .i += 1
1261
+ if self .i >= size - 1 :
1262
+ raise StopIteration
1260
1263
self .j = self .i + 1
1261
- return next (self )
1262
- try :
1263
- item_j = self .rs [self .j ]
1264
- except IndexError :
1264
+ item_i , item_j = self .rs [self .i ], self .rs [self .j ]
1265
+ self .progress += 1
1266
+ self .j += 1
1267
+ if self .key_from_item (item_i ) in self .found :
1268
+ self .progress += max (0 , size - self .j )
1265
1269
self .i += 1
1266
1270
self .j = self .i + 1
1267
1271
return next (self )
1268
- self .j += 1
1269
1272
if self .key_from_item (item_j ) in self .found :
1270
1273
return next (self )
1271
1274
return item_i , item_j
@@ -1274,17 +1277,20 @@ def __next__(self):
1274
1277
def key_from_item (item ):
1275
1278
return "{uid}-{nt}-{nr}-{ar}" .format (** item )
1276
1279
1277
- def key_found (self , key , items ):
1278
- self .keys .add (key )
1279
- for item in items :
1280
- try :
1281
- if item == self .rs [self .i ]:
1282
- self .i += 1
1283
- self .j = self .i + 1
1284
- except IndexError :
1285
- break
1286
- self .found .update (self .key_from_item (item ) for item in items )
1287
-
1280
+ def test_key (self , key , items = list ()):
1281
+ for item in self .rs :
1282
+ item_key = self .key_from_item (item )
1283
+ if item_key in self .found :
1284
+ continue
1285
+ if (item in items ) or (Crypto1 .mfkey32_is_reader_has_key (
1286
+ int (item ['uid' ], 16 ),
1287
+ int (item ['nt' ], 16 ),
1288
+ int (item ['nr' ], 16 ),
1289
+ int (item ['ar' ], 16 ),
1290
+ key ,
1291
+ )):
1292
+ self .keys .add (key )
1293
+ self .found .add (item_key )
1288
1294
1289
1295
@hf_mf .command ('elog' )
1290
1296
class HFMFELog (DeviceRequiredUnit ):
@@ -1296,7 +1302,7 @@ def args_parser(self) -> ArgumentParserNoExit:
1296
1302
parser .add_argument ('--decrypt' , action = 'store_true' , help = "Decrypt key from MF1 log list" )
1297
1303
return parser
1298
1304
1299
- def decrypt_by_list (self , rs : list ):
1305
+ def decrypt_by_list (self , rs : list , uid_found_keys : set = set () ):
1300
1306
"""
1301
1307
Decrypt key from reconnaissance log list
1302
1308
@@ -1306,16 +1312,14 @@ def decrypt_by_list(self, rs: list):
1306
1312
msg1 = f" > { len (rs )} records => "
1307
1313
msg2 = f"/{ (len (rs )* (len (rs )- 1 ))// 2 } combinations. "
1308
1314
msg3 = " key(s) found"
1309
- n = 1
1310
- gen = ItemGenerator ( rs )
1315
+ gen = ItemGenerator ( rs , uid_found_keys )
1316
+ print ( f" { msg1 } { gen . progress } { msg2 } { len ( gen . keys ) } { msg3 } \r " , end = "" )
1311
1317
with Pool (cpu_count ()) as pool :
1312
1318
for result in pool .imap (_run_mfkey32v2 , gen ):
1313
- # TODO: if some keys already recovered, test them on item before running mfkey32 on item
1314
1319
if result is not None :
1315
- gen .key_found (* result )
1316
- print (f"{ msg1 } { n } { msg2 } { len (gen .keys )} { msg3 } \r " , end = "" )
1317
- n += 1
1318
- print ()
1320
+ gen .test_key (* result )
1321
+ print (f"{ msg1 } { gen .progress } { msg2 } { len (gen .keys )} { msg3 } \r " , end = "" )
1322
+ print (f"{ msg1 } { gen .progress } { msg2 } { len (gen .keys )} { msg3 } " )
1319
1323
return gen .keys
1320
1324
1321
1325
def on_exec (self , args : argparse .Namespace ):
@@ -1356,22 +1360,16 @@ def on_exec(self, args: argparse.Namespace):
1356
1360
for uid in result_maps .keys ():
1357
1361
print (f" - Detection log for uid [{ uid .upper ()} ]" )
1358
1362
result_maps_for_uid = result_maps [uid ]
1363
+ uid_found_keys = set ()
1359
1364
for block in result_maps_for_uid :
1360
- print (f" > Block { block } detect log decrypting..." )
1361
- if 'A' in result_maps_for_uid [block ]:
1362
- # print(f" - A record: { result_maps[block]['A'] }")
1363
- records = result_maps_for_uid [block ]['A' ]
1364
- if len (records ) > 1 :
1365
- result_maps [uid ][block ]['A' ] = self .decrypt_by_list (records )
1366
- else :
1367
- print (f" > { len (records )} record" )
1368
- if 'B' in result_maps_for_uid [block ]:
1369
- # print(f" - B record: { result_maps[block]['B'] }")
1370
- records = result_maps_for_uid [block ]['B' ]
1371
- if len (records ) > 1 :
1372
- result_maps [uid ][block ]['B' ] = self .decrypt_by_list (records )
1373
- else :
1374
- print (f" > { len (records )} record" )
1365
+ for keyType in 'AB' :
1366
+ records = result_maps_for_uid [block ][keyType ] if keyType in result_maps_for_uid [block ] else []
1367
+ if len (records ) < 1 :
1368
+ continue
1369
+ print (f" > Decrypting block { block } key { keyType } detect log..." )
1370
+ result_maps [uid ][block ][keyType ] = self .decrypt_by_list (records , uid_found_keys )
1371
+ uid_found_keys .update (result_maps [uid ][block ][keyType ])
1372
+
1375
1373
print (" > Result ---------------------------" )
1376
1374
for block in result_maps_for_uid .keys ():
1377
1375
if 'A' in result_maps_for_uid [block ]:
0 commit comments