在Java中使用已知参数创建RSA密钥

18

我正在实现必应返现功能。为了验证来自Bing的请求是否有效,他们提供了一个签名。该签名是使用RSA加密的URL的160位SHA-1哈希值。

微软提供了RSA“公钥”,包括模数和指数,以便我可以解密哈希。

是否有办法创建Java密钥对象以按照Microsoft的说法解密哈希?

我找到的所有内容都会自动生成RSA密钥对,因为这是RSA的工作方式。如果可能的话,我真的很想使用Java对象,因为这显然比手工编码的解决方案更可靠。

他们提供的示例代码是.NET的,并使用.NET库函数来验证哈希。具体来说,是RSACryptoServiceProvider.VerifyHash()。

3个回答

38
RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent);
KeyFactory factory = KeyFactory.getInstance("RSA");
PublicKey pub = factory.generatePublic(spec);
Signature verifier = Signature.getInstance("SHA1withRSA");
verifier.initVerify(pub);
verifier.update(url.getBytes("UTF-8")); // Or whatever interface specifies.
boolean okay = verifier.verify(signature);

密码学中,Cipher类在DECRYPT_MODE模式下是否接受公钥? - meleager
是的,大多数供应商的RSA密码实现将接受公钥进行解密。他们甚至会检查正确的填充。然而,最好使用“Signature”实例。我会更新我的答案来演示。 - erickson
1
顺便提一下,如果您需要使用Base-64格式(通常在OpenID JWKS响应等中)创建ne所需的BigInteger,请使用new BigInteger(1, org.springframework.util.Base64Utils.decodeFromUrlSafeString((String) key.get("n")))(或支持URL安全解码的其他Base-64库) - 强调将1作为BigIntegersignum - Janaka Bandara

3
使用java.security.spec.RSAPublicKeySpec。它可以从指数和模数构造密钥。然后使用java.security.KeyFactory.generatePublic(),将密钥规范作为参数。

1

类似这样的代码应该可以解决问题:

  private PublicKey convertPublicKey(String publicKey) throws Exception{
    PublicKey pub = null;

    byte[] pubKey = Hex.decodeHex(publicKey.toCharArray());
    X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(pubKey);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    pub = (RSAPublicKey) keyFactory.generatePublic(pubSpec);

    return pub;
  }

假设公钥以十六进制字符串的形式给出,并且您需要使用 Apache Commons Codec 库

如果您的密钥格式不同,请尝试使用 KeyFactory 获取更多信息。


我需要去检查一下我们是否有那个库或者是否能够获取它。此外,Cipher对象在DECRYPT_MODE下会接受公钥吗?这对我来说似乎很不合理。 - meleager
如果您使用的是Sun JRE,则可以。但如果使用IBM版本,则不行。巧合的是,使用Bouncy Castle加密提供程序的IBM JRE也可以正常工作。 - Jason Nichols
看起来有些反向,但实际上你正在解密“签名”哈希。一旦解密,你计算的哈希和微软给你的哈希应该匹配。 - Jason Nichols
1
...但这是通过困难的方式来完成,而Erickson已经用正确的方式完成了。 - President James K. Polk
如果原帖作者的密钥是以十六进制字符串形式(而不是模数/指数格式)存在的,我知道这已经是老话题了,但还是想评论一下... 我认为问题陈述中提到了“我有RSA密钥模数和指数”。因此...这里提供的代码无法帮助。除非还有一种从模数和指数获取十六进制字符串的方法。 - Cheeso
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接