Possible to encrypt non-multiple of 16 bytes when chaining BCryptEncrypt calls using AES in GCM mode?

  aes-gcm, c++, cng, encryption, windows

Is it possible, using Windows CNG API and AES in GCM mode, to encrypt a buffer of data with a size that is not a multiple of 16 bytes (128 bits) when chaining is enabled?

When I try to pass a buffer of 60 bytes to the BCryptEncrypt function with chaining enabled, I get the error: 0xc0000206, which translates to the error string: The size of the buffer is invalid for the specified operation.

Here is a code snippet I made to demonstrate my problem:

#include <windows.h>
#include <stdio.h>
#include <bcrypt.h>
#pragma comment(lib, "bcrypt.lib")

int main() {
    unsigned char key[16] = { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 };
    unsigned char iv[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 };
    unsigned char pt[60] = { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
                         0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
                         0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
                         0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39 };
    unsigned char ct[60];
    unsigned char tag[16];

    NTSTATUS bcryptResult = 0;
    DWORD bytesDone = 0;
    BCRYPT_ALG_HANDLE algHandle = 0;
    DWORD blockLength = 16;

    bcryptResult = BCryptOpenAlgorithmProvider(&algHandle, BCRYPT_AES_ALGORITHM, 0, 0);
    bcryptResult = BCryptSetProperty(algHandle, BCRYPT_CHAINING_MODE,(BYTE*)BCRYPT_CHAIN_MODE_GCM, sizeof(BCRYPT_CHAIN_MODE_GCM), 0);
    BCRYPT_KEY_HANDLE keyHandle = 0;
    bcryptResult = BCryptGenerateSymmetricKey(algHandle, &keyHandle, 0, 0, (PUCHAR)&key[0], sizeof(key), 0);

    /* ---Encrypt data--- */
    {
        unsigned char macContext[16];
        unsigned char contextIV[16];

        BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo;
        BCRYPT_INIT_AUTH_MODE_INFO(authInfo);
        authInfo.pbNonce = iv;
        authInfo.cbNonce = sizeof(iv);
        authInfo.pbTag = tag;
        authInfo.cbTag = sizeof(tag);

        // Enable chaining of BCryptEncrypt calls
        authInfo.pbMacContext = &macContext[0];
        authInfo.cbMacContext = sizeof(macContext);
        authInfo.dwFlags = BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG;

        bcryptResult = BCryptEncrypt(keyHandle, pt, sizeof(pt), &authInfo, contextIV, sizeof(0), ct, sizeof(ct), &bytesDone, 0);
        if (!BCRYPT_SUCCESS(bcryptResult)) {
            printf("Error: 0x%x n", bcryptResult);
        }
    
        // Disable chaining and call BCryptEncrypt again to get tag
        authInfo.dwFlags &= ~BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG;
        bcryptResult = BCryptEncrypt(keyHandle, NULL, 0, &authInfo, contextIV, sizeof(contextIV), NULL, 0, &bytesDone, 0);
        if (!BCRYPT_SUCCESS(bcryptResult)) {
            printf("Error: 0x%x", bcryptResult);
        }
    }
    return 0;
}

I have noticed two things.

  1. Encrypting a buffer with a size that is a multiple of 16 bytes works perfectly with the code I have supplied. For example, if changing the buffers pt and ct:s size to 64, everything works fine.
  2. If I do not enable chaining and simply call BCryptEncrypt once with a buffer of size 60 everything works fine as well, and I get the correct tag.

I have not been able to find any information about this in Microsofts CNG documentation. Is this a limitation when using chaining with AES/GCM?

Source: Windows Questions

LEAVE A COMMENT