【问题标题】:Java rsa decrypt_mode behaviorJava rsa 解密模式行为
【发布时间】:2020-02-03 00:43:31
【问题描述】:

我只是在试验下面的代码,但我不明白为什么代码会这样:

public class Test
{

    public static void main(String args[]) throws Exception
    {
        CertificateFactory certificateFactory1 = CertificateFactory.getInstance("X.509");
        X509Certificate certificate1 = (X509Certificate)certificateFactory1.generateCertificate(Test.class.getResourceAsStream("pub.cer");      //Loading ssl certificate 
        PublicKey pk1 = certificate1.getPublicKey();
        Cipher cipher1 = Cipher.getInstance("RSA/ECB/NOPADDING");
        cipher1.init(Cipher.ENCRYPT_MODE, pk1);
        bytes[] encrypted = cipher1.doFinal("dummy".getBytes("UTF-8");

        CertificateFactory certificateFactory2 = CertificateFactory.getInstance("X.509");
        X509Certificate certificate2 = (X509Certificate)certificateFactory2.generateCertificate(Test.class.getResourceAsStream("pub.cer");     //Loading ssl certificate
        PublicKey pk2 = certificate2.getPublicKey();
        Cipher cipher2 = Cipher.getInstance("RSA/ECB/NOPADDING");
        cipher2.init(Cipher.DECRYPT_MODE, pk2);
        bytes[] decrypted = cipher2.doFinal(encrypted);
    }
}

为什么在byte[] 解密时我得到doFinal 的输出?我正在使用 jdk1.8.0_192。

因为我使用公钥进行解密,并且在非对称公钥加密中,我们可以使用公钥加密并使用私钥解密。

有人可以解释一下并希望有文档支持吗?

【问题讨论】:

  • 您的示例甚至无法编译。请不要输入代码,而是复制粘贴。
  • 无法重现,每次都出现异常。请尝试生成MCVE,否则我怀疑我们能否为您提供帮助。
  • 您可以使用自签名证书进行测试
  • 我确实使用自签名证书对其进行了测试。再次,请生成一个 MCVE。
  • 你能分享一下结果吗?你又得到运行时异常了吗?我只是在执行上面的代码并在 byte[] 中解密输出

标签: java encryption cryptography rsa public-key-encryption


【解决方案1】:

如果你指定NoPadding,那么你基本上会得到模幂。当然,在此之前还有一个步骤是将二进制输入转换为数字,然后再将数字编码为二进制。有趣的是,加密和解密都是如此,因为这些操作对于 RSA 来说是相当对称的。

唯一的区别是您首先使用公钥进行加密,私钥进行解密。但是,有时您必须创建自己的验证 方案。在这种情况下,带有公钥的原始模幂 会很好地为您提供(通常填充的)结果。因此,使用公钥解密是有道理的,即使从技术上讲它不应该被称为解密。

总而言之,如果您的输入大小合适,而不仅仅是将输入解码为数字,那么模块化加密(或解密)和最终编码结果将永远失败。因此,您只需获得与模数相同大小的输出,即以字节为单位的密钥大小。 RSA 的 unpadding 可能会失败。但是您的代码会运行,因为您不进行任何取消填充。

当然,如果你使用了错误的模数和指数,解密的结果将没有任何意义;它看起来像一个介于 0 和用于最后一次操作的模数之间的随机数。

【讨论】:

  • @Maarten Bodewes,感谢您的精彩解释
  • 注意“朴素”的 RSA——只有 1977 年 CACM 论文中的模幂运算——被发现是不安全的,并被填充版本所取代,其中签名与加密确实不同,大约 30 年前。即使是 PKCS1 填充的加密也不是完全安全的,并且在 20 年前被 OAEP 改进过;谷歌“Bleichenbacher 攻击”。在 crypto.SX 和 security.SX 上有很多个问题。
【解决方案2】:

https://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html#init(int,%20java.security.Key)

抛出: InvalidKeyException - 如果给定密钥不适合初始化此密码,或者需要无法从给定密钥确定的算法参数,或者如果给定密钥的密钥大小超过最大允许密钥大小(根据配置的管辖权策略文件确定) .

解密模式下的 RSA 需要 PrivateKey 实例而不是 PublicKey,因此上述示例的情况 2 会抛出此异常。

如果您想知道为什么它不会产生编译时错误,PublicKey 和 PrivateKey 都扩展了 Key Class,因此您的代码的两种情况都满足 Cipher.init(int,Key) 签名。

【讨论】:

  • 最初我也认为这段代码会产生异常,但实际上我得到了 byte[] 中的输出解密,看起来 java 再次加密了输入数据
  • RSA 的 SunJCE Cipher 实例是一个例外;由于早年普遍错误地认为“RSA 签名只是向后加密”,它接受带有 RSAPrivateKey 的 ENCRYPT_MODE 和带有 RSAPublicKey 的 DECRYPT_MODE 并且实际上执行 PKCS1v1.5 签名,或者带有“块类型 1”正如 Maarten 所说,填充或无填充,而不是加密。参见例如hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/69c4f673b33e/src/share/…
【解决方案3】:

这些黑客入侵了我的手机已经使用了这种方法,导致它没有被加密..(除其他外)我的手机不会像植根于他们的计算机一样更新..

【讨论】:

    猜你喜欢
    • 2010-11-17
    • 2013-11-06
    • 1970-01-01
    • 2014-11-24
    • 2014-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-10
    相关资源
    最近更新 更多