Freigeben über


Verschlüsseln von Daten mit CNG

Die primäre Verwendung jeder Kryptografie-API besteht darin, Daten zu verschlüsseln und zu entschlüsseln. Mit CNG können Sie Daten mithilfe einer mindesten Anzahl von Funktionsaufrufen verschlüsseln und die gesamte Speicherverwaltung durchführen. Während viele Details zur Protokollimplementierung dem Benutzer überlassen werden, stellt CNG die Grundtypen bereit, die die eigentlichen Datenverschlüsselungs- und Entschlüsselungsaufgaben ausführen.

Verschlüsseln von Daten

Führen Sie zum Verschlüsseln von Daten die folgenden Schritte aus:

  1. Öffnen Sie einen Algorithmusanbieter, der die Verschlüsselung unterstützt, z. B. BCRYPT_DES_ALGORITHM.

  2. Erstellen Sie einen Schlüssel zum Verschlüsseln der Daten. Ein Schlüssel kann mithilfe einer der folgenden Funktionen erstellt werden:

    Hinweis

    Die Datenverschlüsselung und -entschlüsselung mit einem asymmetrischen Schlüssel ist im Vergleich zur Verschlüsselung mit symmetrischen Schlüsseln rechenintensiv. Wenn Sie Daten mit einem asymmetrischen Schlüssel verschlüsseln müssen, sollten Sie die Daten mit einem symmetrischen Schlüssel verschlüsseln, den symmetrischen Schlüssel mit einem asymmetrischen Schlüssel verschlüsseln und den verschlüsselten symmetrischen Schlüssel in die Nachricht einschließen. Der Empfänger kann dann den symmetrischen Schlüssel entschlüsseln und den symmetrischen Schlüssel verwenden, um die Daten zu entschlüsseln.

     

  3. Rufen Sie die Größe der verschlüsselten Daten ab. Dies basiert auf dem Verschlüsselungsalgorithmus, dem Auffüllungsschema (falls vorhanden) und der Größe der zu verschlüsselnden Daten. Sie können die verschlüsselte Datengröße abrufen, indem Sie die Funktion BCryptEncrypt verwenden und NULL für den pbOutput-Parameter übergeben. Alle anderen Parameter müssen mit denen identisch sein, wenn die Daten tatsächlich verschlüsselt sind, mit Ausnahme des pbInput-Parameters , der in diesem Fall nicht verwendet wird.

  4. Sie können die Daten entweder mit demselben Puffer verschlüsseln oder die Daten in einem separaten Puffer verschlüsseln.

    Wenn Sie die Daten verschlüsseln möchten, übergeben Sie den Klartextpufferzeiger für die Parameter pbInput und pbOutput in der BCryptEncrypt-Funktion . Es ist möglich, dass die verschlüsselte Datengröße größer als die unverschlüsselte Datengröße ist, sodass der Klartextpuffer groß genug sein muss, um die verschlüsselten Daten und nicht nur den Klartext zu speichern. Sie können die in Schritt 3 abgerufene Größe verwenden, um den Klartextpuffer zuzuweisen.

    Wenn Sie die Daten in einem separaten Puffer verschlüsseln möchten, ordnen Sie einen Speicherpuffer für die verschlüsselten Daten zu, indem Sie die in Schritt 3 abgerufene Größe verwenden.

  5. Rufen Sie die BCryptEncrypt-Funktion auf, um die Daten zu verschlüsseln. Diese Funktion schreibt die verschlüsselten Daten an den im pbOutput-Parameter angegebenen Speicherort.

  6. Speichern Sie die verschlüsselten Daten nach Bedarf.

  7. Wiederholen Sie die Schritte 5 und 6, bis alle Daten verschlüsselt wurden.

Beispiel für die Verschlüsselung von Daten

Das folgende Beispiel zeigt, wie Daten mit CNG mithilfe des erweiterten symmetrischen Verschlüsselungsstandardalgorithmus verschlüsselt werden.

// 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);
    }

}

Entschlüsseln von Daten

Führen Sie zum Entschlüsseln von Daten die folgenden Schritte aus:

  1. Öffnen Sie einen Algorithmusanbieter, der die Verschlüsselung unterstützt, z. B. BCRYPT_DES_ALGORITHM.

  2. Rufen Sie den Schlüssel ab, mit dem die Daten verschlüsselt wurden, und verwenden Sie diesen Schlüssel, um ein Handle für den Schlüssel abzurufen.

  3. Rufen Sie die Größe der entschlüsselten Daten ab. Dies basiert auf dem Verschlüsselungsalgorithmus, dem Auffüllungsschema (falls vorhanden) und der Größe der zu entschlüsselnden Daten. Sie können die verschlüsselte Datengröße abrufen, indem Sie die Funktion BCryptDecrypt verwenden und NULL für den pbOutput-Parameter übergeben. Die Parameter, die das Abstandsschema und den Initialisierungsvektor (IV) angeben, müssen mit ausnahme des pbInput-Parameters identisch sein, der in diesem Fall nicht verwendet wird.

  4. Weisen Sie einen Speicherpuffer für die entschlüsselten Daten zu.

  5. Sie können die Daten entweder mithilfe desselben Puffers entschlüsseln oder die Daten in einem separaten Puffer entschlüsseln.

    Wenn Sie die Daten entschlüsseln möchten, übergeben Sie den Verschlüsselungstextpufferzeiger für die Parameter pbInput und pbOutput in der Funktion BCryptDecrypt .

    Wenn Sie die Daten in einem separaten Puffer entschlüsseln möchten, ordnen Sie einen Speicherpuffer für die entschlüsselten Daten zu, indem Sie die in Schritt 3 abgerufene Größe verwenden.

  6. Rufen Sie die BCryptDecrypt-Funktion auf, um die Daten zu entschlüsseln. Die Parameter, die das Abstandsschema und IV angeben, müssen mit denen identisch sein, als die Daten verschlüsselt wurden. Diese Funktion schreibt die entschlüsselten Daten an den im pbOutput-Parameter angegebenen Speicherort.

  7. Speichern Sie die entschlüsselten Daten nach Bedarf.

  8. Wiederholen Sie die Schritte 5 und 6, bis alle Daten entschlüsselt wurden.