5

New to JS, I'm also learning to use crypto libraries. I don't understand why signing/encoding the same message with the same secret yields differing results.

I'm using jsSHA 1.3.1 found here, and CryptoJS 3.0.2 described here trying to create a base64 sha-1 encoded hmac signature. Here's the code:

In html...

<script src="lib/jsSHA/src/sha1.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.0.2/build/rollups/hmac-sha1.js"></script>

And in js...

var message = "shah me";
var secret = "hide me";
var crypto = CryptoJS.HmacSHA1(message, secret).toString(CryptoJS.enc.Base64) + '=';

var shaObj = new jsSHA(message, "ASCII");
var jssha = shaObj.getHMAC(secret, "ASCII", "B64") + '=';

return  "crypto answer is " + crypto + " jssha answer is " + jssha;

Can you help me explain why these results differ?

crypto answer is 3e929e69920fb7d423f816bfcd6654484f1f6d56= jssha answer is PpKeaZIPt9Qj+Ba/zWZUSE8fbVY=

What's more, both of these differ with the signature I'm generating in rails, like this...

digest  = OpenSSL::Digest::Digest.new('sha1')
raw_signature = OpenSSL::HMAC.digest(digest, "hide me","shah me")
b64_signature = Base64.encode64(raw_signature).strip

(would have liked to supply a fiddle, which seems to be a very good common practice, but that, too, is new to me and I was unable to get one working for this question).

Thanks in advance.

Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
danh
  • 62,181
  • 10
  • 95
  • 136

1 Answers1

7

There are 3 errors in your code :)

You're missing the enc-base64-min.js for crypto-js. Without it, CryptoJS.enc.Base64 will be undefined
You're missing a parameter when calling .getHMAC(). It's .getHMAC(secret, secret_type, hash_type, output_encoding)
With 1+2 adding a = isn't necessary (nor right)

<script src="lib/jsSHA/src/sha1.js"></script>  
<script src="http://crypto-js.googlecode.com/svn/tags/3.0.2/build/rollups/hmac-sha1.js"></script>  
<script src="http://crypto-js.googlecode.com/svn/tags/3.0.2/build/components/enc-base64-min.js"></script>  

var message = "shah me";
var secret = "hide me";
var crypto = CryptoJS.HmacSHA1(message, secret).toString(CryptoJS.enc.Base64);
var shaObj = new jsSHA(message, "ASCII");
var jssha = shaObj.getHMAC(secret, "ASCII", "SHA-1", "B64");

return  "crypto answer is " + crypto + " jssha answer is " + jssha;

Example

Andreas
  • 21,535
  • 7
  • 47
  • 56
  • Brilliant, thank you! That nearly works. I see it works perfectly in the jsfiddle, but updating my code with your suggestions left me with two issues: 1) the jsSHA readme says to omit the algorithm name when including sha1.js. Your suggestion on my localhost generated 'undefined format', choking on "SHA-1" as an output format (I think). I band-aided this by including sha.js rather than sha1.js. Good enough. But tougher: (2) on my rig, crypto appended the trailing '=', but jsSHA did not. The sigs are the same, though, so I am already grateful your great answer! – danh Dec 02 '12 at 18:16
  • I just tried including the js from https://raw.github.../sha1.js as you did on jsfiddle. Doing so now gives me a perfect result. So thanks again. My current project has the js copied locally after downloading the zip of 1.3.1. I'm going to mark this correct (and +1). Can you let me know what the correct practice is for including a lib like jssha? – danh Dec 02 '12 at 18:22
  • A quick search didn't show a CDN which hosts this lib so I would go with a local copy. – Andreas Dec 02 '12 at 18:28
  • Ah, but the local copy fails to add the trailing '='. Should I just append one? I'm a little confused about the best practice for including stuff (and about the semantics of the = in hmac). I've opened a new question here and would be much obliged for more of your help. http://stackoverflow.com/questions/13672414/including-local-vs-remote-javascript-libraries – danh Dec 02 '12 at 18:35
  • Why not just copy the current version from github and use this as I've done in the example? – Andreas Dec 02 '12 at 18:37