Le problème que je rencontre est que je suis capable de déchiffrer des données en utilisant la même clé publique RSA 2048 bits qui a été utilisée pour crypter les données. Il me semble que cela va à l'encontre de l'objectif de chiffrer les données en premier lieu, si une clé publique peut le déchiffrer. La seule chose que je peux considérer en ce moment est que je génère des paires d'échange de clés symétriques quand je pense que je génère des paires asymétriques. Le but de l'utilisateur final est de l'utiliser plus tard pour transmettre des informations d'identification d'utilisateur à authentifier en utilisant une application loin du bureau, lorsque je ne peux pas utiliser leurs informations d'identification mises en cache depuis leurs postes de travail sur le domaine. Je serais théoriquement capable de décrypter ces informations d'identification en utilisant seulement la clé privée.Crypto API La clé publique RSA peut déchiffrer des données, n'est pas asymétrique comme prévu
J'ai produit une classe de test simple et un code pour reproduire mon problème. Les étapes que je prends sont les suivantes:
- Acquire un contexte de Microsoft Enhanced Cryptographic Provider v1.0
- Générer une paire de clés publique/privée.
- Exportez les BLOB de clé privée et publique vers des fichiers distincts.
- Chargez la clé publique et cryptez un texte simple.
- Tenter de déchiffrer le même texte chiffré à l'aide de la clé publique (je m'attendais à ce qu'il échoue ici sauf lorsque j'utilise la clé privée - mais les deux fonctionnent).
TestEncryptDecrypt classe d'aide: TestEncryptDecrypt.h
#pragma once
#include <Windows.h>
#include <wincrypt.h>
class TestEncryptDecrypt
{
public:
TestEncryptDecrypt()
{
}
~TestEncryptDecrypt()
{
if (hKey != NULL)
CryptDestroyKey(hKey);
if (hProvider != NULL)
CryptReleaseContext(hProvider, 0);
}
BOOL InitializeProvider(LPCTSTR pszProvider, DWORD dwProvType)
{
if (hProvider != NULL)
{
if (!CryptReleaseContext(hProvider, 0))
return 0;
}
return CryptAcquireContext(&hProvider, NULL, pszProvider, dwProvType, 0);
}
BOOL Generate2048BitKeys(ALG_ID Algid)
{
DWORD dwFlags = (0x800 << 16) | CRYPT_EXPORTABLE;
return CryptGenKey(hProvider, Algid, dwFlags, &hKey);
}
VOID ExportPrivatePublicKey(LPTSTR lpFileName)
{
if (hKey == NULL)
return;
DWORD dwDataLen = 0;
BOOL exportResult = CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, NULL, &dwDataLen);
LPBYTE lpKeyBlob = (LPBYTE)malloc(dwDataLen);
exportResult = CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, lpKeyBlob, &dwDataLen);
WriteBytesFile(lpFileName, lpKeyBlob, dwDataLen);
free(lpKeyBlob);
}
VOID ExportPublicKey(LPTSTR lpFileName)
{
if (hKey == NULL)
return;
DWORD dwDataLen = 0;
BOOL exportResult = CryptExportKey(hKey, NULL, PUBLICKEYBLOB, 0, NULL, &dwDataLen);
LPBYTE lpKeyBlob = (LPBYTE)malloc(dwDataLen);
exportResult = CryptExportKey(hKey, NULL, PUBLICKEYBLOB, 0, lpKeyBlob, &dwDataLen);
WriteBytesFile(lpFileName, lpKeyBlob, dwDataLen);
free(lpKeyBlob);
}
BOOL ImportKey(LPTSTR lpFileName)
{
if (hProvider == NULL)
return 0;
if (hKey != NULL)
CryptDestroyKey(hKey);
LPBYTE lpKeyContent = NULL;
DWORD dwDataLen = 0;
ReadBytesFile(lpFileName, &lpKeyContent, &dwDataLen);
BOOL importResult = CryptImportKey(hProvider, lpKeyContent, dwDataLen, 0, 0, &hKey);
delete[] lpKeyContent;
return importResult;
}
BOOL EncryptDataWriteToFile(LPTSTR lpSimpleDataToEncrypt, LPTSTR lpFileName)
{
DWORD SimpleDataToEncryptLength = _tcslen(lpSimpleDataToEncrypt)*sizeof(TCHAR);
DWORD BufferLength = SimpleDataToEncryptLength * 10;
BYTE *EncryptedBuffer = new BYTE[BufferLength];
SecureZeroMemory(EncryptedBuffer, BufferLength);
CopyMemory(EncryptedBuffer, lpSimpleDataToEncrypt, SimpleDataToEncryptLength);
BOOL cryptResult = CryptEncrypt(hKey, NULL, TRUE, 0, EncryptedBuffer, &SimpleDataToEncryptLength, BufferLength);
DWORD dwGetLastError = GetLastError();
WriteBytesFile(lpFileName, EncryptedBuffer, SimpleDataToEncryptLength);
delete[] EncryptedBuffer;
return cryptResult;
}
BOOL DecryptDataFromFile(LPBYTE *lpDecryptedData, LPTSTR lpFileName, DWORD *dwDecryptedLen)
{
if (hKey == NULL)
return 0;
LPBYTE lpEncryptedData = NULL;
DWORD dwDataLen = 0;
ReadBytesFile(lpFileName, &lpEncryptedData, &dwDataLen);
BOOL decryptResult = CryptDecrypt(hKey, NULL, TRUE, 0, lpEncryptedData, &dwDataLen);
*dwDecryptedLen = dwDataLen;
//WriteBytesFile(L"decryptedtest.txt", lpEncryptedData, dwDataLen);
*lpDecryptedData = new BYTE[dwDataLen + 1];
SecureZeroMemory(*lpDecryptedData, dwDataLen + 1);
CopyMemory(*lpDecryptedData, lpEncryptedData, dwDataLen);
delete[]lpEncryptedData;
return decryptResult;
}
VOID WriteBytesFile(LPTSTR lpFileName, BYTE *content, DWORD dwDataLen)
{
HANDLE hFile = CreateFile(lpFileName, GENERIC_READ | GENERIC_WRITE, 0x7, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwBytesWritten = 0;
WriteFile(hFile, content, dwDataLen, &dwBytesWritten, NULL);
CloseHandle(hFile);
}
private:
HCRYPTPROV hProvider = NULL;
HCRYPTKEY hKey = NULL;
VOID ReadBytesFile(LPTSTR lpFileName, BYTE **content, DWORD *dwDataLen)
{
HANDLE hFile = CreateFile(lpFileName, GENERIC_READ, 0x7, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwFileLength = 0;
DWORD dwBytesToRead = GetFileSize(hFile, NULL);
DWORD dwBytesRead = 0;
*content = new BYTE[dwBytesToRead + 1];
SecureZeroMemory(*content, dwBytesToRead + 1);
ReadFile(hFile, *content, dwBytesToRead, &dwBytesRead, NULL);
*dwDataLen = dwBytesRead;
CloseHandle(hFile);
}
};
Code d'essai: fichier .cpp principal
#include "stdafx.h"
#include "TestEncryptDecrypt.h"
#include <Windows.h>
#include <wincrypt.h>
int main()
{
TestEncryptDecrypt *edc = new TestEncryptDecrypt();
//Initialize the provider
edc->InitializeProvider(MS_ENHANCED_PROV, PROV_RSA_FULL);
//Generate a 2048-bit asymmetric key pair
edc->Generate2048BitKeys(CALG_RSA_KEYX);
//Export the private/public key pair
edc->ExportPrivatePublicKey(L"privpubkey.txt");
//Export only the public key
edc->ExportPublicKey(L"pubkey.txt");
//Import the public key (destroys the private/public key pair already set)
edc->ImportKey(L"pubkey.txt");
//Encrypt and write some test data to file
edc->EncryptDataWriteToFile(TEXT("Hello World!ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), L"encrypteddata.txt");
//Decrypt the data from file using the same public key (this should fail but it doesn't)
DWORD dwDataLen = 0;
LPBYTE lpDecryptedData = NULL;
edc->DecryptDataFromFile(&lpDecryptedData, L"encrypteddata.txt", &dwDataLen);
//Write the supposedly decrypted data to another file
edc->WriteBytesFile(L"decrypteddata.txt", lpDecryptedData, dwDataLen);
//Clear data
delete[] lpDecryptedData;
delete edc;
return 0;
}
Malheureusement je ne suis pas l'occasion de travailler avec C++ très souvent si vous peut remarquer quelques problèmes. N'hésitez pas à critiquer de manière constructive.
Est-ce que quelqu'un sait pourquoi je suis capable de déchiffrer des données en utilisant la même clé publique? Mon but est de pouvoir crypter de façon irréversible quelque chose du côté client où il ne peut être décrypté que sur le serveur, où la clé privée se cache.
Edit: Je considérais que la hKey n'a pas été détruite correctement par la méthode importkey, j'ai donc écrit ce cas de test à la place (même résultat - clé publique peut chiffrer et déchiffrer les données):
// CPPTests.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "TestEncryptDecrypt.h"
#include <Windows.h>
#include <wincrypt.h>
int main()
{
TestEncryptDecrypt *edc = new TestEncryptDecrypt();
//Initialize the provider
edc->InitializeProvider(MS_ENHANCED_PROV, PROV_RSA_FULL);
//Generate a 2048-bit asymmetric key pair
edc->Generate2048BitKeys(CALG_RSA_KEYX);
//Export the private/public key pair
edc->ExportPrivatePublicKey(L"privpubkey.txt");
//Export only the public key
edc->ExportPublicKey(L"pubkey.txt");
//Destroy everything and load up only the public key to write some encrypted data
delete edc;
edc = new TestEncryptDecrypt();
edc->InitializeProvider(MS_ENHANCED_PROV, PROV_RSA_FULL);
edc->ImportKey(L"pubkey.txt");
//Encrypt and write some test data to file
edc->EncryptDataWriteToFile(TEXT("Hello World!ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), L"encrypteddata.txt");
//Destroy everything and load up only the public key to read some encrypted data
delete edc;
edc = new TestEncryptDecrypt();
edc->InitializeProvider(MS_ENHANCED_PROV, PROV_RSA_FULL);
edc->ImportKey(L"pubkey.txt");
//Decrypt the data from file using the same public key (this should fail but it doesn't)
DWORD dwDataLen = 0;
LPBYTE lpDecryptedData = NULL;
edc->DecryptDataFromFile(&lpDecryptedData, L"encrypteddata.txt", &dwDataLen);
//Write the supposedly decrypted data to another file
edc->WriteBytesFile(L"decrypteddata.txt", lpDecryptedData, dwDataLen);
//Clear data
delete[] lpDecryptedData;
delete edc;
return 0;
}
Peut-être l'hypothèse ici '// Importer la clé publique (détruit la paire de clés privée/publique déjà définie)' n'est pas correct? Et si vous réinstanciez 'edc' juste avant cela? – Kenney
@Kenney Je pensais que d'abord, aussi. J'ai pensé que peut-être le CryptDestroyKey dans la fonction d'importation ne faisait pas son travail. La destruction puis la ré-instanciation de l'instance d'edc permettent toujours le décryptage du contenu chiffré tant que I Initialise le même fournisseur et charge avec le blob de clé publique ou privée. – RyanH
@zaph Je veux dire que la fonction CryptDecrypt sous-jacente devrait renvoyer un 0 indiquant l'échec de décryptage et, par conséquent, lpDecryptedData devrait rester NULL et produire un fichier decrypteddata.txt vierge. Au lieu de cela, le fichier decrypteddata.txt est produit avec les résultats parfaitement décryptés. – RyanH