77 lines
2.5 KiB
JavaScript
77 lines
2.5 KiB
JavaScript
(function () {
|
|
'use strict';
|
|
|
|
var crypto = window.crypto;
|
|
var Unibabel = window.Unibabel;
|
|
|
|
function deriveKey(saltHex, passphrase, iter) {
|
|
var keyLenBits = 128;
|
|
var kdfname = "PBKDF2";
|
|
var aesname = "AES-CBC"; // AES-CTR is also popular
|
|
// 100 - probably safe even on a browser running from a raspberry pi using pure js ployfill
|
|
// 10000 - no noticeable speed decrease on my MBP
|
|
// 100000 - you can notice
|
|
// 1000000 - annoyingly long
|
|
var iterations = iter || 100; // something a browser on a raspberry pi or old phone could do
|
|
var hashname = "SHA-256";
|
|
var extractable = true;
|
|
|
|
console.log('');
|
|
console.log('passphrase', passphrase);
|
|
console.log('salt (hex)', saltHex);
|
|
//console.log('salt (hex)', Unibabel.bufferToHex(saltBuf));
|
|
console.log('iterations', iterations);
|
|
console.log('keyLen (bytes)', keyLenBits / 8);
|
|
console.log('digest', hashname);
|
|
|
|
// First, create a PBKDF2 "key" containing the password
|
|
return crypto.subtle.importKey(
|
|
"raw"
|
|
, Unibabel.utf8ToBuffer(passphrase)
|
|
, { "name": kdfname }
|
|
, false
|
|
, ["deriveKey"]).
|
|
// Derive a key from the password
|
|
then(function (passphraseKey) {
|
|
return crypto.subtle.deriveKey(
|
|
{ "name": kdfname
|
|
, "salt": Unibabel.hexToBuffer(saltHex)
|
|
, "iterations": iterations
|
|
, "hash": hashname
|
|
}
|
|
, passphraseKey
|
|
// required to be 128 or 256 bits
|
|
, { "name": aesname, "length": keyLenBits } // Key we want
|
|
, extractable // Extractble
|
|
, [ "encrypt", "decrypt" ] // For new key
|
|
);
|
|
}).
|
|
// Export it so we can display it
|
|
then(function (aesKey) {
|
|
return crypto.subtle.exportKey("raw", aesKey).then(function (arrbuf) {
|
|
return new Uint8Array(arrbuf);
|
|
});
|
|
}).
|
|
catch(function (err) {
|
|
window.alert("Key derivation failed: " + err.message);
|
|
});
|
|
}
|
|
|
|
function test() {
|
|
// Part of the salt is application-specific (same on iOS, Android, and Web)
|
|
var saltHex = '942c2db750b5f57f330226b2b498c6d3';
|
|
var passphrase = 'Pizzas are like children';
|
|
//var passphrase = "I'm a ☢ ☃ who speaks 中国语文!";
|
|
var iter = 1672;
|
|
|
|
// NOTE: the salt will be truncated to the length of the hash algo being used
|
|
return deriveKey(saltHex, passphrase, iter).then(function (keyBuf) {
|
|
var hexKey = Unibabel.bufferToHex(keyBuf);
|
|
console.log('[TEST] hexKey');
|
|
console.log(hexKey);
|
|
});
|
|
}
|
|
|
|
test();
|
|
}());
|