I wrote code to encrypt and decrypt data using a hard-coded RSA key pair that was previously generated using CNG. This is a simple program that simply generates some random input, encrypts it with a public key, and then decrypts the received encrypted buffer using the private key. I print all input, intermediate, and output stages to compare whether the decrypted plaintext is the same as the original source, and repeat all encryption-decryption 10 times.
However, I observe that in some cases encryption and decryption are fine, but in other cases the decrypted plaintext does not match the input plaintext at all. Such error cases are completely random and arbitrary, and there seems to be no scheme for these errors.
Is this a bug in the implementation of CNG RSA or am I doing something wrong?
Code follows:
#include <windows.h> #include <stdio.h> #include <stdlib.h> #include <bcrypt.h> #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) #define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) #define PrivateKeySize 283 #define PublicKeySize 155 #define InputDataSize 128 PUCHAR encryptedBuffer; ULONG encryptedBufferSize = 128; VOID printMem(PVOID Mem, int length) { int i; for (i = 0; i < length; i++) printf("%02x ", ((unsigned char *)Mem)[i]); } VOID Decrypt() { unsigned char PrivateKey[PrivateKeySize] = {0x52, 0x53, 0x41, 0x32, 0x00, 0x04, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xB7, 0x50, 0x52, 0xDD, 0x58, 0xE4, 0x96, 0xAF, 0x91, 0xE5, 0xB2, 0x7B, 0x0A, 0xE6, 0xAA, 0x1F, 0x71, 0x8A, 0x66, 0xC3, 0xF0, 0x21, 0xD8, 0xE6, 0x2C, 0xD6, 0x25, 0x2E, 0x77, 0x3C, 0x61, 0x08, 0x1B, 0x69, 0xE7, 0x58, 0xDF, 0x3B, 0x07, 0xFE, 0xF1, 0xDB, 0xBF, 0xA6, 0x35, 0xDF, 0xC7, 0x49, 0x06, 0xC8, 0xDB, 0x74, 0x2A, 0xB9, 0xED, 0xB3, 0x04, 0x80, 0x75, 0x5F, 0x71, 0x2C, 0xD0, 0x14, 0x0E, 0x81, 0x18, 0x00, 0x5E, 0x34, 0x5A, 0xC2, 0x3A, 0x84, 0x63, 0xB1, 0x6B, 0x04, 0x21, 0x49, 0x7F, 0xE0, 0xF3, 0x52, 0x5E, 0x61, 0x43, 0xB1, 0x8F, 0x7C, 0xF2, 0x74, 0x29, 0x28, 0x69, 0x20, 0x36, 0xC0, 0x92, 0x17, 0x42, 0x99, 0x72, 0xE5, 0xE7, 0x82, 0xBE, 0x8E, 0x3B, 0x3F, 0xC9, 0x0A, 0xE1, 0xC4, 0x63, 0x68, 0x73, 0x1D, 0x67, 0x8D, 0xC0, 0xA3, 0xB4, 0xBA, 0xF0, 0xB7, 0xB0, 0x9B, 0xBB, 0x3F, 0xB8, 0x6E, 0xC0, 0x34, 0x1E, 0xA0, 0x01, 0x4B, 0x6D, 0x47, 0x73, 0x3F, 0xA5, 0x39, 0x05, 0x27, 0xD4, 0xD1, 0x38, 0x34, 0x32, 0x2C, 0x5B, 0x03, 0x5F, 0x16, 0x21, 0x64, 0x04, 0xD5, 0x19, 0xDB, 0xE7, 0x80, 0xDA, 0xBD, 0xC4, 0x1E, 0xAB, 0x61, 0xC8, 0x84, 0xDF, 0x54, 0x16, 0x77, 0x98, 0x9B, 0x90, 0x03, 0x83, 0xC4, 0x8D, 0x25, 0xB1, 0x32, 0x67, 0x77, 0x6A, 0x1C, 0x64, 0x2D, 0xFA, 0x9E, 0xB9, 0x26, 0xB5, 0xF8, 0x47, 0x4A, 0x9C, 0x35, 0x89, 0x5F, 0x12, 0x0E, 0xFF, 0x60, 0x87, 0x1E, 0x27, 0xC1, 0xC5, 0x7C, 0x77, 0x0A, 0xAE, 0x11, 0x37, 0xE3, 0x42, 0x9B, 0xAF, 0x9D, 0xBC, 0xC2, 0x52, 0xF8, 0x85, 0xBA, 0xED, 0x8E, 0xC3, 0x73, 0x04, 0x0A, 0x53, 0xD2, 0x1D, 0xEF, 0xA0, 0x6A, 0xCD, 0xBE, 0x93, 0x49, 0x34, 0x3A, 0xBD, 0xDF, 0x6A, 0x33, 0x25, 0x91, 0xFC, 0xE7}; BCRYPT_ALG_HANDLE hAlgorithm = NULL; BCRYPT_KEY_HANDLE hKey = NULL; ULONG plaintextSize = 128; PUCHAR decryptedBuffer; ULONG decryptedBufferSize; NTSTATUS status; status = BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_RSA_ALGORITHM, NULL, 0); if (!NT_SUCCESS(status)) { printf("Failed to get algorithm provider..status : %08x\n",status); goto cleanup; } status = BCryptImportKeyPair( hAlgorithm, NULL, BCRYPT_RSAPRIVATE_BLOB, &hKey, PrivateKey, PrivateKeySize, BCRYPT_NO_KEY_VALIDATION); if (!NT_SUCCESS(status)) { printf("Failed to import Private key..status : %08x\n",status); goto cleanup; } status = BCryptDecrypt( hKey, encryptedBuffer, encryptedBufferSize, NULL, NULL, 0, NULL, 0, &decryptedBufferSize, 0); if (!NT_SUCCESS(status)) { printf("Failed to get required size of buffer..status : %08x\n", status); goto cleanup; } decryptedBuffer = (PUCHAR)HeapAlloc (GetProcessHeap (), 0, decryptedBufferSize); if (decryptedBuffer == NULL) { printf("failed to allocate memory for buffer\n"); goto cleanup; } status = BCryptDecrypt( hKey, encryptedBuffer, encryptedBufferSize, NULL, NULL, 0, decryptedBuffer, decryptedBufferSize, &decryptedBufferSize, 0); if (!NT_SUCCESS(status)) { printf("Failed decrypt buffer..status : %08x\n",status); goto cleanup; } printf("Decrypted buffer\n"); printMem(decryptedBuffer, decryptedBufferSize); printf("\n\n"); cleanup: HeapFree(GetProcessHeap(), 0, decryptedBuffer); BCryptDestroyKey(hKey); BCryptCloseAlgorithmProvider(hAlgorithm, 0); } VOID Encrypt() { unsigned char PublicKey[PublicKeySize] = {0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xB7, 0x50, 0x52, 0xDD, 0x58, 0xE4, 0x96, 0xAF, 0x91, 0xE5, 0xB2, 0x7B, 0x0A, 0xE6, 0xAA, 0x1F, 0x71, 0x8A, 0x66, 0xC3, 0xF0, 0x21, 0xD8, 0xE6, 0x2C, 0xD6, 0x25, 0x2E, 0x77, 0x3C, 0x61, 0x08, 0x1B, 0x69, 0xE7, 0x58, 0xDF, 0x3B, 0x07, 0xFE, 0xF1, 0xDB, 0xBF, 0xA6, 0x35, 0xDF, 0xC7, 0x49, 0x06, 0xC8, 0xDB, 0x74, 0x2A, 0xB9, 0xED, 0xB3, 0x04, 0x80, 0x75, 0x5F, 0x71, 0x2C, 0xD0, 0x14, 0x0E, 0x81, 0x18, 0x00, 0x5E, 0x34, 0x5A, 0xC2, 0x3A, 0x84, 0x63, 0xB1, 0x6B, 0x04, 0x21, 0x49, 0x7F, 0xE0, 0xF3, 0x52, 0x5E, 0x61, 0x43, 0xB1, 0x8F, 0x7C, 0xF2, 0x74, 0x29, 0x28, 0x69, 0x20, 0x36, 0xC0, 0x92, 0x17, 0x42, 0x99, 0x72, 0xE5, 0xE7, 0x82, 0xBE, 0x8E, 0x3B, 0x3F, 0xC9, 0x0A, 0xE1, 0xC4, 0x63, 0x68, 0x73, 0x1D, 0x67, 0x8D, 0xC0, 0xA3, 0xB4, 0xBA, 0xF0, 0xB7, 0xB0, 0x9B}; unsigned char InputData[InputDataSize]; BCRYPT_ALG_HANDLE hAlgorithm = NULL; BCRYPT_KEY_HANDLE hKey = NULL; NTSTATUS status; for (int i=0; i<128; i++) InputData[i] = (unsigned char)rand(); printf("Random Data is \n"); printMem(InputData, InputDataSize); printf("\n\n"); status = BCryptOpenAlgorithmProvider( &hAlgorithm, BCRYPT_RSA_ALGORITHM, NULL, 0 ); if (!NT_SUCCESS(status)) { printf("Failed to get algorithm provider..status : %08x\n",status); goto cleanup; } status = BCryptImportKeyPair( hAlgorithm, NULL, BCRYPT_RSAPUBLIC_BLOB, &hKey, PublicKey, 155, BCRYPT_NO_KEY_VALIDATION ); if (!NT_SUCCESS(status)) { printf("Failed to import Private key..status : %08x\n",status); goto cleanup; } status = BCryptEncrypt( hKey, InputData, InputDataSize, NULL, NULL, 0, NULL, 0, &encryptedBufferSize, 0 ); if (!NT_SUCCESS(status)) { printf("Failed to get required size of buffer..status : %08x\n",status); goto cleanup; } encryptedBuffer = (PUCHAR)HeapAlloc (GetProcessHeap (), 0, encryptedBufferSize); if (encryptedBuffer == NULL) { printf("failed to allocate memory for blindedFEKBuffer\n"); goto cleanup; } status = BCryptEncrypt( hKey, InputData, InputDataSize, NULL, NULL, 0, encryptedBuffer, encryptedBufferSize, &encryptedBufferSize, 0 ); if (!NT_SUCCESS(status)) { printf("Failed encrypt data..status : %08x\n",status); goto cleanup; } printf("Encrypted Data\n"); printMem(encryptedBuffer, encryptedBufferSize); printf("\n\n"); cleanup: if(hKey) BCryptDestroyKey(hKey); if(hAlgorithm) BCryptCloseAlgorithmProvider(hAlgorithm, 0); } int __cdecl wmain( int argc, __in_ecount(argc) LPWSTR *wargv) { int i; for (i=0; i<10; i++) { Encrypt(); Decrypt(); } }