Question

For now assume this is being done in a browser extension or run locally. I have a use case where I want to hash some data with a cryptographic key using HMAC(key, data). However the key is random bits, not text or some other readable format. I believe the best way to do that is to convert the key to hex or base64 then input that into the hash function.

There is one JavaScript library that can do that and that is jsSHA. It can take an input type of hex, base64 and text for both the key and the text. Unfortunately this library only does the current SHA algorithms, I need a few different algorithms such as SHA3 or Skein.

I have investigated using CryptoJS and jsDigest however it doesn't seem they allow for hex or base64 input, only text.

https://code.google.com/p/crypto-js/
https://github.com/coiscir/jsdigest
  1. Is there another library that can do HMAC with hex/base64 inputs?

  2. Can the above libraries be easily modified to allow hex/base64 inputs?

Update

As @owlstead mentioned you can indeed use CryptoJS to load in hex/base64 as the input. I've added some tests below using all combinations of the key/message in hex/text.

// Test CryptoJS
// CryptoJS.HmacSHA512("Message", "Secret Passphrase");
var wordsKey = CryptoJS.enc.Hex.parse('001122334455');
var wordsMsg = CryptoJS.enc.Hex.parse('aabbccddeeff');
var hash = CryptoJS.HmacSHA512(wordsMsg, wordsKey);
var output = hash.toString(CryptoJS.enc.Hex);

console.log('CryptoJS hex msg and hex key ' + output);

var wordsKey = CryptoJS.enc.Hex.parse('001122334455');
var wordsMsg = CryptoJS.enc.Latin1.parse('aabbccddeeff'); // or simply use string 'aabbccddeeff'
var hash = CryptoJS.HmacSHA512(wordsMsg, wordsKey);
var output = hash.toString(CryptoJS.enc.Hex);

console.log('CryptoJS text msg and hex key ' + output);

var wordsKey = CryptoJS.enc.Latin1.parse('001122334455'); // or simply use string '001122334455' 
var wordsMsg = CryptoJS.enc.Hex.parse('aabbccddeeff');
var hash = CryptoJS.HmacSHA512(wordsMsg, wordsKey);
var output = hash.toString(CryptoJS.enc.Hex);

console.log('CryptoJS hex msg and text key ' + output);

var wordsKey = CryptoJS.enc.Latin1.parse('001122334455'); // or simply use string '001122334455'
var wordsMsg = CryptoJS.enc.Latin1.parse('aabbccddeeff');
var hash = CryptoJS.HmacSHA512(wordsMsg, wordsKey);
var output = hash.toString(CryptoJS.enc.Hex);

console.log('CryptoJS text msg and text key ' + output);

// Test jsSHA
// jsSHA(srcString, inputFormat)
// getHMAC(key, inputFormat, variant, outputFormat)
var shaObj = new jsSHA("aabbccddeeff", "HEX");
var hmac = shaObj.getHMAC("001122334455", "HEX", "SHA-512", "HEX");

console.log('jsSHA hex msg and hex key ' + hmac);

var shaObj = new jsSHA("aabbccddeeff", "TEXT");
var hmac = shaObj.getHMAC("001122334455", "HEX", "SHA-512", "HEX");

console.log('jsSHA text msg and hex key ' + hmac);

var shaObj = new jsSHA("aabbccddeeff", "HEX");
var hmac = shaObj.getHMAC("001122334455", "TEXT", "SHA-512", "HEX");

console.log('jsSHA hex msg and text key ' + hmac);

var shaObj = new jsSHA("aabbccddeeff", "TEXT");
var hmac = shaObj.getHMAC("001122334455", "TEXT", "SHA-512", "HEX");

console.log('jsSHA text msg and text key ' + hmac);

// Test PHP hash_hmac
// string hash_hmac( string $algo , string $data , string $key)
echo 'PHP hash_hmac hex msg and hex key ' . hash_hmac('sha512', "\xaa\xbb\xcc\xdd\xee\xff", "\x00\x11\x22\x33\x44\x55") . '<br>';
echo 'PHP hash_hmac text msg and hex key ' . hash_hmac('sha512', "aabbccddeeff", "\x00\x11\x22\x33\x44\x55") . '<br>';
echo 'PHP hash_hmac hex msg and text key ' . hash_hmac('sha512', "\xaa\xbb\xcc\xdd\xee\xff", "001122334455") . '<br>';
echo 'PHP hash_hmac text msg and text key ' . hash_hmac('sha512', "aabbccddeeff", "001122334455") . '<br>';

And the outputs:

CryptoJS hex msg and hex key 61980b30fed7674f4afae84e32e04d651e8e4b98eb48fde99e9779bb3af6072e56c0b75bb6356fe7bb9d2702d1c4b59eefc987449e8c6275549a6140338be4dd
CryptoJS text msg and hex key afd32064dea61ce40d6f3ccebe9c05d094115f8269c5df7909bc98ccaf43103e1e114ac5b32bb3ebbffa70877992de8814573a6a1b2f3de78bcd17e5807b761d
CryptoJS hex msg and text key 2bc3457beeff6a78d0314d4c3fe7bfa8b185680ececd4573f6d966ade44747d8ac59b75269d034970766aec5265b7fef73d55271f38f62e083f541ca0d679d50
CryptoJS text msg and text key 21ed161ce382581dca99ea41cf8858aa13244eb7edb48ca4cd877b7c925daaf88e70de1339e16bf63c154f6f98a28bdeab6df9a4a69625cba34008368149e22b
jsSHA hex msg and hex key 61980b30fed7674f4afae84e32e04d651e8e4b98eb48fde99e9779bb3af6072e56c0b75bb6356fe7bb9d2702d1c4b59eefc987449e8c6275549a6140338be4dd
jsSHA text msg and hex key afd32064dea61ce40d6f3ccebe9c05d094115f8269c5df7909bc98ccaf43103e1e114ac5b32bb3ebbffa70877992de8814573a6a1b2f3de78bcd17e5807b761d
jsSHA hex msg and text key 2bc3457beeff6a78d0314d4c3fe7bfa8b185680ececd4573f6d966ade44747d8ac59b75269d034970766aec5265b7fef73d55271f38f62e083f541ca0d679d50
jsSHA text msg and text key 21ed161ce382581dca99ea41cf8858aa13244eb7edb48ca4cd877b7c925daaf88e70de1339e16bf63c154f6f98a28bdeab6df9a4a69625cba34008368149e22b
PHP hash_hmac hex msg and hex key 61980b30fed7674f4afae84e32e04d651e8e4b98eb48fde99e9779bb3af6072e56c0b75bb6356fe7bb9d2702d1c4b59eefc987449e8c6275549a6140338be4dd
PHP hash_hmac text msg and hex key afd32064dea61ce40d6f3ccebe9c05d094115f8269c5df7909bc98ccaf43103e1e114ac5b32bb3ebbffa70877992de8814573a6a1b2f3de78bcd17e5807b761d
PHP hash_hmac hex msg and text key 2bc3457beeff6a78d0314d4c3fe7bfa8b185680ececd4573f6d966ade44747d8ac59b75269d034970766aec5265b7fef73d55271f38f62e083f541ca0d679d50
PHP hash_hmac text msg and text key 21ed161ce382581dca99ea41cf8858aa13244eb7edb48ca4cd877b7c925daaf88e70de1339e16bf63c154f6f98a28bdeab6df9a4a69625cba34008368149e22b

Everything seems legit.

Was it helpful?

Solution

CryptoJS accepts WordArray type of input. It is explained for that library that you can do conversions such as:

var words = CryptoJS.enc.Hex.parse('48656c6c6f2c20576f726c6421');

Note that most modern cryptographic algorithms are defined to operate on bits or bytes and that most implementations only accept bytes. Anything that is different from bytes as input for hash functions has to be converted to bytes implicitly or explicitly.

Some cryptographic libraries operate on 32 or 64 bit words instead of bytes. This is due to the fact that some cryptographic functions are best implemented using 32 bit or 64 bit words. Most libraries however hide those kind of implementation details from the user.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top