Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
crypto: fix SHAKE128/256 breaking change introduced with OpenSSL 3.4
Reverts: #56160
Fixes: #56159
Fixes: #58913
Refs: #58121
  • Loading branch information
panva committed Jul 3, 2025
commit d870b4f910c4fa41171519f1bf44c28ec4bbf322
13 changes: 13 additions & 0 deletions doc/api/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -4061,6 +4061,19 @@ Type: Documentation-only

The [`util.types.isNativeError`][] API is deprecated. Please use [`Error.isError`][] instead.

### DEP0198: Creating SHAKE-128 and SHAKE-256 digests without an explicit `options.outputLength`

<!-- YAML
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/58942
description: Documentation-only deprecation with support for `--pending-deprecation`.
-->

Type: Documentation-only (supports [`--pending-deprecation`][])

Creating SHAKE-128 and SHAKE-256 digests without an explicit `options.outputLength` is deprecated.

[DEP0142]: #dep0142-repl_builtinlibs
[NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
[RFC 6066]: https://tools.ietf.org/html/rfc6066#section-3
Expand Down
31 changes: 31 additions & 0 deletions lib/internal/crypto/hash.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const {
ObjectSetPrototypeOf,
ReflectApply,
StringPrototypeReplace,
StringPrototypeToLowerCase,
Symbol,
} = primordials;
Expand Down Expand Up @@ -33,6 +34,8 @@ const {
lazyDOMException,
normalizeEncoding,
encodingsMap,
isPendingDeprecation,
getDeprecationWarningEmitter,
} = require('internal/util');

const {
Expand Down Expand Up @@ -63,6 +66,25 @@ const LazyTransform = require('internal/streams/lazy_transform');
const kState = Symbol('kState');
const kFinalized = Symbol('kFinalized');

/**
* @param {string} name
*/
function normalizeAlgorithm(name) {
return StringPrototypeReplace(StringPrototypeToLowerCase(name), '-', '');
}

const maybeEmitDeprecationWarning = getDeprecationWarningEmitter(
'DEP0198',
'Creating SHAKE128/256 digests without an explicit options.outputLength is deprecated.',
undefined,
false,
(algorithm) => {
if (!isPendingDeprecation()) return false;
const normalized = normalizeAlgorithm(algorithm);
return normalized === 'shake128' || normalized === 'shake256';
},
);

function Hash(algorithm, options) {
if (!new.target)
return new Hash(algorithm, options);
Expand All @@ -80,6 +102,9 @@ function Hash(algorithm, options) {
this[kState] = {
[kFinalized]: false,
};
if (!isCopy && xofLen === undefined) {
maybeEmitDeprecationWarning(algorithm);
}
ReflectApply(LazyTransform, this, [options]);
}

Expand Down Expand Up @@ -213,6 +238,12 @@ function hash(algorithm, input, outputEncoding = 'hex') {
}
}
}
// TODO: ideally we have to ship https://github.com/nodejs/node/pull/58121 so
// that a proper DEP0198 deprecation can be done here as well.
Comment on lines +241 to +242
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// TODO: ideally we have to ship https://github.com/nodejs/node/pull/58121 so
// that a proper DEP0198 deprecation can be done here as well.
// TODO(panva): ideally we have to ship https://github.com/nodejs/node/pull/58121
// so that a proper DEP0198 deprecation can be done here as well.

const normalizedAlgorithm = normalizeAlgorithm(algorithm);
if (normalizedAlgorithm === 'shake128' || normalizedAlgorithm === 'shake256') {
return new Hash(algorithm).update(input).digest(normalized);
}
return oneShotDigest(algorithm, getCachedHashId(algorithm), getHashCache(),
input, normalized, encodingsMap[normalized]);
}
Expand Down
6 changes: 4 additions & 2 deletions lib/internal/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ function getDeprecationWarningEmitter(
shouldEmitWarning = () => true,
) {
let warned = false;
return function() {
if (!warned && shouldEmitWarning()) {
return function(arg) {
if (!warned && shouldEmitWarning(arg)) {
warned = true;
if (code === 'ExperimentalWarning') {
process.emitWarning(msg, code, deprecated);
Expand Down Expand Up @@ -1011,4 +1011,6 @@ module.exports = {
setOwnProperty,
pendingDeprecate,
WeakReference,
isPendingDeprecation,
getDeprecationWarningEmitter,
};
12 changes: 12 additions & 0 deletions src/crypto/crypto_hash.cc
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,18 @@ bool Hash::HashInit(const EVP_MD* md, Maybe<unsigned int> xof_md_len) {
}

md_len_ = mdctx_.getDigestSize();
// TODO(@panva): remove this behaviour when DEP0198 is End-Of-Life
if (mdctx_.hasXofFlag() && !xof_md_len.IsJust() && md_len_ == 0) {
const char* name = OBJ_nid2sn(EVP_MD_type(md));
if (name != nullptr) {
if (strcmp(name, "SHAKE128") == 0) {
md_len_ = 16;
} else if (strcmp(name, "SHAKE256") == 0) {
md_len_ = 32;
}
}
}

if (xof_md_len.IsJust() && xof_md_len.FromJust() != md_len_) {
// This is a little hack to cause createHash to fail when an incorrect
// hashSize option was passed for a non-XOF hash function.
Expand Down
18 changes: 18 additions & 0 deletions test/parallel/test-crypto-default-shake-lengths.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Flags: --pending-deprecation
'use strict';

const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const { createHash } = require('crypto');

common.expectWarning({
DeprecationWarning: {
DEP0198: 'Creating SHAKE128/256 digests without an explicit options.outputLength is deprecated.',
}
});

{
createHash('shake128').update('test').digest();
}