PageRenderTime 49ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/app/lib/pbkdf2/pbkdf2.js

https://github.com/astromme/LocalPass
JavaScript | 183 lines | 83 code | 33 blank | 67 comment | 9 complexity | 2a6dd8f62720adbf5884b7c92d065aad MD5 | raw file
  1. /*
  2. * JavaScript implementation of Password-Based Key Derivation Function 2
  3. * (PBKDF2) as defined in RFC 2898.
  4. * Version 1.3
  5. * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012 Parvez Anandam
  6. * parvez.anandam@cern.ch
  7. * http://anandam.name/pbkdf2
  8. *
  9. * Distributed under the BSD license
  10. *
  11. * Uses Paul Johnston's excellent SHA-1 JavaScript library sha1.js:
  12. * http://pajhome.org.uk/crypt/md5/sha1.html
  13. * (uses the str2binb() function from that libary)
  14. *
  15. * Thanks to Felix Gartsman for pointing out a bug in version 1.0
  16. * Thanks to Thijs Van der Schaeghe for pointing out a bug in version 1.1
  17. * Thanks to Richard Gautier for asking to clarify dependencies in version 1.2
  18. */
  19. /*
  20. * The four arguments to the constructor of the PBKDF2 object are
  21. * the password, salt, number of iterations and number of bytes in
  22. * generated key. This follows the RFC 2898 definition: PBKDF2 (P, S, c, dkLen)
  23. *
  24. * The method deriveKey takes two parameters, both callback functions:
  25. * the first is used to provide status on the computation, the second
  26. * is called with the result of the computation (the generated key in hex).
  27. *
  28. * Example of use:
  29. *
  30. * <script src="sha1.js"></script>
  31. * <script src="pbkdf2.js"></script>
  32. * <script>
  33. * var mypbkdf2 = new PBKDF2("mypassword", "saltines", 1000, 16);
  34. * var status_callback = function(percent_done) {
  35. * document.getElementById("status").innerHTML = "Computed " + percent_done + "%"};
  36. * var result_callback = function(key) {
  37. * document.getElementById("status").innerHTML = "The derived key is: " + key};
  38. * mypbkdf2.deriveKey(status_callback, result_callback);
  39. * </script>
  40. * <div id="status"></div>
  41. *
  42. */
  43. function PBKDF2(password, salt, num_iterations, num_bytes)
  44. {
  45. // Remember the password and salt
  46. var m_bpassword = str2binb(password);
  47. var m_salt = salt;
  48. // Total number of iterations
  49. var m_total_iterations = num_iterations;
  50. // Run iterations in chunks instead of all at once, so as to not block.
  51. // Define size of chunk here; adjust for slower or faster machines if necessary.
  52. var m_iterations_in_chunk = 10;
  53. // Iteration counter
  54. var m_iterations_done = 0;
  55. // Key length, as number of bytes
  56. var m_key_length = num_bytes;
  57. // The hash cache
  58. var m_hash = null;
  59. // The length (number of bytes) of the output of the pseudo-random function.
  60. // Since HMAC-SHA1 is the standard, and what is used here, it's 20 bytes.
  61. var m_hash_length = 20;
  62. // Number of hash-sized blocks in the derived key (called 'l' in RFC2898)
  63. var m_total_blocks = Math.ceil(m_key_length/m_hash_length);
  64. // Start computation with the first block
  65. var m_current_block = 1;
  66. // Used in the HMAC-SHA1 computations
  67. var m_ipad = new Array(16);
  68. var m_opad = new Array(16);
  69. // This is where the result of the iterations gets sotred
  70. var m_buffer = new Array(0x0,0x0,0x0,0x0,0x0);
  71. // The result
  72. var m_key = "";
  73. // This object
  74. var m_this_object = this;
  75. // The function to call with the result
  76. var m_result_func;
  77. // The function to call with status after computing every chunk
  78. var m_status_func;
  79. // Set up the HMAC-SHA1 computations
  80. if (m_bpassword.length > 16) m_bpassword = core_sha1(m_bpassword, password.length * chrsz);
  81. for(var i = 0; i < 16; ++i)
  82. {
  83. m_ipad[i] = m_bpassword[i] ^ 0x36363636;
  84. m_opad[i] = m_bpassword[i] ^ 0x5C5C5C5C;
  85. }
  86. // Starts the computation
  87. this.deriveKey = function(status_callback, result_callback)
  88. {
  89. m_status_func = status_callback;
  90. m_result_func = result_callback;
  91. setTimeout(function() { m_this_object.do_PBKDF2_iterations() }, 0);
  92. }
  93. // The workhorse
  94. this.do_PBKDF2_iterations = function()
  95. {
  96. var iterations = m_iterations_in_chunk;
  97. if (m_total_iterations - m_iterations_done < m_iterations_in_chunk)
  98. iterations = m_total_iterations - m_iterations_done;
  99. for(var i=0; i<iterations; ++i)
  100. {
  101. // compute HMAC-SHA1
  102. if (m_iterations_done == 0)
  103. {
  104. var salt_block = m_salt +
  105. String.fromCharCode(m_current_block >> 24 & 0xF) +
  106. String.fromCharCode(m_current_block >> 16 & 0xF) +
  107. String.fromCharCode(m_current_block >> 8 & 0xF) +
  108. String.fromCharCode(m_current_block & 0xF);
  109. m_hash = core_sha1(m_ipad.concat(str2binb(salt_block)),
  110. 512 + salt_block.length * 8);
  111. m_hash = core_sha1(m_opad.concat(m_hash), 512 + 160);
  112. }
  113. else
  114. {
  115. m_hash = core_sha1(m_ipad.concat(m_hash),
  116. 512 + m_hash.length * 32);
  117. m_hash = core_sha1(m_opad.concat(m_hash), 512 + 160);
  118. }
  119. for(var j=0; j<m_hash.length; ++j)
  120. m_buffer[j] ^= m_hash[j];
  121. m_iterations_done++;
  122. }
  123. // Call the status callback function
  124. m_status_func( (m_current_block - 1 + m_iterations_done/m_total_iterations) / m_total_blocks * 100);
  125. if (m_iterations_done < m_total_iterations)
  126. {
  127. setTimeout(function() { m_this_object.do_PBKDF2_iterations() }, 0);
  128. }
  129. else
  130. {
  131. if (m_current_block < m_total_blocks)
  132. {
  133. // Compute the next block (T_i in RFC 2898)
  134. m_key += binb2hex(m_buffer);
  135. m_current_block++;
  136. m_buffer = new Array(0x0,0x0,0x0,0x0,0x0);
  137. m_iterations_done = 0;
  138. setTimeout(function() { m_this_object.do_PBKDF2_iterations() }, 0);
  139. }
  140. else
  141. {
  142. // We've computed the final block T_l; we're done.
  143. var tmp = binb2hex(m_buffer);
  144. m_key += tmp.substr(0, (m_key_length - (m_total_blocks - 1) * m_hash_length) * 2 );
  145. // Call the result callback function
  146. m_result_func(m_key);
  147. }
  148. }
  149. }
  150. }