# HG changeset patch # User Laman # Date 2019-07-05 13:46:34 # Node ID 64020ac8e211d17165f0ee2f9df6f9d29f958a2c # Parent 7eec13103f809564806a037d5798e4a2310dcef7 added key stretching with PBKDF2 diff --git a/src/blake.js b/src/blake.js --- a/src/blake.js +++ b/src/blake.js @@ -9,6 +9,11 @@ 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 diff --git a/src/chacha.js b/src/chacha.js --- a/src/chacha.js +++ b/src/chacha.js @@ -5,7 +5,7 @@ function lrot(x,shift){ return (x<>>(32-shift))&MASK; } -function createNonce(){ +export function createNonce(){ let nonce=new Uint8Array(12); window.crypto.getRandomValues(nonce); return Array.from(nonce); diff --git a/src/main.js b/src/main.js --- a/src/main.js +++ b/src/main.js @@ -1,16 +1,19 @@ 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); } @@ -19,14 +22,27 @@ function decrypt(s,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<=500){break;} + } + return [i,key]; +} + export default {util,blake2s,pbkdf2,Chacha20,encrypt,decrypt}; // export for tests running on Node