diff --git a/lib/crypto/backend-browser.js b/lib/crypto/backend-browser.js index 4ce7807e..a41b6ee9 100644 --- a/lib/crypto/backend-browser.js +++ b/lib/crypto/backend-browser.js @@ -12,15 +12,20 @@ var assert = require('assert'); var hashjs = require('hash.js'); var aes = require('./aes'); var backend = exports; -var crypto, global; +var global, crypto, subtle; -if (typeof window !== 'undefined') - global = window; -else if (typeof self !== 'undefined') - global = self; +global = (function() { + if (typeof window !== 'undefined') + return window; -if (global) - crypto = global.crypto || global.msCrypto; + if (typeof self !== 'undefined') + return self; + + throw new Error('No global found.'); +})(); + +crypto = global.crypto || global.msCrypto; +subtle = crypto ? crypto.subtle : null; backend.hash = function hash(alg, data) { return new Buffer(hashjs[alg]().update(data).digest()); @@ -39,7 +44,30 @@ backend.hmac = function hmac(alg, data, salt) { backend.pbkdf2 = null; -backend.pbkdf2Async = null; +backend.pbkdf2Async = function pbkdf2Async(key, salt, iter, len, alg) { + var algo = { name: 'PBKDF2' }; + var use = ['deriveBits']; + var length = len * 8; + var options, promise; + + options = { + name: 'PBKDF2', + salt: salt, + iterations: iter, + hash: getHash(alg) + }; + + promise = subtle.importKey('raw', key, algo, false, use); + + return promise.then(function(key) { + return subtle.deriveBits(options, key, length); + }).then(function(result) { + return new Buffer(result); + }); +}; + +if (!subtle || !subtle.importKey || !subtle.deriveBits) + backend.pbkdf2Async = null; backend.encipher = function encipher(data, key, iv) { return aes.cbc.encrypt(data, key, iv); @@ -71,3 +99,18 @@ if (!crypto || !crypto.getRandomValues) { return data; }; } + +function getHash(name) { + switch (name) { + case 'sha1': + return 'SHA-1'; + case 'sha256': + return 'SHA-256'; + case 'sha384': + return 'SHA-384'; + case 'sha512': + return 'SHA-512'; + default: + throw new Error('Unknown hash.'); + } +}