You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
/** * Hash-based Message Authentication Code implementation. Requires a message * digest object that can be obtained, for example, from forge.md.sha1 or * forge.md.md5. * * @author Dave Longley * * Copyright (c) 2010-2012 Digital Bazaar, Inc. All rights reserved. */ var forge = require('./forge'); require('./md'); require('./util');
/* HMAC API */ var hmac = module.exports = forge.hmac = forge.hmac || {};
/** * Creates an HMAC object that uses the given message digest object. * * @return an HMAC object. */ hmac.create = function() { // the hmac key to use
var _key = null;
// the message digest to use
var _md = null;
// the inner padding
var _ipadding = null;
// the outer padding
var _opadding = null;
// hmac context
var ctx = {};
/** * Starts or restarts the HMAC with the given key and message digest. * * @param md the message digest to use, null to reuse the previous one, * a string to use builtin 'sha1', 'md5', 'sha256'. * @param key the key to use as a string, array of bytes, byte buffer, * or null to reuse the previous key. */ ctx.start = function(md, key) { if(md !== null) { if(typeof md === 'string') { // create builtin message digest
md = md.toLowerCase(); if(md in forge.md.algorithms) { _md = forge.md.algorithms[md].create(); } else { throw new Error('Unknown hash algorithm "' + md + '"'); } } else { // store message digest
_md = md; } }
if(key === null) { // reuse previous key
key = _key; } else { if(typeof key === 'string') { // convert string into byte buffer
key = forge.util.createBuffer(key); } else if(forge.util.isArray(key)) { // convert byte array into byte buffer
var tmp = key; key = forge.util.createBuffer(); for(var i = 0; i < tmp.length; ++i) { key.putByte(tmp[i]); } }
// if key is longer than blocksize, hash it
var keylen = key.length(); if(keylen > _md.blockLength) { _md.start(); _md.update(key.bytes()); key = _md.digest(); }
// mix key into inner and outer padding
// ipadding = [0x36 * blocksize] ^ key
// opadding = [0x5C * blocksize] ^ key
_ipadding = forge.util.createBuffer(); _opadding = forge.util.createBuffer(); keylen = key.length(); for(var i = 0; i < keylen; ++i) { var tmp = key.at(i); _ipadding.putByte(0x36 ^ tmp); _opadding.putByte(0x5C ^ tmp); }
// if key is shorter than blocksize, add additional padding
if(keylen < _md.blockLength) { var tmp = _md.blockLength - keylen; for(var i = 0; i < tmp; ++i) { _ipadding.putByte(0x36); _opadding.putByte(0x5C); } } _key = key; _ipadding = _ipadding.bytes(); _opadding = _opadding.bytes(); }
// digest is done like so: hash(opadding | hash(ipadding | message))
// prepare to do inner hash
// hash(ipadding | message)
_md.start(); _md.update(_ipadding); };
/** * Updates the HMAC with the given message bytes. * * @param bytes the bytes to update with. */ ctx.update = function(bytes) { _md.update(bytes); };
/** * Produces the Message Authentication Code (MAC). * * @return a byte buffer containing the digest value. */ ctx.getMac = function() { // digest is done like so: hash(opadding | hash(ipadding | message))
// here we do the outer hashing
var inner = _md.digest().bytes(); _md.start(); _md.update(_opadding); _md.update(inner); return _md.digest(); }; // alias for getMac
ctx.digest = ctx.getMac;
return ctx; };
|