如何通过在 java 中指定不同的输入来生成有效的 RSA 1024 位 public 和私钥?

How can I generate valid RSA 1024 bits public and private keys by specifying different inputs in java?

(如果您不熟悉这个问题,请跳至 编辑、编辑 部分)

我可以使用以下代码生成随机有效的 RSA 1024 位 public 和私钥:

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");    
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKeyGenerated = keyPair.getPublic(); //Sun RSA public key, 1024 bits
PrivateKey privateKeyGenerated = keyPair.getPrivate(); //sun.security.rsa.RSAPrivateCrtKeyImpl@fffbfe07

以上代码中的注释给出了调试器的详细信息。

我不想随机生成 public 和私钥,而是指定输入以生成有效密钥。类似于(link,在下面的评论中):

SecureRandom secureRandom = new SecureRandom();
BigInteger p = new BigInteger("41");
BigInteger q = new BigInteger("13");
BigInteger g = new BigInteger("17");
//http://www.javadocexamples.com/java_source/sun/security/provider/DSAKeyPairGenerator.java.html
//copying the methods generateKeyPair, generateX, generateY
KeyPair keyPair = generateKeyPair(p, q, g, secureRandom);
PublicKey publicKeyGenerated = keyPair.getPublic(); //Sun DSA Public Key
PrivateKey privateKeyGenerated = keyPair.getPrivate(); //DSAPrivateKey@fffa5e6a

使用上面的代码,我没有像第一个示例那样获得有效的 RSA 密钥。

如何通过在 java 中指定不同的输入来生成我自己的有效 RSA 1024 位 public 和私钥?

编辑,回复罗伯特:

是的,我希望使用用户定义的值创建 public 和私钥,而不是随机的。为了回应您提供的link,我写了这个:

BigInteger q = new BigInteger("114...15741");  //big prime number
BigInteger g = new BigInteger("65537"); //modulus
RSAPublicKeySpec publicSpec = new RSAPublicKeySpec(q, g);
RSAPrivateKeySpec privateSpec = new RSAPrivateKeySpec(q, g);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey publicKey = kf.generatePublic(publicSpec);
PrivateKey privateKey = kf.generatePrivate(privateSpec);

我创建了随机密钥,然后将我为 public 密钥获得的指数和模数的值放入变量 qg 以上。我得到相同的 public 密钥,但我没有得到相同的私钥。我尝试添加另一个大素数,而不是 q 但我并没有真正得到我期望的答案。调试器显示出差异。如何创建有效的 public 和私钥?

EDIT, EDIT, 回复 mnistic

把事情整合起来

//randomly generate public and private keys
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");    
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKeyGenerated = keyPair.getPublic(); //Sun RSA public key, 1024 bits
PrivateKey privateKeyGenerated = keyPair.getPrivate(); //sun.security.rsa.RSAPrivateCrtKeyImpl@fffbfe07

//pull out the exponents and modulus
BigInteger publicExponent = ((RSAPublicKey)keyPair.getPublic()).getPublicExponent();
BigInteger privateExponent = ((RSAPrivateKey)keyPair.getPrivate()).getPrivateExponent();
BigInteger modulus = ((RSAPublicKey)keyPair.getPublic()).getModulus();

//generate public and private keys using the above details
RSAPublicKeySpec publicSpec = new RSAPublicKeySpec(modulus, publicExponent);
RSAPrivateKeySpec privateSpec = new RSAPrivateKeySpec(modulus, privateExponent);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey publicKey = kf.generatePublic(publicSpec);
PrivateKey privateKey = kf.generatePrivate(privateSpec);

//check to see that the keys are the same
System.out.println((new BigInteger(publicKeyGenerated.getEncoded())).toString());
System.out.println((new BigInteger(publicKey.getEncoded())).toString());
System.out.println((new BigInteger(privateKeyGenerated.getEncoded())).toString());
System.out.println((new BigInteger(privateKey.getEncoded())).toString());
//the private keys are different :(

私钥不一样,这是怎么回事?

您将 public 指数传递给 RSAPublicKeySpecRSAPrivateKeySpec,这是错误的。 RSAPrivateKeySpec 需要私有指数。如果您想从您的第一个代码片段中重新生成密钥,您可以通过以下方式获取模数和指数:

BigInteger publicExponent = ((RSAPublicKey)keyPair.getPublic()).getPublicExponent();
BigInteger privateExponent = ((RSAPrivateKey)keyPair.getPrivate()).getPrivateExponent();
BigInteger modulus = ((RSAPublicKey)keyPair.getPublic()).getModulus();

然后重新生成密钥:

RSAPublicKeySpec publicSpec = new RSAPublicKeySpec(modulus, publicExponent);
RSAPrivateKeySpec privateSpec = new RSAPrivateKeySpec(modulus, privateExponent);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey publicKey = kf.generatePublic(publicSpec);
PrivateKey privateKey = kf.generatePrivate(privateSpec);

注意:要使私钥编码匹配,您可以尝试以下操作(使用RSAPrivateCrtKeySpec

BigInteger crtCoefficient = ((RSAPrivateCrtKey)keyPair.getPrivate()).getCrtCoefficient();
BigInteger primeExponentP = ((RSAPrivateCrtKey)keyPair.getPrivate()).getPrimeExponentP();
BigInteger primeExponentQ = ((RSAPrivateCrtKey)keyPair.getPrivate()).getPrimeExponentQ();
BigInteger p = ((RSAPrivateCrtKey)keyPair.getPrivate()).getPrimeP();
BigInteger q = ((RSAPrivateCrtKey)keyPair.getPrivate()).getPrimeQ();
BigInteger publicExponent = ((RSAPrivateCrtKey)keyPair.getPrivate()).getPublicExponent();
BigInteger privateExponent = ((RSAPrivateCrtKey)keyPair.getPrivate()).getPrivateExponent();
RSAPrivateCrtKeySpec crtKeySpec = new RSAPrivateCrtKeySpec(modulus, publicExponent, privateExponent, p, q, primeExponentP, primeExponentQ, crtCoefficient);
...
PrivateKey privateKey = kf.generatePrivate(crtKeySpec);