gecko-dev/browser/components/loop/content/shared/libs/token.js

78 lines
2.2 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
var PREFIX_NAME = 'identity.mozilla.com/picl/v1/';
var bitSlice = sjcl.bitArray.bitSlice;
var salt = sjcl.codec.hex.toBits('');
/**
* hkdf - The HMAC-based Key Derivation Function
* based on https://github.com/mozilla/node-hkdf
*
* @class hkdf
* @param {bitArray} ikm Initial keying material
* @param {bitArray} info Key derivation data
* @param {bitArray} salt Salt
* @param {integer} length Length of the derived key in bytes
* @return promise object- It will resolve with `output` data
*/
function hkdf(ikm, info, salt, length, callback) {
var mac = new sjcl.misc.hmac(salt, sjcl.hash.sha256);
mac.update(ikm);
// compute the PRK
var prk = mac.digest();
// hash length is 32 because only sjcl.hash.sha256 is used at this moment
var hashLength = 32;
var num_blocks = Math.ceil(length / hashLength);
var prev = sjcl.codec.hex.toBits('');
var output = '';
for (var i = 0; i < num_blocks; i++) {
var hmac = new sjcl.misc.hmac(prk, sjcl.hash.sha256);
var input = sjcl.bitArray.concat(
sjcl.bitArray.concat(prev, info),
sjcl.codec.utf8String.toBits((String.fromCharCode(i + 1)))
);
hmac.update(input);
prev = hmac.digest();
output += sjcl.codec.hex.fromBits(prev);
}
var truncated = sjcl.bitArray.clamp(sjcl.codec.hex.toBits(output), length * 8);
callback(truncated);
}
/**
* @class hawkCredentials
* @method deriveHawkCredentials
* @param {String} tokenHex
* @param {String} context
* @param {int} size
* @returns {Promise}
*/
function deriveHawkCredentials(tokenHex, context, size, callback) {
var token = sjcl.codec.hex.toBits(tokenHex);
var info = sjcl.codec.utf8String.toBits(PREFIX_NAME + context);
hkdf(token, info, salt, size || 3 * 32, function(out) {
var authKey = bitSlice(out, 8 * 32, 8 * 64);
var bundleKey = bitSlice(out, 8 * 64);
callback({
algorithm: 'sha256',
id: sjcl.codec.hex.fromBits(bitSlice(out, 0, 8 * 32)),
key: sjcl.codec.hex.fromBits(authKey),
bundleKey: bundleKey
});
});
}