Is there a simple way to AES-256 GCM decrypt in C, without any external libraries outside of Windows?

128 Views Asked by At

Is it possible to AES-256 GCM decrypt in C, without any external libraries outside of Windows?

I was trying to look for such POC function that would use for example crypt32.dll, but without success.

It doesn't have to be the Windows encryption API, but something else, as long as it's pre-installed.

Also a example function and links, would be much appreciated.

Edit: I've tried to craft a working decrypt function using bcrypt.h as suggested below, but without success:

#include <stdio.h>
#include <Windows.h>
#include <bcrypt.h>

NTSTATUS decrypt_AES_GCM(const BYTE *encryptedData, ULONG encryptedDataLength,
                         const BYTE *aad, ULONG aadLength,
                         const BYTE *iv, ULONG ivLength,
                         const BYTE *authTag, ULONG authTagLength,
                         const BYTE *key, ULONG keyLength,
                         BYTE *decryptedData, ULONG decryptedDataLength);

int main() {
    // Hardcoded data
    BYTE iv[] = {0x10, 0x8d, 0x92, 0x57, 0x99, 0x1d, 0x95, 0x2d, 0xa1, 0xa3, 0xed, 0xc6};
    BYTE ciphertext[] = {0x7e, 0xea, 0xfe, 0x7d, 0xd6, 0xb7, 0xa7, 0x4d, 0xb2, 0x18, 0x73, 0x67, 0x96, 0x93, ..., 0x80, 0x96};
    BYTE secret_key[] = {0x52, 0x99, 0x17, 0xbd, 0xd5, 0xa1, 0xb9, 0x1f, ..., 0x74, 0x74, 0x1a, 0xe1, 0x87, 0x1b, 0x60, 0x07, 0x02, 0xc6, 0x45, 0xea, 0x17, 0x14};
    BYTE aad[] = {};
    BYTE authTag[] = {};
    BYTE decryptedData[100];
    ULONG decryptedDataLength = sizeof(decryptedData);
    NTSTATUS status = decrypt_AES_GCM(ciphertext, 12,
                                      aad, 0,
                                      iv, 12,
                                      authTag, 0,
                                      secret_key, 32,
                                      decryptedData, decryptedDataLength);

    if (BCRYPT_SUCCESS(status)) {
        printf("Decryption successful.\n");
    } else {
        printf("Decryption failed with status: %08x\n", status);
    }

    return 0;
}


NTSTATUS decrypt_AES_GCM(const BYTE *encryptedData, ULONG encryptedDataLength,
                         const BYTE *aad, ULONG aadLength,
                         const BYTE *iv, ULONG ivLength,
                         const BYTE *authTag, ULONG authTagLength,
                         const BYTE *key, ULONG keyLength,
                         BYTE *decryptedData, ULONG decryptedDataLength) {
    NTSTATUS status = 0;
    DWORD bytesDone = 0;

    BCRYPT_ALG_HANDLE algHandle = 0;
    status = BCryptOpenAlgorithmProvider(&algHandle, BCRYPT_AES_ALGORITHM, NULL, 0);
    if (!BCRYPT_SUCCESS(status)) {
        return status;
    }

    status = BCryptSetProperty(algHandle, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_GCM, sizeof(BCRYPT_CHAIN_MODE_GCM), 0);
    if (!BCRYPT_SUCCESS(status)) {
        BCryptCloseAlgorithmProvider(algHandle, 0);
        return status;
    }

    BCRYPT_KEY_HANDLE keyHandle = 0;
    status = BCryptGenerateSymmetricKey(algHandle, &keyHandle, NULL, 0, (PUCHAR)key, keyLength, 0);
    if (!BCRYPT_SUCCESS(status)) {
        BCryptCloseAlgorithmProvider(algHandle, 0);
        return status;
    }

    BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo;
    memset(&authInfo, 0, sizeof(authInfo));
    authInfo.pbNonce = (PUCHAR)iv;
    authInfo.cbNonce = ivLength;
    authInfo.pbTag = (PUCHAR)authTag;
    authInfo.cbTag = authTagLength;
    authInfo.pbAuthData = (PUCHAR)aad;
    authInfo.cbAuthData = aadLength;

    status = BCryptDecrypt(keyHandle, (PUCHAR)encryptedData, encryptedDataLength, &authInfo, NULL, 0, decryptedData, decryptedDataLength, &bytesDone, 0);
    
    BCryptDestroyKey(keyHandle);
    BCryptCloseAlgorithmProvider(algHandle, 0);

    return status;
}

I keep getting error code c000000d:

0xC000000D

STATUS_INVALID_PARAMETER

An invalid parameter was passed to a service or function.

The hard-coded values are straight from a Python code that uses AES-256 GCM, printed like as hex, then converted to byte arrays.

Reference: How to chain BCryptEncrypt and BCryptDecrypt calls using AES in GCM mode?

Edit 2: I've got the code working, thanks to the notices from @Topaco in the comments. The authentication tag, IV and the Encrypted Data, had all been added to the same ciphertext, so took tag from last 16 bytes (auth tag), which had not been done in the Python version of the script. Also replaced memset(&authInfo, 0, sizeof(authInfo)); with BCRYPT_INIT_AUTH_MODE_INFO(authInfo);.

There is only a little issue left. The output length is over the actual length, meaning when I print the output, it has a few extra bytes.

#include <stdio.h>
#include <Windows.h>
#include <bcrypt.h>

#define NT_SUCCESS(Status)          (((NTSTATUS)(Status)) >= 0)

NTSTATUS decrypt_AES_GCM(const BYTE *encryptedData, ULONG encryptedDataLength,
                         const BYTE *aad, ULONG aadLength,
                         const BYTE *iv, ULONG ivLength,
                         const BYTE *authTag, ULONG authTagLength,
                         const BYTE *key, ULONG keyLength,
                         BYTE *decryptedData, ULONG decryptedDataLength);

int main() {
    // Hardcoded data
    BYTE iv[] = { 0x10, 0x8d, 0x92, 0x57, 0x99, 0x1d, 0x95, 0x2d, 0xa1, 0xa3, 0xed, 0xc6 };
    BYTE ciphertext[] = { 0x7e, 0xea, ..., 0xb7, 0xa7, 0x4d, 0xb2, 0x18, 0x73, 0x67 };
    BYTE secret_key[] = {0x52, 0x99, 0x17, 0xbd, 0xd5, 0xa1, 0xb9, 0x1f, 0xa0, ..., 0x7b, 0x74, 0x74, 0x1a, 0xe1, 0x87, 0x1b, 0x60, 0x07, 0x02, 0xc6, 0x45, 0xea, 0x17, 0x14};
    BYTE aad[] = {  };
    BYTE authTag[16] = { 0x96, 0x93, 0x87, 0x96, 0x7f, 0x14, 0x49, 0x95, 0xaf, 0x3b, 0x9c, 0xb8, 0x80, 0x29, 0x80, 0x96 };
    BYTE decryptedData[100];
    ULONG decryptedDataLength = sizeof(decryptedData);
    NTSTATUS status = decrypt_AES_GCM(ciphertext, sizeof(ciphertext),
                                      aad, 0,
                                      iv, sizeof(iv),
                                      authTag, sizeof(authTag),
                                      secret_key, sizeof(secret_key),
                                      decryptedData, decryptedDataLength);

    if (NT_SUCCESS(status)) {
        printf("Decryption successful.\n");
        printf("Decrypted Data (length = %i): %s", decryptedDataLength, decryptedData);
    } else {
        printf("Decryption failed with status: %08x\n", status);
    }

    return 0;
}

NTSTATUS decrypt_AES_GCM(const BYTE *encryptedData, ULONG encryptedDataLength,
                         const BYTE *aad, ULONG aadLength,
                         const BYTE *iv, ULONG ivLength,
                         const BYTE *authTag, ULONG authTagLength,
                         const BYTE *key, ULONG keyLength,
                         BYTE *decryptedData, ULONG decryptedDataLength) {
    NTSTATUS status = 0;
    DWORD bytesDone = 0;

    BCRYPT_ALG_HANDLE algHandle = 0;
    status = BCryptOpenAlgorithmProvider(&algHandle, BCRYPT_AES_ALGORITHM, NULL, 0);
    if (!NT_SUCCESS(status)) {
        return status;
    }

    status = BCryptSetProperty(algHandle, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_GCM, sizeof(BCRYPT_CHAIN_MODE_GCM), 0);
    if (!NT_SUCCESS(status)) {
        BCryptCloseAlgorithmProvider(algHandle, 0);
        return status;
    }

    BCRYPT_KEY_HANDLE keyHandle = 0;
    status = BCryptGenerateSymmetricKey(algHandle, &keyHandle, NULL, 0, (PUCHAR)key, keyLength, 0);
    if (!NT_SUCCESS(status)) {
        BCryptCloseAlgorithmProvider(algHandle, 0);
        return status;
    }

    BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo;
    BCRYPT_INIT_AUTH_MODE_INFO(authInfo);
    authInfo.pbNonce = (PUCHAR)iv;
    authInfo.cbNonce = ivLength;
    authInfo.pbTag = (PUCHAR)authTag;
    authInfo.cbTag = authTagLength;
    authInfo.pbAuthData = (PUCHAR)aad;
    authInfo.cbAuthData = aadLength;

    status = BCryptDecrypt(keyHandle, (PUCHAR)encryptedData, encryptedDataLength, &authInfo, NULL, 0, decryptedData, decryptedDataLength, &bytesDone, 0);
    
    BCryptDestroyKey(keyHandle);
    BCryptCloseAlgorithmProvider(algHandle, 0);

    return status;
}

0

There are 0 best solutions below