18

I'm working on implementing Bing Cashback. In order to verify an incoming request from Bing as valid they provide a signature. The signature is a 160-bit SHA-1 hash of the url encrypted using RSA.

Microsoft provides the RSA "public key", modulus and exponent, with which I'm supposed to decrypt the hash.

Is there a way to create the Java key objects needed to decrypt the hash as Microsoft says?

Everything I can find creates RSA key pairs automatically since that's how RSA is supposed to work. I'd really like to use the Java objects if at all possible since that's obviously more reliable than a hand coded solution.

The example code they've provided is in .NET and uses a .NET library function to verify the hash. Specifically RSACryptoServiceProvider.VerifyHash()

meleager
  • 183
  • 1
  • 1
  • 5

3 Answers3

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);
erickson
  • 265,237
  • 58
  • 395
  • 493
  • Will Cipher take a public key in DECRYPT_MODE? – meleager Jan 07 '10 at 21:05
  • Yes, the RSA cipher implementation of most providers will accept a public key for decryption. They will even check for the correct padding. However, it is better to use a `Signature` instance. I'll update my answer to demonstrate. – erickson Jan 07 '10 at 21:09
  • 1
    FWIW, to create the necessary `BigInteger` for `n` and `e`, in case you have the two values in base-64 form (as is common with OpenID JWKS responses etc), use `new BigInteger(1, org.springframework.util.Base64Utils.decodeFromUrlSafeString((String) key.get("n")))` (or another base-64 library that supports URL-safe decoding) - emphasis on having `1` as the `signum` of `BigInteger` – Janaka Bandara Nov 19 '21 at 02:15
3

Use java.security.spec.RSAPublicKeySpec. It can construct a key from exponent and modulus. Then use java.security.KeyFactory.generatePublic() with key spec as a parameter.

Seva Alekseyev
  • 59,826
  • 25
  • 160
  • 281
0

Something like this should do the trick:

  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;
  }

This assumes the Public key is given as a hex string, and you'll need the Apache Commons Codec library

If you have the key in a different format, try the KeyFactory for more information.

Jason Nichols
  • 11,603
  • 5
  • 34
  • 53
  • I'll have to check and see if we have that library or if we can get it. Additionally will the Cipher object take a public key in DECRYPT_MODE? This seems very backwards to me. – meleager Jan 07 '10 at 21:01
  • It will if you're using the Sun JRE, but not the IBM version. Coincidentally, the an IBM JRE utilizing the Bouncy Castle crypto provider will also work. – Jason Nichols Jan 07 '10 at 21:04
  • It may seem backwards,but what you're doing is essentially decrypting the 'signed' hash. Once decrypted, the hash you computed and the hash given to you by Microsoft should match. – Jason Nichols Jan 07 '10 at 21:08
  • 1
    ...but this is the hard way of doing what erickson has done the right way. – President James K. Polk Jan 09 '10 at 03:34
  • My code above is perfectly correct (and works). If the original poster has the key in a hex String (instead of modulus/exponent format), it's the only answer that will actually help him. Ironic that I'm the one who got no points for it. – Jason Nichols Jan 09 '10 at 13:51
  • I understand what's going on now. It's an interesting verification process, really all I'm doing is verifying that the hash was calculated and encrypted correctly. Since essentially anyone can do this with no ill effect decrypting with the public key is fine. Not to be contrary but Erickson's code was actually quite useful. While I appreciate your taking the hex encoding into consideration Erickson's code is a little cleaner. Thanks again for the help. – meleager Jan 12 '10 at 17:53
  • *If the original poster has the key in a hex String (instead of modulus/exponent format),* I know this is old, but, just commenting... I think the question stated "I have the RSA key modulus and exponent". So ... the code provided here won't help. Unless there is also a way to get the hex string from the modulus and exponent. – Cheeso Oct 08 '15 at 18:10