0

I want to encrypt a text string in C using the WinAPI implementation of AES-256-CBC, and then manually (using terminal) decrypt it in a linux machine using OpenSSL. I use this code: WinAPI - CryptDecrypt() not working properly in AES 256

    // handles for csp and key
    HCRYPTPROV hProv = NULL;
    HCRYPTKEY hKey = NULL;
    BYTE szKey[DEFAULT_AES_KEY_SIZE + 1] = { 0 };
    BYTE szIV[DEFAULT_IV_SIZE + 1] = { 0 };
    // plain bytes
    BYTE szPlainText[BUFFER_FOR_PLAINTEXT + 1] = { 0 }, * pBuf = NULL;
    AES256KEYBLOB AESBlob;
    memset(&AESBlob, 0, sizeof(AESBlob));

    // initalize key and plaintext
    StrCpyA((LPSTR)szKey, "00112233445566778899001122334455");
    StrCpyA((LPSTR)szIV, "4455667788990011");
    StrCpyA((LPSTR)szPlainText, "abcdefghijklmnopqrstuvwxyzabcdef");
    DWORD dwPlainSize = lstrlenA((LPCSTR)szPlainText), dwBufSize = dwPlainSize, dwBufSize2 = dwPlainSize;

    // blob data for CryptImportKey() function (include key and version and so on...)
    AESBlob.bhHdr.bType = PLAINTEXTKEYBLOB;
    AESBlob.bhHdr.bVersion = CUR_BLOB_VERSION;
    AESBlob.bhHdr.reserved = 0;
    AESBlob.bhHdr.aiKeyAlg = CALG_AES_256;
    AESBlob.dwKeySize = DEFAULT_AES_KEY_SIZE;
    StrCpyA((LPSTR)AESBlob.szBytes, (LPCSTR)szKey);

    // create a cryptographic service provider (CSP)
    if (!CryptAcquireContextA(&hProv, NULL, MS_ENH_RSA_AES_PROV_A, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {goto error;}

    if (!CryptImportKey(hProv, (BYTE*)&AESBlob, sizeof(AES256KEYBLOB), NULL, CRYPT_EXPORTABLE, &hKey)) { goto error; }

    if (!CryptSetKeyParam(hKey, KP_IV, szIV, 0)) { goto error; }

    if (CryptEncrypt(hKey, NULL, TRUE, 0, NULL, &dwBufSize, 0)) {
        if ((pBuf = (BYTE*)calloc(dwBufSize, sizeof(BYTE))) == NULL) { goto error; }

        StrCpyA((LPSTR)pBuf, (LPCSTR)szPlainText);
    }
    else { goto error; }

    if (CryptEncrypt(hKey, NULL, TRUE, 0, pBuf, &dwBufSize2, dwBufSize)) {
        BYTE* reversed = (BYTE*)calloc(dwBufSize, sizeof(BYTE));
        ReverseStream(pBuf, reversed, dwBufSize);// reverse ciphertext

        DWORD bytesWritten = 0;
        if (ResList != INVALID_HANDLE_VALUE)
        {
            WriteFile(
                res,
                (char*)reversed,
                dwBufSize,
                &bytesWritten,
                NULL);
        }
        //if (CryptDecrypt(hKey, NULL, TRUE, 0, pBuf, &dwBufSize)) {
        //  printf("\nDecrypted data: [%s]\nSize: %d\n", (LPCSTR)pBuf, dwBufSize);
        //}else { goto error; }
    } else { goto error; }

    // return encrypted string

    if (pBuf) free(pBuf);
    if (hKey) CryptDestroyKey(hKey);
    if (hProv) CryptReleaseContext(hProv, 0);
    return NULL;
error:
    if (pBuf) free(pBuf);
    if (hKey) CryptDestroyKey(hKey);
    if (hProv) CryptReleaseContext(hProv, 0);
    return NULL;

}

This is the ReverseStream function. It's needed to convert ciphertext from Little Endian to Big Endian, for Openssl compatibility.

void ReverseStream(LPBYTE Source, LPBYTE Destination, DWORD Size)
{
    int SourceCnt = Size;
    int DestCnt = 0;

    for (SourceCnt = Size - 1, DestCnt = 0; SourceCnt >= 0; SourceCnt--, DestCnt++)
        Destination[DestCnt] = Source[SourceCnt];
}

Using WriteFile I create a file encrypted.txt to be decrypted in linux.

The command I use is: openssl aes-256-cbc -d -a -nosalt -k "00112233445566778899001122334455" -in encrypted.txt -out secrets.txt

EDIT: a better command is the following (using hex values of the same key/value below), but it returns the same error

openssl aes-256-cbc -d -nosalt -K "3030313132323333343435353636373738383939303031313232333334343535" -iv "34343535363637373838393930303131" -in encrypted.txt -out secrets.txt

the error:

*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
bad decrypt
140584380352320:error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length:crypto/evp/evp_enc.c:601:

It seems the last block is not correctly written, anyway the decryption in C (commented in the code) works. Where is the problem?

Topaco
  • 40,594
  • 4
  • 35
  • 62
rmroot
  • 9
  • 3
  • 1
    You have to use `-K` and `-iv`. Beware that it does expect both the key and IV in hexadecimals, not ASCII as you are using in your C code. – Maarten Bodewes Jun 09 '22 at 22:23
  • Why should I use -iv in decryption command? Initialization vector is embedded in cyphertext and it shouldn't be added in the decryption command (only in encryption). – rmroot Jun 10 '22 at 06:34
  • While decyption works in code it would be reasonable to assume that the issue is elsewhere, such as in the code that writes the encrypted message to a file, or possibly even in transferring the file between systems. Did you verify that the in-memory contents exactly match the on-disk contents? Can you show the code that's writing the encrypted message to disk? – IInspectable Jun 10 '22 at 07:05
  • Even using HEX values `openssl aes-256-cbc -d -nosalt -K "3030313132323333343435353636373738383939303031313232333334343535" -iv "34343535363637373838393930303131" -in encrypted.txt -out secrets.txt` returns the same error. – rmroot Jun 10 '22 at 16:41
  • The ciphertext must not be reversed. Then decryption works with the last OpenSSL statement (`-nosalt` isn't necessary). – Topaco Jun 13 '22 at 18:19

0 Answers0