mirror of
https://github.com/moparisthebest/mail
synced 2024-08-13 16:43:47 -04:00
197 lines
4.9 KiB
JavaScript
197 lines
4.9 KiB
JavaScript
/**
|
|
* 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.
|
|
*/
|
|
(function() {
|
|
/* ########## Begin module implementation ########## */
|
|
function initModule(forge) {
|
|
|
|
/* HMAC API */
|
|
var hmac = 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(md.constructor == String) {
|
|
// create builtin message digest
|
|
md = md.toLowerCase();
|
|
if(md in forge.md.algorithms) {
|
|
_md = forge.md.algorithms[md].create();
|
|
}
|
|
else {
|
|
throw 'Unknown hash algorithm "' + md + '"';
|
|
}
|
|
}
|
|
else {
|
|
// store message digest
|
|
_md = md;
|
|
}
|
|
}
|
|
|
|
if(key === null) {
|
|
// reuse previous key
|
|
key = _key;
|
|
}
|
|
else {
|
|
// convert string into byte buffer
|
|
if(key.constructor == String) {
|
|
key = forge.util.createBuffer(key);
|
|
}
|
|
// convert byte array into byte buffer
|
|
else if(key.constructor == Array) {
|
|
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;
|
|
};
|
|
|
|
} // end module implementation
|
|
|
|
/* ########## Begin module wrapper ########## */
|
|
var name = 'hmac';
|
|
var deps = ['./md', './util'];
|
|
var nodeDefine = null;
|
|
if(typeof define !== 'function') {
|
|
// NodeJS -> AMD
|
|
if(typeof module === 'object' && module.exports) {
|
|
nodeDefine = function(ids, factory) {
|
|
factory(require, module);
|
|
};
|
|
}
|
|
// <script>
|
|
else {
|
|
if(typeof forge === 'undefined') {
|
|
forge = {};
|
|
}
|
|
initModule(forge);
|
|
}
|
|
}
|
|
// AMD
|
|
if(nodeDefine || typeof define === 'function') {
|
|
// define module AMD style
|
|
(nodeDefine || define)(['require', 'module'].concat(deps),
|
|
function(require, module) {
|
|
module.exports = function(forge) {
|
|
var mods = deps.map(function(dep) {
|
|
return require(dep);
|
|
}).concat(initModule);
|
|
// handle circular dependencies
|
|
forge = forge || {};
|
|
forge.defined = forge.defined || {};
|
|
if(forge.defined[name]) {
|
|
return forge[name];
|
|
}
|
|
forge.defined[name] = true;
|
|
for(var i = 0; i < mods.length; ++i) {
|
|
mods[i](forge);
|
|
}
|
|
return forge[name];
|
|
};
|
|
});
|
|
}
|
|
})();
|