Changeset - 64020ac8e211
[Not reviewed]
default
0 3 0
Laman - 5 years ago 2019-07-05 13:46:34

added key stretching with PBKDF2
3 files changed with 29 insertions and 8 deletions:
0 comments (0 inline, 0 general)
src/blake.js
Show inline comments
 
@@ -6,12 +6,17 @@ const BLOCK_LEN=64;
 
const IV=[0x6A09E667,0xBB67AE85,0x3C6EF372,0xA54FF53A,0x510E527F,0x9B05688C,0x1F83D9AB,0x5BE0CD19];
 

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

	
 
/**
 
 * @param {number} outputLen output length in bytes, 1<=x<=32
 
 * @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();
src/chacha.js
Show inline comments
 
@@ -2,13 +2,13 @@
 
import {MASK,int32s2bytes,bytes2int32s,zeroPad} from "./util.js";
 

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

	
 
function createNonce(){
 
export function createNonce(){
 
	let nonce=new Uint8Array(12);
 
	window.crypto.getRandomValues(nonce);
 
	return Array.from(nonce);
 
}
 

	
 
/**
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 {createNonce,Chacha20,encrypt as _encrypt,decrypt as _decrypt} from "./chacha.js";
 

	
 
const VERSION=1;
 

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

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

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

	
 
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;
0 comments (0 inline, 0 general)