【问题标题】:Why aren't large RSA keys encrypting to a unique value?为什么大型 RSA 密钥不加密为唯一值?
【发布时间】:2020-01-16 01:48:43
【问题描述】:

我正在使用 BigInteger 的 probablePrime 方法计算两个 2048 位素数,如下所示:BigInteger.probablePrime(2048, new Random());。我们分别称这些素数为pq。我正在使用以下代码计算私有指数:BigInteger.TWO.multiply(r).add(BigInteger.ONE).divide(e); 其中e 相当于BigInteger.valueOf(3)r 相当于一个BigInteger,其值为:(p - 1)(q - 1)

创建加密的 BigInteger 如下:message.modPow(e, r),其中message 是一个 BigInteger。

假设我想加密774356626352684872522728355634287624183747537718011900969524254770659766752605764866132228010801740792162094。这个大整数是“敏捷的棕狐跳过了懒惰的狗”。先转换成二进制,再转换成十进制。我的结果是464326058229369014486528960945777245568243099145851675968955902027904135435059026247893552949145149936678174588724345105141605583511438062567406913039976998983678282605288609470234530610515268764924240227134432014767865301287496131771559993377618477929696113174968779730288058725125905006272019930686696412137679303439126584

无论我运行上面的代码多少次,它总是加密到相同的精确值。它生成哪个素数似乎并不重要 - 对于特定的 message 值,加密值始终是上述值。

现在这里变得特别特别,如果我生成 512 位素数,结果是独一无二的。每次我运行上述代码,生成 512 位素数而不是 2048 甚至 1024 位素数时,它每次运行都会生成一个唯一的结果。但是,如果我希望生成 1024 位或 2048 位素数,无论生成什么素数,结果总是相同的。

谁能解释为什么会发生这种情况,或者需要对代码进行哪些更改才能使用 2048 位素数生成唯一的加密整数?具体来说,为什么它适用于 512 位或更低位的素数,而不适用于 1024 位或更大位的素数?如果这不是一个结构最完善的问题,我深表歉意,所以如果有什么令人困惑的地方,请随时要求澄清。

谢谢。

编辑:这是产生问题的代码:

import java.io.IOException;
import java.math.BigInteger;
import java.security.SecureRandom;

public class Yeet {
    public static void main(String[] args) throws IOException {
        int t = (int) (System.currentTimeMillis() / 1000);

        byte[] date = new byte[]{
          (byte) (t >> 24),
          (byte) (t >> 16),
          (byte) (t >> 8),
          (byte) t,
        };  

        BigInteger p = BigInteger.probablePrime(2048, new SecureRandom(date));
        BigInteger q = BigInteger.probablePrime(2048, new SecureRandom(date));
        BigInteger e = BigInteger.valueOf(3);
        BigInteger r = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE));

        BigInteger message = new BigInteger("774356626352684872522728355634287624183747537718011900969524254770659766752605764866132228010801740792162094");

        System.out.println(message.modPow(e, r));
    }
}

根据需要多次运行它。它总是产生464326058229369014486528960945777245568243099145851675968955902027904135435059026247893552949145149936678174588724345105141605583511438062567406913039976998983678282605288609470234530610515268764924240227134432014767865301287496131771559993377618477929696113174968779730288058725125905006272019930686696412137679303439126584。现在,如果我们在第 16 行和第 17 行将 2048 替换为 512,则每次运行都会产生一个唯一值...

【问题讨论】:

  • Random 的文档非常清楚地表明它不适合这种应用程序,建议您改用SecureRandom
  • 感谢您的回复。我已将 Random 换成了 SecureRandom。不幸的是,问题仍然存在。编辑:将尝试使用当前时间播种。
  • @DavidSchwartz Folks,我更新了帖子以包含我正在使用的重现问题的代码示例。谢谢!
  • @Jason SecureRandom 由操作系统播种,不需要随时间播种。这将增加微不足道的熵。
  • RSA 加密应该是m.modPow(e,n),其中n 是p * q -- 不是 r。解密同上,一旦你正确计算了d,如下所示你不会。

标签: java cryptography rsa biginteger key-pair


【解决方案1】:

您正在执行原始/教科书 RSA,其中加密只是与公共指数的模幂运算。好吧,当然还有一些转换或更改或解释到/从整数。

现在,您的情况下的公共指数非常小:3。因此,取幂后小的输入明文很可能小于模数。 The quick brown fox jumped over the lazy dog. 是 45 个字符/字节,或 360 位。如果您有一个 360 位数并且您使用 3 执行幂运算,那么您将得到 360 x 3 = 1080 位的值,远低于 2 x 2048 = 4096 位模数,因此不会执行模减少。 2 x 512 = 1024,因此对于这些素数大小,您的值仅比模数大“几位”,因此模数很重要。

当然,您可以使用值为 65537 的费马的第五个素数 (F4)。这将导致模块化减少为 360 x 65537 > 4096。但是,为了安全起见,您应该使用填充方法,例如 PKCS#1 v2.2 中指定的方法。这些将扩展明文值,因此取决于明文的数字表示将更接近模数,以位为单位。模幂运算的结果实际上至少会执行一些模数减少,因此取决于不同的模数值。

更重要的是,PKCS#1 v2.2 中指定的 PKCS#1 v1.5 或 OAEP 填充本身是随机的,因此加密相同的明文将导致不同的密文 即使相同的密钥对 /使用模数。对于较大的密钥大小,即使是指数 3 也被认为是安全的,尽管大多数 RSA 实现(OpenSSL、Java、C#/.NET 等)仍然首选 F4。

【讨论】:

  • @Marteen Bodewes,非常感谢您富有洞察力的回答!我一定会研究 PKCS#1 v2.2。如果我想暂时用 F4 代替 3,代码还需要做哪些其他的更改?例如,如果我只是将 3 与 65537 交换,在解密时它会返回一个与我开始时不同的值。
  • 嗯,你从来没有说过我现在看到的密钥大小,只是一秒钟。不过,您需要确保您的 RSA 实现是正确的,然后才能看到您的值返回,例如N = P x Q 其中 N 是模数。最好将其与已知的良好实现进行比较。
  • 请参阅this(维基百科)以获得对密钥生成的正确描述。你还没到那里。
  • 感谢您的回复。根据那篇文章,我认为我可能会错误地计算私有指数,但我不确定。正如 OP 中提到的,我使用的当前公式是:BigInteger d = BigInteger.TWO.multiply(r).add(BigInteger.ONE).divide(e); 这适用于小公共指数 (3),但它不能正确解密使用 F4 加密的消息。
  • @broment:您的d 公式通常不正确,但它有 $1/e$ 的机会意外给出正确的结果。对于 e=3,你可能很幸运——但即便如此,解密也必须是模 n 而不是 r;请参阅 Q。e=65537 需要更多的运气才能获得正确的 d。
猜你喜欢
  • 1970-01-01
  • 2021-10-24
  • 1970-01-01
  • 2012-06-26
  • 1970-01-01
  • 1970-01-01
  • 2011-12-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多