initial changes
This commit is contained in:
112
src/utils/byte_order.js
Normal file
112
src/utils/byte_order.js
Normal file
@@ -0,0 +1,112 @@
|
||||
export const is_big_endian_system =
|
||||
new Uint8Array(new Uint32Array([ 0x12345678 ]).buffer)[0] === 0x12;
|
||||
|
||||
export const is_little_endian_system =
|
||||
new Uint8Array(new Uint32Array([ 0x12345678 ]).buffer)[0] === 0x78;
|
||||
|
||||
export const i8_to_ui8_array = num => {
|
||||
if (typeof num === 'string' || num instanceof String) {
|
||||
num = parseInt(num, 10);
|
||||
}
|
||||
|
||||
const buffer = Buffer.alloc(1);
|
||||
buffer.writeInt8(num);
|
||||
return new Uint8Array(buffer);
|
||||
};
|
||||
|
||||
export const ui8_array_to_i8 = (ar, offset) => {
|
||||
const buffer = Buffer.alloc(1);
|
||||
buffer[0] = ar[offset];
|
||||
|
||||
return buffer.readInt8(0);
|
||||
};
|
||||
|
||||
export const ui8_to_ui8_array = num => {
|
||||
if (typeof num === 'string' || num instanceof String) {
|
||||
num = parseInt(num, 10);
|
||||
}
|
||||
|
||||
const buffer = Buffer.alloc(1);
|
||||
buffer.writeUInt8(num);
|
||||
return new Uint8Array(buffer);
|
||||
};
|
||||
|
||||
export const ui8_array_to_ui8 = (ar, offset) => {
|
||||
const buffer = Buffer.alloc(1);
|
||||
buffer[0] = ar[offset];
|
||||
|
||||
return buffer.readUInt8(0);
|
||||
};
|
||||
|
||||
export const i16_to_be_ui8_array = num => {
|
||||
if (typeof num === 'string' || num instanceof String) {
|
||||
num = parseInt(num, 10);
|
||||
}
|
||||
|
||||
const buffer = Buffer.alloc(2);
|
||||
buffer.writeInt16BE(num);
|
||||
return new Uint8Array(buffer);
|
||||
};
|
||||
|
||||
export const be_ui8_array_to_i16 = (ar, offset) => {
|
||||
const buffer = Buffer.alloc(2);
|
||||
for (let i = offset; i < buffer.length + offset; i++) {
|
||||
buffer[i - offset] = ar[i];
|
||||
}
|
||||
return buffer.readInt16BE(0);
|
||||
};
|
||||
|
||||
export const ui16_to_be_ui8_array = num => {
|
||||
if (typeof num === 'string' || num instanceof String) {
|
||||
num = parseInt(num, 10);
|
||||
}
|
||||
|
||||
const buffer = Buffer.alloc(2);
|
||||
buffer.writeUInt16BE(num);
|
||||
return new Uint8Array(buffer);
|
||||
};
|
||||
|
||||
export const be_ui8_array_to_ui16 = (ar, offset) => {
|
||||
const buffer = Buffer.alloc(2);
|
||||
for (let i = offset; i < buffer.length + offset; i++) {
|
||||
buffer[i - offset] = ar[i];
|
||||
}
|
||||
return buffer.readUInt16BE(0);
|
||||
};
|
||||
|
||||
export const i32_to_be_ui8_array = num => {
|
||||
if (typeof num === 'string' || num instanceof String) {
|
||||
num = parseInt(num, 10);
|
||||
}
|
||||
|
||||
const buffer = Buffer.alloc(4);
|
||||
buffer.writeInt32BE(num);
|
||||
return new Uint8Array(buffer);
|
||||
};
|
||||
|
||||
export const be_ui8_array_to_i32 = (ar, offset) => {
|
||||
const buffer = Buffer.alloc(4);
|
||||
for (let i = offset; i < buffer.length + offset; i++) {
|
||||
buffer[i - offset] = ar[i];
|
||||
}
|
||||
return buffer.readInt32BE(0);
|
||||
};
|
||||
|
||||
export const ui32_to_be_ui8_array = num => {
|
||||
if (typeof num === 'string' || num instanceof String) {
|
||||
num = parseInt(num, 10);
|
||||
}
|
||||
|
||||
const buffer = Buffer.alloc(4);
|
||||
buffer.writeUInt32BE(num);
|
||||
return new Uint8Array(buffer);
|
||||
};
|
||||
|
||||
export const be_ui8_array_to_ui32 = (ar, offset) => {
|
||||
const buffer = Buffer.alloc(4);
|
||||
for (let i = offset; i < buffer.length + offset; i++) {
|
||||
buffer[i - offset] = ar[i];
|
||||
}
|
||||
|
||||
return buffer.readUInt32BE(0);
|
||||
};
|
||||
3
src/utils/constants.js
Normal file
3
src/utils/constants.js
Normal file
@@ -0,0 +1,3 @@
|
||||
const {v4 : uuidv4} = require('uuid');
|
||||
|
||||
export const instance_id = uuidv4();
|
||||
322
src/utils/jschacha20.js
Normal file
322
src/utils/jschacha20.js
Normal file
@@ -0,0 +1,322 @@
|
||||
'use strict';
|
||||
/*
|
||||
* Copyright (c) 2017, Bubelich Mykola
|
||||
* https://www.bubelich.com
|
||||
*
|
||||
* (。◕‿‿◕。)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met, 0x
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ChaCha20 is a stream cipher designed by D. J. Bernstein.
|
||||
* It is a refinement of the Salsa20 algorithm, and it uses a 256-bit key.
|
||||
*
|
||||
* ChaCha20 successively calls the ChaCha20 block function, with the same key and nonce, and with successively increasing block counter parameters.
|
||||
* ChaCha20 then serializes the resulting state by writing the numbers in little-endian order, creating a keystream block.
|
||||
*
|
||||
* Concatenating the keystream blocks from the successive blocks forms a keystream.
|
||||
* The ChaCha20 function then performs an XOR of this keystream with the plaintext.
|
||||
* Alternatively, each keystream block can be XORed with a plaintext block before proceeding to create_or_open the next block, saving some memory.
|
||||
* There is no requirement for the plaintext to be an integral multiple of 512 bits. If there is extra keystream from the last block, it is discarded.
|
||||
*
|
||||
* The inputs to ChaCha20 are
|
||||
* - 256-bit key
|
||||
* - 32-bit initial counter
|
||||
* - 96-bit nonce. In some protocols, this is known as the Initialization Vector
|
||||
* - Arbitrary-length plaintext
|
||||
*
|
||||
* Implementation derived from chacha-ref.c version 20080118
|
||||
* See for details, 0x http, 0x//cr.yp.to/chacha/chacha-20080128.pdf
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Uint8Array} key
|
||||
* @param {Uint8Array} nonce
|
||||
* @param {number} counter
|
||||
* @throws {Error}
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
var JSChaCha20 = function(key, nonce, counter) {
|
||||
if (typeof counter === 'undefined') {
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
if (!(key instanceof Uint8Array) || key.length !== 32) {
|
||||
throw new Error('Key should be 32 byte array!');
|
||||
}
|
||||
|
||||
if (!(nonce instanceof Uint8Array) || nonce.length !== 12) {
|
||||
throw new Error('Nonce should be 12 byte array!');
|
||||
}
|
||||
|
||||
this._rounds = 20;
|
||||
// Constants
|
||||
this._sigma = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574];
|
||||
|
||||
// param construction
|
||||
this._param = [
|
||||
this._sigma[0],
|
||||
this._sigma[1],
|
||||
this._sigma[2],
|
||||
this._sigma[3],
|
||||
// key
|
||||
this._get32(key, 0),
|
||||
this._get32(key, 4),
|
||||
this._get32(key, 8),
|
||||
this._get32(key, 12),
|
||||
this._get32(key, 16),
|
||||
this._get32(key, 20),
|
||||
this._get32(key, 24),
|
||||
this._get32(key, 28),
|
||||
// counter
|
||||
counter,
|
||||
// nonce
|
||||
this._get32(nonce, 0),
|
||||
this._get32(nonce, 4),
|
||||
this._get32(nonce, 8),
|
||||
];
|
||||
|
||||
// init 64 byte keystream block //
|
||||
this._keystream = [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
];
|
||||
|
||||
// internal byte counter //
|
||||
this._byteCounter = 0;
|
||||
};
|
||||
|
||||
JSChaCha20.prototype._chacha = function() {
|
||||
var mix = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
var i = 0;
|
||||
var b = 0;
|
||||
|
||||
// copy param array to mix //
|
||||
for (i = 0; i < 16; i++) {
|
||||
mix[i] = this._param[i];
|
||||
}
|
||||
|
||||
// mix rounds //
|
||||
for (i = 0; i < this._rounds; i += 2) {
|
||||
this._quarterround(mix, 0, 4, 8, 12);
|
||||
this._quarterround(mix, 1, 5, 9, 13);
|
||||
this._quarterround(mix, 2, 6, 10, 14);
|
||||
this._quarterround(mix, 3, 7, 11, 15);
|
||||
|
||||
this._quarterround(mix, 0, 5, 10, 15);
|
||||
this._quarterround(mix, 1, 6, 11, 12);
|
||||
this._quarterround(mix, 2, 7, 8, 13);
|
||||
this._quarterround(mix, 3, 4, 9, 14);
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
// add
|
||||
mix[i] += this._param[i];
|
||||
|
||||
// store keystream
|
||||
this._keystream[b++] = mix[i] & 0xff;
|
||||
this._keystream[b++] = (mix[i] >>> 8) & 0xff;
|
||||
this._keystream[b++] = (mix[i] >>> 16) & 0xff;
|
||||
this._keystream[b++] = (mix[i] >>> 24) & 0xff;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The basic operation of the ChaCha algorithm is the quarter round.
|
||||
* It operates on four 32-bit unsigned integers, denoted a, b, c, and d.
|
||||
*
|
||||
* @param {Array} output
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
* @param {number} c
|
||||
* @param {number} d
|
||||
* @private
|
||||
*/
|
||||
JSChaCha20.prototype._quarterround = function(output, a, b, c, d) {
|
||||
output[d] = this._rotl(output[d] ^ (output[a] += output[b]), 16);
|
||||
output[b] = this._rotl(output[b] ^ (output[c] += output[d]), 12);
|
||||
output[d] = this._rotl(output[d] ^ (output[a] += output[b]), 8);
|
||||
output[b] = this._rotl(output[b] ^ (output[c] += output[d]), 7);
|
||||
|
||||
// JavaScript hack to make UINT32 :) //
|
||||
output[a] >>>= 0;
|
||||
output[b] >>>= 0;
|
||||
output[c] >>>= 0;
|
||||
output[d] >>>= 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Little-endian to uint 32 bytes
|
||||
*
|
||||
* @param {Uint8Array|[number]} data
|
||||
* @param {number} index
|
||||
* @return {number}
|
||||
* @private
|
||||
*/
|
||||
JSChaCha20.prototype._get32 = function(data, index) {
|
||||
return (
|
||||
data[index++] ^
|
||||
(data[index++] << 8) ^
|
||||
(data[index++] << 16) ^
|
||||
(data[index] << 24)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Cyclic left rotation
|
||||
*
|
||||
* @param {number} data
|
||||
* @param {number} shift
|
||||
* @return {number}
|
||||
* @private
|
||||
*/
|
||||
JSChaCha20.prototype._rotl = function(data, shift) {
|
||||
return (data << shift) | (data >>> (32 - shift));
|
||||
};
|
||||
|
||||
/**
|
||||
* Encrypt data with key and nonce
|
||||
*
|
||||
* @param {Uint8Array} data
|
||||
* @return {Uint8Array}
|
||||
*/
|
||||
JSChaCha20.prototype.encrypt = function(data) {
|
||||
return this._update(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Decrypt data with key and nonce
|
||||
*
|
||||
* @param {Uint8Array} data
|
||||
* @return {Uint8Array}
|
||||
*/
|
||||
JSChaCha20.prototype.decrypt = function(data) {
|
||||
return this._update(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Encrypt or Decrypt data with key and nonce
|
||||
*
|
||||
* @param {Uint8Array} data
|
||||
* @return {Uint8Array}
|
||||
* @private
|
||||
*/
|
||||
JSChaCha20.prototype._update = function(data) {
|
||||
if (!(data instanceof Uint8Array) || data.length === 0) {
|
||||
throw new Error('Data should be type of bytes (Uint8Array) and not empty!');
|
||||
}
|
||||
|
||||
var output = new Uint8Array(data.length);
|
||||
|
||||
// core function, build block and xor with input data //
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
if (this._byteCounter === 0 || this._byteCounter === 64) {
|
||||
// generate new block //
|
||||
|
||||
this._chacha();
|
||||
// counter increment //
|
||||
this._param[12]++;
|
||||
|
||||
// reset internal counter //
|
||||
this._byteCounter = 0;
|
||||
}
|
||||
|
||||
output[i] = data[i] ^ this._keystream[this._byteCounter++];
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
// EXPORT //
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = JSChaCha20;
|
||||
}
|
||||
Reference in New Issue
Block a user