Skip to content

Commit 707d1dd

Browse files
crypto: runtime-deprecate calling Hmac.digest() more than once
Emit a DEP0206 deprecation warning when Hmac.digest() is called on an already-finalized instance. This behavior is inconsistent with Hash.digest() which throws ERR_CRYPTO_HASH_FINALIZED. Fixes: #62838 Co-authored-by: Filip Skokan <panva.ip@gmail.com> Signed-off-by: developers-universe-1 <madelynreyes2026@gmail.com> Signed-off-by: Filip Skokan <panva.ip@gmail.com>
1 parent 5c78025 commit 707d1dd

5 files changed

Lines changed: 85 additions & 53 deletions

File tree

doc/api/deprecations.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4562,12 +4562,15 @@ removed in a future version of Node.js.
45624562
45634563
<!-- YAML
45644564
changes:
4565+
- version: REPLACEME
4566+
pr-url: https://github.com/nodejs/node/pull/63624
4567+
description: Runtime deprecation.
45654568
- version: v26.2.0
45664569
pr-url: https://github.com/nodejs/node/pull/63121
45674570
description: Documentation-only deprecation.
45684571
-->
45694572
4570-
Type: Documentation-only
4573+
Type: Runtime
45714574
45724575
Calling `hmac.digest()` more than once returns an empty buffer instead of
45734576
throwing an error. This behavior is inconsistent with `hash.digest()` and

lib/internal/crypto/hash.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ const maybeEmitDeprecationWarning = getDeprecationWarningEmitter(
8787
},
8888
);
8989

90+
const emitHmacDigestDeprecation = getDeprecationWarningEmitter(
91+
'DEP0206',
92+
'Calling Hmac.digest() more than once is deprecated.',
93+
);
94+
9095
function Hash(algorithm, options) {
9196
if (!new.target)
9297
return new Hash(algorithm, options);
@@ -183,6 +188,7 @@ Hmac.prototype.digest = function digest(outputEncoding) {
183188
const state = this[kState];
184189

185190
if (state[kFinalized]) {
191+
emitHmacDigestDeprecation();
186192
const buf = Buffer.from('');
187193
if (outputEncoding && outputEncoding !== 'buffer')
188194
return buf.toString(outputEncoding);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
if (!common.hasCrypto)
5+
common.skip('missing crypto');
6+
7+
const assert = require('assert');
8+
const crypto = require('crypto');
9+
10+
common.expectWarning({
11+
DeprecationWarning: {
12+
DEP0181: 'crypto.Hmac constructor is deprecated.',
13+
},
14+
});
15+
16+
const Hmac = crypto.Hmac;
17+
const instance = crypto.Hmac('sha256', 'Node');
18+
assert(instance instanceof Hmac, 'Hmac is expected to return a new instance' +
19+
' when called without `new`');
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
if (!common.hasCrypto)
5+
common.skip('missing crypto');
6+
7+
const assert = require('assert');
8+
const crypto = require('crypto');
9+
10+
common.expectWarning({
11+
DeprecationWarning: {
12+
DEP0206: 'Calling Hmac.digest() more than once is deprecated.',
13+
},
14+
});
15+
16+
// Verify runtime deprecation warning for calling digest() more than once.
17+
{
18+
const h = crypto.createHmac('sha1', 'key').update('data');
19+
h.digest('hex');
20+
h.digest('hex');
21+
}
22+
23+
// Check initialized -> uninitialized state transition after calling digest().
24+
{
25+
const expected =
26+
'\u0010\u0041\u0052\u00c5\u00bf\u00dc\u00a0\u007b\u00c6\u0033' +
27+
'\u00ee\u00bd\u0046\u0019\u009f\u0002\u0055\u00c9\u00f4\u009d';
28+
{
29+
const h = crypto.createHmac('sha1', 'key').update('data');
30+
assert.deepStrictEqual(h.digest('buffer'), Buffer.from(expected, 'latin1'));
31+
assert.deepStrictEqual(h.digest('buffer'), Buffer.from(''));
32+
}
33+
{
34+
const h = crypto.createHmac('sha1', 'key').update('data');
35+
assert.strictEqual(h.digest('latin1'), expected);
36+
assert.strictEqual(h.digest('latin1'), '');
37+
}
38+
}
39+
40+
// Check initialized -> uninitialized state transition after calling digest().
41+
// Calls to update() omitted intentionally.
42+
{
43+
const expected =
44+
'\u00f4\u002b\u00b0\u00ee\u00b0\u0018\u00eb\u00bd\u0045\u0097' +
45+
'\u00ae\u0072\u0013\u0071\u001e\u00c6\u0007\u0060\u0084\u003f';
46+
{
47+
const h = crypto.createHmac('sha1', 'key');
48+
assert.deepStrictEqual(h.digest('buffer'), Buffer.from(expected, 'latin1'));
49+
assert.deepStrictEqual(h.digest('buffer'), Buffer.from(''));
50+
}
51+
{
52+
const h = crypto.createHmac('sha1', 'key');
53+
assert.strictEqual(h.digest('latin1'), expected);
54+
assert.strictEqual(h.digest('latin1'), '');
55+
}
56+
}

test/parallel/test-crypto-hmac.js

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,6 @@ if (!common.hasCrypto) {
77
const assert = require('assert');
88
const crypto = require('crypto');
99

10-
{
11-
const Hmac = crypto.Hmac;
12-
const instance = crypto.Hmac('sha256', 'Node');
13-
assert(instance instanceof Hmac, 'Hmac is expected to return a new instance' +
14-
' when called without `new`');
15-
}
16-
1710
assert.throws(
1811
() => crypto.createHmac(null),
1912
{
@@ -411,41 +404,6 @@ assert.strictEqual(
411404
crypto.createHmac('sha256', 'w00t').digest('ucs2'),
412405
crypto.createHmac('sha256', 'w00t').digest().toString('ucs2'));
413406

414-
// Check initialized -> uninitialized state transition after calling digest().
415-
{
416-
const expected =
417-
'\u0010\u0041\u0052\u00c5\u00bf\u00dc\u00a0\u007b\u00c6\u0033' +
418-
'\u00ee\u00bd\u0046\u0019\u009f\u0002\u0055\u00c9\u00f4\u009d';
419-
{
420-
const h = crypto.createHmac('sha1', 'key').update('data');
421-
assert.deepStrictEqual(h.digest('buffer'), Buffer.from(expected, 'latin1'));
422-
assert.deepStrictEqual(h.digest('buffer'), Buffer.from(''));
423-
}
424-
{
425-
const h = crypto.createHmac('sha1', 'key').update('data');
426-
assert.strictEqual(h.digest('latin1'), expected);
427-
assert.strictEqual(h.digest('latin1'), '');
428-
}
429-
}
430-
431-
// Check initialized -> uninitialized state transition after calling digest().
432-
// Calls to update() omitted intentionally.
433-
{
434-
const expected =
435-
'\u00f4\u002b\u00b0\u00ee\u00b0\u0018\u00eb\u00bd\u0045\u0097' +
436-
'\u00ae\u0072\u0013\u0071\u001e\u00c6\u0007\u0060\u0084\u003f';
437-
{
438-
const h = crypto.createHmac('sha1', 'key');
439-
assert.deepStrictEqual(h.digest('buffer'), Buffer.from(expected, 'latin1'));
440-
assert.deepStrictEqual(h.digest('buffer'), Buffer.from(''));
441-
}
442-
{
443-
const h = crypto.createHmac('sha1', 'key');
444-
assert.strictEqual(h.digest('latin1'), expected);
445-
assert.strictEqual(h.digest('latin1'), '');
446-
}
447-
}
448-
449407
{
450408
assert.throws(
451409
() => crypto.createHmac('sha7', 'key'),
@@ -460,13 +418,3 @@ assert.strictEqual(
460418
crypto.createHmac('sha256', keyObject).update('foo').digest(),
461419
);
462420
}
463-
464-
{
465-
crypto.Hmac('sha256', 'Node');
466-
common.expectWarning({
467-
DeprecationWarning: [
468-
['crypto.Hmac constructor is deprecated.',
469-
'DEP0181'],
470-
]
471-
});
472-
}

0 commit comments

Comments
 (0)