Cipher text generated by OpenSSL and Windows CNG is different for AES-128-CFB

Viewed 291

I am encrypting the same plain text with AES-128-CFB but ciphertext generated by "Windows Cryptography API: Next Generation" and OpenSSL are different for the same IV, and key.

Plain Text: The quick brown fox jumps over the lazy dog

IV: 1234567887654321

Key: 1234567887654321

Cipher Text generated by Windows CNG in Hex: 279CB0C2FD67B37F33A861CDDAFBEDCEEAEFC68FD5B3478E67E4A936BA7CFE75DDBAD370A1E4D6CDC3455E2F4E188A9C

Cipher Text length generated by Windows CNG: 48 Bytes

Cipher Text generated by OpenSSL in Hex: 279CB0C2FD67B37F33A861CDDAFBEDCEEAEFC68FD5B3478E67E4A936BA7CFE75DDBAD370A1E4D6CDC3455E

Cipher Text length generated by Windows CNG: 43 Bytes

Windows CNG adding extra 5 bytes(2F4E188A9C) at the end, I thought it is due to padding and sent dwFlags value as 0 instead of BCRYPT_BLOCK_PADDING then BCryptEncrypt API call failing with error code 0xc0000206/STATUS_INVALID_BUFFER_SIZE.

Windows CNG code:

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

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

#define STATUS_UNSUCCESSFUL         ((NTSTATUS)0xC0000001L)
void
hexdump(const char *msg, const unsigned char *in, unsigned int len)
{
    printf("%s [%d][", msg, len);
    for (; len > 0; len--, in++) {
        printf("%02X", *in);
    }
    printf("]\n");
}
const BYTE rgbPlaintext[] =  "The quick brown fox jumps over the lazy dog";

static const BYTE rgbIV[] = "1234567887654321";

static const BYTE rgbAES128Key[] = "0123456789abcdefghijklmnopqrstuv";

const int ival_len = 16;
const int key_len = 16;
const DWORD block_len = 16;

void __cdecl wmain(
                   int                      argc, 
                   __in_ecount(argc) LPWSTR *wargv)
{

    BCRYPT_ALG_HANDLE       hAesAlg                     = NULL;
    BCRYPT_KEY_HANDLE       hKey                        = NULL;
    NTSTATUS                status                      = STATUS_UNSUCCESSFUL;
    DWORD                   cbCipherText                = 0, 
                            cbData                      = 0, 
                            cbKeyObject                 = 0,
                            cbBlockLen                  = 0,
                            cbBlob                      = 0;
    PBYTE                   pbCipherText                = NULL,
                            pbKeyObject                 = NULL,
                            pbIV                        = NULL,
                            pbBlob                      = NULL;

    UNREFERENCED_PARAMETER(argc);
    UNREFERENCED_PARAMETER(wargv);

    if(!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(
                                                &hAesAlg,
                                                BCRYPT_AES_ALGORITHM,
                                                NULL,
                                                0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
        goto Cleanup;
    }

    if(!NT_SUCCESS(status = BCryptGetProperty(
                                        hAesAlg, 
                                        BCRYPT_OBJECT_LENGTH, 
                                        (PBYTE)&cbKeyObject, 
                                        sizeof(DWORD), 
                                        &cbData, 
                                        0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptGetProperty\n", status);
        goto Cleanup;
    }

    pbKeyObject = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbKeyObject);
    if(NULL == pbKeyObject)
    {
        wprintf(L"**** memory allocation failed\n");
        goto Cleanup;
    }

    if (ival_len > sizeof (rgbIV))
    {
        wprintf (L"**** block length is longer than the provided IV length\n");
        goto Cleanup;
    }

   if(ival_len > 0)
   {       
        pbIV= (PBYTE) HeapAlloc (GetProcessHeap (), 0, ival_len + 1);
        if(NULL == pbIV)
        {
            wprintf(L"**** memory allocation failed\n");
            goto Cleanup;
        }
        strncpy(pbIV,rgbIV,ival_len);
        pbIV[ival_len]='\0';
   }    

    if(!NT_SUCCESS(status = BCryptSetProperty(
                                hAesAlg, 
                                BCRYPT_CHAINING_MODE, 
                                (PBYTE)BCRYPT_CHAIN_MODE_CFB, 
                                sizeof(BCRYPT_CHAIN_MODE_CFB), 
                                0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptSetProperty\n", status);
        goto Cleanup;
    }

    if(!NT_SUCCESS(status = BCryptGetProperty(
                                        hAesAlg, 
                                        BCRYPT_BLOCK_LENGTH, 
                                        (PBYTE)&cbBlockLen, 
                                        sizeof(DWORD), 
                                        &cbData, 
                                        0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptGetProperty\n", status);
        goto Cleanup;
    }

    if(!NT_SUCCESS(status = BCryptGenerateSymmetricKey(
                                        hAesAlg, 
                                        &hKey, 
                                        pbKeyObject, 
                                        cbKeyObject, 
                                        (PBYTE)rgbAES128Key, 
                                        key_len, 
                                        0)))
    {
        wprintf(L"**** Error 0x%x returned by BCryptGenerateSymmetricKey\n ", status);
        fprintf(stderr, "\nError number <%x>", GetLastError());
        goto Cleanup;
    }
    if (!NT_SUCCESS(status = BCryptSetProperty(hKey,
                                            BCRYPT_MESSAGE_BLOCK_LENGTH,
                                            (PBYTE)&block_len,
                                            sizeof(DWORD),
                                            0))) {
        wprintf(L"**** Error 0x%x returned by BCryptSetProperty\n ", status);
        fprintf(stderr, "\nError number <%x>", GetLastError());
        goto Cleanup;
    }

    printf("\nplan text is [%d][%s]\n", sizeof(rgbPlaintext) - 1, rgbPlaintext);
    if(!NT_SUCCESS(status = BCryptEncrypt(
                                        hKey, 
                                        rgbPlaintext, 
                                        sizeof(rgbPlaintext) - 1,
                                        NULL,
                                        pbIV,
                                        ival_len,
                                        NULL, 
                                        0, 
                                        &cbCipherText, 
                                        BCRYPT_BLOCK_PADDING)))
    {
        wprintf(L"\n**** Error 1 0x%x returned by BCryptEncrypt\n", status);
        goto Cleanup;
    }

    pbCipherText = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbCipherText);
    if(NULL == pbCipherText)
    {
        wprintf(L"**** memory allocation failed\n");
        goto Cleanup;
    }

    // Use the key to encrypt the plaintext buffer.
    // For block sized messages, block padding will add an extra block.
    if(!NT_SUCCESS(status = BCryptEncrypt(
                                        hKey, 
                                        rgbPlaintext, 
                                        sizeof(rgbPlaintext) - 1,
                                        NULL,
                                        pbIV,
                                        ival_len, 
                                        pbCipherText, 
                                        cbCipherText, 
                                        &cbData, 
                                        BCRYPT_BLOCK_PADDING)))
    {
        wprintf(L"**** Error 2 0x%x returned by BCryptEncrypt\n", status);
        goto Cleanup;
    }

    hexdump("cipher is", pbCipherText, cbCipherText);

Cleanup:

    if(hAesAlg)
    {
        BCryptCloseAlgorithmProvider(hAesAlg,0);
    }

    if (hKey)    
    {
        BCryptDestroyKey(hKey);
    }

    if(pbCipherText)
    {
        HeapFree(GetProcessHeap(), 0, pbCipherText);
    }

    if(pbKeyObject)
    {
        HeapFree(GetProcessHeap(), 0, pbKeyObject);
    }

    if(pbIV)
    {
        HeapFree(GetProcessHeap(), 0, pbIV);
    }
}

OpenSSL Code:

#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>
void
hexdump(const char *msg, const unsigned char *in, unsigned int len)
{
    printf("%s [%d][", msg, len);
    for (; len > 0; len--, in++) {
        printf("%02X", *in);
    }
    printf("]\n");
}
int main(void)
{
    /* A 256 bit key */
    unsigned char *key = (unsigned char *)"0123456789abcdefghijklmnopqrstuv";
    /* A 128 bit IV */
    unsigned char *iv = (unsigned char *)"1234567887654321";
    /* Message to be encrypted */
    unsigned char *plaintext =
    (unsigned char *)"The quick brown fox jumps over the lazy dog12312";
    unsigned char ciphertext[128];
    int ciphertextLen = encrypt(plaintext, strlen ((char *)plaintext), key, iv, ciphertext);
    hexdump("cipher value is:", ciphertext, ciphertextLen);
    return 0;
}
void handleErrors(void)
{
    ERR_print_errors_fp(stderr);
    abort();
}
int encrypt(unsigned char *plaintext,
int plaintext_len,
unsigned char *key,
unsigned char *iv,
unsigned char *ciphertext)
{
    EVP_CIPHER_CTX *ctx;
    int len;
    int ciphertextLen;
    /* Create and initialise the context */
    if(!(ctx = EVP_CIPHER_CTX_new()))
    handleErrors();
    
    if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_cfb(), NULL, key, iv))
    handleErrors();
    if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
    handleErrors();
    ciphertextLen = len;
    if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
    handleErrors();
    ciphertextLen += len;
    EVP_CIPHER_CTX_free(ctx);
    return ciphertextLen;
}
0 Answers
Related