Кто-то сталкивался с задачей? Имеется контейнер, даволно старый, потому и был утерян пароль. Однако сейчас понадобилась оттуда критичная информация! Есть специалисты? BestCrypt driver 4.18 BestCrypt Control Panel 8.05.6
В джони есть поддержка для взлома BestCrypt контейнеров. Вот сама структура контейнера (правда тут она описана для линукса и 7ая версия.) На данный момент насколько я знаю кот (hashcat) BestCrypt не поддерживает, а вот ElcomSoft недавно научился. В общем для джона (bestcrypt2john лежит в папке джона, стандарт /usr/share/john/): Code: python bestcrypt2john.py /tmp/container-file.jbc > /tmp/bestcrypt_hash.txt john --wordlist=/usr/share/wordlists/rockyou.txt --format=BestCrypt /tmp/bestcrypt_hash.txt НО перебор идёт на джони очень медленно ~200 п/с
\Orange>python.exe bestcrypt2john.py F:\my_files.jbc my_files.jbc: internal error while processing salt, please report this problem! Пока такой результат, к сожалению.
Мда, к сожалению, в 8-ой версии BestCrypt (которая у вас имеется, если я правильно понимаю версии из первого сообщения) поменялся формат хедера и к тому же добавили возможность зашифровать и сам хедер. т.е. для начало надо узнать зашифрован ли сам хедер. -> посмотрите просто в хексе, если ли в хедере (первые 1536 байтов) строка "LOCOS94" или же "CRYPTED_DSK". Если есть, то хедер не зашифрован и можно дальше ковырять.
Надо понять почему у вас падает скрипт, я его чуть подправил: Spoiler: Скрипт Code: #!/usr/bin/env python # This software is Copyright (c) 2017, Dhiru Kholia <dhiru.kholia at gmail.com> # and it is hereby released to the general public under the following terms: # # Redistribution and use in source and binary forms, with or without # modification, are permitted. # # Written in March of 2017 based on BestCrypt-3.0.0.tar.gz. import os import sys import struct from binascii import hexlify """ libs/multi-lib/keygens/kgghost/db_header.h kBCV8_HeaderSize = 1024, kBCV8_InitialDBSize = 1024 * 4, kBCV8_MaximumDBSize = kBCV8_InitialDBSize * 4, kBCV8_JmpCodeSize = 3, kBCV8_SignatureSize = 8, kBCV8_IdLength = 4, kBCV8_OccupiedTag = 28, kBCV8_VolumeLabel = 11, kBCV8_DescriptionLength = 42, kBCV8_DigestSize32 = 32, kBCV8_DigestSize64 = 64, kBCV8_MaxKeys = 64, kBCV8_BlockSize = 16, kBCV8_IVSize = 16, kBCV8_HiddenPartMapIV = 1, kBCV8_InitialDataBlockSize = 4096, kBCV8_DataBlockExtentionUnit = 4096, kBCV8_MaximumExtKeyBlockSize = kBCV8_DataBlockExtentionUnit * 4, kBCV8_MaximumDataBlockSize = kBCV8_InitialDataBlockSize + kBCV8_MaximumExtKeyBlockSize, kBCV8_HiddenPartSpaceMapSize = 4096 typedef struct { bc_u16 size; // encoded key data size. bc_16 type; // encoding type. signed 16 bit value. bc_u32 param; // optional key parameter. } BCKeySlot; // V8 datablock header format. typedef struct db_header { bc_u8 jmpCode[kBCV8_JmpCodeSize]; // On old linux version holds container lock flag. bc_u8 signature[kBCV8_SignatureSize]; // Format version signature, i.e. LOCOSXX bc_u8 cid[kBCV8_IdLength]; // Container id for central management authentication. bc_u8 occupiedTag[kBCV8_OccupiedTag]; // Unused? char volumeLabel[kBCV8_VolumeLabel]; // "BC_KeyGenID" for this version bc_u16 wKeyGenId; // Key generator ID 5 identifier... bc_u16 wVersion; // Key generator ID 5 version... union { bc_u32 iterations; // Key generator ID 5, allows iteration other then 256, but int does never uses the version field. bc_u32 version; // Container version }; char description[kBCV8_DescriptionLength]; // Description string. bc_u64 sparced_position; bc_u64 data_start; // Encrypted body data start. bc_u64 data_length; // Encrypted body data size. bc_u32 alg_id; // The algorithm used for container encryption bc_u32 mode_id; // Encryption mode for container algorithm bc_u32 hash_id; // Hash algorithm used for encryption keys generation BCKeySlot keymap[kBCV8_MaxKeys]; ... } db_header; // libs/multi-lib/keygens/kgghost/kgghost.h kKeySlotSize = 256, // Single encoded key slot. kDigestSize32 = 32, // Digest buffer length. kDigestSize64 = 64, // Digest buffer length. kIVSize = 16, // IV buffer length. kSeedLength = 128, // random seed buffer size for key generation. kEncryptedBlockSize = 16, // Block cipher encryption block size. kMaximumKeySize = 64, // Maximum stored key size. kPoolSize = 512 // Random data pool size. // kgghost -> Default BestCrypt version 8 key generator typedef struct { bc_u8 data[kKeySlotSize]; } KEY_BLOCK; struct db_enc_block64 { db_header header; bc_u8 padding[4]; // --------------------------------------------------------------------------------------------------------------- // Data before this point can be encrypted and should be a multiple of kBCV8_BlockSize bytes in size. bc_u8 digest[kBCV8_DigestSize64]; // header digest. bc_u8 iv[kBCV8_IVSize]; // random initial vector for header encryption. } typedef struct { db_enc_block64 header; bc_u8 padding[1024 - sizeof(db_enc_block64)]; // --------------------------------------------------------------------------------------------- // 1KB boundary bc_u8 pool[kPoolSize]; KEY_BLOCK keys[0]; // real number of keys depends on total data block size. } DATA_BLOCK_64; """ DB_HEADER_SIGNATURE = b"LOCOS94 " kKGID = 4 # Keygen id kKGID_V5 = 5 # Keygen id for BestCrypt version 5 db_header_fmt = '< 3s 8s 4s 28s 11s H H I 42s 24s I I I 512s' db_enc_block64_fmt = "%s 4s 64s 16s" % db_header_fmt DATA_BLOCK_64_fmt = "%s 288s 512s 2560s" % db_enc_block64_fmt # hardcoded 2560s supports 10 KEY_BLOCK(s) while maximum is 64 (kBCV8_MaxKeys) DATA_BLOCK_64_size = struct.calcsize(DATA_BLOCK_64_fmt) db_enc_block64_size = struct.calcsize(db_enc_block64_fmt) keymap_fmt = "< H h I" keymap_size = struct.calcsize(keymap_fmt) db_header_size = struct.calcsize(db_header_fmt) key_slot_fmt = "< H h I" # 8 bytes key_slot_size = 8 # ciphers bcsaRIJN = 240 # block cipher modes. kBCMode_UDF = 0 kBCMode_CBC = 0xBC000002 kBCMode_LRW = 0xBC000001 kBCMode_XTS = 0xBC000004 kBCMode_ECB = 0xBC000008 # hashing algorithms pgphaMD5 = 1 pgphaSHA1 = 2 pgphaRIPEMD160 = 3 pgphaSHA256 = 8 pgphaSHA512 = 10 bchaSHA256 = 0x80 bchaWhirlpool512 = 0x80 + 1 # 129 bchaSHA3_512 = 0x80 + 2 bchaSkein512 = 0x80 + 3 kBCKeyType_Salt = 5 # KeyGen V5 save salt at key map, see DATA_BLOCK::updateSalt kBCV8_InitialDataBlockSize = 4096 DATA_BLOCK_size = 1536 kKeySlotSize = 256 kBCV8_MaxKeys = 64 # slot type kBCKeyType_Part = -1 kBCKeyType_Empty = 0 kBCKeyType_PBE = 1 kBCKeyType_SSS = 2 kBCKeyType_PKE = 3 kBCKeyType_Salt = 5 def DataBlock_CapacityForSize(dbsize): if dbsize <= DATA_BLOCK_size: return 0 capacity = ((dbsize - DATA_BLOCK_size) // kKeySlotSize) if capacity < kBCV8_MaxKeys: return capacity else: return kBCV8_MaxKeys def process_file(filename): try: f = open(filename, "rb") except IOError: e = sys.exc_info()[1] sys.stderr.write("%s\n" % str(e)) return N = DATA_BLOCK_64_size data = f.read(N) if len(data) != N: sys.stdout.write("%s : parsing failed\n" % filename) return -1 data = struct.unpack(DATA_BLOCK_64_fmt, data) (_, signature, cid, occupiedTag, volumeLabel, wKeyGenId, wVersion, iterations, description, _, alg_id, mode_id, hash_id, keymap, _, digest, iv, _, pool, keys) = data # libs/multi-lib/keygens/kgghost/kgghost.cpp -> readDBFromContainer # libs/multi-lib/keygens/kgghost/datablock.cpp -> DataBlock_DecodeKey # libs/multi-lib/keygens/kgghost/datablock.cpp -> walkNotEncrypted # DEBUG print("signature:%s\nvolumeLabel:%s\nwKeyGenId:%s\nwVersion:%s\niterations:%s\ndescription:%s\nalg_id:%s\nmode_id:%s\nhash_id:%s\ndigest:%s\niv:%s" % (signature, volumeLabel, wKeyGenId, wVersion, iterations, description, alg_id, mode_id, hash_id, hexlify(digest), hexlify(iv))) # DEBUG if signature != DB_HEADER_SIGNATURE or volumeLabel != b"BC_KeyGenID": print("%s: encrypted header found, not yet supported, patches welcome!" % os.path.basename(filename)) # look at libs/multi-lib/keygens/kgghost/datablock.cpp -> DataBlock_DecodeKey return description = description.decode("utf-16-le").rstrip("\x00") print("Description: %s" % description) if wKeyGenId == kKGID_V5: resolved_version = wVersion else: resolved_version = iterations # union of iterations and version if (resolved_version != 3) or wKeyGenId != kKGID: print("Invalid header version %s, id %s" % (resolved_version, wKeyGenId)) return if alg_id != bcsaRIJN: print("%s: cipher alg_id %s not supported, patches welcome!" % (os.path.basename(filename), alg_id)) return if mode_id != kBCMode_CBC and mode_id != kBCMode_XTS: print("%s: cipher mode_id %s not supported, patches welcome!" % (os.path.basename(filename), hex(mode_id))) return # handle hash_id and salt if hash_id != bchaWhirlpool512 and hash_id != bchaSHA256 and hash_id != pgphaSHA512: print("%s: hash_id %s not supported, patches welcome!" % (os.path.basename(filename), hash_id)) return 0 salt_size = -1 if hash_id == bchaWhirlpool512: print("Hash algorithm: Whirlpool-512") salt_size = 64 elif hash_id == bchaSHA256: print("Hash algorithm: SHA-256") salt_size = 32 elif hash_id == pgphaSHA512: print("Hash algorithm: SHA-512") salt_size = 64 else: print("Hash algorithm with id %s is not mapped" % hash_id) print("Salt size: %s" % salt_size) salt = hexlify(keys[0:salt_size]).decode("ascii") # this uses data from keys corresponding to slotnum = 0 print("Salt: %s" % salt) size, _type, param = struct.unpack(keymap_fmt, keymap[:keymap_size]) # this uses data from keymap with slotnum = 0 print("Salt size: %s, salt type: %s, parameter: %s" %(size, _type, param)) if _type != kBCKeyType_Salt: print("%s: internal error while processing salt, please report this problem!" % os.path.basename(filename)) return dbsize = kBCV8_InitialDataBlockSize maxSlots = DataBlock_CapacityForSize(dbsize) # find the active slots (look in keymap, data is in keys) slot_size = keymap_size version = 1 # internal format version, unused for slotnum in range(0, maxSlots): slot = keymap[slot_size * slotnum:slot_size * (slotnum + 1)] size, slot_type, _ = struct.unpack(keymap_fmt, slot) if slot_type == kBCKeyType_Part or slot_type == kBCKeyType_Salt or slot_type == kBCKeyType_Empty: continue # find the corresponding bits in "keys", keys[slotnum] active_key = keys[kKeySlotSize * slotnum:kKeySlotSize * (slotnum + 1)] # output one "hash" for every active key slot key = hexlify(active_key).decode("ascii") sys.stdout.write("%s:$BestCrypt$%s$%s$%s$%s$%s$%s$%s$%s$%s$%s$%s\n" % (os.path.basename(filename), version, wKeyGenId, wVersion, iterations, alg_id, mode_id, hash_id, salt_size, salt, 1, key)) f.close() if __name__ == "__main__": if len(sys.argv) < 2: sys.stderr.write("Usage: %s [Jetico BestCrypt Containers, .jbc file(s)]\n" % sys.argv[0]) for i in range(1, len(sys.argv)): process_file(sys.argv[i]) При запуске с примером с джона идёт такой выход Code: python bestcrypt2john.py container-openwall.jbc signature:LOCOS94 volumeLabel:BC_KeyGenID wKeyGenId:5 wVersion:3 iterations:16384 description:first container! alg_id:240 mode_id:3154116612 hash_id:129 digest:9e3efd7a1f4be782b4ad3359254e5a890bbba4b4fd902a09456f11b5d20d1a991e700d2c2724e04de865b92e5b3d42a9dbbedf972ebd6b5dea4dd3be8bef563c iv:43bfe23744eefbecafe8a1bd29a2593b Description: first container! Hash algorithm: Whirlpool-512 -> salt size 64 bytes Salt: 06b513b2ac314636f616747c4171700133c00d335ee6a6c3a8db60bf672531624f099fa90b8047a5aceb2492c5858cab529cf9ba5d7e8c715e33517b64ef4251 Salt size: 64, salt type: 5, parameter: 0 container-openwall.jbc:$BestCrypt$1$5$3$16384$240$3154116612$129$64$06b513b2ac314636f616747c4171700133c00d335ee6a6c3a8db60bf672531624f099fa90b8047a5aceb2492c5858cab529cf9ba5d7e8c715e33517b64ef4251$1$5fc5bf3251a22f40cd23bf7a2bed453915f9037d80630d50c4c1d9d5ed3380fbf495e3013a2f1ada864afb2d4cdcc8dcaa8f86be5898bad53244d4382a42ba857420cff29b85c644c43305e9d0daf70a8db9dcaa0acc2d6b7c7e16374c30936a7d457a155ad5f6427c2818b85065eb6ab3751f91d8321ccdbfd13df038a26a01dbee887db43564588a7387e001ec5d23b22cb003a814ebb7cb4cec9b4cfd93e15bdedff0dd6dbbfff6e7fb3abf5f29ce891e3e432795600ea447c95a0900bd48d5ecc18fd6191b34dffe411412e8e8a8a8840d95cf77a51fb58248fbf940429a977f6f392cf6d1fe7b1ead0ee7ccc5264725c476b3f1fe087ffb8d811b6b2a8b Варианта 2: * Либо у вас контейнер какой-то другой версии * Либо же (что более вероятно) у вас хэш в контейнере не SHA-256/SHA-512/Whrilpool-512 а что-то другое, тогда надо в скрипте подгонять параметры
Благодарю! Сработало, однако хэша не получил. Скорей всего он действительно какой-то другой. Key genarotor у меня KG-Ghost. На выходе получилось следующее:
Попробуйте Code: #!/usr/bin/env python # This software is Copyright (c) 2017, Dhiru Kholia <dhiru.kholia at gmail.com> # and it is hereby released to the general public under the following terms: # # Redistribution and use in source and binary forms, with or without # modification, are permitted. # # Written in March of 2017 based on BestCrypt-3.0.0.tar.gz. import os import sys import struct from binascii import hexlify """ libs/multi-lib/keygens/kgghost/db_header.h kBCV8_HeaderSize = 1024, kBCV8_InitialDBSize = 1024 * 4, kBCV8_MaximumDBSize = kBCV8_InitialDBSize * 4, kBCV8_JmpCodeSize = 3, kBCV8_SignatureSize = 8, kBCV8_IdLength = 4, kBCV8_OccupiedTag = 28, kBCV8_VolumeLabel = 11, kBCV8_DescriptionLength = 42, kBCV8_DigestSize32 = 32, kBCV8_DigestSize64 = 64, kBCV8_MaxKeys = 64, kBCV8_BlockSize = 16, kBCV8_IVSize = 16, kBCV8_HiddenPartMapIV = 1, kBCV8_InitialDataBlockSize = 4096, kBCV8_DataBlockExtentionUnit = 4096, kBCV8_MaximumExtKeyBlockSize = kBCV8_DataBlockExtentionUnit * 4, kBCV8_MaximumDataBlockSize = kBCV8_InitialDataBlockSize + kBCV8_MaximumExtKeyBlockSize, kBCV8_HiddenPartSpaceMapSize = 4096 typedef struct { bc_u16 size; // encoded key data size. bc_16 type; // encoding type. signed 16 bit value. bc_u32 param; // optional key parameter. } BCKeySlot; // V8 datablock header format. typedef struct db_header { bc_u8 jmpCode[kBCV8_JmpCodeSize]; // On old linux version holds container lock flag. bc_u8 signature[kBCV8_SignatureSize]; // Format version signature, i.e. LOCOSXX bc_u8 cid[kBCV8_IdLength]; // Container id for central management authentication. bc_u8 occupiedTag[kBCV8_OccupiedTag]; // Unused? char volumeLabel[kBCV8_VolumeLabel]; // "BC_KeyGenID" for this version bc_u16 wKeyGenId; // Key generator ID 5 identifier... bc_u16 wVersion; // Key generator ID 5 version... union { bc_u32 iterations; // Key generator ID 5, allows iteration other then 256, but int does never uses the version field. bc_u32 version; // Container version }; char description[kBCV8_DescriptionLength]; // Description string. bc_u64 sparced_position; bc_u64 data_start; // Encrypted body data start. bc_u64 data_length; // Encrypted body data size. bc_u32 alg_id; // The algorithm used for container encryption bc_u32 mode_id; // Encryption mode for container algorithm bc_u32 hash_id; // Hash algorithm used for encryption keys generation BCKeySlot keymap[kBCV8_MaxKeys]; ... } db_header; // libs/multi-lib/keygens/kgghost/kgghost.h kKeySlotSize = 256, // Single encoded key slot. kDigestSize32 = 32, // Digest buffer length. kDigestSize64 = 64, // Digest buffer length. kIVSize = 16, // IV buffer length. kSeedLength = 128, // random seed buffer size for key generation. kEncryptedBlockSize = 16, // Block cipher encryption block size. kMaximumKeySize = 64, // Maximum stored key size. kPoolSize = 512 // Random data pool size. // kgghost -> Default BestCrypt version 8 key generator typedef struct { bc_u8 data[kKeySlotSize]; } KEY_BLOCK; struct db_enc_block64 { db_header header; bc_u8 padding[4]; // --------------------------------------------------------------------------------------------------------------- // Data before this point can be encrypted and should be a multiple of kBCV8_BlockSize bytes in size. bc_u8 digest[kBCV8_DigestSize64]; // header digest. bc_u8 iv[kBCV8_IVSize]; // random initial vector for header encryption. } typedef struct { db_enc_block64 header; bc_u8 padding[1024 - sizeof(db_enc_block64)]; // --------------------------------------------------------------------------------------------- // 1KB boundary bc_u8 pool[kPoolSize]; KEY_BLOCK keys[0]; // real number of keys depends on total data block size. } DATA_BLOCK_64; """ DB_HEADER_SIGNATURE = b"LOCOS94 " kKGID = 4 # Keygen id kKGID_V5 = 5 # Keygen id for BestCrypt version 5 # ORIGINAL # db_header_fmt = '< 3s 8s 4s 28s 11s H H I 42s 24s I I I 512s' db_header_fmt = '< 3s 8s 4s 28s 11s H H I 50s Q Q I I I 512s' # Edited #db_header_fmt = '< 3s 8s 4s 28s 11s I I 50s Q Q I I I 512s' # Plain header + 4bytes Padding + Digent + IV db_enc_block64_fmt = "%s 4s 64s 16s" % db_header_fmt #DATA_BLOCK_64_fmt = "%s 288s 512s 2560s" % db_enc_block64_fmt # hardcoded 2560s supports 10 KEY_BLOCK(s) while maximum is 64 (kBCV8_MaxKeys) # Encrypted header + padding + random pool + keys DATA_BLOCK_64_fmt = "%s 288s 512s 2560s" % db_enc_block64_fmt # hardcoded 2560s supports 10 KEY_BLOCK(s) while maximum is 64 (kBCV8_MaxKeys) DATA_BLOCK_64_size = struct.calcsize(DATA_BLOCK_64_fmt) db_enc_block64_size = struct.calcsize(db_enc_block64_fmt) keymap_fmt = "< H h I" keymap_size = struct.calcsize(keymap_fmt) db_header_size = struct.calcsize(db_header_fmt) key_slot_fmt = "< H h I" # 8 bytes key_slot_size = 8 print("db_header_fmt: %s with size %i" % (db_header_fmt, db_header_size)) print("db_enc_block64_fmt: %s with size %i" % (db_enc_block64_fmt, db_enc_block64_size)) print("DATA_BLOCK_64_fmt: %s with size %i" % (DATA_BLOCK_64_fmt, DATA_BLOCK_64_size)) # ciphers bcsaRIJN = 240 # block cipher modes. kBCMode_UDF = 0 kBCMode_CBC = 0xBC000002 kBCMode_LRW = 0xBC000001 kBCMode_XTS = 0xBC000004 kBCMode_ECB = 0xBC000008 # hashing algorithms pgphaMD5 = 1 pgphaSHA1 = 2 pgphaRIPEMD160 = 3 pgphaSHA256 = 8 pgphaSHA512 = 10 bchaSHA256 = 0x80 bchaWhirlpool512 = 0x80 + 1 # 129 bchaSHA3_512 = 0x80 + 2 bchaSkein512 = 0x80 + 3 kBCKeyType_Salt = 5 # KeyGen V5 save salt at key map, see DATA_BLOCK::updateSalt kBCV8_InitialDataBlockSize = 4096 DATA_BLOCK_size = 1536 kKeySlotSize = 256 kBCV8_MaxKeys = 64 # slot type kBCKeyType_Part = -1 kBCKeyType_Empty = 0 kBCKeyType_PBE = 1 kBCKeyType_SSS = 2 kBCKeyType_PKE = 3 kBCKeyType_Salt = 5 def DataBlock_CapacityForSize(dbsize): if dbsize <= DATA_BLOCK_size: return 0 capacity = ((dbsize - DATA_BLOCK_size) // kKeySlotSize) if capacity < kBCV8_MaxKeys: return capacity else: return kBCV8_MaxKeys def process_file(filename): try: f = open(filename, "rb") except IOError: e = sys.exc_info()[1] sys.stderr.write("%s\n" % str(e)) return N = DATA_BLOCK_64_size data = f.read(N) if len(data) != N: sys.stdout.write("%s : parsing failed\n" % filename) return -1 data = struct.unpack(DATA_BLOCK_64_fmt, data) (lock_flag, signature, container_id, occupiedTag, volumeLabel, wKeyGenId, wVersion, iterations, description, offset_main, size_main, alg_id, mode_id, hash_id, keymap, padding_enc, digest, iv, padding_header, random_pool, keys) = data # libs/multi-lib/keygens/kgghost/kgghost.cpp -> readDBFromContainer # libs/multi-lib/keygens/kgghost/datablock.cpp -> DataBlock_DecodeKey # libs/multi-lib/keygens/kgghost/datablock.cpp -> walkNotEncrypted # DEBUG print("lock_flag: %s\n signature: %s\n container_id: %s\n occupiedTag: %s\n volumeLabel: %s\n wKeyGenId: %s\n wVersion: %s\n description: %s\n offset_main: %s\n size_main: %s\n alg_id: %s\n mode_id: %s\n hash_id: %s\n" % (hexlify(lock_flag), signature, hexlify(container_id), hexlify(occupiedTag), volumeLabel, wKeyGenId, wVersion, description, offset_main, size_main, alg_id, mode_id, hash_id)) print("iv: %s\n digest: %s\n random_pool: %s\n keys: %s" %(hexlify(iv), hexlify(digest), hexlify(random_pool), hexlify(keys))) # DEBUG if signature != DB_HEADER_SIGNATURE or volumeLabel != b"BC_KeyGenID": print("%s: encrypted header found, not yet supported, patches welcome!" % os.path.basename(filename)) # look at libs/multi-lib/keygens/kgghost/datablock.cpp -> DataBlock_DecodeKey return description = description.decode("utf-16-le").rstrip("\x00") print("Description: %s" % description) if wKeyGenId == kKGID_V5: resolved_version = wVersion else: resolved_version = wVersion # union of iterations and version if (resolved_version != 3) or wKeyGenId != kKGID: print("Invalid header version %s, id %s" % (resolved_version, wKeyGenId)) return if alg_id != bcsaRIJN: print("%s: cipher alg_id %s not supported, patches welcome!" % (os.path.basename(filename), alg_id)) return if mode_id != kBCMode_CBC and mode_id != kBCMode_XTS: print("%s: cipher mode_id %s not supported, patches welcome!" % (os.path.basename(filename), hex(mode_id))) return # handle hash_id and salt if hash_id != bchaWhirlpool512 and hash_id != bchaSHA256 and hash_id != pgphaSHA512: print("%s: hash_id %s not supported, patches welcome!" % (os.path.basename(filename), hash_id)) return 0 salt_size = -1 if hash_id == bchaWhirlpool512: print("Hash algorithm: Whirlpool-512") salt_size = 64 elif hash_id == bchaSHA256: print("Hash algorithm: SHA-256") salt_size = 32 elif hash_id == pgphaSHA512: print("Hash algorithm: SHA-512") salt_size = 64 else: print("Hash algorithm with id %s is not mapped" % hash_id) print("Salt size: %s" % salt_size) # Extract info for first 10 keyslots for i in range(10): salt_bytes = hexlify(keys[0+i*kKeySlotSize:salt_size+i*kKeySlotSize]).decode("ascii") # this uses data from keys corresponding to slotnum = 0 print("Key: %d Salt: %s" % (i, salt_bytes)) size, _type, param = struct.unpack(keymap_fmt, keymap[i*keymap_size:i*keymap_size+keymap_size]) # this uses data from keymap with slotnum = 0 print("Key: %d Salt size: %s, salt type: %s, parameter: %s" %(i, size, _type, param)) if _type == kBCKeyType_Salt: print("Keyslot: %d salt for %s: %s" % (i, os.path.basename(filename), salt_bytes)) salt = salt_bytes # return elif _type == kBCKeyType_Empty: print("Keyslot: %d is empty" % (i)) elif _type == kBCKeyType_Part: print("Keyslot: %d is of type Part(%d)" % (i, _type)) elif _type == kBCKeyType_PBE: print("Keyslot: %d is of type assword Based Encryption PBE(%d)" % (i, _type)) elif _type == kBCKeyType_PKE: print("Keyslot: %d is of type Public Key Encryption PKE(%d)" % (i, _type)) elif _type == kBCKeyType_SSS: print("Keyslot: %d is of type Secret Sharing Scheme SSS(%d)" % (i, _type)) else: print("Keyslot: %d if of type %d" % (i, _type )) dbsize = kBCV8_InitialDataBlockSize maxSlots = DataBlock_CapacityForSize(dbsize) # find the active slots (look in keymap, data is in keys) slot_size = keymap_size version = 1 # internal format version, unused for slotnum in range(0, maxSlots): slot = keymap[slot_size * slotnum:slot_size * (slotnum + 1)] size, slot_type, _ = struct.unpack(keymap_fmt, slot) if slot_type == kBCKeyType_Part or slot_type == kBCKeyType_Salt or slot_type == kBCKeyType_Empty: continue # find the corresponding bits in "keys", keys[slotnum] active_key = keys[kKeySlotSize * slotnum:kKeySlotSize * (slotnum + 1)] # output one "hash" for every active key slot key = hexlify(active_key).decode("ascii") sys.stdout.write("%s:$BestCrypt$%s$%s$%s$%s$%s$%s$%s$%s$%s$%s$%s\n" % (os.path.basename(filename), version, wKeyGenId, wVersion, iterations, alg_id, mode_id, hash_id, salt_size, salt, 1, key)) f.close() if __name__ == "__main__": if len(sys.argv) < 2: sys.stderr.write("Usage: %s [Jetico BestCrypt Containers, .jbc file(s)]\n" % sys.argv[0]) for i in range(1, len(sys.argv)): process_file(sys.argv[i]) я там немного подправил формат хедера и добавил в скрипте перебор по слотам ключей (там их максимум 64, в заголовке идёт 10 и в конце файла остальные). Плюс для хешкэта уже есть модули
Огромная благодарность! На выходе получилось следующее: Code: python.exe bestcrypt2john.py D:\my_files.jbc db_header_fmt: < 3s 8s 4s 28s 11s H H I 50s Q Q I I I 512s with size 652 db_enc_block64_fmt: < 3s 8s 4s 28s 11s H H I 50s Q Q I I I 512s 4s 64s 16s with size 736 DATA_BLOCK_64_fmt: < 3s 8s 4s 28s 11s H H I 50s Q Q I I I 512s 4s 64s 16s 288s 512s 2560s with size 4096 lock_flag: b'420000' signature: b'LOCOS94 ' container_id: b'33107aea' occupiedTag: b'41005300550053002d00450045004500000000000000000000000000' volumeLabel: b'BC_KeyGenID' wKeyGenId: 4 wVersion: 0 description: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' offset_main: 4096 size_main: 1347416064 alg_id: 240 mode_id: 3154116610 hash_id: 128 iv: b'89a7d898926072b6b0e3968bb688c8d4' digest: b'8e55a10948e9909a9059fbf1985c2c7a1b4447d8c043ed09ef9f8da97e934b9720cddba5da2d4cd8eb3e8ef720287496fe1624e611ab38734b97eb36b48eb21d' random_pool: b'99274f4e1db87f5872a14aa2d5fbf9a0f780ec8552928b63bc7f80943d03245a1e0e36c242c8d3cebad2a2d293cf501ff2243cdf64fb73406f8eded56da2ba399a5149f56b0dc7a321e2a0549ffbe0307868eb5c4d1f6e215640954a3e9d7fcd3479efae3f904421d158abefa087931ab1d561c4b503654d991c0dbc59fb5960150d8fb76658308ef2bc2a6a3e794f27c4f206df46b1410d61aaaff265c43238649593d6896d7533ab97878e22dbfe9dda474374a630e8a9d673e1b60b00f19e4a9a62d450d8f95825702923f4b487c51a5d7e4d7d8844691ffe0ccef3b87edaefa3647862a0a64588cf78f15b0dd2e7adbb203074c23c9465d39903c4f4c1347a38018c68cd6241fb3cdcbf00edc74bbaea92e632e4b774cf7bee1d26baa2f413e1a1d609681795a640bd568b5c4e386a703b3760f99f4f867d75e4c3140961e427ac20ee78ac8ab262837fa3634ff8e5d782eaa606db6eb16195204009dec412918a30be050966472b9600f008b2d152a6d1c9ab15531979b0b59848a10965c8a8a3ce221816718c225fa11c555f0cd9668f9a182def9806f13f1581e5728c2cf260c4c2b7bbf5aacf442ccc523ef0a49e2326945797327fac9a5f93dc018166f927d945ede038c9baae67aa0638c7d8d6f735c89a33300c6a2e3e278f9f8b9f4561d454bf6d830f6c061c5e7933d7a097728f5cfeabdad7b1637ae50432f4' keys: b'8eea1118f92621d705cfdb1ff6e6dd6d11f700a442317c5b2c92f1f01efc7043dd9dc1698ac4a76ce51f4cd7018bfffdf89bc795d370626e34e44a30f15cd499cc6963e5a82650611952c09bf69c232c4c8ee8ff2074970dc518eb8a97977c1536c1fc81028ce923cb55781abae602e4a10276bba43e7edc5721b686829bb5c2e23904b9a2787e59c7cb37fc3bc583a7d2793f286d90820fcecb136c00db36549764f067de5505abcd9a45feda9c03b81108c88c67d249af4c79973c7f8c96d8266db0921e55ca0c909877e0c52b6c3d3b6335d1f8ff26ec1e6993e2c03944b1f4fb23e3293238b6bb9dd77bc5b8183c378688a1288e1e146d2371246ae927272895b124a8f436f0772fcc96834deefc2df92bc49f861b71603097cb25a52984ebc4c21b42a4ab01ecd8befba6f1d6c74645840206ef044920176f9f9b74310e640ebe91a0498132411f1570d7adb8e3a9f1fd2305d2c1e5d4605f67715e280fbcfe0d4f6aeb9fcb9f8c3abebe887c998085fcee4336398da594d1ed526bf4cd1a19171a4792ed142da893ad028a0b31f08aeb2c69235689bb3a2cf7e4a47e91a7e945bddf47535414fa89044cbb4bf3238731a51ea1ff203ddad84ecf10aea28af5fdfedb11b9d57b0b858d43242527410436210bb91c9b53fd3dbabcb76d4aecc5a8a7e3f907dd8b61ed0e90cc811471896268d8729642272ac30253a2a1cff5e2af7e9e0625b56b862a50dabb4803dc9f1d412cd5535ddee9d2f03bd8337accd3784cb540fba54502a51bcafa603caacdcf76afe83c34a3c2d24a1d610c939a206dd8cfaf72f43e5bc5360890b307029ce0cd0ab5390f9c3e2bd9a04612628652f5ec955c70ec801bf16b3b8528ac0c93b80fe5443335f1e445656d8e2f2eb9f0774eaf4eded333c993800be2a672f23abf04e79b10efcb3c88b62b414a415b825dc7c48da5f27eee123e22ae17a3d9195e73b9c4ba8552cf5d9383684be193900e1f7c22ab918a11d66d25f16285ebb9fb2503c7173fad242ac51d0a195789a3f21e8114daf87fba47d5bfb36f6150a100e36caa116405c45815a02f9eeb6642718c786b196e8472cd3d96fd267e3059d3739c778f3e81355048b5dfc1e452f6f3300c304f3cc1bfd06f52d66f26b26ade9d3c3678134a01792903236a8c7446e0d3e36a66ab5f2cb8319c47329ffe5b872bf4edb62c87af3a7f33028129f5baa03da5214501863eed4c1c5757323db438e36ba630d161c8fd11ec85ef04fcda9b36fb5dd4865d7fd788790ec62797fe588f4a68ce4a00d329a8d7b39a65b22f3a868d27fb840d76deac5b7467c633bf4ff5383c78de8b58260c9b946b933f40e3f40286a241bdab6b826c9222563a8284dede2816d62ae05b05e1304ad8ca95ff4a0283b10696a7e4d0516fe021d3cc6111e337907a07f2325b5190207a7bb7f74e3725101bc0f1b35fb513876d27274d58f16ece12471612d592bbd3c27b2d31c94674a8c862113ef73e8701835e1ab079add7b9e615d4633d4db94df8f27f1782da785f55a590ef5f94d234ab9f2ef33dc179373e97b58e592993746408361043993a1e09b0f52d6160fc0a2d12e97c6cd55c3161f540f9f2cf50324ee3d983d22bc1ce2eacc85fc34a0e6a50e0d6b4ce9089909858fe0dcfe6f86efdaef0daf83915550ac092ef4ef90f3b5d317a032a9b073a2be87532ba179410ba8f047c7d6b3f9de515d944ca1607679c2c5fd24a9dde1962cc2fd1790a2affcdae9cd12968468c09d228c6ff48ffd555fa0c87f43f1714842db450d566c5257e344041c4d9320cbd2004ddb538fd6dd0c2098cf129b912db328a1996d46a691549783415650c044827f7f1b38e0c1754addf470902ccfdad043b9284fb23b3d914cd12e5b5db5bf30e886ac2f131bb2be31522037359bc43ca4f256684f7eb13bec643fc70a7fb06fe40b0aa0976419b8b3383a9236637e5ad4c390616effa0b6eec2f223f78cbc91ea52b337fe291edcec1d4c1bbfe56dbd5bc352a5a11c6094dc53f1fca57b38397414424fb7d9469d3487c14e226016c6926839bf767385583dbd9bab84b9b7e909c614724503056c350e36a41e820e191138a2196f9383637b667bcb25d6b00323cec62a3624efec55f718b7f4b9b82770ab283dfcdaff692dc4fee5f940b52a4ab4b3e1fbcd7a702ff8e3e45575a974093638b79ed83dbbbd7fb1568f864bc0f71e8a34164b19aa1b7a24c3b154568173605ff0d619e2eda2fd1fc74915c859b142959b164c61fcb0f157e088c453d227c00a8422fe636196a3b6a2c68dcf76f1e782716c4fc7da8904f9a55c5405d89ecbd4ec161453d9e129f263784cd58b4173cd6198a3dfe5fc1b968c9c61f11750fa2b932ffa28991ae67f93fed15f19185dc2e61c070e8192bb9b20d99cba10e6b18b03b0fe4631bc7faabe9ac9e0a2ff2c2f7976d7d84fd54b83ec8462b557b8a88fd879bf51364e4c004dfc84eebb6e555f9629a4b1a34c61fd5a3d32674e5f45866bcaabce1938d21ccc9490fdb4de7fdfc6b4ec4f2e509543f464aa648732ff2b483452115d04b85ca4e38c8241c7f22c75991cf5339a3c14458b292174ec5bcaf83730cf645a454c7179c610c4c352c23d56b5487581eccac8214d12a9d3e201e653c65cd1722f68bcc7dc1dc059184d887e53cd46902df3e6b774dc9892084cad0a814e2714dd4de14e3d2db6e1c90ae16066d8394d561c3bbe3ed3c3af5527c6dc0027d79ac548897d77b53b05db96d2bd7d0db0321ba041c6199cad744f1fae48b15e657c7df50fe60a48af2dc67dc6d5e4d26db6d51c634f739bc8896c90cdc1136643426defff18735c95d2203c485a5cdaa474290d4abb0b65a7772427cfd5b4e413852b75d1753175819b6f3ed1ab436b16d27def52a91f6ecc960c411f07043c38ad2d43219cc307f4d20a11fd591728175a4a3f059a4e2baa9e8b7925d59ff33532e9b469efa698622e973225e4667628841488edff0620c3d9383c8eb1c68d9baef76614fe6abb4bf98d3bd5cdbff9ece873397657d5f29ade8907b43c368fce89ccc4ad497dc534cb528ba7756207c6efdcdd39254bf5a227047720d55e6e504bd04cad415e5a9f3c9dadf58c1b443902c7e090f7c6ce7c4b10e77f0dbc9dd37da88a9f869afffda5b51f5a723a23c5e9aaf0383fd4c18ba354e50945cfb2aa97cbfafe79a219c29f3f4c30b85d2affdd1c68797e049342d8470c6a2e06314812a11a349b022ca09192d132dee2ce398592d5ef32c4a854424daa1c270e9e5e86de64fc8b49ccfa25664abb566982255b84a503ee93651289ff6a99b1275e305cca6790aad76f41b31ff544af6feb25c788724201ff7e1007d2ba6d6d0ef5801cfb9eab7a398819c3367d694a446dcd6204ba443d7747df544e05f1ab23f8a03fe886a789eeabe4fe204f93d7a58e8eb39fd964c19956d2f7e7f9d10bf4ec234e279c1f5a753f25ac93e85ea801c1ec24a07c3e6eb42f8d5b26f2860ff0247bb02f5b6d5c5be67e56d7e4145bd7bc684dbd0f3b75763670f6918c8b17a4463c1e66512c001106319582af6f6395b275875c0ed6764e002072ae245ab39fd5c' Description: Invalid header version 0, id 4 Я так понимаю, что хэша и в этом случае нет, если судить по завершающей строчки: "Invalid header version 0, id 4"
Да, тут тоже нет, то это мой косяк, т.к. одну переменную лишний раз поменял. Поэтому ошибка даже раньше чем до этого вылетала, пофиксил, попробуйте: Spoiler: Скрипт Code: #!/usr/bin/env python # This software is Copyright (c) 2017, Dhiru Kholia <dhiru.kholia at gmail.com> # and it is hereby released to the general public under the following terms: # # Redistribution and use in source and binary forms, with or without # modification, are permitted. # # Written in March of 2017 based on BestCrypt-3.0.0.tar.gz. import os import sys import struct from binascii import hexlify """ libs/multi-lib/keygens/kgghost/db_header.h kBCV8_HeaderSize = 1024, kBCV8_InitialDBSize = 1024 * 4, kBCV8_MaximumDBSize = kBCV8_InitialDBSize * 4, kBCV8_JmpCodeSize = 3, kBCV8_SignatureSize = 8, kBCV8_IdLength = 4, kBCV8_OccupiedTag = 28, kBCV8_VolumeLabel = 11, kBCV8_DescriptionLength = 42, kBCV8_DigestSize32 = 32, kBCV8_DigestSize64 = 64, kBCV8_MaxKeys = 64, kBCV8_BlockSize = 16, kBCV8_IVSize = 16, kBCV8_HiddenPartMapIV = 1, kBCV8_InitialDataBlockSize = 4096, kBCV8_DataBlockExtentionUnit = 4096, kBCV8_MaximumExtKeyBlockSize = kBCV8_DataBlockExtentionUnit * 4, kBCV8_MaximumDataBlockSize = kBCV8_InitialDataBlockSize + kBCV8_MaximumExtKeyBlockSize, kBCV8_HiddenPartSpaceMapSize = 4096 typedef struct { bc_u16 size; // encoded key data size. bc_16 type; // encoding type. signed 16 bit value. bc_u32 param; // optional key parameter. } BCKeySlot; // V8 datablock header format. typedef struct db_header { bc_u8 jmpCode[kBCV8_JmpCodeSize]; // On old linux version holds container lock flag. bc_u8 signature[kBCV8_SignatureSize]; // Format version signature, i.e. LOCOSXX bc_u8 cid[kBCV8_IdLength]; // Container id for central management authentication. bc_u8 occupiedTag[kBCV8_OccupiedTag]; // Unused? char volumeLabel[kBCV8_VolumeLabel]; // "BC_KeyGenID" for this version bc_u16 wKeyGenId; // Key generator ID 5 identifier... bc_u16 wVersion; // Key generator ID 5 version... union { bc_u32 iterations; // Key generator ID 5, allows iteration other then 256, but int does never uses the version field. bc_u32 version; // Container version }; char description[kBCV8_DescriptionLength]; // Description string. bc_u64 sparced_position; bc_u64 data_start; // Encrypted body data start. bc_u64 data_length; // Encrypted body data size. bc_u32 alg_id; // The algorithm used for container encryption bc_u32 mode_id; // Encryption mode for container algorithm bc_u32 hash_id; // Hash algorithm used for encryption keys generation BCKeySlot keymap[kBCV8_MaxKeys]; ... } db_header; // libs/multi-lib/keygens/kgghost/kgghost.h kKeySlotSize = 256, // Single encoded key slot. kDigestSize32 = 32, // Digest buffer length. kDigestSize64 = 64, // Digest buffer length. kIVSize = 16, // IV buffer length. kSeedLength = 128, // random seed buffer size for key generation. kEncryptedBlockSize = 16, // Block cipher encryption block size. kMaximumKeySize = 64, // Maximum stored key size. kPoolSize = 512 // Random data pool size. // kgghost -> Default BestCrypt version 8 key generator typedef struct { bc_u8 data[kKeySlotSize]; } KEY_BLOCK; struct db_enc_block64 { db_header header; bc_u8 padding[4]; // --------------------------------------------------------------------------------------------------------------- // Data before this point can be encrypted and should be a multiple of kBCV8_BlockSize bytes in size. bc_u8 digest[kBCV8_DigestSize64]; // header digest. bc_u8 iv[kBCV8_IVSize]; // random initial vector for header encryption. } typedef struct { db_enc_block64 header; bc_u8 padding[1024 - sizeof(db_enc_block64)]; // --------------------------------------------------------------------------------------------- // 1KB boundary bc_u8 pool[kPoolSize]; KEY_BLOCK keys[0]; // real number of keys depends on total data block size. } DATA_BLOCK_64; """ DB_HEADER_SIGNATURE = b"LOCOS94 " kKGID = 4 # Keygen id kKGID_V5 = 5 # Keygen id for BestCrypt version 5 # ORIGINAL # db_header_fmt = '< 3s 8s 4s 28s 11s H H I 42s 24s I I I 512s' db_header_fmt = '< 3s 8s 4s 28s 11s H H I 50s Q Q I I I 512s' # Edited #db_header_fmt = '< 3s 8s 4s 28s 11s I I 50s Q Q I I I 512s' # Plain header + 4bytes Padding + Digent + IV db_enc_block64_fmt = "%s 4s 64s 16s" % db_header_fmt #DATA_BLOCK_64_fmt = "%s 288s 512s 2560s" % db_enc_block64_fmt # hardcoded 2560s supports 10 KEY_BLOCK(s) while maximum is 64 (kBCV8_MaxKeys) # Encrypted header + padding + random pool + keys DATA_BLOCK_64_fmt = "%s 288s 512s 2560s" % db_enc_block64_fmt # hardcoded 2560s supports 10 KEY_BLOCK(s) while maximum is 64 (kBCV8_MaxKeys) DATA_BLOCK_64_size = struct.calcsize(DATA_BLOCK_64_fmt) db_enc_block64_size = struct.calcsize(db_enc_block64_fmt) keymap_fmt = "< H h I" keymap_size = struct.calcsize(keymap_fmt) db_header_size = struct.calcsize(db_header_fmt) key_slot_fmt = "< H h I" # 8 bytes key_slot_size = 8 print("db_header_fmt: %s with size %i" % (db_header_fmt, db_header_size)) print("db_enc_block64_fmt: %s with size %i" % (db_enc_block64_fmt, db_enc_block64_size)) print("DATA_BLOCK_64_fmt: %s with size %i" % (DATA_BLOCK_64_fmt, DATA_BLOCK_64_size)) # ciphers bcsaRIJN = 240 # block cipher modes. kBCMode_UDF = 0 kBCMode_CBC = 0xBC000002 kBCMode_LRW = 0xBC000001 kBCMode_XTS = 0xBC000004 kBCMode_ECB = 0xBC000008 # hashing algorithms pgphaMD5 = 1 pgphaSHA1 = 2 pgphaRIPEMD160 = 3 pgphaSHA256 = 8 pgphaSHA512 = 10 bchaSHA256 = 0x80 bchaWhirlpool512 = 0x80 + 1 # 129 bchaSHA3_512 = 0x80 + 2 bchaSkein512 = 0x80 + 3 kBCKeyType_Salt = 5 # KeyGen V5 save salt at key map, see DATA_BLOCK::updateSalt kBCV8_InitialDataBlockSize = 4096 DATA_BLOCK_size = 1536 kKeySlotSize = 256 kBCV8_MaxKeys = 64 # slot type kBCKeyType_Part = -1 kBCKeyType_Empty = 0 kBCKeyType_PBE = 1 kBCKeyType_SSS = 2 kBCKeyType_PKE = 3 kBCKeyType_Salt = 5 def DataBlock_CapacityForSize(dbsize): if dbsize <= DATA_BLOCK_size: return 0 capacity = ((dbsize - DATA_BLOCK_size) // kKeySlotSize) if capacity < kBCV8_MaxKeys: return capacity else: return kBCV8_MaxKeys def process_file(filename): try: f = open(filename, "rb") except IOError: e = sys.exc_info()[1] sys.stderr.write("%s\n" % str(e)) return N = DATA_BLOCK_64_size data = f.read(N) if len(data) != N: sys.stdout.write("%s : parsing failed\n" % filename) return -1 data = struct.unpack(DATA_BLOCK_64_fmt, data) (lock_flag, signature, container_id, occupiedTag, volumeLabel, wKeyGenId, wVersion, iterations, description, offset_main, size_main, alg_id, mode_id, hash_id, keymap, padding_enc, digest, iv, padding_header, random_pool, keys) = data # libs/multi-lib/keygens/kgghost/kgghost.cpp -> readDBFromContainer # libs/multi-lib/keygens/kgghost/datablock.cpp -> DataBlock_DecodeKey # libs/multi-lib/keygens/kgghost/datablock.cpp -> walkNotEncrypted # DEBUG print("lock_flag: %s\n signature: %s\n container_id: %s\n occupiedTag: %s\n volumeLabel: %s\n wKeyGenId: %s\n wVersion: %s\n description: %s\n offset_main: %s\n size_main: %s\n alg_id: %s\n mode_id: %s\n hash_id: %s\n" % (hexlify(lock_flag), signature, hexlify(container_id), hexlify(occupiedTag), volumeLabel, wKeyGenId, wVersion, description, offset_main, size_main, alg_id, mode_id, hash_id)) print("iv: %s\n digest: %s\n random_pool: %s\n keys: %s" %(hexlify(iv), hexlify(digest), hexlify(random_pool), hexlify(keys))) # DEBUG if signature != DB_HEADER_SIGNATURE or volumeLabel != b"BC_KeyGenID": print("%s: encrypted header found, not yet supported, patches welcome!" % os.path.basename(filename)) # look at libs/multi-lib/keygens/kgghost/datablock.cpp -> DataBlock_DecodeKey return description = description.decode("utf-16-le").rstrip("\x00") print("Description: %s" % description) if wKeyGenId == kKGID_V5: resolved_version = wVersion else: resolved_version = iterations # union of iterations and version if (resolved_version != 3) or wKeyGenId != kKGID: print("Invalid header version %s, id %s" % (resolved_version, wKeyGenId)) return if alg_id != bcsaRIJN: print("%s: cipher alg_id %s not supported, patches welcome!" % (os.path.basename(filename), alg_id)) return if mode_id != kBCMode_CBC and mode_id != kBCMode_XTS: print("%s: cipher mode_id %s not supported, patches welcome!" % (os.path.basename(filename), hex(mode_id))) return # handle hash_id and salt if hash_id != bchaWhirlpool512 and hash_id != bchaSHA256 and hash_id != pgphaSHA512: print("%s: hash_id %s not supported, patches welcome!" % (os.path.basename(filename), hash_id)) return 0 salt_size = -1 if hash_id == bchaWhirlpool512: print("Hash algorithm: Whirlpool-512") salt_size = 64 elif hash_id == bchaSHA256: print("Hash algorithm: SHA-256") salt_size = 32 elif hash_id == pgphaSHA512: print("Hash algorithm: SHA-512") salt_size = 64 else: print("Hash algorithm with id %s is not mapped" % hash_id) print("Salt size: %s" % salt_size) # Extract info for first 10 keyslots for i in range(10): salt_bytes = hexlify(keys[0+i*kKeySlotSize:salt_size+i*kKeySlotSize]).decode("ascii") # this uses data from keys corresponding to slotnum = 0 print("Key: %d Salt: %s" % (i, salt_bytes)) size, _type, param = struct.unpack(keymap_fmt, keymap[i*keymap_size:(i+1)*keymap_size]) # this uses data from keymap with slotnum = 0 print("Key: %d Salt size: %s, salt type: %s, parameter: %s" %(i, size, _type, param)) if _type == kBCKeyType_Salt: print("Keyslot: %d salt for %s: %s" % (i, os.path.basename(filename), salt_bytes)) salt = salt_bytes # return elif _type == kBCKeyType_Empty: print("Keyslot: %d is empty" % (i)) elif _type == kBCKeyType_Part: print("Keyslot: %d is of type Part(%d)" % (i, _type)) elif _type == kBCKeyType_PBE: print("Keyslot: %d is of type Password Based Encryption PBE(%d)" % (i, _type)) elif _type == kBCKeyType_PKE: print("Keyslot: %d is of type Public Key Encryption PKE(%d)" % (i, _type)) elif _type == kBCKeyType_SSS: print("Keyslot: %d is of type Secret Sharing Scheme SSS(%d)" % (i, _type)) else: print("Keyslot: %d if of type %d" % (i, _type )) dbsize = kBCV8_InitialDataBlockSize maxSlots = DataBlock_CapacityForSize(dbsize) # find the active slots (look in keymap, data is in keys) slot_size = keymap_size version = 1 # internal format version, unused for slotnum in range(0, maxSlots): slot = keymap[slot_size * slotnum:slot_size * (slotnum + 1)] size, slot_type, _ = struct.unpack(keymap_fmt, slot) if slot_type == kBCKeyType_Part or slot_type == kBCKeyType_Salt or slot_type == kBCKeyType_Empty: continue # find the corresponding bits in "keys", keys[slotnum] active_key = keys[kKeySlotSize * slotnum:kKeySlotSize * (slotnum + 1)] # output one "hash" for every active key slot key = hexlify(active_key).decode("ascii") sys.stdout.write("%s:$BestCrypt$%s$%s$%s$%s$%s$%s$%s$%s$%s$%s$%s\n" % (os.path.basename(filename), version, wKeyGenId, wVersion, iterations, alg_id, mode_id, hash_id, salt_size, salt, 1, key)) f.close() if __name__ == "__main__": if len(sys.argv) < 2: sys.stderr.write("Usage: %s [Jetico BestCrypt Containers, .jbc file(s)]\n" % sys.argv[0]) for i in range(1, len(sys.argv)): process_file(sys.argv[i])
Сейчас в дополнении к тому, что выводилось выше, добавилось: Code: Description: Hash algorithm: SHA-256 Salt size: 32 Key: 0 Salt: 8eea1118f92621d705cfdb1ff6e6dd6d11f700a442317c5b2c92f1f01efc7043 Key: 0 Salt size: 152, salt type: 1, parameter: 0 Keyslot: 0 is of type Password Based Encryption PBE(1) Key: 1 Salt: 2895b124a8f436f0772fcc96834deefc2df92bc49f861b71603097cb25a52984 Key: 1 Salt size: 0, salt type: 0, parameter: 0 Keyslot: 1 is empty Key: 2 Salt: f5e2af7e9e0625b56b862a50dabb4803dc9f1d412cd5535ddee9d2f03bd8337a Key: 2 Salt size: 0, salt type: 0, parameter: 0 Keyslot: 2 is empty Key: 3 Salt: 6642718c786b196e8472cd3d96fd267e3059d3739c778f3e81355048b5dfc1e4 Key: 3 Salt size: 0, salt type: 0, parameter: 0 Keyslot: 3 is empty Key: 4 Salt: 7bb7f74e3725101bc0f1b35fb513876d27274d58f16ece12471612d592bbd3c2 Key: 4 Salt size: 0, salt type: 0, parameter: 0 Keyslot: 4 is empty Key: 5 Salt: 344041c4d9320cbd2004ddb538fd6dd0c2098cf129b912db328a1996d46a6915 Key: 5 Salt size: 0, salt type: 0, parameter: 0 Keyslot: 5 is empty Key: 6 Salt: 92dc4fee5f940b52a4ab4b3e1fbcd7a702ff8e3e45575a974093638b79ed83db Key: 6 Salt size: 0, salt type: 0, parameter: 0 Keyslot: 6 is empty Key: 7 Salt: 938d21ccc9490fdb4de7fdfc6b4ec4f2e509543f464aa648732ff2b483452115 Key: 7 Salt size: 0, salt type: 0, parameter: 0 Keyslot: 7 is empty Key: 8 Salt: 3852b75d1753175819b6f3ed1ab436b16d27def52a91f6ecc960c411f07043c3 Key: 8 Salt size: 0, salt type: 0, parameter: 0 Keyslot: 8 is empty Key: 9 Salt: 812a11a349b022ca09192d132dee2ce398592d5ef32c4a854424daa1c270e9e5 Key: 9 Salt size: 0, salt type: 0, parameter: 0 Keyslot: 9 is empty Traceback (most recent call last): File "bestcrypt2john.py", line 293, in <module> process_file(sys.argv[i]) File "bestcrypt2john.py", line 283, in process_file salt_size, salt, 1, key)) UnboundLocalError: local variable 'salt' referenced before assignment
Посмотрите Spoiler: новый скрипт Code: #!/usr/bin/env python # This software is Copyright (c) 2017, Dhiru Kholia <dhiru.kholia at gmail.com> # and it is hereby released to the general public under the following terms: # # Redistribution and use in source and binary forms, with or without # modification, are permitted. # # Written in March of 2017 based on BestCrypt-3.0.0.tar.gz. import os import sys import struct from binascii import hexlify """ libs/multi-lib/keygens/kgghost/db_header.h kBCV8_HeaderSize = 1024, kBCV8_InitialDBSize = 1024 * 4, kBCV8_MaximumDBSize = kBCV8_InitialDBSize * 4, kBCV8_JmpCodeSize = 3, kBCV8_SignatureSize = 8, kBCV8_IdLength = 4, kBCV8_OccupiedTag = 28, kBCV8_VolumeLabel = 11, kBCV8_DescriptionLength = 42, kBCV8_DigestSize32 = 32, kBCV8_DigestSize64 = 64, kBCV8_MaxKeys = 64, kBCV8_BlockSize = 16, kBCV8_IVSize = 16, kBCV8_HiddenPartMapIV = 1, kBCV8_InitialDataBlockSize = 4096, kBCV8_DataBlockExtentionUnit = 4096, kBCV8_MaximumExtKeyBlockSize = kBCV8_DataBlockExtentionUnit * 4, kBCV8_MaximumDataBlockSize = kBCV8_InitialDataBlockSize + kBCV8_MaximumExtKeyBlockSize, kBCV8_HiddenPartSpaceMapSize = 4096 typedef struct { bc_u16 size; // encoded key data size. bc_16 type; // encoding type. signed 16 bit value. bc_u32 param; // optional key parameter. } BCKeySlot; // V8 datablock header format. typedef struct db_header { bc_u8 jmpCode[kBCV8_JmpCodeSize]; // On old linux version holds container lock flag. bc_u8 signature[kBCV8_SignatureSize]; // Format version signature, i.e. LOCOSXX bc_u8 cid[kBCV8_IdLength]; // Container id for central management authentication. bc_u8 occupiedTag[kBCV8_OccupiedTag]; // Unused? char volumeLabel[kBCV8_VolumeLabel]; // "BC_KeyGenID" for this version bc_u16 wKeyGenId; // Key generator ID 5 identifier... bc_u16 wVersion; // Key generator ID 5 version... union { bc_u32 iterations; // Key generator ID 5, allows iteration other then 256, but int does never uses the version field. bc_u32 version; // Container version }; char description[kBCV8_DescriptionLength]; // Description string. bc_u64 sparced_position; bc_u64 data_start; // Encrypted body data start. bc_u64 data_length; // Encrypted body data size. bc_u32 alg_id; // The algorithm used for container encryption bc_u32 mode_id; // Encryption mode for container algorithm bc_u32 hash_id; // Hash algorithm used for encryption keys generation BCKeySlot keymap[kBCV8_MaxKeys]; ... } db_header; // libs/multi-lib/keygens/kgghost/kgghost.h kKeySlotSize = 256, // Single encoded key slot. kDigestSize32 = 32, // Digest buffer length. kDigestSize64 = 64, // Digest buffer length. kIVSize = 16, // IV buffer length. kSeedLength = 128, // random seed buffer size for key generation. kEncryptedBlockSize = 16, // Block cipher encryption block size. kMaximumKeySize = 64, // Maximum stored key size. kPoolSize = 512 // Random data pool size. // kgghost -> Default BestCrypt version 8 key generator typedef struct { bc_u8 data[kKeySlotSize]; } KEY_BLOCK; struct db_enc_block64 { db_header header; bc_u8 padding[4]; // --------------------------------------------------------------------------------------------------------------- // Data before this point can be encrypted and should be a multiple of kBCV8_BlockSize bytes in size. bc_u8 digest[kBCV8_DigestSize64]; // header digest. bc_u8 iv[kBCV8_IVSize]; // random initial vector for header encryption. } typedef struct { db_enc_block64 header; bc_u8 padding[1024 - sizeof(db_enc_block64)]; // --------------------------------------------------------------------------------------------- // 1KB boundary bc_u8 pool[kPoolSize]; KEY_BLOCK keys[0]; // real number of keys depends on total data block size. } DATA_BLOCK_64; """ DB_HEADER_SIGNATURE = b"LOCOS94 " kKGID = 4 # Keygen id kKGID_V5 = 5 # Keygen id for BestCrypt version 5 # ORIGINAL # db_header_fmt = '< 3s 8s 4s 28s 11s H H I 42s 24s I I I 512s' db_header_fmt = '< 3s 8s 4s 28s 11s H H I 50s Q Q I I I 512s' # Edited #db_header_fmt = '< 3s 8s 4s 28s 11s I I 50s Q Q I I I 512s' # Plain header + 4bytes Padding + Digent + IV db_enc_block64_fmt = "%s 4s 64s 16s" % db_header_fmt #DATA_BLOCK_64_fmt = "%s 288s 512s 2560s" % db_enc_block64_fmt # hardcoded 2560s supports 10 KEY_BLOCK(s) while maximum is 64 (kBCV8_MaxKeys) # Encrypted header + padding + random pool + keys DATA_BLOCK_64_fmt = "%s 288s 512s 2560s" % db_enc_block64_fmt # hardcoded 2560s supports 10 KEY_BLOCK(s) while maximum is 64 (kBCV8_MaxKeys) DATA_BLOCK_64_size = struct.calcsize(DATA_BLOCK_64_fmt) db_enc_block64_size = struct.calcsize(db_enc_block64_fmt) keymap_fmt = "< H h I" keymap_size = struct.calcsize(keymap_fmt) db_header_size = struct.calcsize(db_header_fmt) key_slot_fmt = "< H h I" # 8 bytes key_slot_size = 8 print("db_header_fmt: %s with size %i" % (db_header_fmt, db_header_size)) print("db_enc_block64_fmt: %s with size %i" % (db_enc_block64_fmt, db_enc_block64_size)) print("DATA_BLOCK_64_fmt: %s with size %i" % (DATA_BLOCK_64_fmt, DATA_BLOCK_64_size)) # ciphers bcsaRIJN = 240 # block cipher modes. kBCMode_UDF = 0 kBCMode_CBC = 0xBC000002 kBCMode_LRW = 0xBC000001 kBCMode_XTS = 0xBC000004 kBCMode_ECB = 0xBC000008 # hashing algorithms pgphaMD5 = 1 pgphaSHA1 = 2 pgphaRIPEMD160 = 3 pgphaSHA256 = 8 pgphaSHA512 = 10 bchaSHA256 = 0x80 bchaWhirlpool512 = 0x80 + 1 # 129 bchaSHA3_512 = 0x80 + 2 bchaSkein512 = 0x80 + 3 kBCKeyType_Salt = 5 # KeyGen V5 save salt at key map, see DATA_BLOCK::updateSalt kBCV8_InitialDataBlockSize = 4096 DATA_BLOCK_size = 1536 kKeySlotSize = 256 kBCV8_MaxKeys = 64 # slot type kBCKeyType_Part = -1 kBCKeyType_Empty = 0 kBCKeyType_PBE = 1 kBCKeyType_SSS = 2 kBCKeyType_PKE = 3 kBCKeyType_Salt = 5 def DataBlock_CapacityForSize(dbsize): if dbsize <= DATA_BLOCK_size: return 0 capacity = ((dbsize - DATA_BLOCK_size) // kKeySlotSize) if capacity < kBCV8_MaxKeys: return capacity else: return kBCV8_MaxKeys def process_file(filename): try: f = open(filename, "rb") except IOError: e = sys.exc_info()[1] sys.stderr.write("%s\n" % str(e)) return N = DATA_BLOCK_64_size data = f.read(N) if len(data) != N: sys.stdout.write("%s : parsing failed\n" % filename) return -1 data = struct.unpack(DATA_BLOCK_64_fmt, data) (lock_flag, signature, container_id, occupiedTag, volumeLabel, wKeyGenId, wVersion, iterations, description, offset_main, size_main, alg_id, mode_id, hash_id, keymap, padding_enc, digest, iv, padding_header, random_pool, keys) = data # libs/multi-lib/keygens/kgghost/kgghost.cpp -> readDBFromContainer # libs/multi-lib/keygens/kgghost/datablock.cpp -> DataBlock_DecodeKey # libs/multi-lib/keygens/kgghost/datablock.cpp -> walkNotEncrypted # DEBUG print("lock_flag: %s\n signature: %s\n container_id: %s\n occupiedTag: %s\n volumeLabel: %s\n wKeyGenId: %s\n wVersion: %s\n description: %s\n offset_main: %s\n size_main: %s\n alg_id: %s\n mode_id: %s\n hash_id: %s\n" % (hexlify(lock_flag), signature, hexlify(container_id), hexlify(occupiedTag), volumeLabel, wKeyGenId, wVersion, description, offset_main, size_main, alg_id, mode_id, hash_id)) print("iv: %s\n digest: %s\n" %(hexlify(iv), hexlify(digest))) # DEBUG if signature != DB_HEADER_SIGNATURE or volumeLabel != b"BC_KeyGenID": print("%s: encrypted header found, not yet supported, patches welcome!" % os.path.basename(filename)) # look at libs/multi-lib/keygens/kgghost/datablock.cpp -> DataBlock_DecodeKey return description = description.decode("utf-16-le").rstrip("\x00") print("Description: %s" % description) if wKeyGenId == kKGID_V5: resolved_version = wVersion else: resolved_version = iterations # union of iterations and version if (resolved_version != 3) or wKeyGenId != kKGID: print("Invalid header version %s, id %s" % (resolved_version, wKeyGenId)) return if alg_id != bcsaRIJN: print("%s: cipher alg_id %s not supported, patches welcome!" % (os.path.basename(filename), alg_id)) return if mode_id != kBCMode_CBC and mode_id != kBCMode_XTS: print("%s: cipher mode_id %s not supported, patches welcome!" % (os.path.basename(filename), hex(mode_id))) return # handle hash_id and salt if hash_id != bchaWhirlpool512 and hash_id != bchaSHA256 and hash_id != pgphaSHA512: print("%s: hash_id %s not supported, patches welcome!" % (os.path.basename(filename), hash_id)) return 0 salt_size = -1 if hash_id == bchaWhirlpool512: print("Hash algorithm: Whirlpool-512") salt_size = 64 elif hash_id == bchaSHA256: print("Hash algorithm: SHA-256") salt_size = 32 elif hash_id == pgphaSHA512: print("Hash algorithm: SHA-512") salt_size = 64 else: print("Hash algorithm with id %s is not mapped" % hash_id) print("Salt size: %s" % salt_size) # Check if keys are stored after main data block filesize = os.path.getsize(filename) diff = (filesize - offset_main - size_main) stored_keys = int(diff/ kKeySlotSize) + 10 print("Filesize: %s diff: %s stored keys: %s" %(filesize, diff, stored_keys)) if stored_keys > 10: f.seek(offset_main + size_main, 0) keys2 = f.read() keyslot_type = {-1:"Part", 0:"Empty", 1:"Password Based Encryption (PBE)", 2:"Secret Sharing Scheme (SSS)", 3:"Public Key Encryption (PKE)", 5:"Salt"} # Extract info for stored keyslots for keyslot in range(64): size, _type, param = struct.unpack(keymap_fmt, keymap[keyslot*keymap_size:keymap_size*(keyslot + 1)]) # Extract key data if _type != kBCKeyType_Empty: if keyslot < 10: keyslot_bytes = hexlify(keys[keyslot*kKeySlotSize:size+kKeySlotSize*keyslot]).decode("ascii") # this uses data from keys corresponding to slotnum = 0 else: keyslot_bytes = hexlify(keys2[kKeySlotSize*(keyslot - 10):size+kKeySlotSize*(keyslot-10)]).decode("ascii") print("Keyslot: %d is of type %s with size: %s and parameter: %s and key data: %s" % (keyslot, keyslot_type.get(_type,"Unknown"), size, param, keyslot_bytes)) else: #print("Keyslot: %d is empty" % (keyslot)) continue if _type == kBCKeyType_Salt: salt = keyslot_bytes # for i in range(stored_keys): # if i < 10: # keyslot_bytes = hexlify(keys[0+i*kKeySlotSize:salt_size+i*kKeySlotSize]).decode("ascii") # this uses data from keys corresponding to slotnum = 0 # else: # keyslot_bytes = hexlify(keys2[0+(i-10)*kKeySlotSize:salt_size+(i-10)*kKeySlotSize]).decode("ascii") # print("Keyslot: %d Bytes: %s" % (i, keyslot_bytes)) # size, _type, param = struct.unpack(keymap_fmt, keymap[i*keymap_size:(i+1)*keymap_size]) # this uses data from keymap with slotnum = 0 # print("Keyslot: %d Salt size: %s, salt type: %s, parameter: %s" %(i, size, _type, param)) # if _type == kBCKeyType_Salt: # print("Keyslot: %d salt for %s: %s" % (i, os.path.basename(filename), keyslot_bytes)) # salt = keyslot_bytes # return # elif _type == kBCKeyType_Empty: # print("Keyslot: %d is empty" % (i)) # elif _type == kBCKeyType_Part: # print("Keyslot: %d is of type Part(%d)" % (i, _type)) # elif _type == kBCKeyType_PBE: # print("Keyslot: %d is of type Password Based Encryption PBE(%d)" % (i, _type)) # elif _type == kBCKeyType_PKE: # print("Keyslot: %d is of type Public Key Encryption PKE(%d)" % (i, _type)) # elif _type == kBCKeyType_SSS: # print("Keyslot: %d is of type Secret Sharing Scheme SSS(%d)" % (i, _type)) # else: # print("Keyslot: %d if of type %d" % (i, _type )) # Extract dbsize = kBCV8_InitialDataBlockSize maxSlots = DataBlock_CapacityForSize(dbsize) # find the active slots (look in keymap, data is in keys) slot_size = keymap_size version = 1 # internal format version, unused for slotnum in range(0, maxSlots): slot = keymap[slot_size * slotnum:slot_size * (slotnum + 1)] size, slot_type, _ = struct.unpack(keymap_fmt, slot) if slot_type == kBCKeyType_Part or slot_type == kBCKeyType_Salt or slot_type == kBCKeyType_Empty: continue # find the corresponding bits in "keys", keys[slotnum] active_key = keys[kKeySlotSize * slotnum:kKeySlotSize * (slotnum + 1)] # output one "hash" for every active key slot key = hexlify(active_key).decode("ascii") sys.stdout.write("%s:$BestCrypt$%s$%s$%s$%s$%s$%s$%s$%s$%s$%s$%s\n" % (os.path.basename(filename), version, wKeyGenId, wVersion, iterations, alg_id, mode_id, hash_id, salt_size, salt, 1, key)) f.close() if __name__ == "__main__": if len(sys.argv) < 2: sys.stderr.write("Usage: %s [Jetico BestCrypt Containers, .jbc file(s)]\n" % sys.argv[0]) for i in range(1, len(sys.argv)): process_file(sys.argv[i])
Сейчас вот так: Code: Description: Hash algorithm: SHA-256 Salt size: 32 Filesize: 1347420160 diff: 0 stored keys: 10 Keyslot: 0 is of type Password Based Encryption (PBE) with size: 152 and parameter: 0 and key data: 8eea1118f92621d705cfdb1ff6e6dd6d11f700a442317c5b2c92f1f01efc7043dd9dc1698ac4a76ce51f4cd7018bfffdf89bc795d370626e34e44a30f15cd499cc6963e5a82650611952c09bf69c232c4c8ee8ff2074970dc518eb8a97977c1536c1fc81028ce923cb55781abae602e4a10276bba43e7edc5721b686829bb5c2e23904b9a2787e59c7cb37fc3bc583a7d2793f286d90820f Traceback (most recent call last): File "bestcrypt2john.py", line 320, in <module> process_file(sys.argv[i]) File "bestcrypt2john.py", line 310, in process_file salt_size, salt, 1, key)) UnboundLocalError: local variable 'salt' referenced before assignment
bredbaraded , пришли заголовок контейнера и я тебе точно скажу какая у тебя версия , используемые алгоритмы и так далее ...