Skip to content

Commit

Permalink
Update: Use WebCrypto API for PBKDF2 (#92)
Browse files Browse the repository at this point in the history
  • Loading branch information
linuxwolf committed Mar 3, 2017
1 parent c327c04 commit 5e5b9d3
Showing 1 changed file with 106 additions and 4 deletions.
110 changes: 106 additions & 4 deletions lib/algorithms/pbes2.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,63 @@ function pbes2EncryptFN(hmac, kw) {
return promise;
};

// NOTE: WebCrypto API missing until there's better support
var webcrypto = null;
var webcrypto = function(key, pdata, props) {
var salt = util.asBuffer(props.p2s || new Buffer(0), "base64url"),
itrs = props.p2c || 0;

if (0 >= itrs) {
return Promise.reject(new Error("invalid iteration count"));
}
if (8 > salt.length) {
return Promise.reject(new Error("salt too small"));
}
salt = fixSalt(hmac, kw, salt);

var promise;

// STEP 1: derive shared key
var hash = hmac.replace("HS", "SHA-");
promise = Promise.resolve(key);
promise = promise.then(function(keyval) {
return helpers.subtleCrypto.importKey("raw", keyval, "PBKDF2", false, ["deriveKey"]);
});
promise = promise.then(function(key) {
var mainAlgo = {
name: "PBKDF2",
salt: salt,
iterations: itrs,
hash: hash
};
var deriveAlgo = {
name: "AES-KW",
length: keyLen * 8
};

return helpers.subtleCrypto.deriveKey(mainAlgo, key, deriveAlgo, true, ["wrapKey", "unwrapKey"]);
});
// STEP 2: encrypt cek
promise = promise.then(function(dk) {
// assume subtleCrypto for keywrap
return Promise.all([
helpers.subtleCrypto.importKey("raw", pdata, { name: "HMAC", hash: "SHA-256" }, true, ["sign"]),
dk
]);
});
promise = promise.then(function(keys) {
return helpers.subtleCrypto.wrapKey("raw",
keys[0], // key
keys[1], // wrappingKey
"AES-KW");
});
promise = promise.then(function(result) {
result = new Buffer(result);

return {
data: result
};
});
return promise;
};

var nodejs = function(key, pdata, props) {
if (6 > helpers.nodeCrypto.pbkdf2.length) {
Expand Down Expand Up @@ -165,8 +220,55 @@ function pbes2DecryptFN(hmac, kw) {
return promise;
};

// NOTE: WebCrypto API missing until there's better support
var webcrypto = null;
var webcrypto = function(key, cdata, props) {
props = props || {};

var salt = util.asBuffer(props.p2s || new Buffer(0), "base64url"),
itrs = props.p2c || 0;

if (0 >= itrs) {
return Promise.reject(new Error("invalid iteration count"));
}

if (8 > salt.length) {
return Promise.reject(new Error("salt too small"));
}
salt = fixSalt(hmac, kw, salt);

var hash = hmac.replace("HS", "SHA-");
var promise;
promise = Promise.resolve(key);
promise = promise.then(function(keyval) {
return helpers.subtleCrypto.importKey("raw", keyval, "PBKDF2", false, ["deriveKey"]);
});
promise = promise.then(function(key) {
var mainAlgo = {
name: "PBKDF2",
salt: salt,
iterations: itrs,
hash: hash
};
var deriveAlgo = {
name: "AES-KW",
length: keyLen * 8
};

return helpers.subtleCrypto.deriveKey(mainAlgo, key, deriveAlgo, true, ["wrapKey", "unwrapKey"]);
});
// STEP 2: decrypt cek
promise = promise.then(function(key) {
return helpers.subtleCrypto.unwrapKey("raw", cdata, key, "AES-KW", {name: "HMAC", hash: "SHA-256"}, true, ["sign"]);
});
promise = promise.then(function(result) {
// unwrapped CryptoKey -- extract raw
return helpers.subtleCrypto.exportKey("raw", result);
});
promise = promise.then(function(result) {
result = new Buffer(result);
return result;
});
return promise;
};

var nodejs = function(key, cdata, props) {
if (6 > helpers.nodeCrypto.pbkdf2.length) {
Expand Down

0 comments on commit 5e5b9d3

Please sign in to comment.