2008-11-17 6 views
2

J'ai besoin de crypter un petit bloc de données (16 octets) en utilisant une clé publique RSA 512 bits - une tâche assez facile pour la plupart des bibliothèques de cryptographie connues, sauf pour l'API MS CSP. Documentation pour la fonction CryptEncrypt indique queComment crypter un petit bloc de données avec seulement une clé publique RSA en utilisant Microsoft ECSP?

Le fournisseur Microsoft Enhanced Cryptographic prend en charge le cryptage direct avec les clés publiques RSA et décryptage avec les clés privées RSA. Le chiffrement utilise le remplissage PKCS # 1.

Cela n'a pas fonctionné pour moi cependant. Eh bien, mon code fonctionne et produit un bloc de données crypté avec la taille correcte, mais openssl ne parvient pas à le déchiffrer. Il ressemble beaucoup à CryptEncrypt utilise encore le chiffrement symétrique. Malheureusement, tous les exemples que j'ai trouvés se réfèrent à la cryptographie combinée avec un chiffrement symétrique, donc je n'ai pas d'exemple pratique pour les mains, ce qui rendrait certainement les choses plus faciles.

Pourriez-vous s'il vous plaît me signaler un tel exemple ou laissez-moi savoir s'il y a des pièges pas si évident que j'ai manqué?

Merci.

Répondre

8

Cela ressemble à un problème endianness. La fonction CryptEncrypt de Microsoft renvoie le texte chiffré au format little-endian, tandis qu'OpenSSL s'attend à ce que ses données soient au format big-endian. Vous devrez inverser les données cryptées avant de les transmettre à OpenSSL.

+0

Bingo. Merci d'avoir signalé cela. L'écueil était trop évident :) –

7

Voici le code (juste au cas où quelqu'un a googlé ce sujet sur):

BYTE *spkiData = SPKI; // X.509 ASN.1 encoded SubjectPublicKeyInfo 
DWORD dwSPKISize = SPKI_SIZE; // 94 bytes for RSA 

DWORD dwBufSize = 0; 
// Get buffer size for decoded spki structure 
CryptDecodeObject(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, spkiData, dwSPKISize, 0, NULL, &dwBufSize); 
BYTE* decBuf = new BYTE[dwBufSize]; 
CryptDecodeObject(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, spkiData, dwSPKISize, 0, decBuf, &dwBufSize); 
// Now decode the RSA Public key itself 
CERT_PUBLIC_KEY_INFO * spki = (CERT_PUBLIC_KEY_INFO *) decBuf; 
// Get buffer size for decoded public key structure 
CryptDecodeObject(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, spki->PublicKey.pbData, spki->PublicKey.cbData, 0, 0, &dwBufSize); 
// Get the RSA public key blob 
BYTE *blobBuf = new BYTE[dwBufSize]; 
CryptDecodeObject(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, spki->PublicKey.pbData, spki->PublicKey.cbData, 0, blobBuf, &dwBufSize); 
// Acquire crypto provider context 
HCRYPTPROV hCryptProv = NULL; 
CryptAcquireContext(&hCryptProv, 0, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); 
// Import key 
HCRYPTKEY key = NULL; 
CryptImportKey(hCryptProv, blobBuf, dwBufSize, 0, 0, &key); 
// Get the key size 
DWORD dwKeySize; 
DWORD dwParamSize = sizeof(DWORD); 
CryptGetKeyParam(key, KP_KEYLEN, (BYTE*) &dwKeySize, &dwParamSize, 0); 
// we need it in bytes for convenience 
dwKeySize /= 8; 
// Now the fun 
// allocate a buffer of key size 
BYTE *data = new BYTE[dwKeySize]; 
// Copy data need to be encrypted 
// With PKCS#1 padding data length can not exceed keysize - 11 bytes 
DWORD dataLen = 16; 
memcpy(data, "", dataLen); 
CryptEncrypt(key, 0, TRUE, 0, data, &dataLen, dwKeySize) 
// now convert it to big endian (for the rest of the world) 
for (int i = 0; i < (dwKeySize/2); i++) { 
    BYTE c = data[i]; 
    data[i] = data[dwKeySize - 1 - i]; 
    data[dwKeySize - 1 - i] = c; 
} 
// now data points to a dwKeySize length block of RSA PKCS#v1.5 encrypted data 
Questions connexes