This is a this question, but I'm trying to pass C # code in Java instead of Ruby code in C #, as was the case with the related question. I am trying to verify the encrypted signature returned from the Recurly.js api. Unfortunately, Recurly does not have a Java library to help with its verification, so I have to do a signature verification myself.
In the above question ( this ), the following C # code can generate the hash needed to verify the signature returned with Recurly:
var privateKey = Configuration.RecurlySection.Current.PrivateKey; var hashedKey = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(privateKey)); var hmac = new HMACSHA1(hashedKey); var hash = hmac.ComputeHash(Encoding.ASCII.GetBytes(dataToProtect)); return BitConverter.ToString(hash).Replace("-", "").ToLower();
Re-provides the following sample data on the signature page:
unencrypted verification message : [1312701386, transactioncreate, [account_code: ABC, amount_in_cents: 5000, currency: USD]]
private key : 0123456789ABCDEF0123456789ABCDEF
final signature : 0f5630424b32402ec03800e977cd7a8b13dbd153-1312701386
Here is my Java implementation:
String unencryptedMessage = "[1312701386,transactioncreate,[account_code:ABC,amount_in_cents:5000,currency:USD]]"; String privateKey = "0123456789ABCDEF0123456789ABCDEF"; String encryptedMessage = getHMACSHA1(unencryptedMessage, getSHA1(privateKey)); private static byte[] getSHA1(String source) throws NoSuchAlgorithmException, UnsupportedEncodingException{ MessageDigest md = MessageDigest.getInstance("SHA-1"); byte[] bytes = md.digest(source.getBytes("UTF-8")); return bytes; } private static String getHMACSHA1(String baseString, byte[] keyBytes) throws GeneralSecurityException, UnsupportedEncodingException { SecretKey secretKey = new SecretKeySpec(keyBytes, "HmacSHA1"); Mac mac = Mac.getInstance("HmacSHA1"); mac.init(secretKey); byte[] bytes = baseString.getBytes("ASCII"); return Hex.encodeHexString(mac.doFinal(bytes)); }
However, when I print out the encryptedMessage variable, it does not match the message portion of the sample signature. In particular, I get the value "c8a9188dcf85d1378976729e50f1de5093fabb78" instead of "0f5630424b32402ec03800e977cd7a8b13dbd153".
Update
Per @ M.Babcock, I reprogrammed C # code with the sample data and returned the same result as the Java code. Thus, my hashing approach is correct, but I am transmitting incorrect data (unencryptedMessage). Sigh. I will update this post if / when I can determine what the correct data for encryption is, since the “unencrypted verification message” presented in the Recurly documentation seems to be missing something.
Update 2
The error turned out to be data or the "unencrypted verification message" format. The message in the sample data does not actually encrypt the submitted sample signature, or maybe there is outdated documentation? Anyway, I confirmed that the Java implementation will work for real-world data. Thanks to everyone.