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