Changeset - e2095e3881bf
[Not reviewed]
default
0 9 0
Laman - 2 years ago 2022-04-01 13:09:18

reformated with more whitespace
9 files changed with 383 insertions and 381 deletions:
0 comments (0 inline, 0 general)
spec/test/blakeSpec.js
Show inline comments
 
/* global expect */
 

	
 
describe("Blake2",function(){
 
	let cryptoJS=require("../../dist/main.js");
 
	let util=cryptoJS.util;
 
	let blake2s=cryptoJS.blake2s;
 
	let str2utf8=util.str2utf8;
 
	
 
	let msg=str2utf8("abc");
 
	let longMsg=str2utf8("0123456789.10.456789.20.456789.30.456789.40.456789.50.456789.60.456789.70.456789.80.456789.90.456789");
 
	let key=str2utf8("zoqpiz");
 
	let longKey=str2utf8("zoqpizjutyclcmkamzhhmhvchxjtefjy");
 
	
 
	describe("blake2s",function(){
 
		it("should return a correct variable size output",function(){
 
			expect(util.bytes2hex(blake2s(msg,16))).toEqual("aa4938119b1dc7b87cbad0ffd200d0ae");
 
describe("Blake2", function () {
 
	let cryptoJS = require("../../dist/main.js");
 
	let util = cryptoJS.util;
 
	let blake2s = cryptoJS.blake2s;
 
	let str2utf8 = util.str2utf8;
 

	
 
	let msg = str2utf8("abc");
 
	let longMsg = str2utf8("0123456789.10.456789.20.456789.30.456789.40.456789.50.456789.60.456789.70.456789.80.456789.90.456789");
 
	let key = str2utf8("zoqpiz");
 
	let longKey = str2utf8("zoqpizjutyclcmkamzhhmhvchxjtefjy");
 

	
 
	describe("blake2s", function() {
 
		it("should return a correct variable size output", function() {
 
			expect(util.bytes2hex(blake2s(msg, 16))).toEqual("aa4938119b1dc7b87cbad0ffd200d0ae");
 
		});
 
		it("should work with just a message",function(){
 
		it("should work with just a message", function() {
 
			expect(util.bytes2hex(blake2s(msg))).toEqual("508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982");
 
		});
 
		it("should work for multi block messages",function(){
 
			expect(util.bytes2hex(blake2s(longMsg.slice(0,64)))).toEqual("70484f89974551454d596350dda8af2aa6f0811b527549b9ecfe7adede063753");
 
			expect(util.bytes2hex(blake2s(longMsg.slice(0,65)))).toEqual("af14d4f74947bbde734d0e3015c667cc80676efe4349be235be8046e9e45e0ae");
 
		it("should work for multi block messages", function() {
 
			expect(util.bytes2hex(blake2s(longMsg.slice(0, 64)))).toEqual("70484f89974551454d596350dda8af2aa6f0811b527549b9ecfe7adede063753");
 
			expect(util.bytes2hex(blake2s(longMsg.slice(0, 65)))).toEqual("af14d4f74947bbde734d0e3015c667cc80676efe4349be235be8046e9e45e0ae");
 
			expect(util.bytes2hex(blake2s(longMsg))).toEqual("59a44e5e417d07fb382505ee7e67c23e0d476d354abc81899960bcab677beee1");
 
		});
 
		it("should work for keyed messages",function(){
 
			expect(util.bytes2hex(blake2s(msg,32,key))).toEqual("0da0b6a54e8f294b60bb25c572700166ddb9d124257ff36f9f43f18b844adf9f");
 
		it("should work for keyed messages", function() {
 
			expect(util.bytes2hex(blake2s(msg, 32, key))).toEqual("0da0b6a54e8f294b60bb25c572700166ddb9d124257ff36f9f43f18b844adf9f");
 
		});
 
		it("should work with long keyes",function(){
 
			expect(util.bytes2hex(blake2s(msg,32,longKey))).toEqual("09ef85c9942bebdeb866c6ade769220fd9b851aead642017f6d59bf7e2a32037");
 
		it("should work with long keyes", function() {
 
			expect(util.bytes2hex(blake2s(msg, 32, longKey))).toEqual("09ef85c9942bebdeb866c6ade769220fd9b851aead642017f6d59bf7e2a32037");
 
		});
 
		it("should work with an empty input",function(){
 
		it("should work with an empty input", function() {
 
			expect(util.bytes2hex(blake2s([]))).toEqual("69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9");
 
		});
 
	});
 
	
 

	
 
});
spec/test/chachaSpec.js
Show inline comments
 
/* global expect */
 

	
 
function getRandomValues(arr){
 
	for(let i=0;i<arr.length;i++){
 
		arr[i]=Math.floor(Math.random()*256);
 
function getRandomValues(arr) {
 
	for (let i = 0; i < arr.length; i++) {
 
		arr[i] = Math.floor(Math.random()*256);
 
	}
 
}
 

	
 
window={
 
window = {
 
	crypto: {
 
		getRandomValues: getRandomValues
 
	}
 
};
 

	
 
describe("Chacha",function(){
 
	let cryptoJS=require("../../dist/main.js");
 
	let util=cryptoJS.util;
 
	let Chacha20=cryptoJS.Chacha20;
 
	let encrypt=cryptoJS.encrypt;
 
	let decrypt=cryptoJS.decrypt;
 
	let str2utf8=util.str2utf8;
 
	
 
	let key=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31];
 
	let nonce1=[0,0,0,9,0,0,0,74,0,0,0,0];
 
	let nonce2=[0,0,0,0,0,0,0,74,0,0,0,0];
 
	let plaintext="Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
 
	
 
	describe("Chacha20",function(){
 
		it("should return a correct test vector",function(){
 
			let cipher=new Chacha20(key,nonce1);
 
			let output=cipher._computeBlock().map(x=>x>>>0);
 
			let expected=[0xe4e7f110,0x15593bd1,0x1fdd0f50,0xc47120a3,0xc7f4d1c7,0x0368c033,0x9aaa2204,0x4e6cd4c3,0x466482d2,0x09aa9f07,0x05d7c214,0xa2028bd9,0xd19c12b5,0xb94e16de,0xe883d0cb,0x4e3c50a2];
 
describe("Chacha", function() {
 
	let cryptoJS = require("../../dist/main.js");
 
	let util = cryptoJS.util;
 
	let Chacha20 = cryptoJS.Chacha20;
 
	let encrypt = cryptoJS.encrypt;
 
	let decrypt = cryptoJS.decrypt;
 
	let str2utf8 = util.str2utf8;
 

	
 
	let key = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31];
 
	let nonce1 = [0, 0, 0, 9, 0, 0, 0, 74, 0, 0, 0, 0];
 
	let nonce2 = [0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 0, 0];
 
	let plaintext = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
 

	
 
	describe("Chacha20", function() {
 
		it("should return a correct test vector", function() {
 
			let cipher = new Chacha20(key, nonce1);
 
			let output = cipher._computeBlock().map(x => x >>> 0);
 
			let expected = [0xe4e7f110, 0x15593bd1, 0x1fdd0f50, 0xc47120a3, 0xc7f4d1c7, 0x0368c033, 0x9aaa2204, 0x4e6cd4c3, 0x466482d2, 0x09aa9f07, 0x05d7c214, 0xa2028bd9, 0xd19c12b5, 0xb94e16de, 0xe883d0cb, 0x4e3c50a2];
 
			expect(output).toEqual(expected);
 
		});
 
		
 
		it("should output a correct key stream",function(){
 
			let cipher=new Chacha20(key,nonce2);
 
			let expected=[34,79,81,243,64,27,217,225,47,222,39,111,184,99,29,237,140,19,31,130,61,44,6, 226,126,79,202,236,158,243,207,120,138,59,10,163,114,96,10,146,181,121,116,205,237,43,147,52,121, 76,186,64,198,62,52,205,234,33,44,76,240,125,65,183,105,166,116,159,63,99,15,65,34,202,254,40,236, 77,196,126,38,212,52,109,112,185,140,115,243,233,197,58,196,12,89,69,57,139,110,218,26,131,44,137, 193,103,234,205,144,29,126,43,243,99];
 
			expected.forEach(b=>{
 

	
 
		it("should output a correct key stream", function() {
 
			let cipher = new Chacha20(key, nonce2);
 
			let expected = [34, 79, 81, 243, 64, 27, 217, 225, 47, 222, 39, 111, 184, 99, 29, 237, 140, 19, 31, 130, 61, 44, 6, 226, 126, 79, 202, 236, 158, 243, 207, 120, 138, 59, 10, 163, 114, 96, 10, 146, 181, 121, 116, 205, 237, 43, 147, 52, 121, 76, 186, 64, 198, 62, 52, 205, 234, 33, 44, 76, 240, 125, 65, 183, 105, 166, 116, 159, 63, 99, 15, 65, 34, 202, 254, 40, 236, 77, 196, 126, 38, 212, 52, 109, 112, 185, 140, 115, 243, 233, 197, 58, 196, 12, 89, 69, 57, 139, 110, 218, 26, 131, 44, 137, 193, 103, 234, 205, 144, 29, 126, 43, 243, 99];
 
			expected.forEach(b => {
 
				expect(cipher.getByte()).toEqual(b);
 
			});
 
		});
 
		
 

	
 
	});
 
	
 
	describe("encrypt",function(){
 
		it("should correctly encrypt an example text",function(){
 
			let ciphertext=[110,46,53,154,37,104,249,128,65,186,7,40,221,13,105,129,233,126,122,236,29, 67,96,194,10,39,175,204,253,159,174,11,249,27,101,197,82,71,51,171,143,89,61,171,205,98,179,87,22, 57,214,36,230,81,82,171,143,83,12,53,159,8,97,216,7,202,13,191,80,13,106,97,86,163,142,8,138,34, 182,94,82,188,81,77,22,204,248,6,129,140,233,26,183,121,55,54,90,249,11,191,116,163,91,230,180,11, 142,237,242,120,94,66,135,77];
 
			expect(encrypt(str2utf8(plaintext),key,nonce2)).toEqual([nonce2,ciphertext]);
 

	
 
	describe("encrypt", function() {
 
		it("should correctly encrypt an example text", function() {
 
			let ciphertext = [110, 46, 53, 154, 37, 104, 249, 128, 65, 186, 7, 40, 221, 13, 105, 129, 233, 126, 122, 236, 29, 67, 96, 194, 10, 39, 175, 204, 253, 159, 174, 11, 249, 27, 101, 197, 82, 71, 51, 171, 143, 89, 61, 171, 205, 98, 179, 87, 22, 57, 214, 36, 230, 81, 82, 171, 143, 83, 12, 53, 159, 8, 97, 216, 7, 202, 13, 191, 80, 13, 106, 97, 86, 163, 142, 8, 138, 34, 182, 94, 82, 188, 81, 77, 22, 204, 248, 6, 129, 140, 233, 26, 183, 121, 55, 54, 90, 249, 11, 191, 116, 163, 91, 230, 180, 11, 142, 237, 242, 120, 94, 66, 135, 77];
 
			expect(encrypt(str2utf8(plaintext), key, nonce2)).toEqual([nonce2, ciphertext]);
 
		});
 
	});
 
	
 
	describe("decrypt",function(){
 
		it("should be able to decrypt a Chacha20 encrypted text",function(){
 
			let text=str2utf8(plaintext);
 
			let key=[];
 
			for(let i=0;i<16;i++){key.push(Math.floor(Math.random()*256));}
 
			let [nonce,ciphertext]=encrypt(text,key);
 
			expect(decrypt(ciphertext,key,nonce)).toEqual(text);
 

	
 
	describe("decrypt", function() {
 
		it("should be able to decrypt a Chacha20 encrypted text", function() {
 
			let text = str2utf8(plaintext);
 
			let key = [];
 
			for (let i = 0; i < 16; i++) {key.push(Math.floor(Math.random() * 256));}
 
			let [nonce, ciphertext] = encrypt(text, key);
 
			expect(decrypt(ciphertext, key, nonce)).toEqual(text);
 
		});
 
	});
 
	
 

	
 
});
spec/test/pbkdf2Spec.js
Show inline comments
 
/* global expect */
 

	
 
describe("pbkdf2",function(){
 
	let cryptoJS=require("../../dist/main.js");
 
	let pbkdf2=cryptoJS.pbkdf2;
 
	
 
describe("pbkdf2", function() {
 
	let cryptoJS = require("../../dist/main.js");
 
	let pbkdf2 = cryptoJS.pbkdf2;
 

	
 
	// it is difficult to find an independent implementation or an example of PBKDF2-BLAKE2s with no HMAC.
 
	// so we test against our own values to test at least against bugs introduced later
 
	it("should return a correct test key",function(){
 
		expect(pbkdf2([1,2,3],[4,5,6,7,8,9,10,11],1024,32)).toEqual([2,3,212,35,227,5,152,88,48,219,42, 238,177,51,111,73,233,136,19,10,10,108,89,230,77,23,104,152,86,23,255,14]);
 
		
 
		let longPass="1234567890=10=567890=20=567890=30=56".split("").map(c=>c.charCodeAt(0));
 
		let salt="1234567890_10_56".split("").map(c=>c.charCodeAt(0));
 
		expect(pbkdf2(longPass,salt,1337,48)).toEqual([244,203,226,107,154,99,73,33,255,175,82,97,85, 137,201,104,158,129,12,200,193,48,71,149,117,184,161,189,247,120,62,9,20,30,109,140,190,224,78, 217,133,51,168,25,25,52,247,40]);
 
	it("should return a correct test key", function() {
 
		expect(pbkdf2([1, 2, 3], [4, 5, 6, 7, 8, 9, 10, 11], 1024, 32)).toEqual([2, 3, 212, 35, 227, 5, 152, 88, 48, 219, 42, 238, 177, 51, 111, 73, 233, 136, 19, 10, 10, 108, 89, 230, 77, 23, 104, 152, 86, 23, 255, 14]);
 

	
 
		let longPass = "1234567890=10=567890=20=567890=30=56".split("").map(c => c.charCodeAt(0));
 
		let salt = "1234567890_10_56".split("").map(c => c.charCodeAt(0));
 
		expect(pbkdf2(longPass, salt, 1337, 48)).toEqual([244, 203, 226, 107, 154, 99, 73, 33, 255, 175, 82, 97, 85, 137, 201, 104, 158, 129, 12, 200, 193, 48, 71, 149, 117, 184, 161, 189, 247, 120, 62, 9, 20, 30, 109, 140, 190, 224, 78, 217, 133, 51, 168, 25, 25, 52, 247, 40]);
 
	});
 
	
 

	
 
});
spec/test/utilSpec.js
Show inline comments
 
/* global expect */
 

	
 
describe("Util",function(){
 
  let cryptoJS=require("../../dist/main.js");
 
	let util=cryptoJS.util;
 
	let utf=[ // https://tools.ietf.org/html/rfc3629#page-8
 
		["",[]],
 
		["abc",[97,98,99]],
 
		["Ã¥",[195,165]],
 
		["🚅",[240,159,154,133]],
 
		["žír",[0xc5,0xbe,0xc3,0xad,114]],
 
		["A\u2262\u0391.",[0x41,0xE2,0x89,0xA2,0xCE,0x91,0x2E]],
 
		["\uD55C\uAD6D\uC5B4",[0xED,0x95,0x9C,0xEA,0xB5,0xAD,0xEC,0x96,0xB4]],
 
		["\ud84c\udfb4",[0xf0,0xa3,0x8e,0xb4]]
 
describe("Util", function() {
 
	let cryptoJS = require("../../dist/main.js");
 
	let util = cryptoJS.util;
 
	let utf = [ // https://tools.ietf.org/html/rfc3629#page-8
 
		["", []],
 
		["abc", [97, 98, 99]],
 
		["Ã¥", [195, 165]],
 
		["🚅", [240, 159, 154, 133]],
 
		["žír", [0xc5, 0xbe, 0xc3, 0xad, 114]],
 
		["A\u2262\u0391.", [0x41, 0xE2, 0x89, 0xA2, 0xCE, 0x91, 0x2E]],
 
		["\uD55C\uAD6D\uC5B4", [0xED, 0x95, 0x9C, 0xEA, 0xB5, 0xAD, 0xEC, 0x96, 0xB4]],
 
		["\ud84c\udfb4", [0xf0, 0xa3, 0x8e, 0xb4]]
 
	];
 
	let base64=[
 
		[[],""],
 
		[[102],"Zg=="],
 
		[[102,111],"Zm8="],
 
		[[102,111,111],"Zm9v"],
 
		[[102,111,111,98],"Zm9vYg=="],
 
		[[102,111,111,98,97],"Zm9vYmE="],
 
		[[102,111,111,98,97,114],"Zm9vYmFy"]
 
	let base64 = [
 
		[[], ""],
 
		[[102], "Zg=="],
 
		[[102, 111], "Zm8="],
 
		[[102, 111, 111], "Zm9v"],
 
		[[102, 111, 111, 98], "Zm9vYg=="],
 
		[[102, 111, 111, 98, 97], "Zm9vYmE="],
 
		[[102, 111, 111, 98, 97, 114], "Zm9vYmFy"]
 
	];
 
	
 
	describe("bytes2int32s",function(){
 
		it("should pack bytes into 32b integers",function(){
 

	
 
	describe("bytes2int32s", function() {
 
		it("should pack bytes into 32b integers", function() {
 
			expect(util.bytes2int32s([])).toEqual([]);
 
			expect(util.bytes2int32s([0])).toEqual([0]);
 
			expect(util.bytes2int32s([1])).toEqual([1]);
 
			expect(util.bytes2int32s([0x12,0x34,0x56,0x78,0x9a])).toEqual([0x78563412,0x9a]);
 
			expect(util.bytes2int32s([0x12, 0x34, 0x56, 0x78, 0x9a])).toEqual([0x78563412, 0x9a]);
 
		});
 
	});
 
	
 
	describe("str2utf8",function(){
 
		it("should encode a String into bytes in UTF-8",function(){
 
			utf.forEach(couple=>expect(util.str2utf8(couple[0])).toEqual(couple[1]));
 

	
 
	describe("str2utf8", function() {
 
		it("should encode a String into bytes in UTF-8", function() {
 
			utf.forEach(couple => expect(util.str2utf8(couple[0])).toEqual(couple[1]));
 
		});
 
	});
 
	
 
	describe("utf82str",function(){
 
		it("should decode a String from UTF-8 bytes",function(){
 
			utf.forEach(couple=>expect(util.utf82str(couple[1])).toEqual(couple[0]));
 

	
 
	describe("utf82str", function() {
 
		it("should decode a String from UTF-8 bytes", function() {
 
			utf.forEach(couple => expect(util.utf82str(couple[1])).toEqual(couple[0]));
 
		});
 
	});
 
	
 
	
 
	describe("bytes2base64",function(){
 
		it("should correctly encode bytes into base64",function(){
 
			base64.forEach(couple=>expect(util.bytes2base64(couple[0])).toEqual(couple[1]));
 

	
 

	
 
	describe("bytes2base64", function() {
 
		it("should correctly encode bytes into base64", function() {
 
			base64.forEach(couple => expect(util.bytes2base64(couple[0])).toEqual(couple[1]));
 
		});
 
	});
 
	
 
	describe("base642bytes",function(){
 
		it("should correctly decode bytes from base64",function(){
 
			base64.forEach(couple=>expect(util.base642bytes(couple[1])).toEqual(couple[0]));
 

	
 
	describe("base642bytes", function() {
 
		it("should correctly decode bytes from base64", function() {
 
			base64.forEach(couple => expect(util.base642bytes(couple[1])).toEqual(couple[0]));
 
		});
 
	});
 
});
src/blake.js
Show inline comments
 
// https://tools.ietf.org/html/rfc7693
 
import {MASK,int32s2bytes,bytes2int32s,zeroPad} from "./util.js";
 
import {MASK, int32s2bytes, bytes2int32s, zeroPad} from "./util.js";
 

	
 
const BLOCK_LEN=64;
 
const BLOCK_LEN = 64;
 

	
 
const IV=[0x6A09E667,0xBB67AE85,0x3C6EF372,0xA54FF53A,0x510E527F,0x9B05688C,0x1F83D9AB,0x5BE0CD19];
 
const IV = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19];
 

	
 
function rrot(x,shift){
 
	return ((x>>>shift)|(x<<(32-shift)))&MASK;
 
function rrot(x, shift) {
 
	return ((x >>> shift) | (x << (32-shift))) & MASK;
 
}
 

	
 
/**
 
@@ -14,81 +14,83 @@ function rrot(x,shift){
 
 * @param {Array} key byte array, 0<=key.length<=32
 
 * @returns {BLAKE2S}
 
 */
 
export function BLAKE2S(outputLen=32,key=[]){
 
	this._buffer=[];
 
	this._dataLen=[0,0]; // low, high
 
	this._outputLen=outputLen;
 
	
 
	this._state=IV.slice();
 
	this._state[0]^=0x01010000^(key.length<<8)^this._outputLen;
 
	
 
	if(key.length>0){this.update(zeroPad(key,BLOCK_LEN));}
 
export function BLAKE2S(outputLen = 32, key = []) {
 
	this._buffer = [];
 
	this._dataLen = [0, 0]; // low, high
 
	this._outputLen = outputLen;
 

	
 
	this._state = IV.slice();
 
	this._state[0] ^= 0x01010000 ^ (key.length << 8) ^ this._outputLen;
 

	
 
	if (key.length > 0) {this.update(zeroPad(key, BLOCK_LEN));}
 
}
 

	
 
BLAKE2S.prototype.update=function(data){
 
	for(let i=0;i<data.length;i++){
 
		if(this._buffer.length==BLOCK_LEN){
 
BLAKE2S.prototype.update = function (data) {
 
	for (let i = 0; i < data.length; i++) {
 
		if (this._buffer.length == BLOCK_LEN) {
 
			this._compress(false);
 
			this._buffer=[];
 
			this._buffer = [];
 
		}
 
		this._buffer.push(data[i]);
 
		this._dataLen[0]=(this._dataLen[0]+1)&MASK;
 
		if(this._dataLen[0]<this._buffer.length){this._dataLen[1]++;}
 
		this._dataLen[0] = (this._dataLen[0]+1) & MASK;
 
		if (this._dataLen[0] < this._buffer.length) {this._dataLen[1]++;}
 
	}
 
};
 

	
 
BLAKE2S.prototype.digest=function(){
 
	this._buffer=zeroPad(this._buffer,BLOCK_LEN);
 
BLAKE2S.prototype.digest = function () {
 
	this._buffer = zeroPad(this._buffer, BLOCK_LEN);
 
	this._compress(true);
 
	return int32s2bytes(this._state).slice(0,this._outputLen);
 
	return int32s2bytes(this._state).slice(0, this._outputLen);
 
};
 

	
 
BLAKE2S.prototype._compress=function(last){
 
	const SIGMA=[
 
		[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],
 
		[14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3],
 
		[11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4],
 
		[7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8],
 
		[9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13],
 
		[2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9],
 
		[12,5,1,15,14,13,4,10,0,7,6,3,9,2,8,11],
 
		[13,11,7,14,12,1,3,9,5,0,15,4,8,6,2,10],
 
		[6,15,14,9,11,3,0,8,12,2,13,7,1,4,10,5],
 
		[10,2,8,4,7,6,1,5,15,11,9,14,3,12,13,0]
 
BLAKE2S.prototype._compress = function (last) {
 
	const SIGMA = [
 
		[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
 
		[14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
 
		[11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
 
		[7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
 
		[9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
 
		[2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
 
		[12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
 
		[13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
 
		[6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
 
		[10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0]
 
	];
 
	let v=this._state.concat(IV);
 
	v[12]^=this._dataLen[0];
 
	v[13]^=this._dataLen[1];
 
	if(last){v[14]^=MASK;}
 
	let data=bytes2int32s(this._buffer);
 
	let v = this._state.concat(IV);
 
	v[12] ^= this._dataLen[0];
 
	v[13] ^= this._dataLen[1];
 
	if (last) {v[14] ^= MASK;}
 
	let data = bytes2int32s(this._buffer);
 

	
 
	for(let i=0;i<10;i++){
 
		let perm=SIGMA[i%10];
 
		this._mix(v,0,4,8,12,data[perm[0]],data[perm[1]]);
 
		this._mix(v,1,5,9,13,data[perm[2]],data[perm[3]]);
 
		this._mix(v,2,6,10,14,data[perm[4]],data[perm[5]]);
 
		this._mix(v,3,7,11,15,data[perm[6]],data[perm[7]]);
 
	for (let i = 0; i < 10; i++) {
 
		let perm = SIGMA[i % 10];
 
		this._mix(v, 0, 4, 8, 12, data[perm[0]], data[perm[1]]);
 
		this._mix(v, 1, 5, 9, 13, data[perm[2]], data[perm[3]]);
 
		this._mix(v, 2, 6, 10, 14, data[perm[4]], data[perm[5]]);
 
		this._mix(v, 3, 7, 11, 15, data[perm[6]], data[perm[7]]);
 

	
 
		this._mix(v,0,5,10,15,data[perm[8]],data[perm[9]]);
 
		this._mix(v,1,6,11,12,data[perm[10]],data[perm[11]]);
 
		this._mix(v,2,7,8,13,data[perm[12]],data[perm[13]]);
 
		this._mix(v,3,4,9,14,data[perm[14]],data[perm[15]]);
 
		this._mix(v, 0, 5, 10, 15, data[perm[8]], data[perm[9]]);
 
		this._mix(v, 1, 6, 11, 12, data[perm[10]], data[perm[11]]);
 
		this._mix(v, 2, 7, 8, 13, data[perm[12]], data[perm[13]]);
 
		this._mix(v, 3, 4, 9, 14, data[perm[14]], data[perm[15]]);
 
	}
 

	
 
	this._state=this._state.map((x,i)=>x^v[i]^v[i+8]);
 
	this._state = this._state.map((x, i) => x ^ v[i] ^ v[i+8]);
 
};
 

	
 
BLAKE2S.prototype._mix=function(arr,ia,ib,ic,id,x,y){
 
	let a=arr[ia], b=arr[ib], c=arr[ic], d=arr[id];
 
	a=(a+b+x)&MASK; d=rrot(d^a,16);
 
	c=(c+d)&MASK; b=rrot(b^c,12);
 
	a=(a+b+y)&MASK; d=rrot(d^a,8);
 
	c=(c+d)&MASK; b=rrot(b^c,7);
 
	arr[ia]=a; arr[ib]=b; arr[ic]=c; arr[id]=d;
 
BLAKE2S.prototype._mix = function (arr, ia, ib, ic, id, x, y) {
 
	let a = arr[ia], b = arr[ib], c = arr[ic], d = arr[id];
 
	a = (a + b + x) & MASK; d = rrot(d ^ a, 16);
 
	c = (c + d) & MASK; b = rrot(b ^ c, 12);
 
	a = (a + b + y) & MASK; d = rrot(d ^ a, 8);
 
	c = (c + d) & MASK; b = rrot(b ^ c, 7);
 
	arr[ia] = a; arr[ib] = b; arr[ic] = c; arr[id] = d;
 
};
 

	
 
export function blake2s(data,outputLen=32,key=[]){
 
	let h=new BLAKE2S(outputLen,key);
 
	for(let i=0;i<data.length;i+=BLOCK_LEN){h.update(data.slice(i,i+BLOCK_LEN));}
 
export function blake2s(data, outputLen = 32, key = []) {
 
	let h = new BLAKE2S(outputLen, key);
 
	for (let i = 0; i < data.length; i += BLOCK_LEN) {
 
		h.update(data.slice(i, i + BLOCK_LEN));
 
	}
 
	return h.digest();
 
}
src/chacha.js
Show inline comments
 
// https://tools.ietf.org/html/rfc7539
 
import {MASK,int32s2bytes,bytes2int32s,zeroPad,createRandomNonce} from "./util.js";
 
import {MASK, int32s2bytes, bytes2int32s, zeroPad, createRandomNonce} from "./util.js";
 

	
 
function lrot(x,shift){
 
	return (x<<shift|x>>>(32-shift))&MASK;
 
function lrot(x, shift) {
 
	return (x << shift | x >>> (32-shift)) & MASK;
 
}
 

	
 
/**
 
@@ -10,80 +10,80 @@ function lrot(x,shift){
 
 * @param {Array} key Array of bytes (integers: 0<=x<256). Short keys are padded to 32B, long keys are silently truncated.
 
 * @param {Array} nonce optional. If present, it must be an Array of bytes (integers: 0<=x<256). Short nonces are padded to 12B, long nonces are silently truncated.
 
 */
 
export function Chacha20(key,nonce){
 
	const NONCE_LEN=12;
 
	if(nonce===undefined){
 
		nonce=createRandomNonce(NONCE_LEN);
 
export function Chacha20(key, nonce) {
 
	const NONCE_LEN = 12;
 
	if (nonce === undefined) {
 
		nonce = createRandomNonce(NONCE_LEN);
 
	}
 
	this._nonce=zeroPad(nonce,NONCE_LEN);
 
	nonce=bytes2int32s(this._nonce);
 
	key=bytes2int32s(zeroPad(key,32));
 
	
 
	this._state=[
 
		0x61707865,0x3320646e,0x79622d32,0x6b206574,
 
		key[0],key[1],key[2],key[3],
 
		key[4],key[5],key[6],key[7],
 
		1,nonce[0],nonce[1],nonce[2]
 
	this._nonce = zeroPad(nonce, NONCE_LEN);
 
	nonce = bytes2int32s(this._nonce);
 
	key = bytes2int32s(zeroPad(key, 32));
 

	
 
	this._state = [
 
		0x61707865, 0x3320646e, 0x79622d32, 0x6b206574,
 
		key[0], key[1], key[2], key[3],
 
		key[4], key[5], key[6], key[7],
 
		1, nonce[0], nonce[1], nonce[2]
 
	];
 
	this._buffer=[];
 
	this._buffer = [];
 
}
 

	
 
Chacha20.prototype.setPos=function(pos){
 
	this._state[12]=pos;
 
	this._buffer=[];
 
Chacha20.prototype.setPos = function(pos) {
 
	this._state[12] = pos;
 
	this._buffer = [];
 
}
 

	
 
Chacha20.prototype.getByte=function(){
 
	if(this._buffer.length==0){
 
		this._buffer=int32s2bytes(this._computeBlock());
 
Chacha20.prototype.getByte = function() {
 
	if (this._buffer.length == 0) {
 
		this._buffer = int32s2bytes(this._computeBlock());
 
		this._incrementPos();
 
	}
 
	return this._buffer.shift();
 
};
 

	
 
Chacha20.prototype.getNonce=function(){
 
Chacha20.prototype.getNonce = function() {
 
	return this._nonce.concat();
 
};
 

	
 
Chacha20.prototype._quarterRound=function(arr,ia,ib,ic,id){
 
	let a=arr[ia], b=arr[ib], c=arr[ic], d=arr[id];
 
	a=(a+b)&MASK; d=lrot(d^a,16);
 
	c=(c+d)&MASK; b=lrot(b^c,12);
 
	a=(a+b)&MASK; d=lrot(d^a,8);
 
	c=(c+d)&MASK; b=lrot(b^c,7);
 
	arr[ia]=a; arr[ib]=b; arr[ic]=c; arr[id]=d;
 
Chacha20.prototype._quarterRound = function(arr, ia, ib, ic, id) {
 
	let a = arr[ia], b = arr[ib], c = arr[ic], d = arr[id];
 
	a = (a+b) & MASK; d = lrot(d^a, 16);
 
	c = (c+d) & MASK; b = lrot(b^c, 12);
 
	a = (a+b) & MASK; d = lrot(d^a, 8);
 
	c = (c+d) & MASK; b = lrot(b^c, 7);
 
	arr[ia] = a; arr[ib] = b; arr[ic] = c; arr[id] = d;
 
};
 

	
 
Chacha20.prototype._computeBlock=function(){
 
	let state=this._state.slice();
 
Chacha20.prototype._computeBlock = function() {
 
	let state = this._state.slice();
 

	
 
	for(let i=0;i<10;i++){ // 10 double rounds
 
	for (let i = 0; i < 10; i++) { // 10 double rounds
 
		// column round
 
		this._quarterRound(state,0,4,8,12);
 
		this._quarterRound(state,1,5,9,13);
 
		this._quarterRound(state,2,6,10,14);
 
		this._quarterRound(state,3,7,11,15);
 
		this._quarterRound(state, 0, 4, 8, 12);
 
		this._quarterRound(state, 1, 5, 9, 13);
 
		this._quarterRound(state, 2, 6, 10, 14);
 
		this._quarterRound(state, 3, 7, 11, 15);
 
		// diagonal round
 
		this._quarterRound(state,0,5,10,15);
 
		this._quarterRound(state,1,6,11,12);
 
		this._quarterRound(state,2,7,8,13);
 
		this._quarterRound(state,3,4,9,14);
 
		this._quarterRound(state, 0, 5, 10, 15);
 
		this._quarterRound(state, 1, 6, 11, 12);
 
		this._quarterRound(state, 2, 7, 8, 13);
 
		this._quarterRound(state, 3, 4, 9, 14);
 
	}
 

	
 
	return state.map((xi,i)=>(xi+this._state[i])&MASK);
 
	return state.map((xi, i) => (xi + this._state[i]) & MASK);
 
};
 

	
 
Chacha20.prototype._incrementPos=function(){
 
	this._state[12]=(this._state[12]+1)&MASK;
 
Chacha20.prototype._incrementPos = function() {
 
	this._state[12] = (this._state[12]+1) & MASK;
 
};
 

	
 
export function encrypt(data,key,nonce){
 
	let cipher=new Chacha20(key,nonce);
 
	nonce=cipher.getNonce();
 
	return [nonce,data.map(b=>b^cipher.getByte())];
 
export function encrypt(data, key, nonce) {
 
	let cipher = new Chacha20(key, nonce);
 
	nonce = cipher.getNonce();
 
	return [nonce, data.map(b => b ^ cipher.getByte())];
 
}
 

	
 
export function decrypt(ciphertext,key,nonce){
 
	let cipher=new Chacha20(key,nonce);
 
	return ciphertext.map(b=>b^cipher.getByte());
 
export function decrypt(ciphertext, key, nonce) {
 
	let cipher = new Chacha20(key, nonce);
 
	return ciphertext.map(b => b ^ cipher.getByte());
 
}
src/main.js
Show inline comments
 
import * as util from "./util.js";
 
import {blake2s} from "./blake.js";
 
import {pbkdf2} from "./pbkdf2.js";
 
import {Chacha20,encrypt as _encrypt,decrypt as _decrypt} from "./chacha.js";
 
import {Chacha20, encrypt as _encrypt, decrypt as _decrypt} from "./chacha.js";
 

	
 
const VERSION=1;
 
const MAX_ITERS=24;
 
const VERSION = 1;
 
const MAX_ITERS = 24;
 

	
 
function encrypt(s,password){
 
	let bs=util.str2utf8(s);
 
	let pass=util.str2utf8(password);
 
	let salt=util.createRandomNonce(12);
 
	let [iters,key]=stretchKey(pass,salt);
 
	let [_,ciphertext]=_encrypt(bs,key,salt);
 
	let signature=blake2s([VERSION,iters].concat(salt,ciphertext),16,key);
 
	let arr=[VERSION,iters].concat(signature,salt,ciphertext);
 
function encrypt(s, password) {
 
	let bs = util.str2utf8(s);
 
	let pass = util.str2utf8(password);
 
	let salt = util.createRandomNonce(12);
 
	let [iters, key] = stretchKey(pass, salt);
 
	let [_, ciphertext] = _encrypt(bs, key, salt);
 
	let signature = blake2s([VERSION, iters].concat(salt, ciphertext), 16, key);
 
	let arr = [VERSION, iters].concat(signature, salt, ciphertext);
 
	return util.bytes2base64(arr);
 
}
 

	
 
function decrypt(s,password){
 
	let pass=util.str2utf8(password);
 
	let arr=util.base642bytes(s);
 
	let version=arr[0];
 
	let iters=arr[1];
 
	let signature=arr.slice(2,18);
 
	let salt=arr.slice(18,30);
 
	let ciphertext=arr.slice(30);
 
	
 
	if(ciphertext.length==0){return 4;}
 
	if(version>VERSION){return 2;}
 
	if(iters>MAX_ITERS){return 3;}
 
	let key=pbkdf2(pass,salt,1<<iters,32);
 
	let check=blake2s([version,iters].concat(salt,ciphertext),16,key);
 
	if(!signature.every((b,i)=>b===check[i])){return 1;}
 
	let plainbytes=_decrypt(ciphertext,key,salt);
 
function decrypt(s, password) {
 
	let pass = util.str2utf8(password);
 
	let arr = util.base642bytes(s);
 
	let version = arr[0];
 
	let iters = arr[1];
 
	let signature = arr.slice(2, 18);
 
	let salt = arr.slice(18, 30);
 
	let ciphertext = arr.slice(30);
 

	
 
	if (ciphertext.length == 0) {return 4;}
 
	if (version > VERSION) {return 2;}
 
	if (iters > MAX_ITERS) {return 3;}
 
	let key = pbkdf2(pass, salt, 1 << iters, 32);
 
	let check = blake2s([version, iters].concat(salt, ciphertext), 16, key);
 
	if (!signature.every((b, i) => b === check[i])) {return 1;}
 
	let plainbytes = _decrypt(ciphertext, key, salt);
 
	return util.utf82str(plainbytes);
 
}
 

	
 
function stretchKey(password,salt){
 
	let start=Date.now(); // ms
 
	let i,key;
 
	for(i=0;i<=MAX_ITERS;i++){
 
		key=pbkdf2(password,salt,1<<i,32);
 
		if(Date.now()-start>=500){break;}
 
function stretchKey(password, salt) {
 
	let start = Date.now(); // ms
 
	let i, key;
 
	for (i = 0; i <= MAX_ITERS; i++) {
 
		key = pbkdf2(password, salt, 1<<i, 32);
 
		if (Date.now()-start >= 500) {break;}
 
	}
 
	return [i,key];
 
	return [i, key];
 
}
 

	
 
export default {util,blake2s,pbkdf2,Chacha20,encrypt,decrypt};
 
export default {util, blake2s, pbkdf2, Chacha20, encrypt, decrypt};
 

	
 
// export for tests running on Node
 
if(typeof module!=='undefined'&&module.hasOwnProperty('exports')){
 
	module.exports.util=util;
 
	module.exports.blake2s=blake2s;
 
	module.exports.pbkdf2=pbkdf2;
 
	module.exports.Chacha20=Chacha20;
 
	module.exports.encrypt=_encrypt;
 
	module.exports.decrypt=_decrypt;
 
if (typeof module !== 'undefined' && module.hasOwnProperty('exports')) {
 
	module.exports.util = util;
 
	module.exports.blake2s = blake2s;
 
	module.exports.pbkdf2 = pbkdf2;
 
	module.exports.Chacha20 = Chacha20;
 
	module.exports.encrypt = _encrypt;
 
	module.exports.decrypt = _decrypt;
 
}
src/pbkdf2.js
Show inline comments
 
@@ -2,27 +2,27 @@
 
import {int322bytesBE} from "./util.js";
 
import {blake2s} from "./blake.js";
 

	
 
const HASH_LENGTH=32;
 
const HASH_LENGTH = 32;
 

	
 
export function pbkdf2(password,salt,iterationCount,outLength){
 
export function pbkdf2(password, salt, iterationCount, outLength) {
 
	// max BLAKE2 key length is 32B
 
	if(password.length>32){password=blake2s(password);}
 
	
 
	let blockCount=Math.ceil(outLength/HASH_LENGTH);
 
	let result=[];
 
	
 
	for(let i=0;i<blockCount;i++){
 
		let block=_computeBlock(password,salt,iterationCount,i+1);
 
		result=result.concat(block);
 
	if (password.length > 32) {password = blake2s(password);}
 

	
 
	let blockCount = Math.ceil(outLength / HASH_LENGTH);
 
	let result = [];
 

	
 
	for (let i = 0; i < blockCount; i++) {
 
		let block = _computeBlock(password, salt, iterationCount, i+1);
 
		result = result.concat(block);
 
	}
 
	return result.slice(0,outLength);
 
	return result.slice(0, outLength);
 
}
 

	
 
function _computeBlock(password,salt,iterationCount,blockIndex){
 
	let u=blake2s(salt.concat(int322bytesBE(blockIndex)),HASH_LENGTH,password);
 
	for(let i=1;i<iterationCount;i++){
 
		let ui=blake2s(u,HASH_LENGTH,password);
 
		u=u.map((b,j)=>b^ui[j]);
 
function _computeBlock(password, salt, iterationCount, blockIndex) {
 
	let u = blake2s(salt.concat(int322bytesBE(blockIndex)), HASH_LENGTH, password);
 
	for (let i = 1; i < iterationCount; i++) {
 
		let ui = blake2s(u, HASH_LENGTH, password);
 
		u = u.map((b, j) => b ^ ui[j]);
 
	}
 
	return u;
 
}
src/util.js
Show inline comments
 
export const MASK=0xffffffff;
 
export const MASK = 0xffffffff;
 

	
 
export function zeroPad(arr,length){
 
	return arr.concat((new Array(length)).fill(0)).slice(0,length);
 
export function zeroPad(arr, length) {
 
	return arr.concat((new Array(length)).fill(0)).slice(0, length);
 
}
 

	
 
export function bytes2int32(arr){
 
	return arr.reduce((acc,b,i)=>acc|b<<(i*8));
 
export function bytes2int32(arr) {
 
	return arr.reduce((acc, b, i) => acc | b << (i*8));
 
}
 

	
 
export function bytes2int32s(arr){
 
	let res=[];
 
	for(let i=0;i<arr.length;i+=4){
 
		res.push(bytes2int32(arr.slice(i,i+4)));
 
export function bytes2int32s(arr) {
 
	let res = [];
 
	for (let i = 0; i < arr.length; i += 4) {
 
		res.push(bytes2int32(arr.slice(i, i+4)));
 
	}
 
	return res;
 
}
 
@@ -19,11 +19,11 @@ export function bytes2int32s(arr){
 
/**
 
 * Converts a 32 bit integer into 4 bytes in little endian order.
 
 */
 
export function int322bytes(x){
 
	let res=[];
 
	for(let i=0;i<4;i++){
 
		res.push(x&0xff);
 
		x>>>=8;
 
export function int322bytes(x) {
 
	let res = [];
 
	for (let i = 0; i < 4; i++) {
 
		res.push(x & 0xff);
 
		x >>>= 8;
 
	}
 
	return res;
 
}
 
@@ -31,116 +31,116 @@ export function int322bytes(x){
 
/**
 
 * Converts a 32 bit integer into 4 bytes in big endian order.
 
 */
 
export function int322bytesBE(x){
 
	let res=int322bytes(x);
 
export function int322bytesBE(x) {
 
	let res = int322bytes(x);
 
	res.reverse();
 
	return res;
 
}
 

	
 
export function int32s2bytes(arr){
 
	return arr.map(int322bytes).reduce((acc,bytes)=>acc.concat(bytes));
 
export function int32s2bytes(arr) {
 
	return arr.map(int322bytes).reduce((acc, bytes) => acc.concat(bytes));
 
}
 

	
 
export function bytes2hex(arr){
 
	return arr.map(x=>x.toString(16).padStart(2,"0")).join("");
 
export function bytes2hex(arr) {
 
	return arr.map(x => x.toString(16).padStart(2, "0")).join("");
 
}
 

	
 
export function str2utf8(s){
 
	let res=[];
 
	let c=s.codePointAt(0);
 
	for(let i=0; c!==undefined; i++,c=s.codePointAt(i)){
 
		if(c<0x80){res.push(c);}
 
		else if(c<0x800){
 
			res.push(0b11000000|(c>>>6));
 
			res.push(0b10000000|(c&0b111111));
 
export function str2utf8(s) {
 
	let res = [];
 
	let c = s.codePointAt(0);
 
	for (let i=0; c!==undefined; i++, c=s.codePointAt(i)) {
 
		if (c < 0x80) {res.push(c);}
 
		else if (c < 0x800) {
 
			res.push(0b11000000 | (c >>> 6));
 
			res.push(0b10000000 | (c & 0b111111));
 
		}
 
		else if(c<0x10000){
 
			res.push(0b11100000|(c>>>12));
 
			res.push(0b10000000|((c>>>6)&0b111111));
 
			res.push(0b10000000|(c&0b111111));
 
		else if (c < 0x10000) {
 
			res.push(0b11100000 | (c >>> 12));
 
			res.push(0b10000000 | ((c >>> 6) & 0b111111));
 
			res.push(0b10000000 | (c & 0b111111));
 
		}
 
		else{
 
			res.push(0b11110000|(c>>>18));
 
			res.push(0b10000000|((c>>>12)&0b111111));
 
			res.push(0b10000000|((c>>>6)&0b111111));
 
			res.push(0b10000000|(c&0b111111));
 
		else {
 
			res.push(0b11110000 | (c >>> 18));
 
			res.push(0b10000000 | ((c >>> 12) & 0b111111));
 
			res.push(0b10000000 | ((c >>> 6) & 0b111111));
 
			res.push(0b10000000 | (c & 0b111111));
 
		}
 
		if(c>0xffff){i++;} // skip surrogate
 
		if (c > 0xffff) {i++;} // skip surrogate
 
	}
 
	return res;
 
}
 

	
 
export function utf82str(arr){
 
	let res=[];
 
	for(let i=0;i<arr.length;i++){
 
		let x=arr[i];
 
		if(x<=0b1111111){res.push(x);}
 
		else if(x<=0b11011111){
 
			let a=x&0b11111;
 
			let b=arr[++i]&0b111111;
 
			res.push(a<<6|b);
 
export function utf82str(arr) {
 
	let res = [];
 
	for (let i = 0; i < arr.length; i++) {
 
		let x = arr[i];
 
		if (x <= 0b1111111) {res.push(x);}
 
		else if (x <= 0b11011111) {
 
			let a = x & 0b11111;
 
			let b = arr[++i] & 0b111111;
 
			res.push(a << 6 | b);
 
		}
 
		else if(x<=0b11101111){
 
			let a=x&0b1111;
 
			let b=arr[++i]&0b111111;
 
			let c=arr[++i]&0b111111;
 
			res.push(a<<12|b<<6|c);
 
		else if (x <= 0b11101111) {
 
			let a = x & 0b1111;
 
			let b = arr[++i] & 0b111111;
 
			let c = arr[++i] & 0b111111;
 
			res.push(a << 12 | b << 6 | c);
 
		}
 
		else{
 
			let a=x&0b111;
 
			let b=arr[++i]&0b111111;
 
			let c=arr[++i]&0b111111;
 
			let d=arr[++i]&0b111111;
 
			res.push(a<<18|b<<12|c<<6|d);
 
		else {
 
			let a = x & 0b111;
 
			let b = arr[++i] & 0b111111;
 
			let c = arr[++i] & 0b111111;
 
			let d = arr[++i] & 0b111111;
 
			res.push(a << 18 | b << 12 | c << 6 | d);
 
		}
 
	}
 
	return res.map(x=>String.fromCodePoint(x)).join("");
 
	return res.map(x => String.fromCodePoint(x)).join("");
 
}
 

	
 
const mapping="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");
 
const remapping=new Array(128);
 
mapping.forEach((c,i)=>{remapping[c.charCodeAt(0)]=i;});
 
const mapping = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("");
 
const remapping = new Array(128);
 
mapping.forEach((c, i) => {remapping[c.charCodeAt(0)] = i;});
 

	
 
export function bytes2base64(byteArr) {
 
	let arr = byteArr.concat();
 
	let out = [];
 
	let rem = (3 - arr.length%3) % 3;
 
	for (let i = 0; i < rem; i++) {arr.push(0);} // pad array to a multiple of 3
 

	
 
export function bytes2base64(byteArr){
 
	let arr=byteArr.concat();
 
	let out=[];
 
	let rem=(3-arr.length%3)%3;
 
	for(let i=0;i<rem;i++){arr.push(0);} // pad array to a multiple of 3
 
	
 
	for(let i=0;i<arr.length;i+=3){ // encode 3 bytes into 4 characters
 
		out.push(mapping[arr[i]>>>2&63]);
 
		out.push(mapping[((arr[i]&3)<<4)+(arr[i+1]>>>4&15)]);
 
		out.push(mapping[((arr[i+1]&15)<<2)+(arr[i+2]>>>6&3)]);
 
		out.push(mapping[arr[i+2]&63]);
 
	for (let i = 0; i < arr.length; i += 3) { // encode 3 bytes into 4 characters
 
		out.push(mapping[arr[i]>>>2 & 63]);
 
		out.push(mapping[((arr[i]&3) << 4) + (arr[i+1]>>>4 & 15)]);
 
		out.push(mapping[((arr[i+1]&15) << 2) + (arr[i+2]>>>6 & 3)]);
 
		out.push(mapping[arr[i+2] & 63]);
 
	}
 
	
 
	for(let i=0;i<rem;i++){out.pop();}
 
	for(let i=0;i<rem;i++){out.push("=");}
 

	
 
	for (let i = 0; i < rem; i++) {out.pop();}
 
	for (let i = 0; i < rem; i++) {out.push("=");}
 

	
 
	return out.join("");
 
}
 

	
 
export function base642bytes(str){
 
	let out=[];
 
	
 
	for(let i=0;i<str.length;i+=4){
 
		let b1=remapping[str.charCodeAt(i)];
 
		let b2=remapping[str.charCodeAt(i+1)];
 
		let b3=remapping[str.charCodeAt(i+2)];
 
		let b4=remapping[str.charCodeAt(i+3)];
 
		
 
		out.push((b1<<2)+(b2>>4&3));
 
		out.push(((b2&15)<<4)+(b3>>2&15));
 
		out.push(((b3&3)<<6)+b4);
 
export function base642bytes(str) {
 
	let out = [];
 

	
 
	for (let i = 0; i < str.length; i += 4) {
 
		let b1 = remapping[str.charCodeAt(i)];
 
		let b2 = remapping[str.charCodeAt(i+1)];
 
		let b3 = remapping[str.charCodeAt(i+2)];
 
		let b4 = remapping[str.charCodeAt(i+3)];
 

	
 
		out.push((b1<<2) + (b2>>4 & 3));
 
		out.push(((b2&15) << 4) + (b3>>2 & 15));
 
		out.push(((b3&3) << 6) + b4);
 
	}
 
	
 
	for(let i=1; i<3&&str[str.length-i]=="="; i++){out.pop();}
 

	
 
	for (let i=1; i<3 && str[str.length-i]=="="; i++) {out.pop();}
 

	
 
	return out;
 
}
 

	
 
export function createRandomNonce(n){
 
	let nonce=new Uint8Array(n);
 
export function createRandomNonce(n) {
 
	let nonce = new Uint8Array(n);
 
	window.crypto.getRandomValues(nonce);
 
	return Array.from(nonce);
 
}
0 comments (0 inline, 0 general)