Files
standardnotes-app-web/app/assets/javascripts/app/services/helpers/webcrypto.js
2017-04-28 11:10:10 -05:00

126 lines
3.2 KiB
JavaScript

var subtleCrypto = window.crypto ? window.crypto.subtle : null;
class SNCryptoWeb extends SNCrypto {
/**
Overrides
*/
defaultPasswordGenerationParams() {
return {pw_func: "pbkdf2", pw_alg: "sha512", pw_key_size: 512, pw_cost: 5000};
}
/** Generates two deterministic keys based on one input */
generateSymmetricKeyPair({password, pw_salt, pw_func, pw_alg, pw_cost, pw_key_size} = {}, callback) {
this.stretchPassword({password: password, pw_func: pw_func, pw_alg: pw_alg, pw_salt: pw_salt, pw_cost: pw_cost, pw_key_size: pw_key_size}, function(output){
var outputLength = output.length;
var firstHalf = output.slice(0, outputLength/2);
var secondHalf = output.slice(outputLength/2, outputLength);
callback([firstHalf, secondHalf]);
})
}
/**
Internal
*/
stretchPassword({password, pw_salt, pw_cost, pw_func, pw_alg, pw_key_size} = {}, callback) {
this.webCryptoImportKey(password, pw_func, function(key){
if(!key) {
console.log("Key is null, unable to continue");
callback(null);
return;
}
this.webCryptoDeriveBits({key: key, pw_func: pw_func, pw_alg: pw_alg, pw_salt: pw_salt, pw_cost: pw_cost, pw_key_size: pw_key_size}, function(key){
if(!key) {
callback(null);
return;
}
callback(key);
}.bind(this))
}.bind(this))
}
webCryptoImportKey(input, pw_func, callback) {
subtleCrypto.importKey(
"raw",
this.stringToArrayBuffer(input),
{name: pw_func.toUpperCase()},
false,
["deriveBits"]
)
.then(function(key){
callback(key);
})
.catch(function(err){
console.error(err);
callback(null);
});
}
webCryptoDeriveBits({key, pw_func, pw_alg, pw_salt, pw_cost, pw_key_size} = {}, callback) {
var algMapping = {
"sha256" : "SHA-256",
"sha512" : "SHA-512",
}
var alg = algMapping[pw_alg];
subtleCrypto.deriveBits(
{
"name": pw_func.toUpperCase(),
salt: this.stringToArrayBuffer(pw_salt),
iterations: pw_cost,
hash: {name: alg},
},
key,
pw_key_size
)
.then(function(bits){
var key = this.arrayBufferToHexString(new Uint8Array(bits));
callback(key);
}.bind(this))
.catch(function(err){
console.error(err);
callback(null);
});
}
stringToArrayBuffer(string) {
// not available on Edge/IE
if(window.TextEncoder) {
var encoder = new TextEncoder("utf-8");
var result = encoder.encode(string);
return result;
} else {
string = unescape(encodeURIComponent(string));
var buf = new ArrayBuffer(string.length);
var bufView = new Uint8Array(buf);
for (var i=0, strLen=string.length; i<strLen; i++) {
bufView[i] = string.charCodeAt(i);
}
return buf;
}
}
arrayBufferToHexString(arrayBuffer) {
var byteArray = new Uint8Array(arrayBuffer);
var hexString = "";
var nextHexByte;
for (var i=0; i<byteArray.byteLength; i++) {
nextHexByte = byteArray[i].toString(16);
if (nextHexByte.length < 2) {
nextHexByte = "0" + nextHexByte;
}
hexString += nextHexByte;
}
return hexString;
}
}
export { SNCryptoWeb }