Подбор пароля к BestCrypt

Discussion in 'Криптография, расшифровка хешей' started by bredbaraded, 2 Feb 2021.

  1. bredbaraded

    bredbaraded New Member

    Joined:
    19 Sep 2011
    Messages:
    11
    Likes Received:
    0
    Reputations:
    0
    Кто-то сталкивался с задачей?
    Имеется контейнер, даволно старый, потому и был утерян пароль. Однако сейчас понадобилась оттуда критичная информация!

    Есть специалисты?

    BestCrypt driver 4.18
    BestCrypt Control Panel 8.05.6
     
  2. fandor9

    fandor9 Reservists Of Antichat

    Joined:
    16 Nov 2018
    Messages:
    630
    Likes Received:
    1,050
    Reputations:
    47
    В джони есть поддержка для взлома 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 п/с
     
    bredbaraded likes this.
  3. bredbaraded

    bredbaraded New Member

    Joined:
    19 Sep 2011
    Messages:
    11
    Likes Received:
    0
    Reputations:
    0
    \Orange>python.exe bestcrypt2john.py F:\my_files.jbc
    my_files.jbc: internal error while processing salt, please report this problem!

    Пока такой результат, к сожалению.
     
  4. fandor9

    fandor9 Reservists Of Antichat

    Joined:
    16 Nov 2018
    Messages:
    630
    Likes Received:
    1,050
    Reputations:
    47
    Мда, к сожалению, в 8-ой версии BestCrypt (которая у вас имеется, если я правильно понимаю версии из первого сообщения) поменялся формат хедера и к тому же добавили возможность зашифровать и сам хедер. т.е. для начало надо узнать зашифрован ли сам хедер. -> посмотрите просто в хексе, если ли в хедере (первые 1536 байтов) строка "LOCOS94" или же "CRYPTED_DSK". Если есть, то хедер не зашифрован и можно дальше ковырять.
     
    bredbaraded likes this.
  5. bredbaraded

    bredbaraded New Member

    Joined:
    19 Sep 2011
    Messages:
    11
    Likes Received:
    0
    Reputations:
    0
    Да, глянул, в хексе видна строка "LOCOS94".
    В каком направлении можно двигаться дальше?
     
    #5 bredbaraded, 4 Feb 2021
    Last edited: 4 Feb 2021
  6. fandor9

    fandor9 Reservists Of Antichat

    Joined:
    16 Nov 2018
    Messages:
    630
    Likes Received:
    1,050
    Reputations:
    47
    Надо понять почему у вас падает скрипт, я его чуть подправил:
    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 а что-то другое, тогда надо в скрипте подгонять параметры
     
    bredbaraded likes this.
  7. bredbaraded

    bredbaraded New Member

    Joined:
    19 Sep 2011
    Messages:
    11
    Likes Received:
    0
    Reputations:
    0
    Благодарю!
    Сработало, однако хэша не получил. Скорей всего он действительно какой-то другой.
    Key genarotor у меня KG-Ghost.

    На выходе получилось следующее:
     
    #7 bredbaraded, 7 Feb 2021
    Last edited: 7 Feb 2021
  8. fandor9

    fandor9 Reservists Of Antichat

    Joined:
    16 Nov 2018
    Messages:
    630
    Likes Received:
    1,050
    Reputations:
    47
    Попробуйте
    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 и в конце файла остальные).
    Плюс для хешкэта уже есть модули
     
    bredbaraded likes this.
  9. bredbaraded

    bredbaraded New Member

    Joined:
    19 Sep 2011
    Messages:
    11
    Likes Received:
    0
    Reputations:
    0
    Огромная благодарность!

    На выходе получилось следующее:
    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"
     
  10. fandor9

    fandor9 Reservists Of Antichat

    Joined:
    16 Nov 2018
    Messages:
    630
    Likes Received:
    1,050
    Reputations:
    47
    Да, тут тоже нет, то это мой косяк, т.к. одну переменную лишний раз поменял. Поэтому ошибка даже раньше чем до этого вылетала, пофиксил, попробуйте:
    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])
     
    bredbaraded likes this.
  11. bredbaraded

    bredbaraded New Member

    Joined:
    19 Sep 2011
    Messages:
    11
    Likes Received:
    0
    Reputations:
    0
    Сейчас в дополнении к тому, что выводилось выше, добавилось:

    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
    
     
    #11 bredbaraded, 10 Feb 2021
    Last edited: 10 Feb 2021
  12. fandor9

    fandor9 Reservists Of Antichat

    Joined:
    16 Nov 2018
    Messages:
    630
    Likes Received:
    1,050
    Reputations:
    47
    Посмотрите
    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])
    
     
    bredbaraded likes this.
  13. bredbaraded

    bredbaraded New Member

    Joined:
    19 Sep 2011
    Messages:
    11
    Likes Received:
    0
    Reputations:
    0
    Сейчас вот так:

    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
    
     
  14. digger70

    digger70 New Member

    Joined:
    3 Mar 2018
    Messages:
    11
    Likes Received:
    2
    Reputations:
    0
    А от ElcomSoft то попробовали продукт?
     
  15. bredbaraded

    bredbaraded New Member

    Joined:
    19 Sep 2011
    Messages:
    11
    Likes Received:
    0
    Reputations:
    0
    Не открывает контейнер. По крайней мере демо.
     
  16. Leopard_

    Leopard_ Elder - Старейшина

    Joined:
    24 Jul 2012
    Messages:
    69
    Likes Received:
    15
    Reputations:
    21
    bredbaraded , пришли заголовок контейнера и я тебе точно скажу какая у тебя версия , используемые алгоритмы и так далее ...
     
  17. Ceijedo

    Ceijedo New Member

    Joined:
    6 Apr 2021
    Messages:
    6
    Likes Received:
    0
    Reputations:
    0
    Не знаете какой алгоритм она использует?