UNPKG

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