// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (C) Microsoft. All rights reserved. /*++ Abstract: Sample program for AES-CBC encryption using CNG --*/ #include #include #include #include "common.h" #pragma comment(lib, "Bcrypt.lib") #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) #define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) #define DATA_TO_ENCRYPT "Test Data" const BYTE rgbPlaintext[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; static const BYTE rgbIV[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; static const BYTE rgbAES128Key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; void PrintBytes( IN BYTE *pbPrintData, IN DWORD cbDataLen) { DWORD dwCount = 0; for(dwCount=0; dwCount < cbDataLen;dwCount++) { printf("0x%02x, ",pbPrintData[dwCount]); if(0 == (dwCount + 1 )%10) putchar('\n'); } } void CryptoExample() { BCRYPT_ALG_HANDLE hAesAlg = NULL; BCRYPT_KEY_HANDLE hKey = NULL; NTSTATUS status = STATUS_UNSUCCESSFUL; DWORD cbCipherText = 0, cbPlainText = 0, cbData = 0, cbKeyObject = 0, cbBlockLen = 0, cbBlob = 0; PBYTE pbCipherText = NULL, pbPlainText = NULL, pbKeyObject = NULL, pbIV = NULL, pbBlob = NULL; // Open an algorithm handle. if(!NT_SUCCESS(status = BCryptOpenAlgorithmProvider( &hAesAlg, BCRYPT_AES_ALGORITHM, NULL, 0))) { wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); goto Cleanup; } // Calculate the size of the buffer to hold the KeyObject. 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; } // Allocate the key object on the heap. pbKeyObject = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbKeyObject); if(NULL == pbKeyObject) { wprintf(L"**** memory allocation failed\n"); goto Cleanup; } // Calculate the block length for the IV. 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; } // Determine whether the cbBlockLen is not longer than the IV length. if (cbBlockLen > sizeof (rgbIV)) { wprintf (L"**** block length is longer than the provided IV length\n"); goto Cleanup; } // Allocate a buffer for the IV. The buffer is consumed during the // encrypt/decrypt process. pbIV= (PBYTE) HeapAlloc (GetProcessHeap (), 0, cbBlockLen); if(NULL == pbIV) { wprintf(L"**** memory allocation failed\n"); goto Cleanup; } memcpy(pbIV, rgbIV, cbBlockLen); if(!NT_SUCCESS(status = BCryptSetProperty( hAesAlg, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0))) { wprintf(L"**** Error 0x%x returned by BCryptSetProperty\n", status); goto Cleanup; } // Generate the key from supplied input key bytes. if(!NT_SUCCESS(status = BCryptGenerateSymmetricKey( hAesAlg, &hKey, pbKeyObject, cbKeyObject, (PBYTE)rgbAES128Key, sizeof(rgbAES128Key), 0))) { wprintf(L"**** Error 0x%x returned by BCryptGenerateSymmetricKey\n", status); goto Cleanup; } // Save another copy of the key for later. if(!NT_SUCCESS(status = BCryptExportKey( hKey, NULL, BCRYPT_OPAQUE_KEY_BLOB, NULL, 0, &cbBlob, 0))) { wprintf(L"**** Error 0x%x returned by BCryptExportKey\n", status); goto Cleanup; } // Allocate the buffer to hold the BLOB. pbBlob = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbBlob); if(NULL == pbBlob) { wprintf(L"**** memory allocation failed\n"); goto Cleanup; } if(!NT_SUCCESS(status = BCryptExportKey( hKey, NULL, BCRYPT_OPAQUE_KEY_BLOB, pbBlob, cbBlob, &cbBlob, 0))) { wprintf(L"**** Error 0x%x returned by BCryptExportKey\n", status); goto Cleanup; } cbPlainText = sizeof(rgbPlaintext); pbPlainText = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbPlainText); if(NULL == pbPlainText) { wprintf(L"**** memory allocation failed\n"); goto Cleanup; } memcpy(pbPlainText, rgbPlaintext, sizeof(rgbPlaintext)); // // Get the output buffer size. // if(!NT_SUCCESS(status = BCryptEncrypt( hKey, pbPlainText, cbPlainText, NULL, pbIV, cbBlockLen, NULL, 0, &cbCipherText, BCRYPT_BLOCK_PADDING))) { wprintf(L"**** Error 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, pbPlainText, cbPlainText, NULL, pbIV, cbBlockLen, pbCipherText, cbCipherText, &cbData, BCRYPT_BLOCK_PADDING))) { wprintf(L"**** Error 0x%x returned by BCryptEncrypt\n", status); goto Cleanup; } // Destroy the key and reimport from saved BLOB. if(!NT_SUCCESS(status = BCryptDestroyKey(hKey))) { wprintf(L"**** Error 0x%x returned by BCryptDestroyKey\n", status); goto Cleanup; } hKey = 0; if(pbPlainText) { HeapFree(GetProcessHeap(), 0, pbPlainText); } pbPlainText = NULL; // We can reuse the key object. memset(pbKeyObject, 0 , cbKeyObject); // Reinitialize the IV because encryption would have modified it. memcpy(pbIV, rgbIV, cbBlockLen); #if 0 if(!NT_SUCCESS(status = BCryptImportKey( hAesAlg, NULL, BCRYPT_OPAQUE_KEY_BLOB, &hKey, pbKeyObject, cbKeyObject, pbBlob, cbBlob, 0))) { wprintf(L"**** Error 0x%x returned by BCryptGenerateSymmetricKey\n", status); goto Cleanup; } #else BCryptCloseAlgorithmProvider(hAesAlg,0); if(!NT_SUCCESS(status = BCryptOpenAlgorithmProvider( &hAesAlg, BCRYPT_AES_ALGORITHM, NULL, 0))) { wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); goto Cleanup; } // Generate the key from supplied input key bytes. if(!NT_SUCCESS(status = BCryptGenerateSymmetricKey( hAesAlg, &hKey, pbKeyObject, cbKeyObject, (PBYTE)rgbAES128Key, sizeof(rgbAES128Key), 0))) { wprintf(L"**** Error 0x%x returned by BCryptGenerateSymmetricKey\n", status); goto Cleanup; } #endif // // Get the output buffer size. // if(!NT_SUCCESS(status = BCryptDecrypt( hKey, pbCipherText, cbCipherText, NULL, pbIV, cbBlockLen, NULL, 0, &cbPlainText, BCRYPT_BLOCK_PADDING))) { wprintf(L"**** Error 0x%x returned by BCryptDecrypt\n", status); goto Cleanup; } pbPlainText = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbPlainText); if(NULL == pbPlainText) { wprintf(L"**** memory allocation failed\n"); goto Cleanup; } if(!NT_SUCCESS(status = BCryptDecrypt( hKey, pbCipherText, cbCipherText, NULL, pbIV, cbBlockLen, pbPlainText, cbPlainText, &cbPlainText, BCRYPT_BLOCK_PADDING))) { wprintf(L"**** Error 0x%x returned by BCryptDecrypt\n", status); goto Cleanup; } if (0 != memcmp(pbPlainText, (PBYTE)rgbPlaintext, sizeof(rgbPlaintext))) { wprintf(L"Expected decrypted text comparison failed.\n"); goto Cleanup; } wprintf(L"Success!\n"); Cleanup: if(hAesAlg) { BCryptCloseAlgorithmProvider(hAesAlg,0); } if (hKey) { BCryptDestroyKey(hKey); } if(pbCipherText) { HeapFree(GetProcessHeap(), 0, pbCipherText); } if(pbPlainText) { HeapFree(GetProcessHeap(), 0, pbPlainText); } if(pbKeyObject) { HeapFree(GetProcessHeap(), 0, pbKeyObject); } if(pbIV) { HeapFree(GetProcessHeap(), 0, pbIV); } }