I generated a keypair in python using pycrypto
key=RSA.generate(bit_size,os.urandom)
exportedPrivateKey = key.exportKey('PEM', None, pkcs=1).decode("utf-8")
exportedPublicKey = key.publickey().exportKey('PEM', None, pkcs=1).decode("utf-8")
I wrote a tiny utility that takes the hash of a message and signs the hash...
hash = MD5.new(json_info.encode("utf-8")).digest()
privateKey = RSA.importKey(USER_TOKEN_PRIVATE_KEY)
signature = privateKey.sign(hash,'')
I then wrote something that used the public key to verify that it validated okay..the signature in my tokens work fine..
hash = MD5.new(packet.encode("utf-8")).digest()
publicKey = RSA.importKey(tokenPublicKey)
if publicKey.verify(hash, signature):
return json.loads(packet)
else:
return None
Now, because I needed to use this in Java as well as python, I was porting a similar library to java, but I started running into issues. Namely, my validation would always fail...
I start by creating the PublicKey object from the PEM I exported...
byte[] encoded = Base64.decodeBase64(USER_TOKEN_PUBLIC_KEY);
//decode the encoded RSA public key
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pubKey = kf.generatePublic(keySpec);
I'm able to get the signature, and it's the exact same signature, and the value hashes to the exact same value (well, similar; java represents bytes as signed integers, whereas python represents them as unsigned, but they're the same binary representation). But it seems to always fail to validate my signature..here's what I'm using to do it:
byte[] hash = hasher.digest(packet.getBytes("UTF-8"));
InputStream hashStream = new ByteArrayInputStream(hash);
final Signature sign = Signature.getInstance("MD5withRSA");
sign.initVerify(pubKey);
byte[] buffer = new byte[256];
int length;
while ((length = hashStream.read (buffer)) != -1)
sign.update (buffer, 0, length);
hashStream.close();
System.out.println(sign.verify(signature.getBytes("UTF-8")));
Unfortunately, this only prints false.
The only difference I can really see is that when I pass it to verify in Java, it asks for an array of longs, whereas in python it wants a byte sequence. My best guess was to take the string representation of that long and convert it into a bunch of bytes, but that failed. All of my other attempts failed as well (look at the byte representation of the underlying big integer, look at the byte representation of the array, etc). I feel like I'm missing something REALLY simple, but for the life of me I can't figure out what it is...
For an example of what the signature looks like, in python, I'm given:
[68830459489863257411523011520104203035626147084548742757940226446079486348431212041096334237130703774949375015187747280487790006116898192460644067270457728626039524097117092304115366780581423597886886987279231850120937691165013216970647150989646220735762034864029622135210042186666476516651349805320771941650]