/* * JavaScript implementation of Password-Based Key Derivation Function 2 * (PBKDF2) as defined in RFC 2898. * Version 1.5 * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Parvez Anandam * parvez@anandam.com * http://anandam.com/pbkdf2 * * Distributed under the BSD license * * Uses Paul Johnston's excellent SHA-1 JavaScript library sha1.js: * http://pajhome.org.uk/crypt/md5/sha1.html * (uses the binb_sha1(), rstr2binb(), binb2str(), rstr2hex() functions from that libary) * * Thanks to Felix Gartsman for pointing out a bug in version 1.0 * Thanks to Thijs Van der Schaeghe for pointing out a bug in version 1.1 * Thanks to Richard Gautier for asking to clarify dependencies in version 1.2 * Updated contact information from version 1.3 * Thanks to Stuart Heinrich for pointing out updates to PAJ's SHA-1 library in version 1.4 */ /* * The four arguments to the constructor of the PBKDF2 object are * the password, salt, number of iterations and number of bytes in * generated key. This follows the RFC 2898 definition: PBKDF2 (P, S, c, dkLen) * * The method deriveKey takes two parameters, both callback functions: * the first is used to provide status on the computation, the second * is called with the result of the computation (the generated key in hex). * * Example of use: * * * * *
* */ function PBKDF2(password, salt, num_iterations, num_bytes) { // Remember the password and salt var m_bpassword = rstr2binb(password); var m_salt = salt; // Total number of iterations var m_total_iterations = num_iterations; // Run iterations in chunks instead of all at once, so as to not block. // Define size of chunk here; adjust for slower or faster machines if necessary. var m_iterations_in_chunk = 10; // Iteration counter var m_iterations_done = 0; // Key length, as number of bytes var m_key_length = num_bytes; // The hash cache var m_hash = null; // The length (number of bytes) of the output of the pseudo-random function. // Since HMAC-SHA1 is the standard, and what is used here, it's 20 bytes. var m_hash_length = 20; // Number of hash-sized blocks in the derived key (called 'l' in RFC2898) var m_total_blocks = Math.ceil(m_key_length/m_hash_length); // Start computation with the first block var m_current_block = 1; // Used in the HMAC-SHA1 computations var m_ipad = new Array(16); var m_opad = new Array(16); // This is where the result of the iterations gets sotred var m_buffer = new Array(0x0,0x0,0x0,0x0,0x0); // The result var m_key = ""; // This object var m_this_object = this; // The function to call with the result var m_result_func; // The function to call with status after computing every chunk var m_status_func; // Set up the HMAC-SHA1 computations if (m_bpassword.length > 16) m_bpassword = binb_sha1(m_bpassword, password.length * chrsz); for(var i = 0; i < 16; ++i) { m_ipad[i] = m_bpassword[i] ^ 0x36363636; m_opad[i] = m_bpassword[i] ^ 0x5C5C5C5C; } // Starts the computation this.deriveKey = function(status_callback, result_callback) { m_status_func = status_callback; m_result_func = result_callback; setTimeout(function() { m_this_object.do_PBKDF2_iterations() }, 0); } // The workhorse this.do_PBKDF2_iterations = function() { var iterations = m_iterations_in_chunk; if (m_total_iterations - m_iterations_done < m_iterations_in_chunk) iterations = m_total_iterations - m_iterations_done; for(var i=0; i> 24 & 0xF) + String.fromCharCode(m_current_block >> 16 & 0xF) + String.fromCharCode(m_current_block >> 8 & 0xF) + String.fromCharCode(m_current_block & 0xF); m_hash = binb_sha1(m_ipad.concat(rstr2binb(salt_block)), 512 + salt_block.length * 8); m_hash = binb_sha1(m_opad.concat(m_hash), 512 + 160); } else { m_hash = binb_sha1(m_ipad.concat(m_hash), 512 + m_hash.length * 32); m_hash = binb_sha1(m_opad.concat(m_hash), 512 + 160); } for(var j=0; j