From f56b6887d9296365d701da079d13c7aca91fd88a Mon Sep 17 00:00:00 2001 From: Bart Butler Date: Fri, 1 May 2015 12:41:35 -0700 Subject: [PATCH] native crypto and hash for nodeJS --- src/crypto/hash/forge_sha256.js | 290 ------ src/crypto/hash/forge_util.js | 836 ------------------ src/crypto/hash/index.js | 84 +- src/crypto/index.js | 4 +- .../sym_encrypted_integrity_protected.js | 4 +- 5 files changed, 65 insertions(+), 1153 deletions(-) delete mode 100644 src/crypto/hash/forge_sha256.js delete mode 100644 src/crypto/hash/forge_util.js diff --git a/src/crypto/hash/forge_sha256.js b/src/crypto/hash/forge_sha256.js deleted file mode 100644 index 6dad2271..00000000 --- a/src/crypto/hash/forge_sha256.js +++ /dev/null @@ -1,290 +0,0 @@ -/** - * Secure Hash Algorithm with 256-bit digest (SHA-256) implementation. - * - * See FIPS 180-2 for details. - * - * This implementation is currently limited to message lengths (in bytes) that - * are up to 32-bits in size. - * - * @author Dave Longley - * - * Copyright (c) 2010-2012 Digital Bazaar, Inc. - */ - -var sha256 = module.exports = {}; -var util = require('./forge_util.js'); - -// sha-256 padding bytes not initialized yet -var _padding = null; -var _initialized = false; - -// table of constants -var _k = null; - -/** - * Initializes the constant tables. - */ -var _init = function() { - // create padding - _padding = String.fromCharCode(128); - _padding += util.fillString(String.fromCharCode(0x00), 64); - - // create K table for SHA-256 - _k = [ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 - ]; - - // now initialized - _initialized = true; -}; - -/** - * Updates a SHA-256 state with the given byte buffer. - * - * @param s the SHA-256 state to update. - * @param w the array to use to store words. - * @param bytes the byte buffer to update with. - */ -var _update = function(s, w, bytes) { - // consume 512 bit (64 byte) chunks - var t1, t2, s0, s1, ch, maj, i, a, b, c, d, e, f, g, h; - var len = bytes.length(); - while (len >= 64) { - // the w array will be populated with sixteen 32-bit big-endian words - // and then extended into 64 32-bit words according to SHA-256 - for (i = 0; i < 16; ++i) { - w[i] = bytes.getInt32(); - } - for (; i < 64; ++i) { - // XOR word 2 words ago rot right 17, rot right 19, shft right 10 - t1 = w[i - 2]; - t1 = - ((t1 >>> 17) | (t1 << 15)) ^ - ((t1 >>> 19) | (t1 << 13)) ^ - (t1 >>> 10); - // XOR word 15 words ago rot right 7, rot right 18, shft right 3 - t2 = w[i - 15]; - t2 = - ((t2 >>> 7) | (t2 << 25)) ^ - ((t2 >>> 18) | (t2 << 14)) ^ - (t2 >>> 3); - // sum(t1, word 7 ago, t2, word 16 ago) modulo 2^32 - w[i] = (t1 + w[i - 7] + t2 + w[i - 16]) & 0xFFFFFFFF; - } - - // initialize hash value for this chunk - a = s.h0; - b = s.h1; - c = s.h2; - d = s.h3; - e = s.h4; - f = s.h5; - g = s.h6; - h = s.h7; - - // round function - for (i = 0; i < 64; ++i) { - // Sum1(e) - s1 = - ((e >>> 6) | (e << 26)) ^ - ((e >>> 11) | (e << 21)) ^ - ((e >>> 25) | (e << 7)); - // Ch(e, f, g) (optimized the same way as SHA-1) - ch = g ^ (e & (f ^ g)); - // Sum0(a) - s0 = - ((a >>> 2) | (a << 30)) ^ - ((a >>> 13) | (a << 19)) ^ - ((a >>> 22) | (a << 10)); - // Maj(a, b, c) (optimized the same way as SHA-1) - maj = (a & b) | (c & (a ^ b)); - - // main algorithm - t1 = h + s1 + ch + _k[i] + w[i]; - t2 = s0 + maj; - h = g; - g = f; - f = e; - e = (d + t1) & 0xFFFFFFFF; - d = c; - c = b; - b = a; - a = (t1 + t2) & 0xFFFFFFFF; - } - - // update hash state - s.h0 = (s.h0 + a) & 0xFFFFFFFF; - s.h1 = (s.h1 + b) & 0xFFFFFFFF; - s.h2 = (s.h2 + c) & 0xFFFFFFFF; - s.h3 = (s.h3 + d) & 0xFFFFFFFF; - s.h4 = (s.h4 + e) & 0xFFFFFFFF; - s.h5 = (s.h5 + f) & 0xFFFFFFFF; - s.h6 = (s.h6 + g) & 0xFFFFFFFF; - s.h7 = (s.h7 + h) & 0xFFFFFFFF; - len -= 64; - } -}; - -/** - * Creates a SHA-256 message digest object. - * - * @return a message digest object. - */ -sha256.create = function() { - // do initialization as necessary - if (!_initialized) { - _init(); - } - - // SHA-256 state contains eight 32-bit integers - var _state = null; - - // input buffer - var _input = util.createBuffer(); - - // used for word storage - var _w = new Array(64); - - // message digest object - var md = { - algorithm: 'sha256', - blockLength: 64, - digestLength: 32, - // length of message so far (does not including padding) - messageLength: 0 - }; - - /** - * Starts the digest. - * - * @return this digest object. - */ - md.start = function() { - md.messageLength = 0; - _input = util.createBuffer(); - _state = { - h0: 0x6A09E667, - h1: 0xBB67AE85, - h2: 0x3C6EF372, - h3: 0xA54FF53A, - h4: 0x510E527F, - h5: 0x9B05688C, - h6: 0x1F83D9AB, - h7: 0x5BE0CD19 - }; - return md; - }; - // start digest automatically for first time - md.start(); - - /** - * Updates the digest with the given message input. The given input can - * treated as raw input (no encoding will be applied) or an encoding of - * 'utf8' maybe given to encode the input using UTF-8. - * - * @param msg the message input to update with. - * @param encoding the encoding to use (default: 'raw', other: 'utf8'). - * - * @return this digest object. - */ - md.update = function(msg, encoding) { - if (encoding === 'utf8') { - msg = util.encodeUtf8(msg); - } - - // update message length - md.messageLength += msg.length; - - // add bytes to input buffer - _input.putBytes(msg); - - // process bytes - _update(_state, _w, _input); - - // compact input buffer every 2K or if empty - if (_input.read > 2048 || _input.length() === 0) { - _input.compact(); - } - - return md; - }; - - /** - * Produces the digest. - * - * @return a byte buffer containing the digest value. - */ - md.digest = function() { - /* Note: Here we copy the remaining bytes in the input buffer and - add the appropriate SHA-256 padding. Then we do the final update - on a copy of the state so that if the user wants to get - intermediate digests they can do so. */ - - /* Determine the number of bytes that must be added to the message - to ensure its length is congruent to 448 mod 512. In other words, - a 64-bit integer that gives the length of the message will be - appended to the message and whatever the length of the message is - plus 64 bits must be a multiple of 512. So the length of the - message must be congruent to 448 mod 512 because 512 - 64 = 448. - - In order to fill up the message length it must be filled with - padding that begins with 1 bit followed by all 0 bits. Padding - must *always* be present, so if the message length is already - congruent to 448 mod 512, then 512 padding bits must be added. */ - - // 512 bits == 64 bytes, 448 bits == 56 bytes, 64 bits = 8 bytes - // _padding starts with 1 byte with first bit is set in it which - // is byte value 128, then there may be up to 63 other pad bytes - var len = md.messageLength; - var padBytes = util.createBuffer(); - padBytes.putBytes(_input.bytes()); - padBytes.putBytes(_padding.substr(0, 64 - ((len + 8) % 64))); - - /* Now append length of the message. The length is appended in bits - as a 64-bit number in big-endian order. Since we store the length - in bytes, we must multiply it by 8 (or left shift by 3). So here - store the high 3 bits in the low end of the first 32-bits of the - 64-bit number and the lower 5 bits in the high end of the second - 32-bits. */ - padBytes.putInt32((len >>> 29) & 0xFF); - padBytes.putInt32((len << 3) & 0xFFFFFFFF); - var s2 = { - h0: _state.h0, - h1: _state.h1, - h2: _state.h2, - h3: _state.h3, - h4: _state.h4, - h5: _state.h5, - h6: _state.h6, - h7: _state.h7 - }; - _update(s2, _w, padBytes); - var rval = util.createBuffer(); - rval.putInt32(s2.h0); - rval.putInt32(s2.h1); - rval.putInt32(s2.h2); - rval.putInt32(s2.h3); - rval.putInt32(s2.h4); - rval.putInt32(s2.h5); - rval.putInt32(s2.h6); - rval.putInt32(s2.h7); - return rval; - }; - - return md; -}; \ No newline at end of file diff --git a/src/crypto/hash/forge_util.js b/src/crypto/hash/forge_util.js deleted file mode 100644 index 5c56a118..00000000 --- a/src/crypto/hash/forge_util.js +++ /dev/null @@ -1,836 +0,0 @@ -/** - * Utility functions for web applications. - * - * @author Dave Longley - * - * Copyright (c) 2010-2012 Digital Bazaar, Inc. - */ - -/* Utilities API */ -var util = module.exports = {}; - -// define isArray -util.isArray = Array.isArray || function(x) { - return Object.prototype.toString.call(x) === '[object Array]'; -}; - -// define isArrayBuffer -util.isArrayBuffer = function(x) { - return typeof ArrayBuffer !== 'undefined' && x instanceof ArrayBuffer; -}; - -// define isArrayBufferView -var _arrayBufferViews = []; -if(typeof Int8Array !== 'undefined') { - _arrayBufferViews.push(Int8Array); -} -if(typeof Uint8Array !== 'undefined') { - _arrayBufferViews.push(Uint8Array); -} -if(typeof Uint8ClampedArray !== 'undefined') { - _arrayBufferViews.push(Uint8ClampedArray); -} -if(typeof Int16Array !== 'undefined') { - _arrayBufferViews.push(Int16Array); -} -if(typeof Uint16Array !== 'undefined') { - _arrayBufferViews.push(Uint16Array); -} -if(typeof Int32Array !== 'undefined') { - _arrayBufferViews.push(Int32Array); -} -if(typeof Uint32Array !== 'undefined') { - _arrayBufferViews.push(Uint32Array); -} -if(typeof Float32Array !== 'undefined') { - _arrayBufferViews.push(Float32Array); -} -if(typeof Float64Array !== 'undefined') { - _arrayBufferViews.push(Float64Array); -} -util.isArrayBufferView = function(x) { - for(var i = 0; i < _arrayBufferViews.length; ++i) { - if(x instanceof _arrayBufferViews[i]) { - return true; - } - } - return false; -}; - -/** - * Constructor for a byte buffer. - * - * @param [b] the bytes to wrap (either encoded as string, one byte per - * character, or as an ArrayBuffer or Typed Array). - */ -util.ByteBuffer = function(b) { - // the data in this buffer - this.data = ''; - // the pointer for reading from this buffer - this.read = 0; - - if(typeof b === 'string') { - this.data = b; - } - else if(util.isArrayBuffer(b) || util.isArrayBufferView(b)) { - // convert native buffer to forge buffer - // FIXME: support native buffers internally instead - var arr = new Uint8Array(b); - try { - this.data = String.fromCharCode.apply(null, arr); - } - catch(e) { - for(var i = 0; i < arr.length; ++i) { - this.putByte(arr[i]); - } - } - } -}; - -/** - * Gets the number of bytes in this buffer. - * - * @return the number of bytes in this buffer. - */ -util.ByteBuffer.prototype.length = function() { - return this.data.length - this.read; -}; - -/** - * Gets whether or not this buffer is empty. - * - * @return true if this buffer is empty, false if not. - */ -util.ByteBuffer.prototype.isEmpty = function() { - return this.length() <= 0; -}; - -/** - * Puts a byte in this buffer. - * - * @param b the byte to put. - * - * @return this buffer. - */ -util.ByteBuffer.prototype.putByte = function(b) { - this.data += String.fromCharCode(b); - return this; -}; - -/** - * Puts a byte in this buffer N times. - * - * @param b the byte to put. - * @param n the number of bytes of value b to put. - * - * @return this buffer. - */ -util.ByteBuffer.prototype.fillWithByte = function(b, n) { - b = String.fromCharCode(b); - var d = this.data; - while(n > 0) { - if(n & 1) { - d += b; - } - n >>>= 1; - if(n > 0) { - b += b; - } - } - this.data = d; - return this; -}; - -/** - * Puts bytes in this buffer. - * - * @param bytes the bytes (as a UTF-8 encoded string) to put. - * - * @return this buffer. - */ -util.ByteBuffer.prototype.putBytes = function(bytes) { - this.data += bytes; - return this; -}; - -/** - * Puts a UTF-16 encoded string into this buffer. - * - * @param str the string to put. - * - * @return this buffer. - */ -util.ByteBuffer.prototype.putString = function(str) { - this.data += util.encodeUtf8(str); - return this; -}; - -/** - * Puts a 16-bit integer in this buffer in big-endian order. - * - * @param i the 16-bit integer. - * - * @return this buffer. - */ -util.ByteBuffer.prototype.putInt16 = function(i) { - this.data += - String.fromCharCode(i >> 8 & 0xFF) + - String.fromCharCode(i & 0xFF); - return this; -}; - -/** - * Puts a 24-bit integer in this buffer in big-endian order. - * - * @param i the 24-bit integer. - * - * @return this buffer. - */ -util.ByteBuffer.prototype.putInt24 = function(i) { - this.data += - String.fromCharCode(i >> 16 & 0xFF) + - String.fromCharCode(i >> 8 & 0xFF) + - String.fromCharCode(i & 0xFF); - return this; -}; - -/** - * Puts a 32-bit integer in this buffer in big-endian order. - * - * @param i the 32-bit integer. - * - * @return this buffer. - */ -util.ByteBuffer.prototype.putInt32 = function(i) { - this.data += - String.fromCharCode(i >> 24 & 0xFF) + - String.fromCharCode(i >> 16 & 0xFF) + - String.fromCharCode(i >> 8 & 0xFF) + - String.fromCharCode(i & 0xFF); - return this; -}; - -/** - * Puts a 16-bit integer in this buffer in little-endian order. - * - * @param i the 16-bit integer. - * - * @return this buffer. - */ -util.ByteBuffer.prototype.putInt16Le = function(i) { - this.data += - String.fromCharCode(i & 0xFF) + - String.fromCharCode(i >> 8 & 0xFF); - return this; -}; - -/** - * Puts a 24-bit integer in this buffer in little-endian order. - * - * @param i the 24-bit integer. - * - * @return this buffer. - */ -util.ByteBuffer.prototype.putInt24Le = function(i) { - this.data += - String.fromCharCode(i & 0xFF) + - String.fromCharCode(i >> 8 & 0xFF) + - String.fromCharCode(i >> 16 & 0xFF); - return this; -}; - -/** - * Puts a 32-bit integer in this buffer in little-endian order. - * - * @param i the 32-bit integer. - * - * @return this buffer. - */ -util.ByteBuffer.prototype.putInt32Le = function(i) { - this.data += - String.fromCharCode(i & 0xFF) + - String.fromCharCode(i >> 8 & 0xFF) + - String.fromCharCode(i >> 16 & 0xFF) + - String.fromCharCode(i >> 24 & 0xFF); - return this; -}; - -/** - * Puts an n-bit integer in this buffer in big-endian order. - * - * @param i the n-bit integer. - * @param n the number of bits in the integer. - * - * @return this buffer. - */ -util.ByteBuffer.prototype.putInt = function(i, n) { - do { - n -= 8; - this.data += String.fromCharCode((i >> n) & 0xFF); - } - while(n > 0); - return this; -}; - -/** - * Puts a signed n-bit integer in this buffer in big-endian order. Two's - * complement representation is used. - * - * @param i the n-bit integer. - * @param n the number of bits in the integer. - * - * @return this buffer. - */ -util.ByteBuffer.prototype.putSignedInt = function(i, n) { - if(i < 0) { - i += 2 << (n - 1); - } - return this.putInt(i, n); -}; - -/** - * Puts the given buffer into this buffer. - * - * @param buffer the buffer to put into this one. - * - * @return this buffer. - */ -util.ByteBuffer.prototype.putBuffer = function(buffer) { - this.data += buffer.getBytes(); - return this; -}; - -/** - * Gets a byte from this buffer and advances the read pointer by 1. - * - * @return the byte. - */ -util.ByteBuffer.prototype.getByte = function() { - return this.data.charCodeAt(this.read++); -}; - -/** - * Gets a uint16 from this buffer in big-endian order and advances the read - * pointer by 2. - * - * @return the uint16. - */ -util.ByteBuffer.prototype.getInt16 = function() { - var rval = ( - this.data.charCodeAt(this.read) << 8 ^ - this.data.charCodeAt(this.read + 1)); - this.read += 2; - return rval; -}; - -/** - * Gets a uint24 from this buffer in big-endian order and advances the read - * pointer by 3. - * - * @return the uint24. - */ -util.ByteBuffer.prototype.getInt24 = function() { - var rval = ( - this.data.charCodeAt(this.read) << 16 ^ - this.data.charCodeAt(this.read + 1) << 8 ^ - this.data.charCodeAt(this.read + 2)); - this.read += 3; - return rval; -}; - -/** - * Gets a uint32 from this buffer in big-endian order and advances the read - * pointer by 4. - * - * @return the word. - */ -util.ByteBuffer.prototype.getInt32 = function() { - var rval = ( - this.data.charCodeAt(this.read) << 24 ^ - this.data.charCodeAt(this.read + 1) << 16 ^ - this.data.charCodeAt(this.read + 2) << 8 ^ - this.data.charCodeAt(this.read + 3)); - this.read += 4; - return rval; -}; - -/** - * Gets a uint16 from this buffer in little-endian order and advances the read - * pointer by 2. - * - * @return the uint16. - */ -util.ByteBuffer.prototype.getInt16Le = function() { - var rval = ( - this.data.charCodeAt(this.read) ^ - this.data.charCodeAt(this.read + 1) << 8); - this.read += 2; - return rval; -}; - -/** - * Gets a uint24 from this buffer in little-endian order and advances the read - * pointer by 3. - * - * @return the uint24. - */ -util.ByteBuffer.prototype.getInt24Le = function() { - var rval = ( - this.data.charCodeAt(this.read) ^ - this.data.charCodeAt(this.read + 1) << 8 ^ - this.data.charCodeAt(this.read + 2) << 16); - this.read += 3; - return rval; -}; - -/** - * Gets a uint32 from this buffer in little-endian order and advances the read - * pointer by 4. - * - * @return the word. - */ -util.ByteBuffer.prototype.getInt32Le = function() { - var rval = ( - this.data.charCodeAt(this.read) ^ - this.data.charCodeAt(this.read + 1) << 8 ^ - this.data.charCodeAt(this.read + 2) << 16 ^ - this.data.charCodeAt(this.read + 3) << 24); - this.read += 4; - return rval; -}; - -/** - * Gets an n-bit integer from this buffer in big-endian order and advances the - * read pointer by n/8. - * - * @param n the number of bits in the integer. - * - * @return the integer. - */ -util.ByteBuffer.prototype.getInt = function(n) { - var rval = 0; - do { - rval = (rval << 8) + this.data.charCodeAt(this.read++); - n -= 8; - } - while(n > 0); - return rval; -}; - -/** - * Gets a signed n-bit integer from this buffer in big-endian order, using - * two's complement, and advances the read pointer by n/8. - * - * @param n the number of bits in the integer. - * - * @return the integer. - */ -util.ByteBuffer.prototype.getSignedInt = function(n) { - var x = this.getInt(n); - var max = 2 << (n - 2); - if(x >= max) { - x -= max << 1; - } - return x; -}; - -/** - * Reads bytes out into a UTF-8 string and clears them from the buffer. - * - * @param count the number of bytes to read, undefined or null for all. - * - * @return a UTF-8 string of bytes. - */ -util.ByteBuffer.prototype.getBytes = function(count) { - var rval; - if(count) { - // read count bytes - count = Math.min(this.length(), count); - rval = this.data.slice(this.read, this.read + count); - this.read += count; - } - else if(count === 0) { - rval = ''; - } - else { - // read all bytes, optimize to only copy when needed - rval = (this.read === 0) ? this.data : this.data.slice(this.read); - this.clear(); - } - return rval; -}; - -/** - * Gets a UTF-8 encoded string of the bytes from this buffer without modifying - * the read pointer. - * - * @param count the number of bytes to get, omit to get all. - * - * @return a string full of UTF-8 encoded characters. - */ -util.ByteBuffer.prototype.bytes = function(count) { - return (typeof(count) === 'undefined' ? - this.data.slice(this.read) : - this.data.slice(this.read, this.read + count)); -}; - -/** - * Gets a byte at the given index without modifying the read pointer. - * - * @param i the byte index. - * - * @return the byte. - */ -util.ByteBuffer.prototype.at = function(i) { - return this.data.charCodeAt(this.read + i); -}; - -/** - * Puts a byte at the given index without modifying the read pointer. - * - * @param i the byte index. - * @param b the byte to put. - * - * @return this buffer. - */ -util.ByteBuffer.prototype.setAt = function(i, b) { - this.data = this.data.substr(0, this.read + i) + - String.fromCharCode(b) + - this.data.substr(this.read + i + 1); - return this; -}; - -/** - * Gets the last byte without modifying the read pointer. - * - * @return the last byte. - */ -util.ByteBuffer.prototype.last = function() { - return this.data.charCodeAt(this.data.length - 1); -}; - -/** - * Creates a copy of this buffer. - * - * @return the copy. - */ -util.ByteBuffer.prototype.copy = function() { - var c = util.createBuffer(this.data); - c.read = this.read; - return c; -}; - -/** - * Compacts this buffer. - * - * @return this buffer. - */ -util.ByteBuffer.prototype.compact = function() { - if(this.read > 0) { - this.data = this.data.slice(this.read); - this.read = 0; - } - return this; -}; - -/** - * Clears this buffer. - * - * @return this buffer. - */ -util.ByteBuffer.prototype.clear = function() { - this.data = ''; - this.read = 0; - return this; -}; - -/** - * Shortens this buffer by triming bytes off of the end of this buffer. - * - * @param count the number of bytes to trim off. - * - * @return this buffer. - */ -util.ByteBuffer.prototype.truncate = function(count) { - var len = Math.max(0, this.length() - count); - this.data = this.data.substr(this.read, len); - this.read = 0; - return this; -}; - -/** - * Converts this buffer to a hexadecimal string. - * - * @return a hexadecimal string. - */ -util.ByteBuffer.prototype.toHex = function() { - var rval = ''; - for(var i = this.read; i < this.data.length; ++i) { - var b = this.data.charCodeAt(i); - if(b < 16) { - rval += '0'; - } - rval += b.toString(16); - } - return rval; -}; - -/** - * Converts this buffer to a UTF-16 string (standard JavaScript string). - * - * @return a UTF-16 string. - */ -util.ByteBuffer.prototype.toString = function() { - return util.decodeUtf8(this.bytes()); -}; - -/** - * Creates a buffer that stores bytes. A value may be given to put into the - * buffer that is either a string of bytes or a UTF-16 string that will - * be encoded using UTF-8 (to do the latter, specify 'utf8' as the encoding). - * - * @param [input] the bytes to wrap (as a string) or a UTF-16 string to encode - * as UTF-8. - * @param [encoding] (default: 'raw', other: 'utf8'). - */ -util.createBuffer = function(input, encoding) { - encoding = encoding || 'raw'; - if(input !== undefined && encoding === 'utf8') { - input = util.encodeUtf8(input); - } - return new util.ByteBuffer(input); -}; - -/** - * Fills a string with a particular value. If you want the string to be a byte - * string, pass in String.fromCharCode(theByte). - * - * @param c the character to fill the string with, use String.fromCharCode - * to fill the string with a byte value. - * @param n the number of characters of value c to fill with. - * - * @return the filled string. - */ -util.fillString = function(c, n) { - var s = ''; - while(n > 0) { - if(n & 1) { - s += c; - } - n >>>= 1; - if(n > 0) { - c += c; - } - } - return s; -}; - -/** - * Performs a per byte XOR between two byte strings and returns the result as a - * string of bytes. - * - * @param s1 first string of bytes. - * @param s2 second string of bytes. - * @param n the number of bytes to XOR. - * - * @return the XOR'd result. - */ -util.xorBytes = function(s1, s2, n) { - var s3 = ''; - var b = ''; - var t = ''; - var i = 0; - var c = 0; - for(; n > 0; --n, ++i) { - b = s1.charCodeAt(i) ^ s2.charCodeAt(i); - if(c >= 10) { - s3 += t; - t = ''; - c = 0; - } - t += String.fromCharCode(b); - ++c; - } - s3 += t; - return s3; -}; - -/** - * Converts a hex string into a UTF-8 string of bytes. - * - * @param hex the hexadecimal string to convert. - * - * @return the string of bytes. - */ -util.hexToBytes = function(hex) { - var rval = ''; - var i = 0; - if(hex.length & 1 == 1) { - // odd number of characters, convert first character alone - i = 1; - rval += String.fromCharCode(parseInt(hex[0], 16)); - } - // convert 2 characters (1 byte) at a time - for(; i < hex.length; i += 2) { - rval += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); - } - return rval; -}; - -/** - * Converts a UTF-8 byte string into a string of hexadecimal characters. - * - * @param bytes the byte string to convert. - * - * @return the string of hexadecimal characters. - */ -util.bytesToHex = function(bytes) { - return util.createBuffer(bytes).toHex(); -}; - -/** - * Converts an 32-bit integer to 4-big-endian byte string. - * - * @param i the integer. - * - * @return the byte string. - */ -util.int32ToBytes = function(i) { - return ( - String.fromCharCode(i >> 24 & 0xFF) + - String.fromCharCode(i >> 16 & 0xFF) + - String.fromCharCode(i >> 8 & 0xFF) + - String.fromCharCode(i & 0xFF)); -}; - -// base64 characters, reverse mapping -var _base64 = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; -var _base64Idx = [ -/*43 -43 = 0*/ -/*'+', 1, 2, 3,'/' */ - 62, -1, -1, -1, 63, - -/*'0','1','2','3','4','5','6','7','8','9' */ - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - -/*15, 16, 17,'=', 19, 20, 21 */ - -1, -1, -1, 64, -1, -1, -1, - -/*65 - 43 = 22*/ -/*'A','B','C','D','E','F','G','H','I','J','K','L','M', */ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - -/*'N','O','P','Q','R','S','T','U','V','W','X','Y','Z' */ - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - -/*91 - 43 = 48 */ -/*48, 49, 50, 51, 52, 53 */ - -1, -1, -1, -1, -1, -1, - -/*97 - 43 = 54*/ -/*'a','b','c','d','e','f','g','h','i','j','k','l','m' */ - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - -/*'n','o','p','q','r','s','t','u','v','w','x','y','z' */ - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 -]; - -/** - * Base64 encodes a UTF-8 string of bytes. - * - * @param input the UTF-8 string of bytes to encode. - * @param maxline the maximum number of encoded bytes per line to use, - * defaults to none. - * - * @return the base64-encoded output. - */ -util.encode64 = function(input, maxline) { - var line = ''; - var output = ''; - var chr1, chr2, chr3; - var i = 0; - while(i < input.length) { - chr1 = input.charCodeAt(i++); - chr2 = input.charCodeAt(i++); - chr3 = input.charCodeAt(i++); - - // encode 4 character group - line += _base64.charAt(chr1 >> 2); - line += _base64.charAt(((chr1 & 3) << 4) | (chr2 >> 4)); - if(isNaN(chr2)) { - line += '=='; - } - else { - line += _base64.charAt(((chr2 & 15) << 2) | (chr3 >> 6)); - line += isNaN(chr3) ? '=' : _base64.charAt(chr3 & 63); - } - - if(maxline && line.length > maxline) { - output += line.substr(0, maxline) + '\r\n'; - line = line.substr(maxline); - } - } - output += line; - - return output; -}; - -/** - * Base64 decodes a string into a UTF-8 string of bytes. - * - * @param input the base64-encoded input. - * - * @return the raw bytes. - */ -util.decode64 = function(input) { - // remove all non-base64 characters - input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); - - var output = ''; - var enc1, enc2, enc3, enc4; - var i = 0; - - while(i < input.length) { - enc1 = _base64Idx[input.charCodeAt(i++) - 43]; - enc2 = _base64Idx[input.charCodeAt(i++) - 43]; - enc3 = _base64Idx[input.charCodeAt(i++) - 43]; - enc4 = _base64Idx[input.charCodeAt(i++) - 43]; - - output += String.fromCharCode((enc1 << 2) | (enc2 >> 4)); - if(enc3 !== 64) { - // decoded at least 2 bytes - output += String.fromCharCode(((enc2 & 15) << 4) | (enc3 >> 2)); - if(enc4 !== 64) { - // decoded 3 bytes - output += String.fromCharCode(((enc3 & 3) << 6) | enc4); - } - } - } - - return output; -}; - -/** - * UTF-8 encodes the given UTF-16 encoded string (a standard JavaScript - * string). Non-ASCII characters will be encoded as multiple bytes according - * to UTF-8. - * - * @param str the string to encode. - * - * @return the UTF-8 encoded string. - */ -util.encodeUtf8 = function(str) { - return unescape(encodeURIComponent(str)); -}; - -/** - * Decodes a UTF-8 encoded string into a UTF-16 string. - * - * @param str the string to encode. - * - * @return the UTF-16 encoded string (standard JavaScript string). - */ -util.decodeUtf8 = function(str) { - return decodeURIComponent(escape(str)); -}; diff --git a/src/crypto/hash/index.js b/src/crypto/hash/index.js index 80be7403..bb783c62 100644 --- a/src/crypto/hash/index.js +++ b/src/crypto/hash/index.js @@ -1,32 +1,74 @@ /** * @requires crypto/hash/sha + * @requires crypto/hash/rusha + * @requires util + * @requires config * @module crypto/hash */ var sha = require('./sha.js'), - forge_sha256 = require('./forge_sha256.js'), rusha = require('./rusha.js'), + config = require('../../config') util = require('../../util.js'); var rusha_obj = new rusha(); +function node_hash(type) { + return function (data) { + var nodeCrypto = require('crypto'); + var Buffer = require('buffer').Buffer; + var shasum = nodeCrypto.createHash(type); + shasum.update(new Buffer(data)); + return new Uint8Array(shasum.digest()); + } +} + +var hash_fns; +if(typeof module !== 'undefined' && module.exports && config.useNative) { // Use Node native crypto + hash_fns = { + md5: node_hash('md5'), + sha1: node_hash('sha1'), + sha224: node_hash('sha224'), + sha256: node_hash('sha256'), + sha384: node_hash('sha384'), + sha512: node_hash('sha512'), + ripemd: node_hash('ripemd160') + }; +} +else { // JS + hash_fns = { + /** @see module:crypto/hash/md5 */ + md5: require('./md5.js'), + /** @see module:crypto/hash/sha.sha1 */ + /** @see module:crypto/hash/rusha */ + // sha1: sha.sha1, + sha1: function (data) { + return util.str2Uint8Array(util.hex2bin(rusha_obj.digest(data))); + }, + //sha1: asmCrypto.SHA1.bytes, + /** @see module:crypto/hash/sha.sha224 */ + sha224: sha.sha224, + /** @see module:crypto/hash/sha.sha256 */ + /** @see module:crypto/asmcrypto */ + //sha256: sha.sha256, + sha256: asmCrypto.SHA256.bytes, + /** @see module:crypto/hash/sha.sha384 */ + sha384: sha.sha384, + /** @see module:crypto/hash/sha.sha512 */ + sha512: sha.sha512, + /** @see module:crypto/hash/ripe-md */ + ripemd: require('./ripe-md.js') + }; +} + module.exports = { - /** @see module:crypto/hash/md5 */ - md5: require('./md5.js'), - /** @see module:crypto/hash/sha.sha1 */ - sha1: sha.sha1, - sha1: function (data) { - return util.str2Uint8Array(util.hex2bin(rusha_obj.digest(data))); - }, - /** @see module:crypto/hash/sha.sha224 */ - sha224: sha.sha224, - /** @see module:crypto/hash/sha.sha256 */ - sha256: sha.sha256, - /** @see module:crypto/hash/sha.sha384 */ - sha384: sha.sha384, - /** @see module:crypto/hash/sha.sha512 */ - sha512: sha.sha512, - /** @see module:crypto/hash/ripe-md */ - ripemd: require('./ripe-md.js'), + + md5: hash_fns.md5, + sha1: hash_fns.sha1, + sha224: hash_fns.sha224, + sha256: hash_fns.sha256, + sha384: hash_fns.sha384, + sha512: hash_fns.sha512, + ripemd: hash_fns.ripemd, /** * Create a hash on the specified data using the specified algorithm @@ -47,11 +89,7 @@ module.exports = { return this.ripemd(data); case 8: // - SHA256 [FIPS180] - //return this.sha256(data); - - var sha256 = forge_sha256.create(); - sha256.update(util.Uint8Array2str(data)); - return util.str2Uint8Array(sha256.digest().getBytes()); + return this.sha256(data); case 9: // - SHA384 [FIPS180] return this.sha384(data); diff --git a/src/crypto/index.js b/src/crypto/index.js index 075d4311..6e674c4e 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -3,8 +3,8 @@ * @module crypto */ -// asmCrypto global object -require('./asmcrypto-aes-cfb'); +// asmCrypto global object (AES CFB, SHA1, SHA256, SHA512) +require('./asmcrypto.js'); module.exports = { /** @see module:crypto/cipher */ diff --git a/src/packet/sym_encrypted_integrity_protected.js b/src/packet/sym_encrypted_integrity_protected.js index c9a7a1ad..66c75312 100644 --- a/src/packet/sym_encrypted_integrity_protected.js +++ b/src/packet/sym_encrypted_integrity_protected.js @@ -93,7 +93,7 @@ SymEncryptedIntegrityProtected.prototype.encrypt = function (sessionKeyAlgorithm tohash = util.concatUint8Array([tohash, hash]); - // AES optimizations. Native code for node, asmCrypto is about 50% faster than the default, but does not support resync. + // AES optimizations. Native code for node, asmCrypto for browser. if(sessionKeyAlgorithm.substr(0,3) === 'aes') { var blockSize = crypto.cipher[sessionKeyAlgorithm].blockSize; // Node crypto library. Not clear that it is faster than asmCrypto @@ -130,7 +130,7 @@ SymEncryptedIntegrityProtected.prototype.encrypt = function (sessionKeyAlgorithm SymEncryptedIntegrityProtected.prototype.decrypt = function (sessionKeyAlgorithm, key) { var decrypted; - // AES optimizations. Native code for node, asmCrypto is about 50% faster than the default, but does not support resync. + // AES optimizations. Native code for node, asmCrypto for browser. if(sessionKeyAlgorithm.substr(0,3) === 'aes') { var blockSize = crypto.cipher[sessionKeyAlgorithm].blockSize; // Node crypto library. Not clear that it is faster than asmCrypto