2012-04-16 89 views
2

我试图在Android上使用Java确定性地生成RSA密钥对。我的要求是,我不能存储密钥对,并且它必须在运行时生成,与之前/未来的运行相同。确定性生成RSA加密密钥对

我的过程是,我会确定性地播种一个随机数字生成器并传递该生成器以创建密钥。我的代码是:

SecureRandom random=SecureRandom.getInstance("SHA1PRNG"); 
random.setSeed(1234); //something device specific will be used to set this 
KeyPairGenerator keyGen=KeyPairGenerator.getInstance("RSA"); 
keyGen.initialize(1024, random); 

KeyPair pair=keyGen.generateKeyPair(); 
PublicKey pub=pair.getPublic(); 
PrivateKey priv=pair.getPrivate(); 

生成的密钥与运行不同。但是,从运行到运行SecureRandom数字是相同的,甚至在不同设备上相同。

我错过了什么?我怎样才能重复生成这些密钥?

谢谢

+0

你为什么要这样做?当然,如果你不想存储RSA密钥对,那么你也不想存储用来生成RSA对的随机种子?奇怪的是,这段代码并没有按照你想要的那样做,但对我来说,似乎你可能会这样做,而没有想到它通过 – 2012-04-16 06:00:09

回答

8

你在做什么?即使这样做,这段代码也会依赖Android上的SHA1PRNG实现,所以它可能随时崩溃。一般来说,setSeed()增加了熵,所以即使您使用相同种子种子SecureRandom,也不能保证获得相同的数字。如果您在桌面Java上尝试此代码,它很可能会失败。到目前为止,它适用于大多数(全部)当前的Android版本,但不能保证。

如果您需要可预测的密钥,则可能需要为每个设备配置预先生成的密钥。如果您需要安全地存储它们,请在ICS上使用KeyChain API,或者在ICS前设备上使用密码保护的密钥库。即使你没有存储真正的密钥,如果有人知道密钥是如何生成的(种子),它们可以生成相同的密钥,并且你的密钥只与种子一样安全。如果它是特定于设备的,那么很可能不难找到。

至于为什么这不起作用,RSA密钥生成器基本上在循环中生成随机BigIntegers,测试素数。主要测试是概率性的,所以你可能会在每次运行中选择不同的素数。你可能想要得到SpongyCastle,在模拟器上运行它并在RSAKeyPairGenerator.java中设置断点来检查究竟发生了什么。

+0

感谢关于密钥生成器如何工作和SpongyCastle实现的详细解释。这是(误导)尝试最大限度地减少应用内购买内容盗版的一部分。我的希望是我可以加密服务器上的内容,并在没有密钥交换的情况下将其交付给客户端,并即时解密内容。我必须在服务器上生成密钥对,将私钥传输给客户端,然后使用KeyStore(如您所建议的)以及一些算法生成的密码来增加难度。 – Aaron 2012-04-17 02:57:00

+0

我看到(种)。您正在尝试实施各种DRM。 RSA可能不是最好的。如果您将密钥传输给客户端,您自然需要确保安全地发生这种情况,这可能并不容易。在想法是将一些设备特定位(IMEI等)放入IAB developerPayload中,并在验证服务器上的签名时获取它。然后使用它来生成绑定到该特定设备的对称(AES)密钥,对内容进行加密并将其发送到设备。设备然后生成相同的对称密钥,并解密内容。 – 2012-04-17 03:35:48

+0

当然,您可能需要散列IMEI等,以便您不收集实际的设备识别信息。 – 2012-04-17 03:42:40