0

I have this code in python and I am trying to convent it into C++ using CNG. What's wrong with code

import sys
sys.dont_write_bytecode = True
#!/usr/bin/env python3

import hashlib,base64, binascii, argparse,sys,base64,hashlib,sys
from Cryptodome.Cipher import AES

def main():
    
    enc_data = base64.b64decode('ncCn1qKVH4QHU+EI8NP3rOadN9tqqhmjG05tbemGYLnk6/0YWwQ79JrTXiSG+jHpHk0jC+U=')
    
    salt = enc_data[:16]
    associated_data = enc_data[:16]
    nonce = enc_data[16:32]
    ciphertext = enc_data[32:-16]
    tag = enc_data[-16:]
    key = binascii.unhexlify('881c05dfbd888bce1513a9903233575618c31d295bb262a1619bd19f9339a9cb')

    cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
    cipher.update(associated_data)
    plaintext = cipher.decrypt_and_verify(ciphertext, tag)
    
    print("Password: {}".format(plaintext.decode("utf-8")))

if __name__ == "__main__":
    main()

C++ CODE

bool aes_gcm(__in PBYTE iv, __in DWORD ivlen, __in const void *key, DWORD key_len, __in void * data, __in DWORD idata, __in DWORD padding, BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO * padinfo, __out PBYTE * out, __out DWORD * outlen) {
    DWORD u, x, tmp_len, key_objlen;
    BCRYPT_ALG_HANDLE hprov;
    BCRYPT_KEY_HANDLE hkey;
    BYTE * key_obj;
    NTSTATUS status;
    bool ret;

    ret = false;
    *outlen = 0;

    status = BCryptOpenAlgorithmProvider(&hprov, BCRYPT_AES_ALGORITHM, nullptr, 0);
    if (NT_SUCCESS(status)) {

        status = BCryptSetProperty(hprov, BCRYPT_CHAINING_MODE, (PUCHAR)BCRYPT_CHAIN_MODE_GCM, sizeof(BCRYPT_CHAIN_MODE_GCM), 0);
        if (NT_SUCCESS(status)) {

            status = BCryptGetProperty(hprov, BCRYPT_OBJECT_LENGTH, (PBYTE)&key_objlen, sizeof(DWORD), &tmp_len, 0);
            if (NT_SUCCESS(status)) {

                key_obj = (BYTE*)malloc(key_objlen);
                if (key_obj) {

                    status = BCryptGenerateSymmetricKey(hprov, &hkey, key_obj, key_objlen, (PUCHAR)key, key_len, 0);
                    if (NT_SUCCESS(status)) {
                        
                        u = 0;
                        status = BCryptDecrypt(hkey, (PUCHAR)data, idata, padinfo, iv, ivlen, nullptr, 0, &u, padding);
                        if (NT_SUCCESS(status)) {

                            *out = (PBYTE)malloc(u);
                            if (*out) {

                                status = BCryptDecrypt(hkey, (PUCHAR)data, idata, padinfo, iv, ivlen, *out, u, outlen, padding);
                                if (NT_SUCCESS(status)) {
                                    *outlen = u;
                                    ret = true;
                                }
                                else {
                                    free(*out);
                                    printf("BCryptDecrypt() error 0x%x\n", status);
                                }
                            }
                        }
                        else printf("BCryptDecrypt() error 0x%x\n", status);
                        
                        BCryptDestroyKey(hkey);
                    }
                    free(key_obj);
                }
            }
        }

        BCryptCloseAlgorithmProvider(hprov, 0);
    }

    return ret;
}
BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO info;
BCRYPT_INIT_AUTH_MODE_INFO(info);
unsigned char enc[] = { 
    0x9d,0xc0,0xa7,0xd6,0xa2,0x95,0x1f,0x84,0x07,0x53,0xe1,0x08,0xf0,0xd3,0xf7,0xac,0xe6,0x9d,0x37,0xdb,0x6a,0xaa,0x19,0xa3,0x1b,0x4e,0x6d,0x6d,0xe9,0x86,0x60,0xb9,0xe4,0xeb,0xfd,0x18,0x5b,0x04,0x3b,
    0xf4,0x9a,0xd3,0x5e,0x24,0x86,0xfa,0x31,0xe9,0x1e,0x4d,0x23,0x0b,0xe5 
};

unsigned char key[] = {
    0x88,0x1c,0x05,0xdf,0xbd,0x88,0x8b,0xce,0x15,0x13,0xa9,0x90,0x32,0x33,0x57,0x56,0x18,0xc3,0x1d,0x29,0x5b,0xb2,0x62,0xa1,0x61,0x9b,0xd1,0x9f,0x93,0x39,0xa9,0xcb
};

info.pbNonce = enc + 16;
info.cbNonce = 16;

info.pbTag = enc + sizeof(enc) - 16;
info.cbTag = 16;

info.pbAuthData = enc;
info.cbAuthData = 16;

byte nonce[16];
memcpy(nonce, enc + 16, 16);
DWORD u;
PBYTE output;
if (aes_gcm(nonce, 16, key, 32, enc + 32, sizeof(enc) - 32 - 16, 0, &info, &output, &u)) {
    printf("password: %s\n", (char*)output);
}

BCryptDecrypt keeps returning error 0xc000000d (STATUS_INVALID_PARAMETER).

Help will be greatly appreciated. This is my first post on stackoverflow. I don't mind giving it out as a job to be paid for.

Thank you

273K
  • 29,503
  • 10
  • 41
  • 64
osand
  • 1
  • 2
  • 1
    I haven't looked at your implementation in detail but `BCryptEncrypt` only supports a 12 bytes nonce for GCM as far as I know. GCM itself supports other nonce sizes, but the recommended (and commonly used) length is 12 bytes. You however use a 16 bytes nonce. I don't know if a configuration for 16 bytes is possible. – Topaco Mar 30 '22 at 10:08
  • the python script is using 16byte nonce. besides, if I limit the nonce to 12 decryption fails with error STATUS_AUTH_TAG_MISMATCH – osand Mar 30 '22 at 10:16
  • The Python implementation supports a 16 bytes nonce, `BCryptEncrypt` does not. Therefore, both implementations are incompatible. Of course you can't just shorten the nonce for the posted data, because for a successful decryption the nonce of the encryption must be used. – Topaco Mar 30 '22 at 10:34
  • after checking wine source, it appears the 16byte limit is on only tag. which means its supported. https://github.com/wine-mirror/wine/blob/1d178982ae5a73b18f367026c8689b56789c39fd/dlls/bcrypt/bcrypt_main.c if (auth_info->cbTag < 12 || auth_info->cbTag > 16) return STATUS_INVALID_PARAMETER; – osand Mar 30 '22 at 11:02
  • On my machine, a `BCryptEncrypt`/`BCryptDecrypt` for a 16 bytes nonce fails with a *0xc000000d* error, while it works with a 12 bytes nonce. Yes, there is also a length constraint for the tag, which however is not violated, so that should not be the reason. – Topaco Mar 30 '22 at 11:30
  • do you ave reference to gcm using wincrypt CALG_AES_256 – osand Mar 30 '22 at 12:17
  • No, I haven't. Sorry. – Topaco Mar 30 '22 at 12:30

0 Answers0