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