破解RSA/ECB/OAEPWithSHA-256AndMGF1Padding

26

Java有一种叫做RSA/ECB/OAEPWithSHA-256AndMGF1Padding的模式。那是什么意思呢?

RFC3447公钥密码标准(PKCS) #1: RSA密码规范版本2.1,第7.1.2节解密操作说哈希和MGF都是RSAES-OAEP-DECRYPT的选项。MGF是它自己的函数,在第B.2.1节MGF1中定义,并且它自己的哈希“选项”也是如此。

也许在RSAES-OAEP-DECRYPT和MGF1中,哈希“选项”应该是相同的,或者也许不应该是相同的,对我来说还不清楚。如果它们相同,那么我猜当你使用RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING时,这意味着应该同时使用sha256。但如果它们不应该是相同的,那么你可以在RSAES-OAEP-DECRYPT中使用sha256,例如在MGF1中使用sha1。如果是这种情况,那么sha256应该用于哪个函数?另一个函数应该使用什么哈希算法?

这种情况下ECB是什么意思呢?ECB是一种对称块密码模式。电子代码本。也许它的意思是Java如何处理大于模数的明文?比如将明文分成与模数一样大的块,然后用RSA加密每个块,并将它们连接在一起?我只是猜测..

1个回答

55

OAEP使用单独的哈希调用来哈希(通常为空的)标签以及MGF1的参数(掩码生成函数),用于大多数OAEP填充。

哈希对OAEP的安全性影响不大,因此可以将其保留为默认值。然而,大多数库都会使用相同的哈希算法来进行MGF-1和(始终为空的)标签的哈希。Java默认使用MGF1。

我们可以通过比较使用“OAEPWITHSHA-256ANDMGF1PADDING”实例化的标准Java Cipher与使用“OAEPPadding”和“OAEPParameterSpec”实例化的Cipher来轻松测试此内容:

// --- we need a key pair to test encryption/decryption
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024); // speedy generation, but not secure anymore
KeyPair kp = kpg.generateKeyPair();
RSAPublicKey pubkey = (RSAPublicKey) kp.getPublic();
RSAPrivateKey privkey = (RSAPrivateKey) kp.getPrivate();

// --- encrypt given algorithm string
Cipher oaepFromAlgo = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
oaepFromAlgo.init(Cipher.ENCRYPT_MODE, pubkey);
byte[] ct = oaepFromAlgo.doFinal("owlstead".getBytes(StandardCharsets.UTF_8));
    
// --- decrypt given OAEPParameterSpec
Cipher oaepFromInit = Cipher.getInstance("RSA/ECB/OAEPPadding");
OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-1"), PSpecified.DEFAULT);
oaepFromInit.init(Cipher.DECRYPT_MODE, privkey, oaepParams);
byte[] pt = oaepFromInit.doFinal(ct);
System.out.println(new String(pt, StandardCharsets.UTF_8));

如果您将参数MGF1替换为"SHA-256",代码将因与填充相关的异常而失败,这表明SHA-1确实是默认值。

需要长算法字符串的原因是为了与其他Cipher算法兼容。例如,针对"RSA/ECB/PKCS1Padding"编写的代码不使用任何参数;如果没有更长的字符串,OAEP因此无法作为替代品。


在这种情况下,操作模式"ECB"没有意义,应该是"None"或者完全省略。你只能使用SunRSA提供程序的RSA实现加密单个块。

如果要加密更多数据,请创建一个随机(AES)对称密钥并使用OAEP加密该密钥。然后使用AES密钥加密特定数据。这被称为混合加密系统,因为它使用非对称和对称原语来加密数据。


请注意,OAEP不受JDK 7(1.7)或更早版本支持。OAEP包含在Java运行时的实现要求中自Java 8以来

  • RSA/ECB/OAEPWithSHA-1AndMGF1Padding(1024,2048)
  • RSA/ECB/OAEPWithSHA-256AndMGF1Padding(1024,2048)

一些协议可能要求您在填充中使用SHA-256或SHA-512,因为对于大多数用途而言,SHA-1正在被弃用 - 即使它不直接容易受到此类目的攻击。SHA-224或SHA-384都没有任何意义,因为它们是具有减小输出大小的SHA-256和SHA-512版本,因此需要更多调用来创建填充,而没有提供任何安全优势(是的,测试表明这会导致性能劣势)。


如果您有无效的OAEP密码文本,应首先确保正确使用了标签和MGF1的“默认值”。

选择自己的默认库实现是不可能出错的;最终由协议定义所使用的哈希函数。

不幸的是,不存在强制性默认设置 - 这特别是在协议所有者忘记完全指定算法配置时会造成问题。


5
我在玩弄BouncyCastle加密提供程序时发现,对于RSA / ECB / OAEPWITHSHA-256ANDMGF1PADDING,BouncyCastle似乎有不同的操作方式。也就是说,虽然Java的默认加密提供程序使用sha1作为MGF哈希,但BouncyCastle似乎使用sha256。这应该需要进行独立验证,但这是我观察到的情况。 - neubert
5
我刚验证了这个问题,当sun.security.rsa.RSAPadding与OAEP SHA256一起使用时,它会在MGF1函数中使用SHA1,而bouncy castle则同时使用SHA256,这就是它们不兼容的原因。 - peceps
3
WebCrypto也同时使用它。谢谢 - 这让我感到困惑。 - rich
1
上面的代码示例仅适用于Bouncy Castle提供程序。SunJCE不支持填充“OAEPPadding”(至少在JDK7中不支持)。也许你可以将此作为附注添加进去。 - Heri
1
@MaartenBodewes:当然,你是对的。但你不应该低估行业的懒惰(“不要改变一个运行良好的系统”)。我无法影响我们的客户使用哪个Java版本。而且:是的,我确定:在Oracle 1.7.0_75和OpenJDK 1.7.0-u80中,´´Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding")´´会产生NoSuchAlgorithmException异常。只有在添加BC-Provider之后,密码才能被初始化。 - Heri
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接