Microsoft ECSPを使用してRSA公開キーのみで小さなデータブロックを暗号化する方法は?

StackOverflow https://stackoverflow.com/questions/295345

  •  08-07-2019
  •  | 
  •  

質問

512ビットのRSA公開キーを使用して小さなデータブロック(16バイト)を暗号化する必要があります-MS CSP APIを除き、私が知っているほとんどの暗号化ライブラリにとっては非常に簡単な作業です。 CryptEncrypt 関数のドキュメントには、

  

Microsoft Enhanced Cryptographic Providerは、RSA公開キーによる直接暗号化とRSA秘密キーによる復号化をサポートしています。暗号化はPKCS#1パディングを使用します。

それは私にはうまくいきませんでした。まあ、私のコードは動作し、正しいサイズの暗号化されたデータブロックを生成しますが、opensslはそれを解読できません。 CryptEncryptはまだ対称暗号を使用しているようです。

残念ながら、私が見つけたすべての例は、暗号化と対称暗号を組み合わせたものを参照しているので、間違いなく作業を容易にする手元の実例はありません。

誰かにそのような例を教えてもらえますか、それとも私が見逃した明らかな落とし穴がないか教えてください。

ありがとう。

役に立ちましたか?

解決

これはエンディアンネスの問題のようです。 Microsoftの CryptEncrypt 関数暗号文をリトルエンディアン形式で返しますが、OpenSSLはビッグエンディアン形式のデータを期待しています。 OpenSSLに渡す前に、暗号化されたデータを逆にする必要があります。

他のヒント

コードは次のとおりです(誰かがこのトピックをグーグルで検索した場合に備えて):

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
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top