为什么大型 RSA 密钥不加密为唯一值?



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

创建加密的 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,则每次运行都会产生一个唯一的值......

您正在执行原始/教科书 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,所以对于这些素数的大小,你的值只比模量大"几位",所以模值很重要。

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

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

最新更新