aes 128 cbc block

Doubts, help and support about QuickBMS and other game research tools
chrrox
Posts: 388
Joined: Thu Aug 07, 2014 10:28 pm

aes 128 cbc block

Post by chrrox »

I have this function in c#

Code: Select all

    private void cipher(byte[] buffer, int offset, int count, long streamPos)
    {
        //find block number
        var blockSizeInByte = aes.BlockSize / 8;
        var blockNumber = (streamPos / blockSizeInByte) + 1;
        var keyPos = streamPos % blockSizeInByte;
 
        //buffer
        var outBuffer = new byte[blockSizeInByte];
        var nonce = new byte[blockSizeInByte];
        var init = false;
 
        for (int i = offset; i < count; i++)
        {
            //encrypt the nonce to form next xor buffer (unique key)
            if (!init || (keyPos % blockSizeInByte) == 0)
            {
                BitConverter.GetBytes(blockNumber).CopyTo(nonce, 0);
                encryptor.TransformBlock(nonce, 0, nonce.Length, outBuffer, 0);
                if (init) keyPos = 0;
                init = true;
                blockNumber++;
            }
            buffer[i] ^= outBuffer[keyPos]; //simple XOR with generated unique key
            keyPos++;
        }
    }


its generating a xor key 16 bytes at a time starting with 1 going to x number and ending at 0.

and here is a quick example

Code: Select all

# py 3.9
# pip install pycryptodome
# pip install passlib
from Crypto.Cipher import AES
from passlib.utils.pbkdf2 import pbkdf1
from struct import pack_into


password = b'Jr9DW9ksMRv1Lc796mrwv145fXC3L5VcpmKE5VfCuvbrpZGfYwXMpwo9sGkJ54zHse4G7zftpjkhqHHY60O7aQPj4M2ekKMSw094PmXRkN4ftTmDFlYMPmwK8QvhJ20H'
salt = b'Jr9DW9ksMRv1Lc796mrwv145fXC3L5VcpmKE5VfCuvbrpZGfYwXMpwo9sGkJ54zHse4G7zftpjkhqHHY60O7aQPj4M2ekKMSw094PmXRkN4ftTmDFlYMPmwK8QvhJ20H'
key = pbkdf1(password, salt, 100, keylen=16, hash='sha1')

block_key = key[:16]
block_size = 0x2000
nonce = bytearray([0] * (block_size * 16))

aes = AES.new(block_key, mode = AES.MODE_ECB)

for i in range(0,block_size):
   pack_into('I', nonce, i * 16, (i + 1) % block_size)

out = aes.encrypt(nonce)
print(out.hex())


Code: Select all

   PasswordDeriveBytes pdb = new PasswordDeriveBytes(pwd, salt, "Sha1", 100);
       var buffer = pdb.GetBytes(0x10);
       var nonce = new byte[0x2000];
       var outBuffer = new byte[0x2000];
 
            var aes = new AesManaged();
            aes.KeySize = 128;
            aes.Mode = CipherMode.ECB;
            aes.Padding = PaddingMode.None;
            aes.Key = buffer;
            aes.IV = buffer;
            var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
       var block = 1;
 
            BitConverter.GetBytes(block).CopyTo(nonce, 0);
            encryptor.TransformBlock(nonce, 0, nonce.Length, outBuffer, 0);


so lets say
buffer is '8e2e1d5a5e3a4a1c7388f6b8d7779d7b'

the key is pushed to outbuffer
the first key block 1 would be
"31 0D 83 A9 D0 C0 10 4F FC ED 31 A7 56 E7 8A 85"
the 2nd key block 2 would be
"12 5F 47 C9 11 0C 35 12 D1 AE 25 EA 15 6C C0 0D"
the third key block 3 would be
"E4 E8 EF A9 4C B1 A2 92 AF 54 F0 E8 A4 88 BF BC"
and it would end on block 0
"FA DB B4 83 B5 DC CC EB 51 1C 3D 28 A3 00 53 3F"

How would this be handled in quickbms?
Last edited by chrrox on Thu Jan 14, 2021 5:42 pm, edited 10 times in total.
chrrox
Posts: 388
Joined: Thu Aug 07, 2014 10:28 pm

Re: aes 128 cbc block

Post by chrrox »

Working example to try it online

Code: Select all

using System;
using System.Security.Cryptography;
using System.Text;

               
public class Program
{
   public static void Main()
   {
      string password = "Jr9DW9ksMRv1Lc796mrwv145fXC3L5VcpmKE5VfCuvbrpZGfYwXMpwo9sGkJ54zHse4G7zftpjkhqHHY60O7aQPj4M2ekKMSw094PmXRkN4ftTmDFlYMPmwK8QvhJ20H";
      byte[] salt = Encoding.UTF8.GetBytes( "Jr9DW9ksMRv1Lc796mrwv145fXC3L5VcpmKE5VfCuvbrpZGfYwXMpwo9sGkJ54zHse4G7zftpjkhqHHY60O7aQPj4M2ekKMSw094PmXRkN4ftTmDFlYMPmwK8QvhJ20H" );
      var key = new PasswordDeriveBytes(password, salt, "Sha1", 100);

      
       byte[] Key = key.GetBytes(16);
       var nonce = new byte[0x2000];
       var outBuffer = new byte[0x2000];
 
            var aes = new AesManaged();
            aes.KeySize = 128;
            aes.Mode = CipherMode.ECB;
            aes.Padding = PaddingMode.None;
            aes.Key = Key;
            aes.IV = new byte[16];
            var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
             var block = 1;
 
            BitConverter.GetBytes(block).CopyTo(nonce, 0);
            encryptor.TransformBlock(nonce, 0, nonce.Length, outBuffer, 0);
          Console.WriteLine(outBuffer[0]);
         Console.WriteLine(outBuffer[1]);
          Console.WriteLine(outBuffer[2]);
         Console.WriteLine(outBuffer[3]);
   }
}
chrrox
Posts: 388
Joined: Thu Aug 07, 2014 10:28 pm

Re: aes 128 cbc block

Post by chrrox »

This does this in quickbms to match the xor key.

Code: Select all

set FINAL_SIZE 0x20000
putvarchr MEMORY_FILE FINAL_SIZE 0
for i = 0 < 0x2000
set j long i
math j * 16
set k long i
math k + 1
math k % 0x2000
putvarchr MEMORY_FILE j k long
next i
encryption mcrypt_rijndael-128_ecb "\x8E\x2E\x1D\x5A\x5E\x3A\x4A\x1C\x73\x88\xF6\xB8\xD7\x77\x9D\x7B"  "" 1 16
log NAME 0 FINAL_SIZE MEMORY_FILE


I just can't generate the key in quickbms can't find PBKDF1
aluigi
Site Admin
Posts: 12984
Joined: Wed Jul 30, 2014 9:32 pm

Re: aes 128 cbc block

Post by aluigi »

It can probably be done because there are some functions available in the Encryption command supporting pbkdf1 and others.
But I have no idea how to make them working easily because they need multiple arguments and their implementation may differ in some settings.
chrrox
Posts: 388
Joined: Thu Aug 07, 2014 10:28 pm

Re: aes 128 cbc block

Post by chrrox »

make new specific encryption command for them?
aluigi
Site Admin
Posts: 12984
Joined: Wed Jul 30, 2014 9:32 pm

Re: aes 128 cbc block

Post by aluigi »

Honestly I don't know what to do.
Imagine having many functions (current and in the future) with their own prototype and many settings, then finding a way to set them in a simple language like bms.

Since these algorithms are already implemented in quickbms, I guess the best way is checking the source code and understanding how to pass all the settings.
PKCS5_PBKDF2_HMAC, Rfc2898DeriveBytes, BytesToKey, PBKDF1, PBKDF1_openssl, PBKDF2, and others are already available in quickbms, the source code to check is in cmd.c and perform.c

Examples:

Code: Select all

    } else if(!strnicmp(type, "PKCS5_PBKDF2_HMAC", 17)) {
        myhash   = EVP_sha1();
        if(type[17]) openssl_get_algo(type + 17, &mycrypto, &myhash);
        memset(hash_key, 0, sizeof(hash_key));
        PKCS5_PBKDF2_HMAC(key, keysz, ivec, ivecsz, ((var3_backup != 0) && (var3_backup != 1)) ? var3_backup : 1000, myhash, sizeof(hash_key), hash_key);
        mycrypto = NULL;
        myhash   = NULL;
        DO_QUICKBMS_HASH(hash_key, sizeof(hash_key));

Code: Select all

    } else if(!strnicmp(type, "Rfc2898DeriveBytes", 18)) {
        myhash   = EVP_sha1();
        if(type[18]) openssl_get_algo(type + 18, &mycrypto, &myhash);
        memset(hash_key, 0, sizeof(hash_key));
        PKCS5_PBKDF2_HMAC(key, keysz, ivec, ivecsz, ((var3_backup != 0) && (var3_backup != 1)) ? var3_backup : 1000, myhash, sizeof(hash_key), hash_key);
        mycrypto = NULL;
        myhash   = NULL;
        hash = DO_QUICKBMS_HASH(hash_key, sizeof(hash_key));

        keysz  = 32;
        memcpy(key,  hash, keysz);
        ivecsz = 32;
        memcpy(ivec, hash + keysz, ivecsz);

        mcrypt_ctx = quick_mcrypt_check("mcrypt_rijndael-256_cbc");  // libmcrypt
        if(mcrypt_generic_init(mcrypt_ctx, key, keysz, ivec) < 0) {
            fprintf(stderr, "\nError: mcrypt key failed\n");
            myexit_cmd(cmd, QUICKBMS_ERROR_ENCRYPTION);
        }


Code: Select all

    } else if(!strnicmp(type, "BytesToKey", 10)) {
        mycrypto = EVP_aes_256_cbc();
        myhash   = EVP_sha1();
        openssl_get_algo(type + 10, &mycrypto, &myhash);
        openssl_get_algo(strstr(type + 10, " "), &mycrypto, &myhash);
        memset(hash_key, 0, sizeof(hash_key));
        EVP_BytesToKey(mycrypto, myhash, ivec, key, keysz, ((var3_backup != 0) && (var3_backup != 1)) ? var3_backup : 1000, hash_key, hash_key + sizeof(hash_key) / 2);
        mycrypto = NULL;
        myhash   = NULL;
        DO_QUICKBMS_HASH(hash_key, sizeof(hash_key));


Code: Select all

    } else if(!strnicmp(type, "PBKDF", 5)) {
        PBKDF_ctx = calloc(1, sizeof(*PBKDF_ctx));
        if(!PBKDF_ctx) STD_ERR(QUICKBMS_ERROR_MEMORY);
        PBKDF_ctx->key      = key;
        PBKDF_ctx->keysz    = keysz;
        PBKDF_ctx->ivec     = ivec;
        PBKDF_ctx->ivecsz   = ivecsz;
        PBKDF_ctx->iter     = ((var3_backup != 0) && (var3_backup != 1)) ? var3_backup : 1000;

        u8 *p = strchr(type, ' ');
        if(p) {
            p = "SHA1";
        } else {
            while(*p && !myisalnum(*p)) p++;
        }
        tomcrypt_doit(NULL, NULL, NULL, 0, NULL, 0, NULL);
        PBKDF_ctx->hash  = find_hash(p);

        if(type[5] == '2') {
            PBKDF_ctx->algo = 2;
        } else {    //'1'
            PBKDF_ctx->algo = 1;
            if(stristr(type, "openssl")) {
                PBKDF_ctx->openssl = 1;
            }
        }