3

I have this program working that encrypts a string of 9 bytes using AES128 from wincrypt.h but something strange happens when I change last character of the key:

from L"3igcZhRdWq96m3GUmTAiv2" to for example L"3igcZhRdWq96m3GUmTAiv1" or L"3igcZhRdWq96m3GUmTAiv9" the encrypted texts are still the same as each other.

#include <Windows.h>
#include <wincrypt.h>
#include <stdio.h>
#pragma comment(lib, "crypt32.lib")

#define BUFFER_SIZE 16

//params: <input file> <output file> <is decrypt mode> <key>
int wmain()
{

    wchar_t key[] = L"3igcZhRdWq96m3GUmTAiv2";
    wchar_t *key_str = key;


    size_t len = lstrlenW(key_str);


    DWORD dwStatus = 0;
    BOOL bResult = FALSE;
    wchar_t info[] = L"Microsoft Enhanced RSA and AES Cryptographic Provider";
    HCRYPTPROV hProv;

    if (!CryptAcquireContextW(&hProv, NULL, info, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
        dwStatus = GetLastError();
        printf("CryptAcquireContext failed: %x\n", dwStatus);
        CryptReleaseContext(hProv, 0);
        system("pause");
        return dwStatus;
    }
    HCRYPTHASH hHash;
    if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)) {
        dwStatus = GetLastError();
        printf("CryptCreateHash failed: %x\n", dwStatus);
        CryptReleaseContext(hProv, 0);
        system("pause");
        return dwStatus;
    }

    if (!CryptHashData(hHash, (BYTE*)key_str, len, 0)) {
        DWORD err = GetLastError();
        printf("CryptHashData Failed : %#x\n", err);
        system("pause");
        return (-1);
    }
    printf("[+] CryptHashData Success\n");

    HCRYPTKEY hKey;
    if (!CryptDeriveKey(hProv, CALG_AES_128, hHash, 0, &hKey)) {
        dwStatus = GetLastError();
        printf("CryptDeriveKey failed: %x\n", dwStatus);
        CryptReleaseContext(hProv, 0);
        system("pause");
        return dwStatus;
    }
    printf("[+] CryptDeriveKey Success\n");

    const size_t string_size = BUFFER_SIZE;
    BYTE string[string_size] = { "Fooooooo" };
    DWORD out_len = 9;



    if (!CryptEncrypt(hKey, NULL, TRUE, 0, string, &out_len, string_size)) {
            printf("[-] CryptEncrypt failed\n");
    }


    for (DWORD i = 0; i < out_len; i++)
        printf("%02x ", string[i]);
    printf("\n"); 

    printf("%lu\n", out_len);
    //printf("%s", string);
    //printf("\n");

    if (!CryptDecrypt(hKey, NULL, TRUE, 0, string, &out_len)) {
        printf("[-] CryptDecrypt failed\n");
    }

    printf("%lu\n", out_len);
    printf("%s", string);
    printf("\n");

    memset(string, 0, string_size);

    CryptReleaseContext(hProv, 0);
    CryptDestroyKey(hKey);
    CryptDestroyHash(hHash);

    printf("Finished\n");
    system("pause");
    return 0;

}

Note also that the SHA256 hashes of the keys that I exposed before are diferent each other:

3igcZhRdWq96m3GUmTAiv2 -> F5584805AA52AC68062331F3B852001F2585D23105C22D61CF25C3C71D998F9B
3igcZhRdWq96m3GUmTAiv1 -> 25DF6A58974E67ABD2DE6EE29F1A045F87ADCDC05C879235C450D12ABAA549C1
3igcZhRdWq96m3GUmTAiv9 -> AE6FFA99AFF1A72ED31B4A16CE86CE060B1DB3C0ECA3769F27D8891155B1E16D

Source: https://passwordsgenerator.net/sha256-hash-generator/

If I change a middle or first character of the key (for example the first 3) or add more characters, the encrypted text will change this time as expected behaviour.

Do you know why happens that? The encrypted text should change if I change any character of the key, but this don't happens when I change only the last character.

IInspectable
  • 35,521
  • 8
  • 69
  • 148
  • 1
    Presumably, the encryption service doesn't use all 22 wide characters of the key you provide. You could work out how many it does use by changing the next to last wide character and seeing whether that causes a change to the encrypted data, repeating until you hit the point in the middle where a change in the key does trigger a change in the encrypted data. Or you could find out where in the documentation the limit is specified. – Jonathan Leffler Aug 18 '18 at 19:50

1 Answers1

6
if (!CryptHashData(hHash, (BYTE*)key_str, len, 0)) {

You are passing len, the length of key_str in characters (wchar_t), while CryptHashData expects the number of bytes. This means that it is effectively using only the first half of key_str (as wchar_t is 2 bytes on Win32).

You can fix this easily:

if (!CryptHashData(hHash, (BYTE*)key_str, len*sizeof(*key_str), 0)) {
Matteo Italia
  • 115,256
  • 16
  • 181
  • 279
  • yes that's the fix I sometimes forget wchar is 2 bytes. –  Aug 18 '18 at 20:08
  • One more question, why my AES encryption accepts a 256 bit key ( hashed with SHA256 )? if its set to AES128 which its fixed keysize is 128 bits. –  Aug 18 '18 at 20:09
  • 1
    https://docs.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-cryptderivekey "Let n be the required derived key length, in bytes. The derived key is the first n bytes of the hash value after the hash computation has been completed by CryptDeriveKey." the extra bytes of the hash are simply discarded. This is not a problem, as cryptographic hashes are such that any byte of the input influence all the bytes of the hash, so truncating a hash to the desired length doesn't affect its dependence from the input data. – Matteo Italia Aug 18 '18 at 20:15
  • Ok thank you very much I'm new to cryptography, thanks for your answers –  Aug 18 '18 at 20:25