| var Buffer = require('safe-buffer').Buffer | 
|   | 
| var checkParameters = require('./precondition') | 
| var defaultEncoding = require('./default-encoding') | 
| var sync = require('./sync') | 
| var toBuffer = require('./to-buffer') | 
|   | 
| var ZERO_BUF | 
| var subtle = global.crypto && global.crypto.subtle | 
| var toBrowser = { | 
|   sha: 'SHA-1', | 
|   'sha-1': 'SHA-1', | 
|   sha1: 'SHA-1', | 
|   sha256: 'SHA-256', | 
|   'sha-256': 'SHA-256', | 
|   sha384: 'SHA-384', | 
|   'sha-384': 'SHA-384', | 
|   'sha-512': 'SHA-512', | 
|   sha512: 'SHA-512' | 
| } | 
| var checks = [] | 
| function checkNative (algo) { | 
|   if (global.process && !global.process.browser) { | 
|     return Promise.resolve(false) | 
|   } | 
|   if (!subtle || !subtle.importKey || !subtle.deriveBits) { | 
|     return Promise.resolve(false) | 
|   } | 
|   if (checks[algo] !== undefined) { | 
|     return checks[algo] | 
|   } | 
|   ZERO_BUF = ZERO_BUF || Buffer.alloc(8) | 
|   var prom = browserPbkdf2(ZERO_BUF, ZERO_BUF, 10, 128, algo) | 
|     .then(function () { | 
|       return true | 
|     }).catch(function () { | 
|       return false | 
|     }) | 
|   checks[algo] = prom | 
|   return prom | 
| } | 
| var nextTick | 
| function getNextTick () { | 
|   if (nextTick) { | 
|     return nextTick | 
|   } | 
|   if (global.process && global.process.nextTick) { | 
|     nextTick = global.process.nextTick | 
|   } else if (global.queueMicrotask) { | 
|     nextTick = global.queueMicrotask | 
|   } else if (global.setImmediate) { | 
|     nextTick = global.setImmediate | 
|   } else { | 
|     nextTick = global.setTimeout | 
|   } | 
|   return nextTick | 
| } | 
| function browserPbkdf2 (password, salt, iterations, length, algo) { | 
|   return subtle.importKey( | 
|     'raw', password, { name: 'PBKDF2' }, false, ['deriveBits'] | 
|   ).then(function (key) { | 
|     return subtle.deriveBits({ | 
|       name: 'PBKDF2', | 
|       salt: salt, | 
|       iterations: iterations, | 
|       hash: { | 
|         name: algo | 
|       } | 
|     }, key, length << 3) | 
|   }).then(function (res) { | 
|     return Buffer.from(res) | 
|   }) | 
| } | 
|   | 
| function resolvePromise (promise, callback) { | 
|   promise.then(function (out) { | 
|     getNextTick()(function () { | 
|       callback(null, out) | 
|     }) | 
|   }, function (e) { | 
|     getNextTick()(function () { | 
|       callback(e) | 
|     }) | 
|   }) | 
| } | 
| module.exports = function (password, salt, iterations, keylen, digest, callback) { | 
|   if (typeof digest === 'function') { | 
|     callback = digest | 
|     digest = undefined | 
|   } | 
|   | 
|   digest = digest || 'sha1' | 
|   var algo = toBrowser[digest.toLowerCase()] | 
|   | 
|   if (!algo || typeof global.Promise !== 'function') { | 
|     getNextTick()(function () { | 
|       var out | 
|       try { | 
|         out = sync(password, salt, iterations, keylen, digest) | 
|       } catch (e) { | 
|         return callback(e) | 
|       } | 
|       callback(null, out) | 
|     }) | 
|     return | 
|   } | 
|   | 
|   checkParameters(iterations, keylen) | 
|   password = toBuffer(password, defaultEncoding, 'Password') | 
|   salt = toBuffer(salt, defaultEncoding, 'Salt') | 
|   if (typeof callback !== 'function') throw new Error('No callback provided to pbkdf2') | 
|   | 
|   resolvePromise(checkNative(algo).then(function (resp) { | 
|     if (resp) return browserPbkdf2(password, salt, iterations, keylen, algo) | 
|   | 
|     return sync(password, salt, iterations, keylen, digest) | 
|   }), callback) | 
| } |