我正在用Java实现RSA公钥加密算法。它需要生成两个随机素数。我一直在使用SecureRandom类生成两个1024位的数字来创建一个2048位的密钥。我使用BigInteger类处理数字。我使用isProbablePrime()函数来确定它是否是素数,确定度为100。然而,我注意到这个函数对负数返回了true,即使根据定义,素数不可能是负数。
关于素数,我指出这可能无关紧要。但重要的是在将1024个随机位转换为整数时,必须考虑哪种方法是正确的;将其视为已签名(像您一样)还是未签名?
例如,在8位中,如果我随机生成11010011
,当被视为素数的无符号整数时,它就是211
。
如果我把相同的比特11010011
当作一个有符号整数,我得到的-45
不是素数,即使你接受负素数。
如果弄错了这一点,您的代码将错误地排除有效密钥,并错误地接受无效密钥。如果为了安全起见,你排除了所有的负片,那么你只会得到1023位素数(两个补码负片的最高有效位总是有一个1)。
因此,处理从位到整数的转换的方法能够避免负数,并避免整个负素数问题,而RSA对所选数字只有一个正确的解释作为密钥。我的猜测是解释是无符号的。
对于"为什么"这个问题,我们无法给您一个明确的答案。为此,您需要与设计API的人员交谈。
我倾向于同意@weston的猜想,即"这无关紧要";请参阅此链接。该链接的另一个结论是,它取决于素数的哪个定义被用于素数是否为负数。(根据最广泛使用的定义,它们不是,但…)
但是,我可以告诉您,实现行为是经过深思熟虑的。该方法的实现如下:
public boolean isProbablePrime(int certainty) {
if (certainty <= 0)
return true;
BigInteger w = this.abs();
if (w.equals(TWO))
return true;
if (!w.testBit(0) || w.equals(ONE))
return false;
return w.primeToCertainty(certainty, null);
}
请注意,在测试之前,它是如何获取候选者的绝对值的。
这种行为已经存在很长一段时间了,(据我所见)ZERO记录了关于它的Java Bug报告。这支持了@weston的猜测。
无论isProbablePrime
的行为是否正确,务实的解决方案都是在测试之前添加一个测试,看看你的候选人是否呈阴性。