问题
I am working with the keybase.io API - trying to drive it from javascript. Logging in is a two step process. The second step is detailed at https://keybase.io/docs/api/1.0/call/login.
I am stuck on the following;
The server and the client share this secret, and for the client to successfully log the user in, it must prove knowledge of this secret to the server. To protect against replay attacks, it does not send the secret itself. Rather, it treats pwh as MAC key, and MACs the temporary login_session retrieved in the previous step:
hmac_pwh = HMAC-SHA512(pwh, base64decode(login_session))
Both inputs are in binary format; the pwh key was output in binary format from scrypt above, and the login_session is base64-decoded and then fed into HMAC in binary.
I am using the CryptoJS library which gives the following example for implementation
var hash = CryptoJS.HmacSHA256('Message','Secret Passphrase');
I have a couple of problems;
as a matter of terminology does 'MAC key' equal 'Secret Passphrase' and hence the CryptoJS function parameters are reversed in their order vs the code example given on Keybase?
The CryptoJS example has plain ascii inputs whilst the instructions on Keybase are to feed binary inputs. When I try and feed it a uint8array parameter (which is what I get from the previous step in using the keybase API) it keels over as follows;
TypeError: g.clamp is not a function
e,m=4*h; g.sigBytes>m&&(g=f.finalize(g)); g.clamp(); for(var r=this._oKey=g.clone()
回答1:
CryptoJS.HmacSHA256()
happily takes its own WordArray
as a key. So you only need to convert your UInt8Array
to CryptoJS' WordArray
.
This post provides such an (untested) converter created by Vincenzo Ciancia:
CryptoJS.enc.u8array = {
/**
* Converts a word array to a Uint8Array.
*
* @param {WordArray} wordArray The word array.
*
* @return {Uint8Array} The Uint8Array.
*
* @static
*
* @example
*
* var u8arr = CryptoJS.enc.u8array.stringify(wordArray);
*/
stringify: function (wordArray) {
// Shortcuts
var words = wordArray.words;
var sigBytes = wordArray.sigBytes;
// Convert
var u8 = new Uint8Array(sigBytes);
for (var i = 0; i < sigBytes; i++) {
var byte = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
u8[i]=byte;
}
return u8;
},
/**
* Converts a Uint8Array to a word array.
*
* @param {string} u8Str The Uint8Array.
*
* @return {WordArray} The word array.
*
* @static
*
* @example
*
* var wordArray = CryptoJS.enc.u8array.parse(u8arr);
*/
parse: function (u8arr) {
// Shortcut
var len = u8arr.length;
// Convert
var words = [];
for (var i = 0; i < len; i++) {
words[i >>> 2] |= (u8arr[i] & 0xff) << (24 - (i % 4) * 8);
}
return CryptoJS.lib.WordArray.create(words, len);
}
};
来源:https://stackoverflow.com/questions/29448968/implementing-hmac-sha256-for-keybase-in-javascript