Spaces:
Configuration error
Configuration error
/** | |
* 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; | |
}; | |