PBKDF2Async.js 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. (function () {
  2. var C = typeof window === 'undefined' ? require('./Crypto').Crypto : window.Crypto;
  3. // Shortcuts
  4. var util = C.util;
  5. var charenc = C.charenc;
  6. var UTF8 = charenc.UTF8;
  7. var Binary = charenc.Binary;
  8. if (!C.nextTick) {
  9. // node.js has setTime out but prefer process.nextTick
  10. if (typeof process != 'undefined' && typeof process.nextTick !== 'undefined') {
  11. C.nextTick = process.nextTick;
  12. } else if (typeof setTimeout !== 'undefined') {
  13. C.nextTick = function (callback) {
  14. setTimeout(callback, 0);
  15. };
  16. }
  17. }
  18. C.PBKDF2Async = function (password, salt, keylen, callback, options) {
  19. // Convert to byte arrays
  20. if (password.constructor == String) {
  21. password = UTF8.stringToBytes(password);
  22. }
  23. if (salt.constructor == String) {
  24. salt = UTF8.stringToBytes(salt);
  25. }
  26. /* else, assume byte arrays already */
  27. // Defaults
  28. var hasher = (options && options.hasher) || C.SHA1;
  29. var iterations = (options && options.iterations) || 1; // Progress callback option
  30. var progressChangeHandler = options && options.onProgressChange;
  31. var totalIterations = Math.ceil(keylen / hasher._digestsize) * iterations;
  32. function fireProgressChange(currentIteration) {
  33. if (progressChangeHandler) {
  34. var iterationsSoFar = (derivedKeyBytes.length / hasher._digestsize) * iterations + currentIteration;
  35. setTimeout(function () {
  36. progressChangeHandler(Math.round((iterationsSoFar / totalIterations) * 100));
  37. }, 0);
  38. }
  39. }
  40. // Pseudo-random function
  41. function PRF(password, salt) {
  42. return C.HMAC(hasher, salt, password, {
  43. asBytes: true
  44. });
  45. }
  46. var nextTick = C.nextTick;
  47. // Generate key
  48. var derivedKeyBytes = [];
  49. var blockindex = 1;
  50. var outer;
  51. var inner;
  52. nextTick(
  53. (outer = function () {
  54. if (derivedKeyBytes.length < keylen) {
  55. var block = PRF(password, salt.concat(util.wordsToBytes([blockindex])));
  56. fireProgressChange(1);
  57. var u = block;
  58. var i = 1;
  59. nextTick(
  60. (inner = function () {
  61. if (i < iterations) {
  62. u = PRF(password, u);
  63. for (var j = 0; j < block.length; j++) {
  64. block[j] ^= u[j];
  65. }
  66. i++;
  67. fireProgressChange(i);
  68. nextTick(inner);
  69. } else {
  70. derivedKeyBytes = derivedKeyBytes.concat(block);
  71. blockindex++;
  72. nextTick(outer);
  73. }
  74. })
  75. );
  76. } else {
  77. // Truncate excess bytes
  78. derivedKeyBytes.length = keylen;
  79. callback(options && options.asBytes ? derivedKeyBytes : options && options.asString ? Binary.bytesToString(derivedKeyBytes) : util.bytesToHex(derivedKeyBytes));
  80. }
  81. })
  82. );
  83. };
  84. })();