pythonccorruptionaes-gcm

Could bcrypts AES-256 GCM encryption corrupt ZIP files?


I'm trying to encrypt a ZIP file using AES-256 GCM in C and decrypting it in Python. Here is the C code I'm using:

NTSTATUS generateRandomBytes(BYTE *buffer, ULONG length)
{
    BCRYPT_ALG_HANDLE hProvider;
    NTSTATUS status = BCryptOpenAlgorithmProvider(&hProvider, BCRYPT_RNG_ALGORITHM, NULL, 0);
    if (!NT_SUCCESS(status))
    {
        return status;
    }

    status = BCryptGenRandom(hProvider, buffer, length, 0);
    BCryptCloseAlgorithmProvider(hProvider, 0);
    return status;
}

NTSTATUS encrypt_AES_GCM(const BYTE *plainData, ULONG plainDataLength,
                         const BYTE *iv, ULONG ivLength,
                         const BYTE *key, ULONG keyLength,
                         BYTE *encryptedData, ULONG encryptedDataLength,
                         BYTE *authTag, ULONG authTagLength)
{
    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 = authTag;
    authInfo.cbTag = authTagLength;

    status = BCryptEncrypt(keyHandle, (PUCHAR)plainData, plainDataLength, &authInfo, NULL, 0, encryptedData, encryptedDataLength, &bytesDone, 0);
    if (!NT_SUCCESS(status))
    {
        BCryptDestroyKey(keyHandle);
        BCryptCloseAlgorithmProvider(algHandle, 0);
        return status;
    }

    BCryptDestroyKey(keyHandle);
    BCryptCloseAlgorithmProvider(algHandle, 0);

    return status;
}

int GCM_Encrypt_File(char *FileToEncrypt, char *keys, char *OutputFile)
{
    int fd;
    long file_size;
    char *input;
    _sopen_s(&fd, FileToEncrypt, _O_RDONLY, _SH_DENYRW, _S_IREAD);
    file_size = _filelength(fd);
    input = (char *)malloc(file_size);
    size_t bytes_read = fread(input, 1, file_size, _fdopen(fd, "rb"));
    BYTE key[32];
    BYTE iv[12];
    BYTE KeyTagIV[60];
    BYTE *encrypted;
    ULONG encryptedSize = file_size;
    ULONG authTagLength = 16;
    BYTE authTag[16];

    // Generate key and iv
    generateRandomBytes(key, sizeof(key));
    generateRandomBytes(iv, sizeof(iv));
    // Concatenate key and IV
    memcpy(KeyTagIV, key, sizeof(key));
    memcpy(KeyTagIV + sizeof(key), iv, sizeof(iv));
    // Print the info

    encrypted = (BYTE *)malloc(encryptedSize);

    // Encrypt
    encrypt_AES_GCM((BYTE *)input, file_size, iv, 12, key, 32, encrypted, encryptedSize, authTag, authTagLength);
    
    // Print data
    printf("KEY:\n");
    for (ULONG i = 0; i < sizeof(key); i++)
    {
        printf("%02X", key[i]);
    }
    printf("\n");
    printf("IV:\n");
    for (ULONG i = 0; i < sizeof(iv); i++)
    {
        printf("%02X", iv[i]);
    }
    printf("\n");
    printf("Authentication tag:\n");
    for (ULONG i = 0; i < authTagLength; i++)
    {
        printf("%02X", authTag[i]);
    }
    printf("\n");

    // Add authentication tag to the KeyTagIV variable 
    memcpy(KeyTagIV + 44, authTag, authTagLength);
    memcpy(keys, KeyTagIV, 60);
    printf("FULL:\n");
    for (ULONG i = 0; i < 60; i++)
    {
        printf("%02X", KeyTagIV[i]);
    }
    printf("\n");
    FILE *encryptedFile = fopen(OutputFile, "wb");
    fwrite(encrypted, sizeof(char), file_size, encryptedFile);
    free(encrypted);
    return 1;
}

int main()
{
        // GCM Encrypt the File.
        char key_data[60];
        char path[] = "test.txt";
        char path1[] = "test.enc";
        GCM_Encrypt_File(path, key_data, path1);
        printf("Decryption Data:");
        for (int i = 0; i < 60; i++) {
            printf("%02X ", key_data[i]);
        }

    return 0;
}

and I'm trying to decrypt the data with this Python code:

import rsa
from Crypto.Cipher import AES
import base64
import os
if __name__ == '__main__':
    # Decryption data in HEX KEY; IV; TAG
    KEYS = """540AA548ADBBF19820FEC1DDF9BC19B6230A746C0CF0EA87E083FDF314867DA525F299D2B9FEBC26A864A9F149D3A60B05E03CA9C3328E5AB10228DB"""
    encrypted_keys = bytearray.fromhex(KEYS)

    ENC_PATH = "test.enc"
    keys_data = encrypted_keys

    key = keys_data[:32]
    iv = keys_data[32:44]
    authTag = keys_data[44:60]
    ciphertext = open(ENC_PATH, mode="rb").read()
    cipher = AES.new(key, AES.MODE_GCM, nonce=iv)
    plaintext = cipher.decrypt_and_verify(ciphertext, authTag)
    with open('decrypted_test.txt', 'wb') as f:
        f.write(plaintext)
    print("Done.")

#decrypt_rsa(input_filename, output_filename)

This code seems to work, when for example encrypting a .txt file with just "Hello, world!". So it's able to decrypt it correctly.

The problem is that when I try and encrypt a .zip file like this: enter image description here

The decrypted output data looks like this:

enter image description here

The .txt file is gone, and the test2.zip says "Corrupted" when trying to open. The test1.zip still opens correctly.

Could the algorithm be corrupting it? Or is there something wrong in my code?


Solution

  • You need to open fd in binary mode.

    _sopen_s(&fd, FileToEncrypt, _O_RDONLY, _SH_DENYRW, _S_IREAD);
    

    should be

    _sopen_s(&fd, FileToEncrypt, _O_RDONLY | _O_BINARY, _SH_DENYRW, _S_IREAD);