blocktrail-sdk
Version:
BlockTrail's Developer Friendly API binding for NodeJS
143 lines (107 loc) • 3.69 kB
JavaScript
function hmac_constructor ( options ) {
options = options || {};
if ( !options.hash )
throw new SyntaxError("option 'hash' is required");
if ( !options.hash.HASH_SIZE )
throw new SyntaxError("option 'hash' supplied doesn't seem to be a valid hash function");
this.hash = options.hash;
this.BLOCK_SIZE = this.hash.BLOCK_SIZE;
this.HMAC_SIZE = this.hash.HASH_SIZE;
this.key = null;
this.verify = null;
this.result = null;
if ( options.password !== undefined || options.verify !== undefined )
this.reset(options);
return this;
}
function _hmac_key ( hash, password ) {
if ( is_buffer(password) )
password = new Uint8Array(password);
if ( is_string(password) )
password = string_to_bytes(password);
if ( !is_bytes(password) )
throw new TypeError("password isn't of expected type");
var key = new Uint8Array( hash.BLOCK_SIZE );
if ( password.length > hash.BLOCK_SIZE ) {
key.set( hash.reset().process(password).finish().result );
}
else {
key.set(password);
}
return key;
}
function _hmac_init_verify ( verify ) {
if ( is_buffer(verify) || is_bytes(verify) ) {
verify = new Uint8Array(verify);
}
else if ( is_string(verify) ) {
verify = string_to_bytes(verify);
}
else {
throw new TypeError("verify tag isn't of expected type");
}
if ( verify.length !== this.HMAC_SIZE )
throw new IllegalArgumentError("illegal verification tag size");
this.verify = verify;
}
function hmac_reset ( options ) {
options = options || {};
var password = options.password;
if ( this.key === null && !is_string(password) && !password )
throw new IllegalStateError("no key is associated with the instance");
this.result = null;
this.hash.reset();
if ( password || is_string(password) )
this.key = _hmac_key( this.hash, password );
var ipad = new Uint8Array(this.key);
for ( var i = 0; i < ipad.length; ++i )
ipad[i] ^= 0x36;
this.hash.process(ipad);
var verify = options.verify;
if ( verify !== undefined ) {
_hmac_init_verify.call( this, verify );
}
else {
this.verify = null;
}
return this;
}
function hmac_process ( data ) {
if ( this.key === null )
throw new IllegalStateError("no key is associated with the instance");
if ( this.result !== null )
throw new IllegalStateError("state must be reset before processing new data");
this.hash.process(data);
return this;
}
function hmac_finish () {
if ( this.key === null )
throw new IllegalStateError("no key is associated with the instance");
if ( this.result !== null )
throw new IllegalStateError("state must be reset before processing new data");
var inner_result = this.hash.finish().result;
var opad = new Uint8Array(this.key);
for ( var i = 0; i < opad.length; ++i )
opad[i] ^= 0x5c;
var verify = this.verify;
var result = this.hash.reset().process(opad).process(inner_result).finish().result;
if ( verify ) {
if ( verify.length === result.length ) {
var diff = 0;
for ( var i = 0; i < verify.length; i++ ) {
diff |= ( verify[i] ^ result[i] );
}
this.result = !diff;
} else {
this.result = false;
}
}
else {
this.result = result;
}
return this;
}
var hmac_prototype = hmac_constructor.prototype;
hmac_prototype.reset = hmac_reset;
hmac_prototype.process = hmac_process;
hmac_prototype.finish = hmac_finish;