diff --git a/docs/changes.txt b/docs/changes.txt index 159eaf23b..dc685dce6 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -159,6 +159,7 @@ - Fixed incompatible pointer types (salt1 and salt2 buf) in 3730 a3 kernel - Fixed incorrect plaintext check for 25400 and 26610. Increased plaintext check to 32 bytes to prevent false positives. - Fixed keys extraction in luks2hashcat - now extracts all active keys +- Fixed keys extraction in luks2hashcat - now extracts all LUKS2 keyslots - Fixed maximum password length in module/test_module of hash-mode 2400 - Fixed maximum password length in module/test_module of hash-mode 2410 - Fixed memory leaks in tuning_db_init in tuningdb.c diff --git a/src/modules/module_34200.c b/src/modules/module_34200.c old mode 100755 new mode 100644 diff --git a/src/modules/module_34201.c b/src/modules/module_34201.c old mode 100755 new mode 100644 diff --git a/src/modules/module_34211.c b/src/modules/module_34211.c old mode 100755 new mode 100644 diff --git a/tools/luks2hashcat.py b/tools/luks2hashcat.py index c00458286..ee70cb253 100755 --- a/tools/luks2hashcat.py +++ b/tools/luks2hashcat.py @@ -230,7 +230,7 @@ def extract_version1(file): # read header header = file.read(header_struct.size) if len(header) < header_struct.size: - raise ValueError("file contains less data than needed") + raise ValueError("file contains less data than needed (invalid header len)") # convert bytes into temporary header header = header_struct.unpack(header) @@ -245,7 +245,7 @@ def extract_version1(file): file.seek(key.material_offset * SECTOR_SIZE, SEEK_SET) af = file.read(header.key_bytes * key.stripes) if len(af) < (header.key_bytes * key.stripes): - raise ValueError("file contains less data than needed") + raise ValueError("file contains less data than needed (invalid af len)") key = KeyVersion1(key.active, key.iterations, key.salt, af) keys.append(key) @@ -254,7 +254,7 @@ def extract_version1(file): file.seek(header.payload_offset * SECTOR_SIZE, SEEK_SET) payload = file.read(PAYLOAD_SIZE) if len(payload) < PAYLOAD_SIZE: - raise ValueError("file contains less data than needed") + raise ValueError("file contains less data than needed (invalid payload len)") if sum(payload) == 0: raise ValueError("file not initialized - payload contains zeros only") @@ -315,51 +315,55 @@ def extract_version2(file): json_header = json.loads(json_data[:json_end]) # print("\nWe got the following large json header:\n") - # print(json.dumps(json_header, indent=4)) + #print(json.dumps(json_header, indent=4)) - keyslot_offset = int(json_header['keyslots']['0']['area']['offset']) - keyslot_size = int(json_header['keyslots']['0']['area']['key_size']) - encryption = json_header['keyslots']['0']['area']['encryption'] + keyslots_cnt = len(json_header['keyslots']) + if keyslots_cnt == 0: + raise ValueError("no keyslots founds") - (cipher_type, cipher_mode) = tuple(encryption.split("-", 1)) - - file.seek(keyslot_offset) - keyslot_encrypted_data = file.read(256000) #don't yet know how to calculate this length exactly - - blocknumbers = int(json_header['keyslots']['0']['af']['stripes']) - hash_mode = json_header['keyslots']['0']['af']['hash'] - - # Include first sector of the segment for entropy check + # extract first sector of the segment for entropy check segment_offset = int(json_header['segments']['0']['offset']) file.seek(segment_offset) first_sector = file.read(512) - kdf = json_header['keyslots']['0']['kdf']['type'] - time = int(json_header['keyslots']['0']['kdf']['time']) - memory = int(json_header['keyslots']['0']['kdf']['memory']) - cpus = int(json_header['keyslots']['0']['kdf']['cpus']) - salt = b64decode(json_header['keyslots']['0']['kdf']['salt']) + for key in json_header['keyslots']: + print(key) + keyslot_offset = int(json_header['keyslots'][key]['area']['offset']) + encryption = json_header['keyslots'][key]['area']['encryption'] + stripes = int(json_header['keyslots'][key]['af']['stripes']) + key_size = int(json_header['keyslots'][key]['key_size']) - key_size = int(json_header['keyslots']['0']['key_size']) * 8 + (cipher_type, cipher_mode) = tuple(encryption.split("-", 1)) - hash = SIGNATURE + "$".join( - map( - str, - [ - HeaderVersion2.VERSION, - kdf, - hash_mode, - cipher_type, - cipher_mode, - key_size, - f"m={memory},t={time},p={cpus}", - salt.hex(), - keyslot_encrypted_data.hex(), - first_sector.hex(), - ], + file.seek(keyslot_offset) + keyslot_encrypted_data = file.read(key_size * stripes) + + hash_mode = json_header['keyslots'][key]['af']['hash'] + + kdf = json_header['keyslots'][key]['kdf']['type'] + time = int(json_header['keyslots'][key]['kdf']['time']) + memory = int(json_header['keyslots'][key]['kdf']['memory']) + cpus = int(json_header['keyslots'][key]['kdf']['cpus']) + salt = b64decode(json_header['keyslots'][key]['kdf']['salt']) + + hash = SIGNATURE + "$".join( + map( + str, + [ + HeaderVersion2.VERSION, + kdf, + hash_mode, + cipher_type, + cipher_mode, + key_size * 8, + f"m={memory},t={time},p={cpus}", + salt.hex(), + keyslot_encrypted_data.hex(), + first_sector.hex(), + ], + ) ) - ) - print(hash) + print(hash) # main