|
|
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;
|
|
|
}
|