2008-11-17 4 views
2

Мне нужно зашифровать небольшой блок данных (16 байтов) с использованием открытого ключа с открытым битом RSA - довольно простая задача для большинства известных мне криптографических библиотек, за исключением MS CSP API. Документация для CryptEncrypt функции утверждает, чтоКак зашифровать небольшой блок данных только с открытым ключом RSA с помощью Microsoft ECSP?

для Microsoft Enhanced Cryptographic Provider поддерживает прямое шифрование с открытым ключом RSA и дешифрования с секретными ключами RSA. Шифрование использует дополнение PKCS # 1.

Это не сработало для меня, хотя. Ну, мой код работает и создает зашифрованный блок данных с правильным размером, но openssl не может его дешифровать. Это похоже на то, что CryptEncrypt по-прежнему использует симметричный cypher.

К сожалению, все примеры, которые я нашел, относятся к комбинированной криптографии с симметричным cypher, поэтому у меня нет рабочего примера на руках, что определенно упростит ситуацию.

Может ли кто-нибудь указать мне на такой пример или сообщить мне, есть ли некоторые из этих очевидных ошибок, которые я пропустил?

спасибо.

ответ

8

Это звучит как вопрос endianness. Функция CryptEncrypt Microsoft возвращает зашифрованный текст в формате little-endian, в то время как OpenSSL ожидает, что его данные будут в формате big-endian. Вам нужно будет отменить зашифрованные данные, прежде чем передавать их в OpenSSL.

+0

Бинго. Спасибо, что указали это. Ловушка была слишком очевидна :) –

7

Вот код (только в случае, если кто-то гугле эту тему вне):

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