keepassxc-browser/chromeKeePassXC/background/cryptoHelpers.js
2017-03-29 16:49:28 +03:00

181 lines
4.5 KiB
JavaScript

/*
* cryptoHelpers.js: implements AES - Advanced Encryption Standard
* from the SlowAES project, http://code.google.com/p/slowaes/
*
* Copyright (c) 2008 Josh Davis ( http://www.josh-davis.org ),
* Mark Percival ( http://mpercival.com ),
* Johan Sundstrom ( http://ecmanaut.blogspot.com ),
* John Resig ( http://ejohn.org )
*
* Licensed under the Apache License, Version 2.0
* http://www.apache.org/licenses/
*/
var cryptoHelpers = {
// encodes a unicode string to UTF8 (8 bit characters are critical to AES functioning properly)
encode_utf8:function(s)
{
try{return unescape(encodeURIComponent(s));}
catch(e){throw 'error during utf8 encoding: cryptoHelpers.encode_utf8.';}
},
// decodes a UTF8 string back to unicode
decode_utf8:function(s)
{
try{return decodeURIComponent(escape(s));}
catch(e){throw('error during utf8 decoding: cryptoHelpers.decode_utf8.');}
},
//convert a number array to a hex string
toHex:function()
{
var array = [];
if(arguments.length == 1 && arguments[0].constructor == Array)
array = arguments[0];
else
array = arguments;
var ret = '';
for(var i = 0;i < array.length;i++)
ret += (array[i] < 16 ? '0' : '') + array[i].toString(16);
return ret.toLowerCase();
},
//convert a hex string to a number array
toNumbers:function(s)
{
var ret = [];
s.replace(/(..)/g,function(s){
ret.push(parseInt(s,16));
});
return ret;
},
// get a random number in the range [min,max]
getRandom:function(min,max)
{
if(min === null)
min = 0;
if(max === null)
max = 1;
return Math.floor(Math.random()*(max+1)) + min;
},
generateSharedKey:function(len)
{
if(len === null)
len = 16;
var key = [];
for(var i = 0; i < len*2; i++)
key.push(this.getRandom(0,255));
return key;
},
generatePrivateKey:function(s,size)
{
var sha = jsHash.sha2.arr_sha256(s);
return sha.slice(0,size);
},
convertStringToByteArray: function(s)
{
var byteArray = [];
for(var i = 0;i < s.length;i++)
{
byteArray.push(s.charCodeAt(i));
}
return byteArray;
},
convertByteArrayToString: function(byteArray)
{
var s = '';
for(var i = 0;i < byteArray.length;i++)
{
s += String.fromCharCode(byteArray[i])
}
return s;
},
base64: {
// Takes a Nx16x1 byte array and converts it to Base64
chars: [
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/',
'=', // for decoding purposes
],
encode_line: function(flatArr){
var b64 = '';
for (var i = 0; i < flatArr.length; i += 3){
b64 += this.chars[flatArr[i] >> 2];
b64 += this.chars[((flatArr[i] & 3) << 4) | (flatArr[i + 1] >> 4)];
if (!(flatArr[i + 1] == null)){
b64 += this.chars[((flatArr[i + 1] & 15) << 2) | (flatArr[i + 2] >> 6)];
}else{
b64 += '=';
}
if (!(flatArr[i + 2] == null)){
b64 += this.chars[flatArr[i + 2] & 63];
}else{
b64 += '=';
}
}
return b64;
},
encode: function(flatArr)
{
var b64 = this.encode_line(flatArr);
// OpenSSL is super particular about line breaks
var broken_b64 = b64.slice(0, 64) + '\n';
for (var i = 1; i < (Math.ceil(b64.length / 64)); i++)
{
broken_b64 += b64.slice(i * 64, i * 64 + 64) + (Math.ceil(b64.length / 64) == i + 1 ? '': '\n');
}
return broken_b64;
},
decode: function(string)
{
string = string.replace(/[\r\n\t ]+/g, '') + '===='; // drop all whitespaces and pad with '=' (end of b64 marker)
var flatArr = [];
var c = [];
var b = [];
for (var i = 0; ; i = i + 4){
c[0] = this.chars.indexOf(string.charAt(i));
if(c[0] == 64){
return flatArr;
}
c[1] = this.chars.indexOf(string.charAt(i + 1));
c[2] = this.chars.indexOf(string.charAt(i + 2));
c[3] = this.chars.indexOf(string.charAt(i + 3));
if(
(c[0] < 0) || // char1 is wrong
(c[1] < 0) || (c[1] == 64) || // char2 is wrong
(c[2] < 0) || // char3 is neither an valid char nor '='
(c[3] < 0) // char4 is neither an valid char nor '='
){
throw 'error during base64 decoding at pos '+i+': cryptoHelpers.base64.decode.';
}
flatArr.push((c[0] << 2) | (c[1] >> 4));
if(c[2] >= 0 && c[2] < 64){
flatArr.push(((c[1] & 15) << 4) | (c[2] >> 2));
if(c[3] >= 0 && c[2] < 64){
flatArr.push(((c[2] & 3) << 6) | c[3]);
}
}
}
},
},
};