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