mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 10:15:07 +08:00
crypto: wire up SHA-3 with BoringSSL
Add SHA3-256, SHA3-384, and SHA3-512 to name lookup and getHashes(). BoringSSL exposes EVP_sha3_* descriptors but omits them from its digest registry. Map the names directly to those descriptors so node:crypto can use them too. When using BoringSSL, limit WebCrypto SHA-3 support to digest operations. Signed-off-by: Filip Skokan <panva.ip@gmail.com> Assisted-by: Codex PR-URL: https://github.com/nodejs/node/pull/66922 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
1 parent
a2ce2c6def
commit
7e58295439
28 files changed
+616
-246
No files matched your search
Vendored
+7
@@ -2804,6 +2804,13 @@ const EVP_MD* getDigestByName(const char* name) {
|
||||
if (strcmp(name, "dss1") == 0 || strcmp(name, "DSS1") == 0) [[unlikely]] {
|
||||
return EVP_sha1();
|
||||
}
|
||||
#if NCRYPTO_USE_BORINGSSL
|
||||
// BoringSSL exposes SHA-3 through EVP_MD descriptors without registering
|
||||
// their names or assigning them NIDs.
|
||||
if (CaseInsensitiveNameEqual()(name, "sha3-256")) return EVP_sha3_256();
|
||||
if (CaseInsensitiveNameEqual()(name, "sha3-384")) return EVP_sha3_384();
|
||||
if (CaseInsensitiveNameEqual()(name, "sha3-512")) return EVP_sha3_512();
|
||||
#endif
|
||||
return EVP_get_digestbyname(name);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,8 @@ const {
|
||||
isKeyAlgorithmAvailable,
|
||||
} = internalBinding('crypto');
|
||||
|
||||
const { openssl_is_boringssl: isBoringSSL } = process.features;
|
||||
|
||||
let fips;
|
||||
let fipsGeneration;
|
||||
function isFips() {
|
||||
@@ -533,7 +535,7 @@ function getConditionalAlgorithms() {
|
||||
'Argon2d': !!Argon2Job && !fips,
|
||||
'Argon2i': !!Argon2Job && !fips,
|
||||
'Argon2id': !!Argon2Job && !fips,
|
||||
'ChaCha20-Poly1305': process.features.openssl_is_boringssl ||
|
||||
'ChaCha20-Poly1305': isBoringSSL ||
|
||||
has(ciphers, 'chacha20-poly1305'),
|
||||
'cSHAKE128': has(hashes, 'shake128'),
|
||||
'cSHAKE256': has(hashes, 'shake256'),
|
||||
@@ -550,15 +552,15 @@ function getConditionalAlgorithms() {
|
||||
'ML-KEM-768': mlKem768,
|
||||
'ML-KEM-1024': mlKem1024,
|
||||
'MLKEM768-P256': !fips && mlKem768 &&
|
||||
(!process.features.openssl_is_boringssl ||
|
||||
(!isBoringSSL ||
|
||||
(has(hashes, 'sha3-256') &&
|
||||
has(hashes, 'shake256'))),
|
||||
'MLKEM768-X25519': !fips && mlKem768 &&
|
||||
(!process.features.openssl_is_boringssl ||
|
||||
(!isBoringSSL ||
|
||||
(has(hashes, 'sha3-256') &&
|
||||
has(hashes, 'shake256'))),
|
||||
'MLKEM1024-P384': !fips && mlKem1024 &&
|
||||
(!process.features.openssl_is_boringssl ||
|
||||
(!isBoringSSL ||
|
||||
(has(hashes, 'sha3-256') &&
|
||||
has(hashes, 'shake256'))),
|
||||
'SHA-1': has(hashes, 'sha1'),
|
||||
@@ -847,6 +849,11 @@ function normalizeAlgorithm(algorithm, op) {
|
||||
throw lazyDOMException(
|
||||
`Only SHA hashes are supported in ${desiredType}`, 'NotSupportedError');
|
||||
}
|
||||
if (isBoringSSL && StringPrototypeStartsWith(hash.name, 'SHA3-')) {
|
||||
throw lazyDOMException(
|
||||
'SHA-3 is only supported for digest operations',
|
||||
'NotSupportedError');
|
||||
}
|
||||
normalizedAlgorithm[member] = hash;
|
||||
} else if (idlType === 'AlgorithmIdentifier') {
|
||||
// This extension point is not used by any supported algorithm (yet?)
|
||||
|
||||
@@ -14,6 +14,8 @@ const {
|
||||
TypedArrayPrototypeIncludes,
|
||||
} = primordials;
|
||||
|
||||
const { openssl_is_boringssl: isBoringSSL } = process.features;
|
||||
|
||||
const {
|
||||
lazyDOMException,
|
||||
} = require('internal/util');
|
||||
@@ -670,7 +672,7 @@ converters.ContextParams = createAlgorithmDictionaryConverter(
|
||||
const validateLength = (V) =>
|
||||
validateMaxBufferLength(V, 'ContextParams.context', 255);
|
||||
|
||||
if (process.features.openssl_is_boringssl) {
|
||||
if (isBoringSSL) {
|
||||
this.validator = validateLength;
|
||||
} else {
|
||||
let { 0: major, 1: minor } =
|
||||
|
||||
@@ -255,6 +255,12 @@ const std::vector<std::string>& GetSupportedHashAlgorithms(Environment* env) {
|
||||
EVP_MD_do_all_provided(nullptr, SaveSupportedProviderHashAlgorithms, env);
|
||||
#else
|
||||
EVP_MD_do_all_sorted(SaveSupportedHashAlgorithms, env);
|
||||
#endif
|
||||
#if NCRYPTO_USE_BORINGSSL
|
||||
// SHA-3 descriptors are not included in BoringSSL's name registry.
|
||||
for (const char* name : {"sha3-256", "sha3-384", "sha3-512"}) {
|
||||
env->supported_hash_algorithms.emplace_back(name);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
const uint64_t current_generation = ncrypto::getFipsStateGeneration();
|
||||
|
||||
Vendored
+6
-5
@@ -2,7 +2,8 @@
|
||||
|
||||
const { isBoringSSL } = require('../../common/crypto');
|
||||
|
||||
module.exports = function() {
|
||||
module.exports = function({ includeUnsupported = false } = {}) {
|
||||
const includeSha3 = !isBoringSSL || includeUnsupported;
|
||||
const pkcs8 = {
|
||||
'P-256': Buffer.from(
|
||||
'308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b020101' +
|
||||
@@ -74,7 +75,7 @@ module.exports = function() {
|
||||
'b6a0a14d7e4bc6dd2eda82c9234f174b670b60c8f7d101f68fdf5889e02373b025' +
|
||||
'dcbc4c82f2929b8e06c68535da98e38fe399c53a814b097935581ef21535eb',
|
||||
'hex'),
|
||||
...(!isBoringSSL ? {
|
||||
...(includeSha3 ? {
|
||||
'SHA3-256': Buffer.from(
|
||||
'f6a48eb5557f484ed0c3e4b5c78a3cf497cbd346db06a4165d429248aa2cc51a69' +
|
||||
'747d09f57af145469a8b607a9b8b9709629d74e8f5ca337c6ddc581b6f6103',
|
||||
@@ -106,7 +107,7 @@ module.exports = function() {
|
||||
'72fbdb369fd34c1c54264d07f4facd69b02e4206f8a8bb259b882a305c56fde2d3' +
|
||||
'5107e493c53cd6b4af0b31306f4d03fd43cfc762a1030e17a3d775453a1212b142' +
|
||||
'9f7b3d93066a5f42a10b138cd177dc09616e827d598822d78d4627b754e6', 'hex'),
|
||||
...(!isBoringSSL ? {
|
||||
...(includeSha3 ? {
|
||||
'SHA3-256': Buffer.from(
|
||||
'0b07c078be30fa5925a307d6fc559c5f398e63fb5d007d6b24a834847f2d3d18d5' +
|
||||
'b5e840711c52a7bc6626c3ced93301e873c013a706f6b297c12cc6d47a71e0529e' +
|
||||
@@ -146,7 +147,7 @@ module.exports = function() {
|
||||
'01f0071e6a32867fa70f695cd39c4e87e142b9e4134d38740bd6fee354a575167e' +
|
||||
'13524e94832637910fe11e53a85fb21b91adb81bb1779c4e2b8bc87c717dc35084',
|
||||
'hex'),
|
||||
...(!isBoringSSL ? {
|
||||
...(includeSha3 ? {
|
||||
'SHA3-256': Buffer.from(
|
||||
'00463679f47a4c705e03447360dcf34d1743e0d4b2591cc66832a6bc80d92e538c' +
|
||||
'169a1fd330f98e7235ca7fec7e16ac44fb13095b8edf2c76b75c4845177d59e425' +
|
||||
@@ -172,7 +173,7 @@ module.exports = function() {
|
||||
const curves = ['P-256', 'P-384', 'P-521'];
|
||||
const hashes = ['SHA-1', 'SHA-256', 'SHA-384', 'SHA-512'];
|
||||
|
||||
if (!isBoringSSL) {
|
||||
if (includeSha3) {
|
||||
hashes.push('SHA3-256', 'SHA3-384', 'SHA3-512');
|
||||
}
|
||||
|
||||
|
||||
Vendored
+20
-26
@@ -1,7 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
const { isBoringSSL } = require('../../common/crypto');
|
||||
|
||||
module.exports = function () {
|
||||
const plaintext = Buffer.from(
|
||||
'5f4dba4f320c0ce876725afce5fbd25bf83e5a7125a08cafe73c3ebac421779df9d55d' +
|
||||
@@ -24,18 +22,16 @@ module.exports = function () {
|
||||
'5dcc359443aaf652fa1375d6b3e61fdcf29bb4a28bd5d3dcfa40f82f906bb280' +
|
||||
'0455db03b5d31fb972a15a6d0103a24e56d156a119c0e5a1e92a44c3c5657cf9',
|
||||
'hex'),
|
||||
...(!isBoringSSL ? {
|
||||
'SHA3-256': Buffer.from(
|
||||
'e588ec0811463d767241df1074b47ae4071b51f2ce36537ba69ccdc3fdc2b7a8',
|
||||
'hex'),
|
||||
'SHA3-384': Buffer.from(
|
||||
'6b1da28eab1f582ad9718effe05e23d5fd2c9877a2d9443f90bec093bece2ea7' +
|
||||
'd2354cd0bdc5e147d2e9009373494488', 'hex'),
|
||||
'SHA3-512': Buffer.from(
|
||||
'5dcc359443aaf652fa1375d6b3e61fdcf29bb4a28bd5d3dcfa40f82f906bb280' +
|
||||
'0455db03b5d31fb972a15a6d0103a24e56d156a119c0e5a1e92a44c3c5657cf9',
|
||||
'hex')
|
||||
} : {})
|
||||
'SHA3-256': Buffer.from(
|
||||
'e588ec0811463d767241df1074b47ae4071b51f2ce36537ba69ccdc3fdc2b7a8',
|
||||
'hex'),
|
||||
'SHA3-384': Buffer.from(
|
||||
'6b1da28eab1f582ad9718effe05e23d5fd2c9877a2d9443f90bec093bece2ea7' +
|
||||
'd2354cd0bdc5e147d2e9009373494488', 'hex'),
|
||||
'SHA3-512': Buffer.from(
|
||||
'5dcc359443aaf652fa1375d6b3e61fdcf29bb4a28bd5d3dcfa40f82f906bb280' +
|
||||
'0455db03b5d31fb972a15a6d0103a24e56d156a119c0e5a1e92a44c3c5657cf9',
|
||||
'hex')
|
||||
}
|
||||
|
||||
const signatures = {
|
||||
@@ -50,18 +46,16 @@ module.exports = function () {
|
||||
'61fb278c3ffb0cce2bf1cf723ddfd8ef1f931c0c618c25907324605939e3f9a2' +
|
||||
'c6f4af690bda3407dc2f5770f6a0a44b954d64a332e3ee0821abf82b7f3e99c1',
|
||||
'hex'),
|
||||
...(!isBoringSSL ? {
|
||||
'SHA3-256': Buffer.from(
|
||||
'c1ac5e11fcd50c48bf567f6e296632f5801c4eb07a8a47579b41dee971a3099b',
|
||||
'hex'),
|
||||
'SHA3-384': Buffer.from(
|
||||
'ac8c97f6dd8d9e16101063077c16b23fe291a5e6d149653e9ac7002365159317' +
|
||||
'adcfad511996578b0053a5c14b75f16c', 'hex'),
|
||||
'SHA3-512': Buffer.from(
|
||||
'2162c2a8907e6b2f68599a69e81a464d8f076b5eeb555d98b4d20330034df3c7' +
|
||||
'cf35b1fa958a074ca12f0d242df39f0da3d4f1dbfb3629057798fe1f883974ee',
|
||||
'hex')
|
||||
} : {})
|
||||
'SHA3-256': Buffer.from(
|
||||
'c1ac5e11fcd50c48bf567f6e296632f5801c4eb07a8a47579b41dee971a3099b',
|
||||
'hex'),
|
||||
'SHA3-384': Buffer.from(
|
||||
'ac8c97f6dd8d9e16101063077c16b23fe291a5e6d149653e9ac7002365159317' +
|
||||
'adcfad511996578b0053a5c14b75f16c', 'hex'),
|
||||
'SHA3-512': Buffer.from(
|
||||
'2162c2a8907e6b2f68599a69e81a464d8f076b5eeb555d98b4d20330034df3c7' +
|
||||
'cf35b1fa958a074ca12f0d242df39f0da3d4f1dbfb3629057798fe1f883974ee',
|
||||
'hex')
|
||||
}
|
||||
|
||||
const vectors = [];
|
||||
|
||||
Vendored
+4
-3
@@ -2,7 +2,8 @@
|
||||
|
||||
const { isBoringSSL } = require('../../common/crypto');
|
||||
|
||||
module.exports = function () {
|
||||
module.exports = function ({ includeUnsupported = false } = {}) {
|
||||
const includeSha3 = !isBoringSSL || includeUnsupported;
|
||||
const pkcs8 = Buffer.from(
|
||||
'308204bf020100300d06092a864886f70d0101010500048204a9308204a50201000282' +
|
||||
'010100d3576092e62957364544e7e4233b7bdb293db2085122c479328546f9f0f712f6' +
|
||||
@@ -99,7 +100,7 @@ module.exports = function () {
|
||||
'7a6335c70e193235dcda48add6858626bd96311e60f7e5ea4491b6c1e6248afe12b' +
|
||||
'bbd54f8869b043a5b0444562813f0a98b300356f306e6b783a29f3bec97ca40ea20' +
|
||||
'062cab8926ec5d96aa387cc84821a6d72b8ea126e7d', 'hex'),
|
||||
...(!isBoringSSL ? {
|
||||
...(includeSha3 ? {
|
||||
'sha3-256': Buffer.from(
|
||||
'be1b476c1911a01d71710fd8a2f3158d6f7839e91443b01bed30dfdd04336d80c6b' +
|
||||
'f692c06fad254877901c10a73853e8fb202a29cddefdf16c3adcda1fc123625897d' +
|
||||
@@ -163,7 +164,7 @@ module.exports = function () {
|
||||
plaintext,
|
||||
signature: signatures['sha-512']
|
||||
},
|
||||
...(!isBoringSSL ? [
|
||||
...(includeSha3 ? [
|
||||
{
|
||||
publicKeyBuffer: spki,
|
||||
privateKeyBuffer: pkcs8,
|
||||
|
||||
Vendored
+84
-90
@@ -1,7 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
const { isBoringSSL } = require('../../common/crypto');
|
||||
|
||||
module.exports = function() {
|
||||
const pkcs8 = Buffer.from(
|
||||
'308204bf020100300d06092a864886f70d0101010500048204a9308204a5020100028' +
|
||||
@@ -152,44 +150,42 @@ module.exports = function() {
|
||||
'b68c04bfe452c3adc6c10066a915231b7b404727eb6201b4921eb96d9407de2b963' +
|
||||
'3879ceb71d759d9828d7b4d062f6ef100757d8328187caf57dfb859d1555345207c' +
|
||||
'1cce7905c3564c08fec78867a53d5a2cf84810e1ffa', 'hex'),
|
||||
...(!isBoringSSL ? {
|
||||
'sha3-512, no salt': Buffer.from(
|
||||
'd2430dc87abeaa7d13f7cec8510f1a296e1c608f44b1696829c59a99e8eefe9b2ee' +
|
||||
'6ee8ad6fdc93c24fcba2f04d1da195924b6209717e1992c10ed9f4783478765fe34' +
|
||||
'3e761203bff9d326bb6dc2061b0a7554c8ce0814b29249136c20c8e30054df0c6bc' +
|
||||
'656509a82845149368896690e32ff5dd32ef01543686f01d6a69bb438b049e66a8b' +
|
||||
'df485a13edcd7dc482da4cc57d0b740aca3e56f0da247794e600afd27b22b6da13b' +
|
||||
'cc15dd2059b525f8cb6bcd07540aa843f0ae51d4b0eea27045485914b908bdd01d0' +
|
||||
'a9d42379f9f7180f4ad162ff73df5fed0200eb02ad01473975d54a77c15a9c61a3c' +
|
||||
'b5e27de5d1eecc363d45506f7123a5ddd115c5e4c9e', 'hex'),
|
||||
'sha3-256, salted': Buffer.from(
|
||||
'59cb9cce6ae838eb20d38d6af4acb9b866b0753bb7df9e441037d788512c03279e8' +
|
||||
'3d9a9cf5c0921fe1c0b6e8e895a8c0ad24a18b123f809b34ef2a3a1f05974030320' +
|
||||
'435692ef5d378cef4368c3658c098a25371dfaf1c0b6910f653a4ec15f2c08956c1' +
|
||||
'405136c2aba7f25a808fa7dbf57a4cb2978bd91af710b27ee239d955c8cac7a76ae' +
|
||||
'9085cefeda2a585a99cc948f064b5da66a9c4aa4f3f767ac905a9f314b47038e05c' +
|
||||
'3608fbb7e67a278e4f009a62c3cd3fdf43692e759d9361be1217999a76a69d4d119' +
|
||||
'f8791a90e207e46b3f6125721f56fd819292d06a3cdae2c62c9a1dc0d964a06036c' +
|
||||
'8c18661cc6c873532a3536ab51e1ce210926db299e2', 'hex'),
|
||||
'sha3-384, salted': Buffer.from(
|
||||
'8d1f9297c8169f27f0c58827dba991d862de58c1155f612ad2995d2bf862d051c4a' +
|
||||
'91b48571849b0412384382e5b77990de6a3c84010046b35c4a504f175a3479483d9' +
|
||||
'5c58f86bb96d53a27e59d6f67fddaae295ce90610f5086acc711557c2c85aac32d3' +
|
||||
'24199cff2367ae44e1d91307a98c8cbfb085a8bce6b1c20714711bc15b0eddb7881' +
|
||||
'823227d4be477ffdad8093663a6a1fc62eb39c49c2c3a821c2b202cf7904b49ca92' +
|
||||
'3c83819602bb13931577354a80f99309030044935b1cd41f0513160e661db1959fb' +
|
||||
'1ec15f087f3d288e875d54cbf070ec860b0aeecc951ea65e97cd5460750d4b7de52' +
|
||||
'22cb9e7466b1f506ecf6a81fc399dfd8334160f9084', 'hex'),
|
||||
'sha3-512, salted': Buffer.from(
|
||||
'7b6d7be418c5d37cc8070698b8b03d818ecd8b673d047d34921913f6d59c69cb496' +
|
||||
'172d6118207d9ff92b8e1246acf0e03a845d935a70f8a82c3d5d6db6a1a0e337269' +
|
||||
'4b904372413dcbaa7ac5486bc8ccaf70d7e9470be82b928a90017e272cf9761ed26' +
|
||||
'c160fe874a2675a4fb2acad72c50fbfffdd70b5a6f2919553d7ea1829934670f8de' +
|
||||
'f2a5c2816404b1aa153323c92c58400622f184b9b0463fa48d6b27091f68c287e3f' +
|
||||
'6d9ab9eb451711a5d984c547f3d56f14a686a89ddf36c47ce25092b8c6530904de9' +
|
||||
'5df7fc602fe9394315f1b1847aae304cb5ad71e2cb78acfbc997a87a9d62a6898bb' +
|
||||
'6d84a81bb89b50186265f4be171a93d837a4bf777c8', 'hex')
|
||||
} : {})
|
||||
'sha3-512, no salt': Buffer.from(
|
||||
'd2430dc87abeaa7d13f7cec8510f1a296e1c608f44b1696829c59a99e8eefe9b2ee' +
|
||||
'6ee8ad6fdc93c24fcba2f04d1da195924b6209717e1992c10ed9f4783478765fe34' +
|
||||
'3e761203bff9d326bb6dc2061b0a7554c8ce0814b29249136c20c8e30054df0c6bc' +
|
||||
'656509a82845149368896690e32ff5dd32ef01543686f01d6a69bb438b049e66a8b' +
|
||||
'df485a13edcd7dc482da4cc57d0b740aca3e56f0da247794e600afd27b22b6da13b' +
|
||||
'cc15dd2059b525f8cb6bcd07540aa843f0ae51d4b0eea27045485914b908bdd01d0' +
|
||||
'a9d42379f9f7180f4ad162ff73df5fed0200eb02ad01473975d54a77c15a9c61a3c' +
|
||||
'b5e27de5d1eecc363d45506f7123a5ddd115c5e4c9e', 'hex'),
|
||||
'sha3-256, salted': Buffer.from(
|
||||
'59cb9cce6ae838eb20d38d6af4acb9b866b0753bb7df9e441037d788512c03279e8' +
|
||||
'3d9a9cf5c0921fe1c0b6e8e895a8c0ad24a18b123f809b34ef2a3a1f05974030320' +
|
||||
'435692ef5d378cef4368c3658c098a25371dfaf1c0b6910f653a4ec15f2c08956c1' +
|
||||
'405136c2aba7f25a808fa7dbf57a4cb2978bd91af710b27ee239d955c8cac7a76ae' +
|
||||
'9085cefeda2a585a99cc948f064b5da66a9c4aa4f3f767ac905a9f314b47038e05c' +
|
||||
'3608fbb7e67a278e4f009a62c3cd3fdf43692e759d9361be1217999a76a69d4d119' +
|
||||
'f8791a90e207e46b3f6125721f56fd819292d06a3cdae2c62c9a1dc0d964a06036c' +
|
||||
'8c18661cc6c873532a3536ab51e1ce210926db299e2', 'hex'),
|
||||
'sha3-384, salted': Buffer.from(
|
||||
'8d1f9297c8169f27f0c58827dba991d862de58c1155f612ad2995d2bf862d051c4a' +
|
||||
'91b48571849b0412384382e5b77990de6a3c84010046b35c4a504f175a3479483d9' +
|
||||
'5c58f86bb96d53a27e59d6f67fddaae295ce90610f5086acc711557c2c85aac32d3' +
|
||||
'24199cff2367ae44e1d91307a98c8cbfb085a8bce6b1c20714711bc15b0eddb7881' +
|
||||
'823227d4be477ffdad8093663a6a1fc62eb39c49c2c3a821c2b202cf7904b49ca92' +
|
||||
'3c83819602bb13931577354a80f99309030044935b1cd41f0513160e661db1959fb' +
|
||||
'1ec15f087f3d288e875d54cbf070ec860b0aeecc951ea65e97cd5460750d4b7de52' +
|
||||
'22cb9e7466b1f506ecf6a81fc399dfd8334160f9084', 'hex'),
|
||||
'sha3-512, salted': Buffer.from(
|
||||
'7b6d7be418c5d37cc8070698b8b03d818ecd8b673d047d34921913f6d59c69cb496' +
|
||||
'172d6118207d9ff92b8e1246acf0e03a845d935a70f8a82c3d5d6db6a1a0e337269' +
|
||||
'4b904372413dcbaa7ac5486bc8ccaf70d7e9470be82b928a90017e272cf9761ed26' +
|
||||
'c160fe874a2675a4fb2acad72c50fbfffdd70b5a6f2919553d7ea1829934670f8de' +
|
||||
'f2a5c2816404b1aa153323c92c58400622f184b9b0463fa48d6b27091f68c287e3f' +
|
||||
'6d9ab9eb451711a5d984c547f3d56f14a686a89ddf36c47ce25092b8c6530904de9' +
|
||||
'5df7fc602fe9394315f1b1847aae304cb5ad71e2cb78acfbc997a87a9d62a6898bb' +
|
||||
'6d84a81bb89b50186265f4be171a93d837a4bf777c8', 'hex')
|
||||
}
|
||||
|
||||
const vectors = [
|
||||
@@ -257,56 +253,54 @@ module.exports = function() {
|
||||
plaintext,
|
||||
signature: signatures['sha-512, salted']
|
||||
},
|
||||
...(!isBoringSSL ? [
|
||||
{
|
||||
publicKeyBuffer: spki,
|
||||
privateKeyBuffer: pkcs8,
|
||||
algorithm: { name: 'RSA-PSS', saltLength: 0 },
|
||||
hash: 'SHA3-256',
|
||||
plaintext,
|
||||
signature: signatures['sha3-256, no salt']
|
||||
},
|
||||
{
|
||||
publicKeyBuffer: spki,
|
||||
privateKeyBuffer: pkcs8,
|
||||
algorithm: { name: 'RSA-PSS', saltLength: 0 },
|
||||
hash: 'SHA3-384',
|
||||
plaintext,
|
||||
signature: signatures['sha3-384, no salt']
|
||||
},
|
||||
{
|
||||
publicKeyBuffer: spki,
|
||||
privateKeyBuffer: pkcs8,
|
||||
algorithm: { name: 'RSA-PSS', saltLength: 0 },
|
||||
hash: 'SHA3-512',
|
||||
plaintext,
|
||||
signature: signatures['sha3-512, no salt']
|
||||
},
|
||||
{
|
||||
publicKeyBuffer: spki,
|
||||
privateKeyBuffer: pkcs8,
|
||||
algorithm: { name: 'RSA-PSS', saltLength: 32 },
|
||||
hash: 'SHA3-256',
|
||||
plaintext,
|
||||
signature: signatures['sha3-256, salted']
|
||||
},
|
||||
{
|
||||
publicKeyBuffer: spki,
|
||||
privateKeyBuffer: pkcs8,
|
||||
algorithm: { name: 'RSA-PSS', saltLength: 48 },
|
||||
hash: 'SHA3-384',
|
||||
plaintext,
|
||||
signature: signatures['sha3-384, salted']
|
||||
},
|
||||
{
|
||||
publicKeyBuffer: spki,
|
||||
privateKeyBuffer: pkcs8,
|
||||
algorithm: { name: 'RSA-PSS', saltLength: 64 },
|
||||
hash: 'SHA3-512',
|
||||
plaintext,
|
||||
signature: signatures['sha3-512, salted']
|
||||
}
|
||||
] : []),
|
||||
{
|
||||
publicKeyBuffer: spki,
|
||||
privateKeyBuffer: pkcs8,
|
||||
algorithm: { name: 'RSA-PSS', saltLength: 0 },
|
||||
hash: 'SHA3-256',
|
||||
plaintext,
|
||||
signature: signatures['sha3-256, no salt']
|
||||
},
|
||||
{
|
||||
publicKeyBuffer: spki,
|
||||
privateKeyBuffer: pkcs8,
|
||||
algorithm: { name: 'RSA-PSS', saltLength: 0 },
|
||||
hash: 'SHA3-384',
|
||||
plaintext,
|
||||
signature: signatures['sha3-384, no salt']
|
||||
},
|
||||
{
|
||||
publicKeyBuffer: spki,
|
||||
privateKeyBuffer: pkcs8,
|
||||
algorithm: { name: 'RSA-PSS', saltLength: 0 },
|
||||
hash: 'SHA3-512',
|
||||
plaintext,
|
||||
signature: signatures['sha3-512, no salt']
|
||||
},
|
||||
{
|
||||
publicKeyBuffer: spki,
|
||||
privateKeyBuffer: pkcs8,
|
||||
algorithm: { name: 'RSA-PSS', saltLength: 32 },
|
||||
hash: 'SHA3-256',
|
||||
plaintext,
|
||||
signature: signatures['sha3-256, salted']
|
||||
},
|
||||
{
|
||||
publicKeyBuffer: spki,
|
||||
privateKeyBuffer: pkcs8,
|
||||
algorithm: { name: 'RSA-PSS', saltLength: 48 },
|
||||
hash: 'SHA3-384',
|
||||
plaintext,
|
||||
signature: signatures['sha3-384, salted']
|
||||
},
|
||||
{
|
||||
publicKeyBuffer: spki,
|
||||
privateKeyBuffer: pkcs8,
|
||||
algorithm: { name: 'RSA-PSS', saltLength: 64 },
|
||||
hash: 'SHA3-512',
|
||||
plaintext,
|
||||
signature: signatures['sha3-512, salted']
|
||||
}
|
||||
];
|
||||
|
||||
return vectors;
|
||||
|
||||
+1
-2
@@ -13,10 +13,9 @@ const shake128 = crypto.getHashes().includes('shake128');
|
||||
const shake256 = crypto.getHashes().includes('shake256');
|
||||
const cshake128 = crypto.getHashes().includes('cshake128');
|
||||
const cshake256 = crypto.getHashes().includes('cshake256');
|
||||
const sha3 = crypto.getHashes().includes('sha3-256');
|
||||
const ocb = hasOpenSSL(3) && crypto.getCiphers().includes('aes-128-ocb');
|
||||
const kmac = hasOpenSSL(3) && crypto.getMacs().includes('kmac128');
|
||||
const hybridKems = !fips && pqc && (!boringSSL || (sha3 && shake256));
|
||||
const hybridKems = !fips && pqc && (!boringSSL || shake256);
|
||||
|
||||
|
||||
export const vectors = {
|
||||
|
||||
+35
-33
@@ -1,28 +1,30 @@
|
||||
import { getHashes } from 'node:crypto';
|
||||
import { isBoringSSL } from '../../common/crypto.js';
|
||||
import { ECDH, X25519 } from './supports-level-2.mjs';
|
||||
|
||||
const hashes = getHashes();
|
||||
const hasSha3 = hashes.includes('sha3-256');
|
||||
|
||||
const RSA_KEY_GEN = {
|
||||
modulusLength: 2048,
|
||||
publicExponent: new Uint8Array([1, 0, 1])
|
||||
};
|
||||
|
||||
export const vectors = {
|
||||
'sign': [
|
||||
[!isBoringSSL, { name: 'ECDSA', hash: 'SHA3-256' }],
|
||||
[!isBoringSSL, { name: 'ECDSA', hash: 'SHA3-384' }],
|
||||
[!isBoringSSL, { name: 'ECDSA', hash: 'SHA3-512' }],
|
||||
],
|
||||
'digest': [
|
||||
[hasSha3, 'SHA3-256'],
|
||||
[hashes.includes('sha3-384'), 'SHA3-384'],
|
||||
[hashes.includes('sha3-512'), 'SHA3-512'],
|
||||
[true, 'SHA3-256'],
|
||||
[true, 'SHA3-384'],
|
||||
[true, 'SHA3-512'],
|
||||
],
|
||||
'generateKey': [
|
||||
[hasSha3, { name: 'HMAC', hash: 'SHA3-256', length: 256 }],
|
||||
[hasSha3, { name: 'HMAC', hash: 'SHA3-256', length: 25 }],
|
||||
[hasSha3, { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA3-256', ...RSA_KEY_GEN }],
|
||||
[hasSha3, { name: 'RSA-PSS', hash: 'SHA3-256', ...RSA_KEY_GEN }],
|
||||
[hasSha3, { name: 'RSA-OAEP', hash: 'SHA3-256', ...RSA_KEY_GEN }],
|
||||
[hasSha3, { name: 'HMAC', hash: 'SHA3-256', length: 256 }],
|
||||
[hasSha3, { name: 'HMAC', hash: 'SHA3-256', length: 25 }],
|
||||
[!isBoringSSL, { name: 'HMAC', hash: 'SHA3-256', length: 256 }],
|
||||
[!isBoringSSL, { name: 'HMAC', hash: 'SHA3-256', length: 25 }],
|
||||
[!isBoringSSL, { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA3-256', ...RSA_KEY_GEN }],
|
||||
[!isBoringSSL, { name: 'RSA-PSS', hash: 'SHA3-256', ...RSA_KEY_GEN }],
|
||||
[!isBoringSSL, { name: 'RSA-OAEP', hash: 'SHA3-256', ...RSA_KEY_GEN }],
|
||||
[!isBoringSSL, { name: 'HMAC', hash: 'SHA3-256', length: 256 }],
|
||||
[!isBoringSSL, { name: 'HMAC', hash: 'SHA3-256', length: 25 }],
|
||||
[false, { name: 'HMAC', hash: 'SHA3-256', length: 0 }],
|
||||
|
||||
// This interaction is not defined for now.
|
||||
@@ -30,28 +32,28 @@ export const vectors = {
|
||||
[false, { name: 'HMAC', hash: 'SHA3-256' }],
|
||||
],
|
||||
'deriveKey': [
|
||||
[hasSha3,
|
||||
[!isBoringSSL,
|
||||
{ name: 'HKDF', hash: 'SHA3-256', salt: Buffer.alloc(0), info: Buffer.alloc(0) },
|
||||
{ name: 'AES-CBC', length: 128 }],
|
||||
[hasSha3,
|
||||
[!isBoringSSL,
|
||||
{ name: 'HKDF', hash: 'SHA3-256', salt: Buffer.alloc(0), info: Buffer.alloc(0) },
|
||||
{ name: 'HMAC', hash: 'SHA3-256', length: 256 }],
|
||||
[false,
|
||||
{ name: 'HKDF', hash: 'SHA3-256', salt: Buffer.alloc(0), info: Buffer.alloc(0) },
|
||||
'HKDF'],
|
||||
[hasSha3,
|
||||
[!isBoringSSL,
|
||||
{ name: 'PBKDF2', hash: 'SHA3-256', salt: Buffer.alloc(0), iterations: 1 },
|
||||
{ name: 'AES-CBC', length: 128 }],
|
||||
[hasSha3,
|
||||
[!isBoringSSL,
|
||||
{ name: 'PBKDF2', hash: 'SHA3-256', salt: Buffer.alloc(0), iterations: 1 },
|
||||
{ name: 'HMAC', hash: 'SHA3-256', length: 256 }],
|
||||
[false,
|
||||
{ name: 'PBKDF2', hash: 'SHA3-256', salt: Buffer.alloc(0), iterations: 1 },
|
||||
'HKDF'],
|
||||
[hasSha3 && X25519 !== undefined,
|
||||
[!isBoringSSL && X25519 !== undefined,
|
||||
{ name: 'X25519', public: X25519?.publicKey },
|
||||
{ name: 'HMAC', hash: 'SHA3-256', length: 256 }],
|
||||
[hasSha3,
|
||||
[!isBoringSSL,
|
||||
{ name: 'ECDH', public: ECDH.publicKey },
|
||||
{ name: 'HMAC', hash: 'SHA3-256', length: 256 }],
|
||||
|
||||
@@ -71,27 +73,27 @@ export const vectors = {
|
||||
{ name: 'HMAC', hash: 'SHA3-256' }],
|
||||
],
|
||||
'deriveBits': [
|
||||
[hasSha3, { name: 'HKDF', hash: 'SHA3-256', salt: Buffer.alloc(0), info: Buffer.alloc(0) }, 8],
|
||||
[hasSha3, { name: 'HKDF', hash: 'SHA3-256', salt: Buffer.alloc(0), info: Buffer.alloc(0) }, 0],
|
||||
[!isBoringSSL, { name: 'HKDF', hash: 'SHA3-256', salt: Buffer.alloc(0), info: Buffer.alloc(0) }, 8],
|
||||
[!isBoringSSL, { name: 'HKDF', hash: 'SHA3-256', salt: Buffer.alloc(0), info: Buffer.alloc(0) }, 0],
|
||||
[false, { name: 'HKDF', hash: 'SHA3-256', salt: Buffer.alloc(0), info: Buffer.alloc(0) }, null],
|
||||
[false, { name: 'HKDF', hash: 'SHA3-256', salt: Buffer.alloc(0), info: Buffer.alloc(0) }, 7],
|
||||
|
||||
[hasSha3, { name: 'PBKDF2', hash: 'SHA3-256', salt: Buffer.alloc(0), iterations: 1 }, 8],
|
||||
[hasSha3, { name: 'PBKDF2', hash: 'SHA3-256', salt: Buffer.alloc(0), iterations: 1 }, 0],
|
||||
[!isBoringSSL, { name: 'PBKDF2', hash: 'SHA3-256', salt: Buffer.alloc(0), iterations: 1 }, 8],
|
||||
[!isBoringSSL, { name: 'PBKDF2', hash: 'SHA3-256', salt: Buffer.alloc(0), iterations: 1 }, 0],
|
||||
[false, { name: 'PBKDF2', hash: 'SHA3-256', salt: Buffer.alloc(0), iterations: 0 }, 8],
|
||||
[false, { name: 'PBKDF2', hash: 'SHA3-256', salt: Buffer.alloc(0), iterations: 1 }, null],
|
||||
[false, { name: 'PBKDF2', hash: 'SHA3-256', salt: Buffer.alloc(0), iterations: 1 }, 7],
|
||||
],
|
||||
'importKey': [
|
||||
[hasSha3, { name: 'HMAC', hash: 'SHA3-256' }],
|
||||
[hasSha3, { name: 'HMAC', hash: 'SHA3-256', length: 256 }],
|
||||
[hasSha3, { name: 'HMAC', hash: 'SHA3-256', length: 25 }],
|
||||
[hasSha3, { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA3-256', ...RSA_KEY_GEN }],
|
||||
[hasSha3, { name: 'RSA-PSS', hash: 'SHA3-256', ...RSA_KEY_GEN }],
|
||||
[hasSha3, { name: 'RSA-OAEP', hash: 'SHA3-256', ...RSA_KEY_GEN }],
|
||||
[hasSha3, { name: 'HMAC', hash: 'SHA3-256' }],
|
||||
[hasSha3, { name: 'HMAC', hash: 'SHA3-256', length: 256 }],
|
||||
[hasSha3, { name: 'HMAC', hash: 'SHA3-256', length: 25 }],
|
||||
[!isBoringSSL, { name: 'HMAC', hash: 'SHA3-256' }],
|
||||
[!isBoringSSL, { name: 'HMAC', hash: 'SHA3-256', length: 256 }],
|
||||
[!isBoringSSL, { name: 'HMAC', hash: 'SHA3-256', length: 25 }],
|
||||
[!isBoringSSL, { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA3-256', ...RSA_KEY_GEN }],
|
||||
[!isBoringSSL, { name: 'RSA-PSS', hash: 'SHA3-256', ...RSA_KEY_GEN }],
|
||||
[!isBoringSSL, { name: 'RSA-OAEP', hash: 'SHA3-256', ...RSA_KEY_GEN }],
|
||||
[!isBoringSSL, { name: 'HMAC', hash: 'SHA3-256' }],
|
||||
[!isBoringSSL, { name: 'HMAC', hash: 'SHA3-256', length: 256 }],
|
||||
[!isBoringSSL, { name: 'HMAC', hash: 'SHA3-256', length: 25 }],
|
||||
[false, { name: 'HMAC', hash: 'SHA3-256', length: 0 }],
|
||||
],
|
||||
'get key length': [
|
||||
|
||||
@@ -30,4 +30,7 @@ const hashes = getHashes();
|
||||
'sha1',
|
||||
'sha256',
|
||||
'sha512-256',
|
||||
'sha3-256',
|
||||
'sha3-384',
|
||||
'sha3-512',
|
||||
].forEach((hash) => assert(hashes.includes(hash), hash));
|
||||
@@ -0,0 +1,104 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const { isBoringSSL } = require('../common/crypto');
|
||||
if (!isBoringSSL)
|
||||
common.skip('BoringSSL-only test');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
constants,
|
||||
createPrivateKey,
|
||||
createPublicKey,
|
||||
createSign,
|
||||
createVerify,
|
||||
sign,
|
||||
subtle,
|
||||
verify,
|
||||
} = require('crypto');
|
||||
const { promisify } = require('util');
|
||||
const signAsync = promisify(sign);
|
||||
const verifyAsync = promisify(verify);
|
||||
// BoringSSL exposes SHA-3 digests, but its PKCS1v1.5 DigestInfo table and ECDSA
|
||||
// digest restrictions still reject them. Use valid independent signatures so
|
||||
// these assertions fail when support lands and the fixture skips can be removed.
|
||||
const vectors = [
|
||||
...require('../fixtures/crypto/rsa_pkcs')({ includeUnsupported: true }),
|
||||
...require('../fixtures/crypto/ecdsa')({ includeUnsupported: true }),
|
||||
].filter(({ hash }) => hash.startsWith('SHA3-'));
|
||||
assert.strictEqual(vectors.length, 12);
|
||||
|
||||
async function test(vector) {
|
||||
const {
|
||||
hash,
|
||||
namedCurve,
|
||||
plaintext,
|
||||
privateKeyBuffer,
|
||||
publicKeyBuffer,
|
||||
signature,
|
||||
} = vector;
|
||||
const isECDSA = vector.name === 'ECDSA';
|
||||
const name = isECDSA ? vector.name : vector.algorithm.name;
|
||||
const context = `${name} ${namedCurve ?? ''} ${hash}`;
|
||||
const error = {
|
||||
code: isECDSA ? 'ERR_OSSL_EVP_INVALID_DIGEST_TYPE' :
|
||||
'ERR_OSSL_RSA_UNKNOWN_ALGORITHM_TYPE',
|
||||
};
|
||||
const privateKey = createPrivateKey({
|
||||
key: privateKeyBuffer, format: 'der', type: 'pkcs8',
|
||||
});
|
||||
const publicKey = createPublicKey({
|
||||
key: publicKeyBuffer, format: 'der', type: 'spki',
|
||||
});
|
||||
const options = isECDSA ? { dsaEncoding: 'ieee-p1363' } :
|
||||
{ padding: constants.RSA_PKCS1_PADDING };
|
||||
const signingKey = { key: privateKey, ...options };
|
||||
const verificationKey = { key: publicKey, ...options };
|
||||
|
||||
assert.throws(() => sign(hash, plaintext, signingKey), error, context);
|
||||
await assert.rejects(signAsync(hash, plaintext, signingKey), error, context);
|
||||
assert.throws(() => createSign(hash).update(plaintext).sign(signingKey),
|
||||
error, context);
|
||||
|
||||
if (isECDSA) {
|
||||
assert.throws(() => verify(hash, plaintext, verificationKey, signature),
|
||||
error, context);
|
||||
await assert.rejects(verifyAsync(hash, plaintext, verificationKey, signature),
|
||||
error, context);
|
||||
} else {
|
||||
assert.strictEqual(verify(hash, plaintext, verificationKey, signature), false,
|
||||
context);
|
||||
assert.strictEqual(
|
||||
await verifyAsync(hash, plaintext, verificationKey, signature), false,
|
||||
context);
|
||||
}
|
||||
assert.strictEqual(createVerify(hash).update(plaintext)
|
||||
.verify(verificationKey, signature), false, context);
|
||||
|
||||
const unsupportedHash = { name: 'NotSupportedError' };
|
||||
if (!isECDSA) {
|
||||
const algorithm = { name, hash };
|
||||
await assert.rejects(subtle.importKey(
|
||||
'pkcs8', privateKeyBuffer, algorithm, false, ['sign']),
|
||||
unsupportedHash, context);
|
||||
await assert.rejects(subtle.importKey(
|
||||
'spki', publicKeyBuffer, algorithm, false, ['verify']),
|
||||
unsupportedHash, context);
|
||||
return;
|
||||
}
|
||||
|
||||
const [webPrivateKey, webPublicKey] = await Promise.all([
|
||||
subtle.importKey('pkcs8', privateKeyBuffer, { name, namedCurve }, false, ['sign']),
|
||||
subtle.importKey('spki', publicKeyBuffer, { name, namedCurve }, false, ['verify']),
|
||||
]);
|
||||
await assert.rejects(subtle.sign({ name, hash }, webPrivateKey, plaintext),
|
||||
unsupportedHash, context);
|
||||
await assert.rejects(subtle.verify({ name, hash }, webPublicKey, signature,
|
||||
plaintext), unsupportedHash, context);
|
||||
}
|
||||
|
||||
for (const vector of vectors)
|
||||
test(vector).then(common.mustCall());
|
||||
@@ -22,7 +22,6 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const { isBoringSSL } = require('../common/crypto');
|
||||
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
@@ -32,14 +31,8 @@ const crypto = require('crypto');
|
||||
|
||||
const stream = require('stream');
|
||||
const s = new stream.PassThrough();
|
||||
const h = isBoringSSL ?
|
||||
crypto.createHash('sha512') :
|
||||
crypto.createHash('sha3-512');
|
||||
const expect = isBoringSSL ?
|
||||
'fba055c6fd0c5b6645407749ed7a8b41' +
|
||||
'b8f629f2163c3ca3701d864adabda1f8' +
|
||||
'93c37bf82b22fdd151ba8e357f611da4' +
|
||||
'88a74b6a5525dd9b69554c6ce5138ad7' :
|
||||
const h = crypto.createHash('sha3-512');
|
||||
const expect =
|
||||
'36a38a2a35e698974d4e5791a3f05b05' +
|
||||
'198235381e864f91a0e8cd6a26b677ec' +
|
||||
'dcde8e2b069bd7355fabd68abd6fc801' +
|
||||
|
||||
@@ -12,13 +12,15 @@ const {
|
||||
randomBytes,
|
||||
generateKeyPairSync,
|
||||
} = require('crypto');
|
||||
const { hasFIPS } = require('../common/crypto');
|
||||
const { hasFIPS, isBoringSSL } = require('../common/crypto');
|
||||
const { kSupportedAlgorithms } = require('internal/crypto/util');
|
||||
const rejectsXCurves = hasFIPS(3, 5);
|
||||
|
||||
const hashes = Object.keys(kSupportedAlgorithms.digest).filter((name) => {
|
||||
return name.startsWith('SHA-') || name.startsWith('SHA3-');
|
||||
});
|
||||
const unsupportedKeyHashes = isBoringSSL ? ['SHA3-256', 'SHA3-384', 'SHA3-512'] : [];
|
||||
const keyHashes = hashes.filter((hash) => !unsupportedKeyHashes.includes(hash));
|
||||
const namedCurves = ['P-256', 'P-384', 'P-521'];
|
||||
|
||||
const signingUsages = {
|
||||
@@ -105,6 +107,17 @@ function runVector(vector) {
|
||||
assertVector(vector, false);
|
||||
}
|
||||
|
||||
function assertUnsupportedKeyHashes(keyObject, name, usages) {
|
||||
for (const hash of unsupportedKeyHashes) {
|
||||
for (const extractable of [true, false]) {
|
||||
assert.throws(() => keyObject.toCryptoKey({ name, hash }, extractable, usages), {
|
||||
name: 'NotSupportedError',
|
||||
message: 'SHA-3 is only supported for digest operations',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function symmetricVectors(name, usages) {
|
||||
const vectors = [];
|
||||
for (const length of [128, 192, 256]) {
|
||||
@@ -181,7 +194,8 @@ function hmacVectors() {
|
||||
const vectors = [];
|
||||
for (const length of [128, 192, 256]) {
|
||||
const key = secretKey(length);
|
||||
for (const hash of hashes) {
|
||||
assertUnsupportedKeyHashes(key, 'HMAC', ['sign', 'verify']);
|
||||
for (const hash of keyHashes) {
|
||||
vectors.push(vector(
|
||||
key,
|
||||
{ name: 'HMAC', hash },
|
||||
@@ -219,7 +233,8 @@ function rsaVectors(name, usagesByType) {
|
||||
const keyPair = generateKeyPairSync('rsa', { modulusLength: 2048 });
|
||||
const vectors = [];
|
||||
for (const keyObject of [keyPair.publicKey, keyPair.privateKey]) {
|
||||
for (const hash of hashes) {
|
||||
assertUnsupportedKeyHashes(keyObject, name, getUsages(keyObject, usagesByType));
|
||||
for (const hash of keyHashes) {
|
||||
vectors.push(vector(
|
||||
keyObject,
|
||||
{ name, hash },
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const {
|
||||
constants,
|
||||
createHash,
|
||||
createHmac,
|
||||
createPrivateKey,
|
||||
createPublicKey,
|
||||
createSign,
|
||||
createVerify,
|
||||
getHashes,
|
||||
hash,
|
||||
hkdf,
|
||||
hkdfSync,
|
||||
pbkdf2,
|
||||
pbkdf2Sync,
|
||||
sign,
|
||||
verify,
|
||||
} = require('crypto');
|
||||
const rsaPss = require('../fixtures/crypto/rsa_pss');
|
||||
|
||||
const vectors = [
|
||||
{
|
||||
name: 'sha3-256',
|
||||
digest: '3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532',
|
||||
hmac: '961fcf59ed455732e405e74f5dc78beb7aa41ad315af5e2b2a0dcf8cef9887e0',
|
||||
hkdf: '38c2d1e7b3933f7df51e35f3eeaa0a0138b1b812e2bf57810ad4e2300e2c4a81',
|
||||
pbkdf2: 'db7d83f5e7ebc6b0ea83e9b6c57a27e254e96cfef315278e9ed96b10483a7ad0',
|
||||
},
|
||||
{
|
||||
name: 'sha3-384',
|
||||
digest: 'ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b29' +
|
||||
'8d88cea927ac7f539f1edf228376d25',
|
||||
hmac: 'f1d3898bb4cd7b7904fe4e7cecb84d3225b3add0265842ec7386867d662ee3364' +
|
||||
'8a90e98a5c673b2266eb1077fb91ed6',
|
||||
hkdf: '3ca21ccc4e742ec6a365ee5857db1ab5a0a8843196467d7a0b26c724e542f6f5',
|
||||
pbkdf2: '7f049e44bfddb1b591d1ae2beaa1f3be54d683063bd25759b412a86012186c16',
|
||||
},
|
||||
{
|
||||
name: 'sha3-512',
|
||||
digest: 'b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e1' +
|
||||
'0e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0',
|
||||
hmac: '5576c01b021fc928ae1bc83a6ddb8db5f9a201681e940ecf1f7d5c8a6ec80ac34' +
|
||||
'614d4a68c9581957f69dc8a8c0fbf413984b0f938db3e8212c0744a1a9c5915',
|
||||
hkdf: 'cd54f848a5f6ffb9e730d4bfbdff30d69a4b86316afdf5ba61b4fe95bd022037',
|
||||
pbkdf2: '2b5150c50e0bf48dcb5b32205ad81e8c42d97f8f8dff57dcc365a38e857a05c7',
|
||||
},
|
||||
];
|
||||
|
||||
const hashes = getHashes();
|
||||
for (const vector of vectors) {
|
||||
assert(hashes.includes(vector.name));
|
||||
for (const name of [vector.name, vector.name.toUpperCase(),
|
||||
vector.name.replace('sha', 'sHa')]) {
|
||||
assert.strictEqual(hash(name, 'abc'), vector.digest);
|
||||
|
||||
const original = createHash(name).update('a');
|
||||
const copy = original.copy();
|
||||
assert.strictEqual(original.update('bc').digest('hex'), vector.digest);
|
||||
assert.strictEqual(copy.update('b').copy().update('c').digest('hex'), vector.digest);
|
||||
|
||||
// Exceed every SHA-3 block size so HMAC also hashes the key.
|
||||
assert.strictEqual(createHmac(name, Buffer.alloc(200, 0xaa))
|
||||
.update('abc').digest('hex'), vector.hmac);
|
||||
|
||||
assert.strictEqual(Buffer.from(hkdfSync(name, 'passwordpassword', 'saltsaltsaltsalt', 'info', 32))
|
||||
.toString('hex'), vector.hkdf);
|
||||
hkdf(name, 'passwordpassword', 'saltsaltsaltsalt', 'info', 32, common.mustSucceed((result) => {
|
||||
assert.strictEqual(Buffer.from(result).toString('hex'), vector.hkdf);
|
||||
}));
|
||||
|
||||
assert.strictEqual(pbkdf2Sync('passwordpassword', 'saltsaltsaltsalt', 1000, 32, name)
|
||||
.toString('hex'), vector.pbkdf2);
|
||||
pbkdf2('passwordpassword', 'saltsaltsaltsalt', 1000, 32, name, common.mustSucceed((result) => {
|
||||
assert.strictEqual(result.toString('hex'), vector.pbkdf2);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// Reuse independent RSA-PSS signature vectors to check SHA-3 in both the
|
||||
// one-shot and streaming APIs, including zero-length and digest-length salts.
|
||||
for (const vector of rsaPss()) {
|
||||
if (!vector.hash.startsWith('SHA3-')) continue;
|
||||
const privateKey = createPrivateKey({
|
||||
key: vector.privateKeyBuffer, format: 'der', type: 'pkcs8',
|
||||
});
|
||||
const publicKey = createPublicKey({
|
||||
key: vector.publicKeyBuffer, format: 'der', type: 'spki',
|
||||
});
|
||||
const options = {
|
||||
padding: constants.RSA_PKCS1_PSS_PADDING,
|
||||
saltLength: vector.algorithm.saltLength,
|
||||
};
|
||||
const signingKey = { key: privateKey, ...options };
|
||||
const verificationKey = { key: publicKey, ...options };
|
||||
|
||||
assert(verify(vector.hash, vector.plaintext, verificationKey,
|
||||
vector.signature));
|
||||
assert(createVerify(vector.hash).update(vector.plaintext)
|
||||
.verify(verificationKey, vector.signature));
|
||||
|
||||
for (const signature of [
|
||||
sign(vector.hash, vector.plaintext, signingKey),
|
||||
createSign(vector.hash).update(vector.plaintext).sign(signingKey),
|
||||
]) {
|
||||
assert(verify(vector.hash, vector.plaintext, verificationKey, signature));
|
||||
assert(createVerify(vector.hash).update(vector.plaintext)
|
||||
.verify(verificationKey, signature));
|
||||
if (options.saltLength === 0)
|
||||
assert.deepStrictEqual(signature, vector.signature);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const { isBoringSSL } = require('../common/crypto');
|
||||
if (!isBoringSSL)
|
||||
common.skip('BoringSSL-only test');
|
||||
|
||||
const assert = require('assert');
|
||||
const { subtle } = require('crypto');
|
||||
const { SubtleCrypto } = globalThis;
|
||||
|
||||
const unsupportedHash = {
|
||||
name: 'NotSupportedError',
|
||||
message: 'SHA-3 is only supported for digest operations',
|
||||
};
|
||||
|
||||
async function test() {
|
||||
const data = Buffer.from('abc');
|
||||
const secret = Buffer.alloc(32);
|
||||
const wrappingKey = await subtle.importKey(
|
||||
'raw', Buffer.alloc(16), 'AES-KW', false, ['wrapKey', 'unwrapKey']);
|
||||
const keyToWrap = await subtle.importKey(
|
||||
'raw', secret, { name: 'HMAC', hash: 'SHA-256' }, true, ['sign']);
|
||||
const wrapped = await subtle.wrapKey('raw', keyToWrap, wrappingKey, 'AES-KW');
|
||||
const bases = await Promise.all(['HKDF', 'PBKDF2'].map((name) =>
|
||||
subtle.importKey('raw', secret, name, false, ['deriveBits', 'deriveKey'])));
|
||||
|
||||
for (const [hash, length] of [
|
||||
['SHA3-256', 32],
|
||||
['SHA3-384', 48],
|
||||
['SHA3-512', 64],
|
||||
]) {
|
||||
assert.strictEqual(SubtleCrypto.supports('digest', hash), true);
|
||||
assert.strictEqual((await subtle.digest(hash, data)).byteLength, length);
|
||||
|
||||
for (const name of ['RSASSA-PKCS1-v1_5', 'RSA-PSS', 'RSA-OAEP']) {
|
||||
const algorithm = {
|
||||
name, hash, modulusLength: 2048,
|
||||
publicExponent: new Uint8Array([1, 0, 1]),
|
||||
};
|
||||
const usages = name === 'RSA-OAEP' ? ['encrypt', 'decrypt'] : ['sign', 'verify'];
|
||||
assert.strictEqual(SubtleCrypto.supports('generateKey', algorithm), false);
|
||||
assert.strictEqual(SubtleCrypto.supports('importKey', algorithm), false);
|
||||
await assert.rejects(subtle.generateKey(algorithm, true, usages), unsupportedHash);
|
||||
}
|
||||
|
||||
const hmac = { name: 'HMAC', hash, length: 256 };
|
||||
assert.strictEqual(SubtleCrypto.supports('generateKey', hmac), false);
|
||||
assert.strictEqual(SubtleCrypto.supports('importKey', hmac), false);
|
||||
await assert.rejects(subtle.generateKey(hmac, true, ['sign']), unsupportedHash);
|
||||
await assert.rejects(subtle.importKey('raw', secret, hmac, false, ['sign']),
|
||||
unsupportedHash);
|
||||
assert.strictEqual(SubtleCrypto.supports('unwrapKey', 'AES-KW', hmac), false);
|
||||
await assert.rejects(subtle.unwrapKey(
|
||||
'raw', wrapped, wrappingKey, 'AES-KW', hmac, false, ['sign']), unsupportedHash);
|
||||
|
||||
for (const [index, algorithm] of [
|
||||
{ name: 'HKDF', hash, salt: secret, info: data },
|
||||
{ name: 'PBKDF2', hash, salt: secret, iterations: 1 },
|
||||
].entries()) {
|
||||
const base = bases[index];
|
||||
const derivedKey = { name: 'AES-GCM', length: 128 };
|
||||
assert.strictEqual(SubtleCrypto.supports('deriveBits', algorithm, 128), false);
|
||||
assert.strictEqual(SubtleCrypto.supports('deriveKey', algorithm, derivedKey), false);
|
||||
await assert.rejects(subtle.deriveBits(algorithm, base, 128), unsupportedHash);
|
||||
await assert.rejects(subtle.deriveKey(
|
||||
algorithm, base, derivedKey, false, ['encrypt']), unsupportedHash);
|
||||
|
||||
const sha256 = { ...algorithm, hash: 'SHA-256' };
|
||||
assert.strictEqual(SubtleCrypto.supports('deriveKey', sha256, hmac), false);
|
||||
await assert.rejects(subtle.deriveKey(
|
||||
sha256, base, hmac, false, ['sign']), unsupportedHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test().then(common.mustCall());
|
||||
@@ -35,7 +35,7 @@ if (!isBoringSSL) {
|
||||
['HMAC', 256, 'SHA3-512', 'sign', 'verify'],
|
||||
);
|
||||
} else {
|
||||
common.printSkipMessage('Skipping unsupported test cases');
|
||||
common.printSkipMessage('SHA-3 is only supported for digest operations');
|
||||
}
|
||||
|
||||
if (hasOpenSSL(3)) {
|
||||
|
||||
@@ -97,7 +97,7 @@ const fips4 = hasFIPS(4);
|
||||
'ac5d90a6bc848961e78a491887539b29c532a9c0d0b39cec464df071a63e0061'],
|
||||
);
|
||||
} else {
|
||||
common.printSkipMessage('Skipping unsupported SHA-3 test cases');
|
||||
common.printSkipMessage('SHA-3 is only supported for digest operations');
|
||||
}
|
||||
|
||||
const tests = Promise.all(kTests.map((args) => test(...args)));
|
||||
@@ -150,7 +150,7 @@ const fips4 = hasFIPS(4);
|
||||
'03431052c37d626ae3fc1df582ff2a4d610642fc27e1b8130ca5980c0b0756ac']
|
||||
);
|
||||
} else {
|
||||
common.printSkipMessage('Skipping unsupported SHA-3 test cases');
|
||||
common.printSkipMessage('SHA-3 is only supported for digest operations');
|
||||
}
|
||||
|
||||
const promises = kTests.map((args) => test(...args));
|
||||
@@ -188,7 +188,7 @@ const fips4 = hasFIPS(4);
|
||||
// [{ name: 'HMAC', hash: 'SHA3-512' }, 'sign', 512],
|
||||
);
|
||||
} else {
|
||||
common.printSkipMessage('Skipping unsupported SHA-3 test cases');
|
||||
common.printSkipMessage('SHA-3 is only supported for digest operations');
|
||||
}
|
||||
|
||||
if (hasOpenSSL(3)) {
|
||||
@@ -248,7 +248,7 @@ const fips4 = hasFIPS(4);
|
||||
// [{ name: 'HMAC', hash: 'SHA3-512' }, 'sign', 512],
|
||||
);
|
||||
} else {
|
||||
common.printSkipMessage('Skipping unsupported SHA-3 test cases');
|
||||
common.printSkipMessage('SHA-3 is only supported for digest operations');
|
||||
}
|
||||
|
||||
if (hasOpenSSL(3)) {
|
||||
|
||||
@@ -16,15 +16,15 @@ const kTests = [
|
||||
['SHA-256', ['sha256'], 256],
|
||||
['SHA-384', ['sha384'], 384],
|
||||
['SHA-512', ['sha512'], 512],
|
||||
['SHA3-256', ['sha3-256'], 256],
|
||||
['SHA3-384', ['sha3-384'], 384],
|
||||
['SHA3-512', ['sha3-512'], 512],
|
||||
];
|
||||
|
||||
if (!isBoringSSL) {
|
||||
kTests.push(
|
||||
[{ name: 'cSHAKE128', outputLength: 256 }, ['shake128', { outputLength: 256 >> 3 }], 256],
|
||||
[{ name: 'cSHAKE256', outputLength: 512 }, ['shake256', { outputLength: 512 >> 3 }], 512],
|
||||
['SHA3-256', ['sha3-256'], 256],
|
||||
['SHA3-384', ['sha3-384'], 384],
|
||||
['SHA3-512', ['sha3-512'], 512],
|
||||
);
|
||||
} else {
|
||||
common.printSkipMessage('Skipping unsupported test cases');
|
||||
@@ -175,41 +175,41 @@ const kDigestedData = {
|
||||
'd5290933492f9d17411926a613dd0611668c2ac999e8' +
|
||||
'c011aabaa9004323425fbad75b0f58ee6e777a94'
|
||||
},
|
||||
'sha3-256': {
|
||||
empty: 'a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a',
|
||||
short: '3059af7aa33b517084e8ad7bbc4fb208a44c28ef32b4698d103dd540e4f91aa1',
|
||||
medium: '1fa7cd1da74cd8046417508c8314e74a9a4a9d38f9f18e6cb215b8c891a0a80e',
|
||||
long: 'b2cfc61e0386cdaef5e10a2be189891f5ef52a7624bfcd8edc893acc64fec600'
|
||||
},
|
||||
'sha3-384': {
|
||||
empty: '0c63a75b845e4f7d01107d852e4c2485c51a50aaaa9' +
|
||||
'4fc61995e71bbee983a2ac3713831264adb47fb6bd1' +
|
||||
'e058d5f004',
|
||||
short: '54b8f0e4cf4974de740098f66b3024479b01631315a' +
|
||||
'6773606c33eadc32556a6e778e08f0225ae79265aec' +
|
||||
'666cb2390b',
|
||||
medium: '437b7d8b68b250b5c1739ea4cc86db2033879dfb18' +
|
||||
'de292c9c50d9c193a4c79a08a6cae3f4e483c2795e' +
|
||||
'a5d1ef7e69d2',
|
||||
long: '3b39c4c97ad87613305d0ccc987181713e2d5e84b1f9' +
|
||||
'760011bcce0c297499005bdce8a3d2409b5ad0164f32' +
|
||||
'bb8778d0'
|
||||
},
|
||||
'sha3-512': {
|
||||
empty: 'a69f73cca23a9ac5c8b567dc185a756e97c982164fe' +
|
||||
'25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9' +
|
||||
'402c3ac558f500199d95b6d3e301758586281dcd26',
|
||||
short: '2dd2e07a62e6ad0498ba84f313c4d4024cb46001f78' +
|
||||
'f75db336b0d4d8bd2a9ec152c4ad20878735d82ba08' +
|
||||
'72ecf59608ef3ced2b2a8669427e7da31e362333d8',
|
||||
medium: 'e640a21909536640369e9b0a48931c5cb2efcbc91f' +
|
||||
'ecf247306bc96a0e4ca33307cb8e1b9af367946dd01' +
|
||||
'c243f3907508d04f1692a3161df1f898de8ee25febe',
|
||||
long: 'bd262cecf565c338032de5ba0138f0aacfe7dde83d27' +
|
||||
'2d0d37d952829ed25de1a1342d98659ef7d2fa4aca7c' +
|
||||
'e2b1aa0784d8fc1dcbf81bcec7a7431a3da36bf7'
|
||||
}
|
||||
} : {}),
|
||||
'sha3-256': {
|
||||
empty: 'a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a',
|
||||
short: '3059af7aa33b517084e8ad7bbc4fb208a44c28ef32b4698d103dd540e4f91aa1',
|
||||
medium: '1fa7cd1da74cd8046417508c8314e74a9a4a9d38f9f18e6cb215b8c891a0a80e',
|
||||
long: 'b2cfc61e0386cdaef5e10a2be189891f5ef52a7624bfcd8edc893acc64fec600'
|
||||
},
|
||||
'sha3-384': {
|
||||
empty: '0c63a75b845e4f7d01107d852e4c2485c51a50aaaa9' +
|
||||
'4fc61995e71bbee983a2ac3713831264adb47fb6bd1' +
|
||||
'e058d5f004',
|
||||
short: '54b8f0e4cf4974de740098f66b3024479b01631315a' +
|
||||
'6773606c33eadc32556a6e778e08f0225ae79265aec' +
|
||||
'666cb2390b',
|
||||
medium: '437b7d8b68b250b5c1739ea4cc86db2033879dfb18' +
|
||||
'de292c9c50d9c193a4c79a08a6cae3f4e483c2795e' +
|
||||
'a5d1ef7e69d2',
|
||||
long: '3b39c4c97ad87613305d0ccc987181713e2d5e84b1f9' +
|
||||
'760011bcce0c297499005bdce8a3d2409b5ad0164f32' +
|
||||
'bb8778d0'
|
||||
},
|
||||
'sha3-512': {
|
||||
empty: 'a69f73cca23a9ac5c8b567dc185a756e97c982164fe' +
|
||||
'25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9' +
|
||||
'402c3ac558f500199d95b6d3e301758586281dcd26',
|
||||
short: '2dd2e07a62e6ad0498ba84f313c4d4024cb46001f78' +
|
||||
'f75db336b0d4d8bd2a9ec152c4ad20878735d82ba08' +
|
||||
'72ecf59608ef3ced2b2a8669427e7da31e362333d8',
|
||||
medium: 'e640a21909536640369e9b0a48931c5cb2efcbc91f' +
|
||||
'ecf247306bc96a0e4ca33307cb8e1b9af367946dd01' +
|
||||
'c243f3907508d04f1692a3161df1f898de8ee25febe',
|
||||
long: 'bd262cecf565c338032de5ba0138f0aacfe7dde83d27' +
|
||||
'2d0d37d952829ed25de1a1342d98659ef7d2fa4aca7c' +
|
||||
'e2b1aa0784d8fc1dcbf81bcec7a7431a3da36bf7'
|
||||
}
|
||||
};
|
||||
|
||||
async function testDigest(size, alg) {
|
||||
|
||||
@@ -48,18 +48,21 @@ async function testRSAOaep(publicKey, privateKey) {
|
||||
|
||||
await testRSAOaep(publicKey, privateKey);
|
||||
|
||||
// SHA-3 is only supported for digest operations in BoringSSL.
|
||||
if (!isBoringSSL) {
|
||||
// Import the same key material with SHA-3 to avoid another RSA keygen.
|
||||
const [spki, pkcs8] = await Promise.all([
|
||||
subtle.exportKey('spki', publicKey),
|
||||
subtle.exportKey('pkcs8', privateKey),
|
||||
]);
|
||||
const algorithm = { name: 'RSA-OAEP', hash: 'SHA3-384' };
|
||||
const [sha3PublicKey, sha3PrivateKey] = await Promise.all([
|
||||
subtle.importKey('spki', spki, algorithm, false, ['encrypt']),
|
||||
subtle.importKey('pkcs8', pkcs8, algorithm, false, ['decrypt']),
|
||||
]);
|
||||
await testRSAOaep(sha3PublicKey, sha3PrivateKey);
|
||||
for (const hash of ['SHA3-256', 'SHA3-384', 'SHA3-512']) {
|
||||
const algorithm = { name: 'RSA-OAEP', hash };
|
||||
const [sha3PublicKey, sha3PrivateKey] = await Promise.all([
|
||||
subtle.importKey('spki', spki, algorithm, false, ['encrypt']),
|
||||
subtle.importKey('pkcs8', pkcs8, algorithm, false, ['decrypt']),
|
||||
]);
|
||||
await testRSAOaep(sha3PublicKey, sha3PrivateKey);
|
||||
}
|
||||
}
|
||||
})().then(common.mustCall());
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
const common = require('../common');
|
||||
|
||||
const { isBoringSSL } = require('../common/crypto');
|
||||
const fixtures = require('../common/fixtures');
|
||||
|
||||
if (!common.hasCrypto)
|
||||
@@ -10,6 +9,7 @@ if (!common.hasCrypto)
|
||||
|
||||
const assert = require('assert');
|
||||
const crypto = require('crypto');
|
||||
const { isBoringSSL } = require('../common/crypto');
|
||||
const { subtle } = globalThis.crypto;
|
||||
|
||||
const sizes = [1024, 2048, 4096];
|
||||
@@ -19,18 +19,11 @@ const hashes = [
|
||||
'SHA-256',
|
||||
'SHA-384',
|
||||
'SHA-512',
|
||||
'SHA3-256',
|
||||
'SHA3-384',
|
||||
'SHA3-512',
|
||||
];
|
||||
|
||||
if (!isBoringSSL) {
|
||||
hashes.push(
|
||||
'SHA3-256',
|
||||
'SHA3-384',
|
||||
'SHA3-512',
|
||||
);
|
||||
} else {
|
||||
common.printSkipMessage('Skipping unsupported SHA-3 test cases');
|
||||
}
|
||||
|
||||
const keyData = {
|
||||
1024: {
|
||||
spki: Buffer.from(
|
||||
@@ -643,6 +636,22 @@ const testVectors = [
|
||||
hashes.forEach((hash) => {
|
||||
[true, false].forEach((extractable) => {
|
||||
testVectors.forEach((vector) => {
|
||||
if (isBoringSSL && hash.startsWith('SHA3-')) {
|
||||
const { spki, pkcs8, jwk } = keyData[size];
|
||||
for (const [format, data, usages] of [
|
||||
['spki', spki, vector.publicUsages],
|
||||
['pkcs8', pkcs8, vector.privateUsages],
|
||||
['jwk', { kty: jwk.kty, n: jwk.n, e: jwk.e }, vector.publicUsages],
|
||||
['jwk', jwk, vector.privateUsages],
|
||||
]) {
|
||||
variations.push(assert.rejects(subtle.importKey(
|
||||
format, data, { name: vector.name, hash }, extractable, usages), {
|
||||
name: 'NotSupportedError',
|
||||
message: 'SHA-3 is only supported for digest operations',
|
||||
}));
|
||||
}
|
||||
return;
|
||||
}
|
||||
variations.push(testImportSpki(vector, size, hash, extractable));
|
||||
variations.push(testImportPkcs8(vector, size, hash, extractable));
|
||||
variations.push(testImportJwk(vector, size, hash, extractable));
|
||||
|
||||
@@ -484,12 +484,19 @@ if (hasOpenSSL(3)) {
|
||||
}
|
||||
|
||||
// SHA-3 hashes and JWK "alg"
|
||||
if (!isBoringSSL) {
|
||||
{
|
||||
const rsa = fixtures.readKey('rsa_private_2048.pem');
|
||||
const privateKey = createPrivateKey(rsa);
|
||||
const publicKey = createPublicKey(privateKey);
|
||||
|
||||
async function test(keyObject, algorithm, usages) {
|
||||
if (isBoringSSL) {
|
||||
assert.throws(() => keyObject.toCryptoKey(algorithm, true, usages), {
|
||||
name: 'NotSupportedError',
|
||||
message: 'SHA-3 is only supported for digest operations',
|
||||
});
|
||||
return;
|
||||
}
|
||||
const key = keyObject.toCryptoKey(algorithm, true, usages);
|
||||
const jwk = await subtle.exportKey('jwk', key);
|
||||
assert.strictEqual(jwk.alg, undefined);
|
||||
@@ -501,7 +508,8 @@ if (!isBoringSSL) {
|
||||
test(privateKey, { name, hash }, [name === 'RSA-OAEP' ? 'unwrapKey' : 'sign']).then(common.mustCall());
|
||||
}
|
||||
|
||||
test(createSecretKey(Buffer.alloc(32)), { name: 'HMAC', hash }, ['sign']);
|
||||
test(createSecretKey(Buffer.alloc(32)), { name: 'HMAC', hash }, ['sign'])
|
||||
.then(common.mustCall());
|
||||
}
|
||||
|
||||
{
|
||||
@@ -517,7 +525,16 @@ if (!isBoringSSL) {
|
||||
message: 'JWK "alg" does not match the requested algorithm',
|
||||
}).then(common.mustCall());
|
||||
|
||||
subtle.importKey('jwk', jwk, { name: 'HMAC', hash: 'SHA3-256' }, false, ['sign', 'verify']).then(common.mustCall());
|
||||
const imported = subtle.importKey(
|
||||
'jwk', jwk, { name: 'HMAC', hash: 'SHA3-256' }, false, ['sign', 'verify']);
|
||||
if (isBoringSSL) {
|
||||
assert.rejects(imported, {
|
||||
name: 'NotSupportedError',
|
||||
message: 'SHA-3 is only supported for digest operations',
|
||||
}).then(common.mustCall());
|
||||
} else {
|
||||
imported.then(common.mustCall());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -527,7 +527,7 @@ if (hasOpenSSL(3, 5) || isBoringSSL) {
|
||||
);
|
||||
}
|
||||
} else {
|
||||
common.printSkipMessage('Skipping unsupported SHA-3 test case');
|
||||
common.printSkipMessage('SHA-3 is only supported for digest operations');
|
||||
}
|
||||
|
||||
const tests = kTests.map((args) => test(...args));
|
||||
@@ -733,7 +733,7 @@ if (hasOpenSSL(3, 5) || isBoringSSL) {
|
||||
// [undefined, 'SHA3-512', ['sign', 'verify']],
|
||||
);
|
||||
} else {
|
||||
common.printSkipMessage('Skipping unsupported SHA-3 test cases');
|
||||
common.printSkipMessage('SHA-3 is only supported for digest operations');
|
||||
}
|
||||
|
||||
const tests = Promise.all(kTests.map((args) => test(...args)));
|
||||
|
||||
@@ -39,7 +39,7 @@ const { subtle } = globalThis.crypto;
|
||||
{ name: 'OperationError' });
|
||||
await assert.rejects(subtle.generateKey({ name: 'HMAC', hash: 'SHA-256', length: 0 }, false, []),
|
||||
{ name: 'OperationError' });
|
||||
if (SubtleCrypto.supports('digest', 'SHA3-256')) {
|
||||
if (SubtleCrypto.supports('generateKey', { name: 'HMAC', hash: 'SHA3-256', length: 256 })) {
|
||||
const hmac = { name: 'HMAC', hash: 'SHA3-256' };
|
||||
await assert.rejects(subtle.generateKey(hmac, false, ['encrypt']), { name: 'SyntaxError' });
|
||||
await assert.rejects(subtle.generateKey(hmac, false, []), { name: 'NotSupportedError' });
|
||||
|
||||
@@ -4,13 +4,10 @@ const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const { isBoringSSL } = require('../common/crypto');
|
||||
if (isBoringSSL)
|
||||
common.skip('missing SHA-3');
|
||||
|
||||
const assert = require('assert');
|
||||
const { createPrivateKey, createPublicKey } = require('crypto');
|
||||
const fixtures = require('../common/fixtures');
|
||||
const { isBoringSSL } = require('../common/crypto');
|
||||
const { subtle } = globalThis.crypto;
|
||||
|
||||
(async () => {
|
||||
@@ -24,6 +21,14 @@ const { subtle } = globalThis.crypto;
|
||||
const usages = name === 'RSA-OAEP' ? [jwk.d ? 'decrypt' : 'encrypt'] :
|
||||
[jwk.d ? 'sign' : 'verify'];
|
||||
const algorithm = { name, hash };
|
||||
if (isBoringSSL) {
|
||||
await assert.rejects(
|
||||
subtle.importKey('jwk', jwk, algorithm, true, usages), {
|
||||
name: 'NotSupportedError',
|
||||
message: 'SHA-3 is only supported for digest operations',
|
||||
});
|
||||
continue;
|
||||
}
|
||||
// There is no JWK alg identifier for RSA with SHA-3. Omitting alg is
|
||||
// valid, but an identifier for SHA-2 or an unknown identifier is not.
|
||||
const key = await subtle.importKey('jwk', jwk, algorithm, true, usages);
|
||||
|
||||
@@ -7,6 +7,7 @@ if (!common.hasCrypto)
|
||||
|
||||
const assert = require('assert');
|
||||
const { getFips } = require('crypto');
|
||||
const { isBoringSSL } = require('../common/crypto');
|
||||
const { subtle } = globalThis.crypto;
|
||||
|
||||
const vectors = require('../fixtures/crypto/hmac')();
|
||||
@@ -174,6 +175,10 @@ async function testSign({ hash,
|
||||
const variations = [];
|
||||
|
||||
for (const vector of vectors) {
|
||||
// The shared fixtures also cover node:crypto; WebCrypto only supports
|
||||
// SHA-3 for digest operations in BoringSSL.
|
||||
if (isBoringSSL && vector.hash.startsWith('SHA3-'))
|
||||
continue;
|
||||
variations.push(testVerify(vector));
|
||||
variations.push(testSign(vector));
|
||||
}
|
||||
|
||||
@@ -267,6 +267,7 @@ async function testSaltLengths(keyLength) {
|
||||
['SHA-256', 32],
|
||||
['SHA-384', 48],
|
||||
['SHA-512', 64],
|
||||
// SHA-3 is only supported for digest operations in BoringSSL.
|
||||
...(!isBoringSSL ? [
|
||||
['SHA3-256', 32],
|
||||
['SHA3-384', 48],
|
||||
@@ -283,12 +284,18 @@ async function testSaltLengths(keyLength) {
|
||||
(async function() {
|
||||
const variations = [];
|
||||
|
||||
// The shared fixtures also cover node:crypto; WebCrypto only supports
|
||||
// SHA-3 for digest operations in BoringSSL.
|
||||
rsa_pkcs().forEach((vector) => {
|
||||
if (isBoringSSL && vector.hash.startsWith('SHA3-'))
|
||||
return;
|
||||
variations.push(testVerify(vector));
|
||||
variations.push(rejectsSha1Signing && vector.hash === 'SHA-1' ?
|
||||
testFipsSignRejected(vector) : testSign(vector));
|
||||
});
|
||||
rsa_pss().forEach((vector) => {
|
||||
if (isBoringSSL && vector.hash.startsWith('SHA3-'))
|
||||
return;
|
||||
variations.push(testVerify(vector));
|
||||
variations.push(rejectsSha1Signing && vector.hash === 'SHA-1' ?
|
||||
testFipsSignRejected(vector) : testSign(vector));
|
||||
|
||||
@@ -81,7 +81,6 @@ if (isBoringSSL) {
|
||||
'secure-curves/derive_bits_keys/cfrg_curves_bits_curve448.https.any.js',
|
||||
'secure-curves/derive_bits_keys/cfrg_curves_keys_curve448.https.any.js',
|
||||
'modern-algos/digest/cshake.https.any.js',
|
||||
'modern-algos/digest/sha3.https.any.js',
|
||||
'secure-curves/generateKey/failures_Ed448.https.any.js',
|
||||
'modern-algos/generateKey/failures_Hybrid-KEM.https.any.js',
|
||||
'secure-curves/generateKey/failures_X448.https.any.js',
|
||||
|
||||
Reference in new issue
Block a user