web-dev-qa-db-ja.com

弾力がある城vs Java OAEPを使用したデフォルトのRSA

誰かが私に、このコードがキーを復号化するときに最後の行にjavax.crypto.BadPaddingException: Decryption errorをスローする理由を説明できますか?

// Given an RSA key pair...
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.genKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();

// ... and an AES key:
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256);
SecretKey aesKey = keyGenerator.generateKey();

// When I encrypt the key with this Bouncy Castle cipher:
Cipher encryptionCipher = Cipher.getInstance("RSA/NONE/OAEPWithSHA256AndMGF1Padding", "BC");
encryptionCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedKey = encryptionCipher.doFinal(aesKey.getEncoded());

// Then trying to decrypt the key with this cipher...
Cipher decryptionCipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
decryptionCipher.init(Cipher.DECRYPT_MODE, privateKey);
// ... throws `javax.crypto.BadPaddingException: Decryption error` here:
decryptionCipher.doFinal(encryptedKey);

https://stackoverflow.com/a/27886397/66722 の次のステートメントはOAEPを使用するRSAにも当てはまりますか?

「RSA/ECB/PKCS1Padding」は、実際にはECBモードの暗号化を実装していません。プレーンテキスト(または実際には秘密鍵)の単一ブロックの暗号化にのみ使用できるため、「RSA/None/PKCS1Padding」と呼ばれるべきでした。これは、Sun/Oracleの名前の間違いにすぎません。

もしそうなら、私はこれらの変換が同等であり、上記の私のテストに合格することを期待します。両方で同じパディングが指定されているのに、なぜBadPaddingException

いずれにせよ、違いが何であるかについての素人の説明をいただければ幸いです。

6
Martin Dow

詳細についての同様のStackoverflowの質問については、 Maarten Bodewes 回答 this および this を参照してください。

変換文字列の「モード」部分は効果がありません。問題は、さまざまなプロバイダーによって使用されるさまざまなデフォルトです。これは残念なことであり、間違いなく最適ではありません。 Sun/Oracleのせいにする必要がありますか?結果に不満がある以外に意見はありません。

OAEPは、パラメーターとして2つの異なるハッシュ関数を使用するかなり複雑な構造です。暗号変換文字列を使用すると、SHA-256として指定したこれらのいずれかを指定できます。ただし、MGF1関数は、暗号変換文字列で指定できないハッシュ関数によってもパラメーター化されます。 OracleプロバイダーのデフォルトはSHA1ですが、BouncyCastleプロバイダーのデフォルトはSHA-256です。したがって、実際には、相互運用性にとって重要な隠れたパラメータがあります。

解決策は、次の例のようにCipher.init(...)メソッドに OAEPParameterSpec を指定することにより、これらの非表示パラメーターが何であるかをより完全に指定することです。

Cipher encryptionCipher = Cipher.getInstance("RSA/NONE/OAEPWithSHA256AndMGF1Padding", "BC");
OAEPParameterSpec oaepParameterSpec = new OAEPParameterSpec("SHA-256", "MGF1",
                MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT);
encryptionCipher.init(Cipher.ENCRYPT_MODE, publicKey, oaepParameterSpec);
// ...
// ...
// ...
Cipher decryptionCipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
oaepParameterSpec = new OAEPParameterSpec("SHA-256", "MGF1",
                MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT);
decryptionCipher.init(Cipher.DECRYPT_MODE, privateKey, oaepParameterSpec);

最初のものは、Bouncycastleのデフォルトであるため、事実上何もしません。