Gegevens versleutelen met CNG
Het primaire gebruik van een cryptografie-API is het versleutelen en ontsleutelen van gegevens. Met CNG kunt u gegevens versleutelen met behulp van een minimum aantal functie-aanroepen en kunt u al het geheugenbeheer uitvoeren. Hoewel veel van de details van de protocol-implementatie aan de gebruiker worden overgelaten, biedt CNG de primitieven die de werkelijke gegevensversleuteling en ontsleutelingstaken uitvoeren.
Gegevens versleutelen
Voer de volgende stappen uit om gegevens te versleutelen:
Open een algoritmeprovider die versleuteling ondersteunt, zoals BCRYPT_DES_ALGORITHM.
Maak een sleutel om de gegevens mee te versleutelen. U kunt een sleutel maken met behulp van een van de volgende functies:
- BCryptGenerateKeyPair of BCryptImportKeyPair voor asymmetrische providers.
- BCryptGenerateSymmetricKey of BCryptImportKey voor symmetrische aanbieders.
Notitie
Gegevensversleuteling en -ontsleuteling met een asymmetrische sleutel is rekenintensief vergeleken met symmetrische sleutelversleuteling. Als u gegevens wilt versleutelen met een asymmetrische sleutel, moet u de gegevens versleutelen met een symmetrische sleutel, de symmetrische sleutel versleutelen met een asymmetrische sleutel en de versleutelde symmetrische sleutel met het bericht opnemen. De ontvanger kan vervolgens de symmetrische sleutel ontsleutelen en de symmetrische sleutel gebruiken om de gegevens te ontsleutelen.
De grootte van de versleutelde gegevens verkrijgen. Dit is gebaseerd op het versleutelingsalgoritmen, het opvullingsschema (indien aanwezig) en de grootte van de gegevens die moeten worden versleuteld. U kunt de versleutelde gegevensgrootte verkrijgen met behulp van de functie BCryptEncrypt, waarbij NULL- wordt doorgegeven voor de parameter pbOutput. Alle andere parameters moeten hetzelfde zijn als wanneer de gegevens daadwerkelijk worden versleuteld, met uitzondering van de pbInput-parameter, die in dit geval niet wordt gebruikt.
U kunt de gegevens versleutelen met dezelfde buffer of de gegevens versleutelen in een afzonderlijke buffer.
Als u de gegevens wilt versleutelen, geeft u de bufferpointer zonder opmaak door voor zowel de pbInput- als pbOutput-parameters in de functie BCryptEncrypt. Het is mogelijk dat de versleutelde gegevensgrootte groter is dan de niet-versleutelde gegevensgrootte, dus de buffer zonder tekst moet groot genoeg zijn om de versleutelde gegevens op te slaan, niet alleen de niet-versleutelde tekst. U kunt de grootte die u in stap 3 hebt verkregen, gebruiken om de buffer voor tekst zonder opmaak toe te wijzen.
Als u de gegevens in een afzonderlijke buffer wilt versleutelen, wijst u een geheugenbuffer toe voor de versleutelde gegevens met behulp van de grootte die u in stap 3 hebt verkregen.
Roep de BCryptEncrypt functie aan om de gegevens te versleutelen. Met deze functie worden de versleutelde gegevens naar de locatie geschreven die is opgegeven in de parameter pbOutput.
Behoud de versleutelde gegevens indien nodig.
Herhaal stap 5 en 6 totdat alle gegevens zijn versleuteld.
Voorbeeld van het versleutelen van gegevens
In het volgende voorbeeld ziet u hoe u gegevens versleutelt met CNG met behulp van de geavanceerde versleutelingsstandaard (AES) symmetrische encryptie-algoritme.
// 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 <windows.h>
#include <stdio.h>
#include <bcrypt.h>
#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 __cdecl wmain(
int argc,
__in_ecount(argc) LPWSTR *wargv)
{
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;
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(wargv);
// 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(!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;
}
//
// 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);
}
}
Gegevens ontsleutelen
Voer de volgende stappen uit om gegevens te ontsleutelen:
Open een algoritmeprovider die versleuteling ondersteunt, zoals BCRYPT_DES_ALGORITHM.
Haal de sleutel op waarmee de gegevens zijn versleuteld en gebruik die sleutel om een ingang voor de sleutel te verkrijgen.
De grootte van de ontsleutelde gegevens verkrijgen. Dit is gebaseerd op het versleutelingsalgoritmen, het opvullingsschema (indien aanwezig) en de grootte van de gegevens die moeten worden ontsleuteld. U kunt de versleutelde gegevensgrootte verkrijgen met behulp van de functie BCryptDecrypt, waarbij NULL- wordt doorgegeven voor de parameter pbOutput. De parameters die het opvullingsschema en initialisatievector (IV) opgeven, moeten hetzelfde zijn als wanneer de gegevens zijn versleuteld, met uitzondering van de parameter pbInput, die in dit geval niet wordt gebruikt.
Wijs een geheugenbuffer toe voor de ontsleutelde gegevens.
U kunt de gegevens ontsleutelen met behulp van dezelfde buffer of de gegevens ontsleutelen in een afzonderlijke buffer.
Als u de gegevens wilt ontsleutelen, geeft u de bufferaanwijzer voor coderingstekst door voor zowel de pbInput- als pbOutput parameters in de functie BCryptDecrypt.
Als u de gegevens in een afzonderlijke buffer wilt ontsleutelen, wijst u een geheugenbuffer toe voor de ontsleutelde gegevens met behulp van de grootte die u in stap 3 hebt verkregen.
Roep de functie BCryptDecrypt aan om de gegevens te ontsleutelen. De parameters die het opvullingsschema en IV opgeven, moeten hetzelfde zijn als wanneer de gegevens zijn versleuteld. Met deze functie worden de ontsleutelde gegevens naar de locatie geschreven die is opgegeven in de parameter pbOutput.
Behoud de ontsleutelde gegevens indien nodig.
Herhaal stap 5 en 6 totdat alle gegevens zijn ontsleuteld.