rittenhop-dev/versions/5.94.2/node_modules/node-jose/lib/algorithms/hmac.js
2024-09-23 19:40:12 -04:00

206 lines
4.8 KiB
JavaScript

/*!
* algorithms/hmac.js - HMAC-based "signatures"
*
* Copyright (c) 2015 Cisco Systems, Inc. See LICENSE file.
*/
"use strict";
var CONSTANTS = require("./constants"),
forge = require("../deps/forge.js"),
DataBuffer = require("../util/databuffer.js"),
helpers = require("./helpers.js");
function hmacSignFN(name) {
var md = name.replace("HS", "SHA").toLowerCase(),
hash = name.replace("HS", "SHA-");
function checkKeyLength(len, key) {
len = (len || CONSTANTS.HASHLENGTH[hash]) / 8;
if (len > key.length) {
return Promise.reject(new Error("invalid key length"));
}
return Promise.resolve(key);
}
// ### Fallback Implementation -- uses forge
var fallback = function(key, pdata, props) {
props = props || {};
var promise;
promise = checkKeyLength(props.length, key);
promise = promise.then(function() {
var sig = forge.hmac.create();
sig.start(md, key.toString("binary"));
sig.update(pdata.toString("binary"));
sig = Buffer.from(sig.digest().bytes(), "binary");
return {
data: pdata,
mac: sig
}
});
return promise;
};
// ### WebCryptoAPI Implementation
var webcrypto = function(key, pdata, props) {
props = props || {};
var alg = {
name: "HMAC",
hash: {
name: hash
}
};
var promise;
promise = checkKeyLength(props.length, key);
promise = promise.then(function() {
return helpers.subtleCrypto.importKey("raw", key, alg, true, ["sign"]);
});
promise = promise.then(function(key) {
return helpers.subtleCrypto.sign(alg, key, pdata);
});
promise = promise.then(function(result) {
var sig = Buffer.from(result);
return {
data: pdata,
mac: sig
};
});
return promise;
};
// ### NodeJS implementation
var nodejs = function(key, pdata, props) {
props = props || {};
var promise;
promise = checkKeyLength(props.length, key);
promise = promise.then(function() {
var hmac = helpers.nodeCrypto.createHmac(md, key);
hmac.update(pdata);
var sig = hmac.digest();
return {
data: pdata,
mac: sig
};
});
return promise;
};
return helpers.setupFallback(nodejs, webcrypto, fallback);
}
function hmacVerifyFN(name) {
var md = name.replace("HS", "SHA").toLowerCase(),
hash = name.replace("HS", "SHA-");
function compare(len, expected, actual) {
len = (len || CONSTANTS.HASHLENGTH[hash]) / 8;
var valid = true;
for (var idx = 0; len > idx; idx++) {
valid = valid && (expected[idx] === actual[idx]);
}
return valid;
}
// ### Fallback Implementation -- uses forge
var fallback = function(key, pdata, mac, props) {
props = props || {};
var vrfy = forge.hmac.create();
vrfy.start(md, new DataBuffer(key));
vrfy.update(pdata.toString("binary"));
vrfy = Buffer.from(vrfy.digest().bytes(), "binary");
if (compare(props.length, mac, vrfy)) {
return Promise.resolve({
data: pdata,
mac: mac,
valid: true
});
} else {
return Promise.reject(new Error("verification failed"));
}
};
var webcrypto = function(key, pdata, mac, props) {
props = props || {};
var alg = {
name: "HMAC",
hash: {
name: hash
}
};
var promise;
if (props.length) {
promise = helpers.subtleCrypto.importKey("raw", key, alg, true, ["sign"]);
promise = promise.then(function(key) {
return helpers.subtleCrypto.sign(alg, key, pdata);
});
promise = promise.then(function(result) {
var sig = Buffer.from(result);
return compare(props.length, mac, sig);
});
} else {
promise = helpers.subtleCrypto.importKey("raw", key, alg, true, ["verify"]);
promise = promise.then(function(key) {
return helpers.subtleCrypto.verify(alg, key, mac, pdata);
});
}
promise = promise.then(function(result) {
if (!result) {
return Promise.reject(new Error("verifaction failed"));
}
return {
data: pdata,
mac: mac,
valid: true
};
});
return promise;
};
var nodejs = function(key, pdata, mac, props) {
props = props || {};
var hmac = helpers.nodeCrypto.createHmac(md, key);
hmac.update(pdata);
var sig = hmac.digest();
if (!compare(props.length, mac, sig)) {
throw new Error("verification failed");
}
return {
data: pdata,
mac: sig,
valid: true
};
};
return helpers.setupFallback(nodejs, webcrypto, fallback);
}
// ### Public API
// * [name].sign
// * [name].verify
var hmac = {};
[
"HS1",
"HS256",
"HS384",
"HS512"
].forEach(function(alg) {
hmac[alg] = {
sign: hmacSignFN(alg),
verify: hmacVerifyFN(alg)
};
});
module.exports = hmac;