forked from coolaj86/walnut.js
		
	
		
			
	
	
		
			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();
							 | 
						||
| 
								 | 
							
								}());
							 |