Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
- Generieren von Diffie-Hellman Schlüsseln
- Austausch von Diffie-Hellman Schlüsseln
- Exportieren eines Diffie-Hellman privaten Schlüssels
- Beispielcode-
Generieren von Diffie-Hellman Schlüsseln
Führen Sie die folgenden Schritte aus, um einen Diffie-Hellman Schlüssel zu generieren:
Rufen Sie die CryptAcquireContext--Funktion auf, um einen Handle an den Microsoft Diffie-Hellman Kryptografieanbieter zu erhalten.
Generieren Sie den neuen Schlüssel. Dazu gibt es zwei Möglichkeiten: Indem CryptoAPI alle neuen Werte für G, P und X generiert oder vorhandene Werte für G und P verwendet und einen neuen Wert für X generiert.
So generieren Sie den Schlüssel durch Generieren aller neuen Werte
- Rufen Sie die CryptGenKey--Funktion auf, und übergeben Sie entweder CALG_DH_SF (Speicher und Weiterleitung) oder CALG_DH_EPHEM (kurzlebig) im Algid Parameter. Der Schlüssel wird mit neuen Zufallswerten für G und P, einem neu berechneten Wert für X generiert, und sein Handle wird im phKey-Parameter zurückgegeben.
- Der neue Schlüssel ist jetzt einsatzbereit. Die Werte von G und P müssen zusammen mit dem Schlüssel (oder von einer anderen Methode) an den Empfänger gesendet werden, wenn ein Schlüsselaustausch.
So generieren Sie den Schlüssel mithilfe vordefinierter Werte für die G- und P-
- Rufen Sie CryptGenKey auf, entweder CALG_DH_SF (Speichern und Weiterleiten) oder CALG_DH_EPHEM (kurzlebig) im Algid Parameter übergeben und für den dwFlags Parameter CRYPT_PREGEN. Ein Schlüsselhandle wird generiert und im phKey Parameter zurückgegeben.
- Initialisieren Sie eine CRYPT_DATA_BLOB Struktur, wobei das pbData- element auf den P-Wert festgelegt ist. Die BLOB- enthält keine Kopfzeileninformationen, und das PbData--Element weist little-endian Format auf.
- Der Wert von P wird festgelegt, indem die CryptSetKeyParam--Funktion aufgerufen wird, und übergeben Sie das in Schritt a im hKey Parameter abgerufene Schlüsselhandle, das KP_P Flag im dwParam--Parameter und einen Zeiger auf die Struktur, die den Wert von P im pbData--Parameter enthält.
- Initialisieren Sie eine CRYPT_DATA_BLOB Struktur, wobei das pbData- element auf den G-Wert festgelegt ist. The BLOB contains no header information and the pbData member is in little-endian format.
- Der Wert von G wird festgelegt, indem die CryptSetKeyParam--Funktion aufgerufen wird, und übergeben Sie das in Schritt a im hKey Parameter abgerufene Schlüsselhandle, das KP_G Flag im dwParam--Parameter und einen Zeiger auf die Struktur, die den Wert von G im pbData--Parameter enthält.
- Der Wert von X wird durch Aufrufen der CryptSetKeyParam--Funktion generiert, das in Schritt a im hKey-Parameter abgerufene Schlüsselhandle übergeben, das KP_X Flag im dwParam--Parameter und NULL- im pbData--Parameter.
- Wenn alle Funktionsaufrufe erfolgreich waren, ist der Diffie-Hellman öffentlichen Schlüssel einsatzbereit.
Wenn der Schlüssel nicht mehr benötigt wird, zerstören Sie ihn, indem Sie den Tastenziehpunkt an die CryptDestroyKey--Funktion übergeben.
Wenn CALG_DH_SF in den vorherigen Prozeduren angegeben wurde, werden die Schlüsselwerte bei jedem Aufruf von CryptSetKeyParamgespeichert. Die G- und P-Werte können dann mithilfe der CryptGetKeyParam--Funktion abgerufen werden. Einige CSPs weisen möglicherweise hartcodierte G- und P-Werte auf. In diesem Fall wird ein NTE_FIXEDPARAMETER Fehler zurückgegeben, wenn CryptSetKeyParam- mit KP_G oder KP_P aufgerufen wird, die im dwParam--Parameter angegeben ist. Wenn CryptDestroyKey aufgerufen wird, wird der Handle für den Schlüssel zerstört, die Schlüsselwerte werden jedoch im CSP beibehalten. Wenn CALG_DH_EPHEM jedoch angegeben wurde, wird der Handle für den Schlüssel zerstört, und alle Werte werden vom CSP gelöscht.
Austauschen von Diffie-Hellman Schlüsseln
Der Zweck des Diffie-Hellman Algorithmus besteht darin, es zwei oder mehr Parteien zu ermöglichen, einen identischen geheimen Sitzungsschlüssel zu erstellen und freizugeben, indem Informationen über ein nicht sicheres Netzwerk freigegeben werden. Die Informationen, die über das Netzwerk freigegeben werden, befinden sich in Form einiger konstanter Werte und eines Diffie-Hellman öffentlichen Schlüssels. Der von zwei Schlüsselaustauschparteien verwendete Prozess lautet wie folgt:
- Beide Parteien stimmen den Diffie-Hellman Parametern zu, die eine Primzahl (P) und eine Generatornummer (G) sind.
- Partei 1 sendet ihren Diffie-Hellman öffentlichen Schlüssel an Partei 2.
- Partei 2 berechnet den geheimen Sitzungsschlüssel mithilfe der Informationen, die im privaten Schlüssel und dem öffentlichen Schlüssel der Partei 1 enthalten sind.
- Partei 2 sendet ihren Diffie-Hellman öffentlichen Schlüssel an partei 1.
- Party 1 berechnet den geheimen Sitzungsschlüssel mithilfe der Informationen, die im privaten Schlüssel und dem öffentlichen Schlüssel der Partei 2 enthalten sind.
- Beide Parteien verfügen jetzt über denselben Sitzungsschlüssel, der zum Verschlüsseln und Entschlüsseln von Daten verwendet werden kann. Die hierfür erforderlichen Schritte werden im folgenden Verfahren gezeigt.
So bereiten Sie einen Diffie-Hellman öffentlichen Schlüssel für die Übertragung
- Rufen Sie die CryptAcquireContext--Funktion auf, um einen Handle an den Microsoft Diffie-Hellman Kryptografieanbieter zu erhalten.
- Erstellen Sie einen Diffie-Hellman Schlüssel, indem Sie die CryptGenKey--Funktion aufrufen, um einen neuen Schlüssel zu erstellen, oder indem Sie die CryptGetUserKey--Funktion aufrufen, um einen vorhandenen Schlüssel abzurufen.
- Rufen Sie die größe ab, die zum Halten des Diffie-Hellman Schlüssel-BLOB erforderlich ist, indem Sie den CryptExportKey-aufrufen und NULL- für den parameter pbData übergeben. Die erforderliche Größe wird in pdwDataLen-zurückgegeben.
- Weisen Sie Speicher für das Schlüssel-BLOB zu.
- Erstellen Sie eine Diffie-Hellman BLOB- für öffentliche Schlüssel, indem Sie die CryptExportKey--Funktion aufrufen und PUBLICKEYBLOB- im parameter dwBlob Type und das Handle für den Diffie-Hellman Schlüssel im hKey--Parameter übergeben. Dieser Funktionsaufruf bewirkt die Berechnung des öffentlichen Schlüsselwerts (G^X) mod P.
- Wenn alle vorherigen Funktionsaufrufe erfolgreich waren, ist das Diffie-Hellman public key BLOB jetzt bereit, codiert und übertragen zu werden.
So importieren Sie einen Diffie-Hellman öffentlichen Schlüssel und berechnen den geheimen Sitzungsschlüssel
- Rufen Sie die CryptAcquireContext--Funktion auf, um einen Handle an den Microsoft Diffie-Hellman Kryptografieanbieter zu erhalten.
- Erstellen Sie einen Diffie-Hellman Schlüssel, indem Sie die CryptGenKey--Funktion aufrufen, um einen neuen Schlüssel zu erstellen, oder indem Sie die CryptGetUserKey--Funktion aufrufen, um einen vorhandenen Schlüssel abzurufen.
- Rufen Sie zum Importieren des Diffie-Hellman öffentlichen Schlüssels in den CSP die CryptImportKey--Funktion auf, übergeben Sie einen Zeiger auf den öffentlichen Schlüssel-BLOB im pbData--Parameter, die Länge des BLOB im parameter dwDataLen und das Handle zum Diffie-Hellman Schlüssel im hPubKey Parameter. Dies führt dazu, dass die Berechnung (Y^X) mod P ausgeführt wird, wodurch der freigegebene, geheime Schlüssel erstellt und der Schlüsselaustauschabgeschlossen wird. Dieser Funktionsaufruf gibt ein Handle an den neuen geheimen Sitzungsschlüssel im hKey Parameter zurück.
- An diesem Punkt ist die importierte Diffie-Hellman vom Typ CALG_AGREEDKEY_ANY. Bevor der Schlüssel verwendet werden kann, muss er in einen Sitzungsschlüsseltyp konvertiert werden. Dazu wird die CryptSetKeyParam--Funktion aufgerufen, wobei dwParam- auf KP_ALGID festgelegt ist und pbData- auf einen ALG_ID Wert festgelegt ist, der einen Sitzungsschlüssel darstellt, z. B. CALG_RC4. Der Schlüssel muss konvertiert werden, bevor der gemeinsam genutzte Schlüssel in der CryptEncrypt oder CryptDecrypt Funktion verwendet wird. Aufrufe an eine dieser Funktionen vor dem Konvertieren des Schlüsseltyps schlagen fehl.
- Der geheime Sitzungsschlüssel kann jetzt zur Verschlüsselung oder Entschlüsselung verwendet werden.
- Wenn der Schlüssel nicht mehr benötigt wird, zerstören Sie den Tastenziehpunkt, indem Sie die CryptDestroyKey--Funktion aufrufen.
Exportieren eines Diffie-Hellman privaten Schlüssels
Führen Sie die folgenden Schritte aus, um einen Diffie-Hellman privaten Schlüssel zu exportieren:
- Rufen Sie die CryptAcquireContext--Funktion auf, um einen Handle an den Microsoft Diffie-Hellman Kryptografieanbieter zu erhalten.
- Erstellen Sie einen Diffie-Hellman Schlüssel, indem Sie die CryptGenKey--Funktion aufrufen, um einen neuen Schlüssel zu erstellen, oder indem Sie die CryptGetUserKey--Funktion aufrufen, um einen vorhandenen Schlüssel abzurufen.
- Erstellen Sie einen Diffie-Hellman privaten SCHLÜSSEL-BLOB-, indem Sie die CryptExportKey--Funktion aufrufen und PRIVATEKEYBLOB- im dwBlobType Parameter übergeben und das Handle für den Diffie-Hellman Schlüssel im hKey Parameter übergeben.
- Wenn der Tastenhandle nicht mehr benötigt wird, rufen Sie die CryptDestroyKey--Funktion auf, um den Tastenziehpunkt zu zerstören.
Beispielcode
Das folgende Beispiel zeigt, wie Sie einen Diffie-Hellman Schlüssel zum Ausführen eines Schlüsselaustauschs erstellen, exportieren, importieren und verwenden.
#include <tchar.h>
#include <windows.h>
#include <wincrypt.h>
#pragma comment(lib, "crypt32.lib")
// The key size, in bits.
#define DHKEYSIZE 512
// Prime in little-endian format.
static const BYTE g_rgbPrime[] =
{
0x91, 0x02, 0xc8, 0x31, 0xee, 0x36, 0x07, 0xec,
0xc2, 0x24, 0x37, 0xf8, 0xfb, 0x3d, 0x69, 0x49,
0xac, 0x7a, 0xab, 0x32, 0xac, 0xad, 0xe9, 0xc2,
0xaf, 0x0e, 0x21, 0xb7, 0xc5, 0x2f, 0x76, 0xd0,
0xe5, 0x82, 0x78, 0x0d, 0x4f, 0x32, 0xb8, 0xcb,
0xf7, 0x0c, 0x8d, 0xfb, 0x3a, 0xd8, 0xc0, 0xea,
0xcb, 0x69, 0x68, 0xb0, 0x9b, 0x75, 0x25, 0x3d,
0xaa, 0x76, 0x22, 0x49, 0x94, 0xa4, 0xf2, 0x8d
};
// Generator in little-endian format.
static BYTE g_rgbGenerator[] =
{
0x02, 0x88, 0xd7, 0xe6, 0x53, 0xaf, 0x72, 0xc5,
0x8c, 0x08, 0x4b, 0x46, 0x6f, 0x9f, 0x2e, 0xc4,
0x9c, 0x5c, 0x92, 0x21, 0x95, 0xb7, 0xe5, 0x58,
0xbf, 0xba, 0x24, 0xfa, 0xe5, 0x9d, 0xcb, 0x71,
0x2e, 0x2c, 0xce, 0x99, 0xf3, 0x10, 0xff, 0x3b,
0xcb, 0xef, 0x6c, 0x95, 0x22, 0x55, 0x9d, 0x29,
0x00, 0xb5, 0x4c, 0x5b, 0xa5, 0x63, 0x31, 0x41,
0x13, 0x0a, 0xea, 0x39, 0x78, 0x02, 0x6d, 0x62
};
BYTE g_rgbData[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
int _tmain(int argc, _TCHAR* argv[])
{
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
BOOL fReturn;
HCRYPTPROV hProvParty1 = NULL;
HCRYPTPROV hProvParty2 = NULL;
DATA_BLOB P;
DATA_BLOB G;
HCRYPTKEY hPrivateKey1 = NULL;
HCRYPTKEY hPrivateKey2 = NULL;
PBYTE pbKeyBlob1 = NULL;
PBYTE pbKeyBlob2 = NULL;
HCRYPTKEY hSessionKey1 = NULL;
HCRYPTKEY hSessionKey2 = NULL;
PBYTE pbData = NULL;
/************************
Construct data BLOBs for the prime and generator. The P and G
values, represented by the g_rgbPrime and g_rgbGenerator arrays
respectively, are shared values that have been agreed to by both
parties.
************************/
P.cbData = DHKEYSIZE/8;
P.pbData = (BYTE*)(g_rgbPrime);
G.cbData = DHKEYSIZE/8;
G.pbData = (BYTE*)(g_rgbGenerator);
/************************
Create the private Diffie-Hellman key for party 1.
************************/
// Acquire a provider handle for party 1.
fReturn = CryptAcquireContext(
&hProvParty1,
NULL,
MS_ENH_DSS_DH_PROV,
PROV_DSS_DH,
CRYPT_VERIFYCONTEXT);
if(!fReturn)
{
goto ErrorExit;
}
// Create an ephemeral private key for party 1.
fReturn = CryptGenKey(
hProvParty1,
CALG_DH_EPHEM,
DHKEYSIZE << 16 | CRYPT_EXPORTABLE | CRYPT_PREGEN,
&hPrivateKey1);
if(!fReturn)
{
goto ErrorExit;
}
// Set the prime for party 1's private key.
fReturn = CryptSetKeyParam(
hPrivateKey1,
KP_P,
(PBYTE)&P,
0);
if(!fReturn)
{
goto ErrorExit;
}
// Set the generator for party 1's private key.
fReturn = CryptSetKeyParam(
hPrivateKey1,
KP_G,
(PBYTE)&G,
0);
if(!fReturn)
{
goto ErrorExit;
}
// Generate the secret values for party 1's private key.
fReturn = CryptSetKeyParam(
hPrivateKey1,
KP_X,
NULL,
0);
if(!fReturn)
{
goto ErrorExit;
}
/************************
Create the private Diffie-Hellman key for party 2.
************************/
// Acquire a provider handle for party 2.
fReturn = CryptAcquireContext(
&hProvParty2,
NULL,
MS_ENH_DSS_DH_PROV,
PROV_DSS_DH,
CRYPT_VERIFYCONTEXT);
if(!fReturn)
{
goto ErrorExit;
}
// Create an ephemeral private key for party 2.
fReturn = CryptGenKey(
hProvParty2,
CALG_DH_EPHEM,
DHKEYSIZE << 16 | CRYPT_EXPORTABLE | CRYPT_PREGEN,
&hPrivateKey2);
if(!fReturn)
{
goto ErrorExit;
}
// Set the prime for party 2's private key.
fReturn = CryptSetKeyParam(
hPrivateKey2,
KP_P,
(PBYTE)&P,
0);
if(!fReturn)
{
goto ErrorExit;
}
// Set the generator for party 2's private key.
fReturn = CryptSetKeyParam(
hPrivateKey2,
KP_G,
(PBYTE)&G,
0);
if(!fReturn)
{
goto ErrorExit;
}
// Generate the secret values for party 2's private key.
fReturn = CryptSetKeyParam(
hPrivateKey2,
KP_X,
NULL,
0);
if(!fReturn)
{
goto ErrorExit;
}
/************************
Export Party 1's public key.
************************/
// Public key value, (G^X) mod P is calculated.
DWORD dwDataLen1;
// Get the size for the key BLOB.
fReturn = CryptExportKey(
hPrivateKey1,
NULL,
PUBLICKEYBLOB,
0,
NULL,
&dwDataLen1);
if(!fReturn)
{
goto ErrorExit;
}
// Allocate the memory for the key BLOB.
if(!(pbKeyBlob1 = (PBYTE)malloc(dwDataLen1)))
{
goto ErrorExit;
}
// Get the key BLOB.
fReturn = CryptExportKey(
hPrivateKey1,
0,
PUBLICKEYBLOB,
0,
pbKeyBlob1,
&dwDataLen1);
if(!fReturn)
{
goto ErrorExit;
}
/************************
Export Party 2's public key.
************************/
// Public key value, (G^X) mod P is calculated.
DWORD dwDataLen2;
// Get the size for the key BLOB.
fReturn = CryptExportKey(
hPrivateKey2,
NULL,
PUBLICKEYBLOB,
0,
NULL,
&dwDataLen2);
if(!fReturn)
{
goto ErrorExit;
}
// Allocate the memory for the key BLOB.
if(!(pbKeyBlob2 = (PBYTE)malloc(dwDataLen2)))
{
goto ErrorExit;
}
// Get the key BLOB.
fReturn = CryptExportKey(
hPrivateKey2,
0,
PUBLICKEYBLOB,
0,
pbKeyBlob2,
&dwDataLen2);
if(!fReturn)
{
goto ErrorExit;
}
/************************
Party 1 imports party 2's public key.
The imported key will contain the new shared secret
key (Y^X) mod P.
************************/
fReturn = CryptImportKey(
hProvParty1,
pbKeyBlob2,
dwDataLen2,
hPrivateKey1,
0,
&hSessionKey2);
if(!fReturn)
{
goto ErrorExit;
}
/************************
Party 2 imports party 1's public key.
The imported key will contain the new shared secret
key (Y^X) mod P.
************************/
fReturn = CryptImportKey(
hProvParty2,
pbKeyBlob1,
dwDataLen1,
hPrivateKey2,
0,
&hSessionKey1);
if(!fReturn)
{
goto ErrorExit;
}
/************************
Convert the agreed keys to symmetric keys. They are currently of
the form CALG_AGREEDKEY_ANY. Convert them to CALG_RC4.
************************/
ALG_ID Algid = CALG_RC4;
// Enable the party 1 public session key for use by setting the
// ALGID.
fReturn = CryptSetKeyParam(
hSessionKey1,
KP_ALGID,
(PBYTE)&Algid,
0);
if(!fReturn)
{
goto ErrorExit;
}
// Enable the party 2 public session key for use by setting the
// ALGID.
fReturn = CryptSetKeyParam(
hSessionKey2,
KP_ALGID,
(PBYTE)&Algid,
0);
if(!fReturn)
{
goto ErrorExit;
}
/************************
Encrypt some data with party 1's session key.
************************/
// Get the size.
DWORD dwLength = sizeof(g_rgbData);
fReturn = CryptEncrypt(
hSessionKey1,
0,
TRUE,
0,
NULL,
&dwLength,
sizeof(g_rgbData));
if(!fReturn)
{
goto ErrorExit;
}
// Allocate a buffer to hold the encrypted data.
pbData = (PBYTE)malloc(dwLength);
if(!pbData)
{
goto ErrorExit;
}
// Copy the unencrypted data to the buffer. The data will be
// encrypted in place.
memcpy(pbData, g_rgbData, sizeof(g_rgbData));
// Encrypt the data.
dwLength = sizeof(g_rgbData);
fReturn = CryptEncrypt(
hSessionKey1,
0,
TRUE,
0,
pbData,
&dwLength,
sizeof(g_rgbData));
if(!fReturn)
{
goto ErrorExit;
}
/************************
Decrypt the data with party 2's session key.
************************/
dwLength = sizeof(g_rgbData);
fReturn = CryptDecrypt(
hSessionKey2,
0,
TRUE,
0,
pbData,
&dwLength);
if(!fReturn)
{
goto ErrorExit;
}
ErrorExit:
if(pbData)
{
free(pbData);
pbData = NULL;
}
if(hSessionKey2)
{
CryptDestroyKey(hSessionKey2);
hSessionKey2 = NULL;
}
if(hSessionKey1)
{
CryptDestroyKey(hSessionKey1);
hSessionKey1 = NULL;
}
if(pbKeyBlob2)
{
free(pbKeyBlob2);
pbKeyBlob2 = NULL;
}
if(pbKeyBlob1)
{
free(pbKeyBlob1);
pbKeyBlob1 = NULL;
}
if(hPrivateKey2)
{
CryptDestroyKey(hPrivateKey2);
hPrivateKey2 = NULL;
}
if(hPrivateKey1)
{
CryptDestroyKey(hPrivateKey1);
hPrivateKey1 = NULL;
}
if(hProvParty2)
{
CryptReleaseContext(hProvParty2, 0);
hProvParty2 = NULL;
}
if(hProvParty1)
{
CryptReleaseContext(hProvParty1, 0);
hProvParty1 = NULL;
}
return 0;
}