2

我需要使用 512 位 RSA 公钥加密一小块数据(16 字节)——对于我所知的大多数加密库来说,这是一项相当容易的任务,除了 MS CSP API,看起来。CryptEncrypt函数的文档指出

Microsoft Enhanced Cryptographic Provider 支持使用 RSA 公钥的直接加密和使用 RSA 私钥的解密。加密使用 PKCS #1 填充。

但这对我不起作用。好吧,我的代码可以正常工作并生成大小正确的加密数据块,但 openssl 无法解密它。看起来 CryptEncrypt 仍然使用对称密码。

不幸的是,我发现的所有示例都指的是组合密码学与对称密码,所以我手头没有一个工作示例,这肯定会使事情变得更容易。

请任何人指出这样一个例子,或者让我知道我是否错过了一些不那么明显的陷阱?

谢谢你。

4

2 回答 2

8

这听起来像一个字节顺序问题。Microsoft 的CryptEncrypt函数以 little-endian 格式返回密文,而 OpenSSL 希望其数据采用 big-endian 格式。在将加密数据传递给 OpenSSL 之前,您需要对其进行反转。

于 2008-11-18T03:42:05.847 回答
8

这是代码(以防万一有人用谷歌搜索了这个主题):

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, "0123456789012345", 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
于 2008-11-18T16:58:26.753 回答