async.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. var Buffer = require('safe-buffer').Buffer
  2. var checkParameters = require('./precondition')
  3. var defaultEncoding = require('./default-encoding')
  4. var sync = require('./sync')
  5. var toBuffer = require('./to-buffer')
  6. var ZERO_BUF
  7. var subtle = global.crypto && global.crypto.subtle
  8. var toBrowser = {
  9. sha: 'SHA-1',
  10. 'sha-1': 'SHA-1',
  11. sha1: 'SHA-1',
  12. sha256: 'SHA-256',
  13. 'sha-256': 'SHA-256',
  14. sha384: 'SHA-384',
  15. 'sha-384': 'SHA-384',
  16. 'sha-512': 'SHA-512',
  17. sha512: 'SHA-512'
  18. }
  19. var checks = []
  20. function checkNative (algo) {
  21. if (global.process && !global.process.browser) {
  22. return Promise.resolve(false)
  23. }
  24. if (!subtle || !subtle.importKey || !subtle.deriveBits) {
  25. return Promise.resolve(false)
  26. }
  27. if (checks[algo] !== undefined) {
  28. return checks[algo]
  29. }
  30. ZERO_BUF = ZERO_BUF || Buffer.alloc(8)
  31. var prom = browserPbkdf2(ZERO_BUF, ZERO_BUF, 10, 128, algo)
  32. .then(function () {
  33. return true
  34. }).catch(function () {
  35. return false
  36. })
  37. checks[algo] = prom
  38. return prom
  39. }
  40. function browserPbkdf2 (password, salt, iterations, length, algo) {
  41. return subtle.importKey(
  42. 'raw', password, { name: 'PBKDF2' }, false, ['deriveBits']
  43. ).then(function (key) {
  44. return subtle.deriveBits({
  45. name: 'PBKDF2',
  46. salt: salt,
  47. iterations: iterations,
  48. hash: {
  49. name: algo
  50. }
  51. }, key, length << 3)
  52. }).then(function (res) {
  53. return Buffer.from(res)
  54. })
  55. }
  56. function resolvePromise (promise, callback) {
  57. promise.then(function (out) {
  58. process.nextTick(function () {
  59. callback(null, out)
  60. })
  61. }, function (e) {
  62. process.nextTick(function () {
  63. callback(e)
  64. })
  65. })
  66. }
  67. module.exports = function (password, salt, iterations, keylen, digest, callback) {
  68. if (typeof digest === 'function') {
  69. callback = digest
  70. digest = undefined
  71. }
  72. digest = digest || 'sha1'
  73. var algo = toBrowser[digest.toLowerCase()]
  74. if (!algo || typeof global.Promise !== 'function') {
  75. return process.nextTick(function () {
  76. var out
  77. try {
  78. out = sync(password, salt, iterations, keylen, digest)
  79. } catch (e) {
  80. return callback(e)
  81. }
  82. callback(null, out)
  83. })
  84. }
  85. checkParameters(iterations, keylen)
  86. password = toBuffer(password, defaultEncoding, 'Password')
  87. salt = toBuffer(salt, defaultEncoding, 'Salt')
  88. if (typeof callback !== 'function') throw new Error('No callback provided to pbkdf2')
  89. resolvePromise(checkNative(algo).then(function (resp) {
  90. if (resp) return browserPbkdf2(password, salt, iterations, keylen, algo)
  91. return sync(password, salt, iterations, keylen, digest)
  92. }), callback)
  93. }