【问题标题】:Bouncy Castle vs Java default RSA with OAEPBouncy Castle 与带有 OAEP 的 Java 默认 RSA
【发布时间】:2018-05-11 19:02:32
【问题描述】:

有人可以向我解释为什么这段代码在解密密钥时会在最后一行抛出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

无论哪种方式,我都希望外行能解释一下两者之间的区别。

【问题讨论】:

  • 这些转换是等价的。没有 RSA 的“模式”,它不能那样工作。

标签: java encryption rsa bouncycastle jce


【解决方案1】:

有关更多信息的类似 Stackoverflow 问题,请参阅 Maarten Bodewesthisthis 的回答。

转换字符串的“模式”部分无效。问题是不同的提供者使用不同的默认值。这是不幸的,而且绝对不是最理想的。我们应该责怪 Sun/Oracle 吗?除了对结果不满意,我没有意见。

OAEP 是一个相当复杂的结构,具有两个不同的哈希函数作为参数。密码转换字符串允许您指定其中之一,您已将其指定为 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 的默认设置。

【讨论】:

  • 正是我想要的——谢谢。您能否指出以下声明的证据:“Oracle 提供程序默认为 SHA1,而 BouncyCastle 提供程序默认为 SHA-256。”?我很想知道我自己是如何发现这一点的——很难理解隐藏在那些神奇的转换字符串后面的实现。
  • @MartinDow:不,我找不到它说的地方。因为我怀疑它,所以我能够使用调试器将代码单步调试到 sun.* 类中并查看它。 Oracle/Sun 倾向于尽可能地符合标准,我认为在PKCS#1, section A.2.1 中暗示了maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-22
  • 2023-04-02
  • 1970-01-01
  • 2018-08-15
  • 1970-01-01
相关资源
最近更新 更多