|
|
- /**
- * 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;
- };
|