Skip to content

Commit 4d747ea

Browse files
jtdowneylittledivy
andauthored
fix(ext/node): use correct block sizes for HMAC algorithms (#31775)
The HMAC implementation was hardcoded to use 64-byte blocks for most algorithms and 128-byte blocks only for sha512/sha384. This is incorrect for many algorithms like sha3-* variants and blake2 which have different block sizes. Add a lookup table with correct block sizes for all supported hash algorithms and throw an error for unsupported algorithms. Fixes #31765 <!-- Before submitting a PR, please read https://docs.deno.com/runtime/manual/references/contributing 1. Give the PR a descriptive title. Examples of good title: - fix(std/http): Fix race condition in server - docs(console): Update docstrings - feat(doc): Handle nested reexports Examples of bad title: - fix #7123 - update docs - fix bugs 2. Ensure there is a related issue and it is referenced in the PR text. 3. Ensure there are tests that cover the changes. 4. Ensure `cargo test` passes. 5. Ensure `./tools/format.js` passes without changing files. 6. Ensure `./tools/lint.js` passes. 7. Open as a draft PR if your work is still in progress. The CI won't run all steps, but you can add '[ci]' to a commit message to force it to. 8. If you would like to run the benchmarks on the CI, add the 'ci-bench' label. --> Co-authored-by: Divy <[email protected]>
1 parent f47ad1f commit 4d747ea

File tree

3 files changed

+123
-2
lines changed

3 files changed

+123
-2
lines changed

ext/node/polyfills/internal/crypto/hash.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import {
4545
import LazyTransform from "ext:deno_node/internal/streams/lazy_transform.js";
4646
import {
4747
getDefaultEncoding,
48+
getHashBlockSize,
4849
toBuf,
4950
} from "ext:deno_node/internal/crypto/util.ts";
5051
import {
@@ -231,7 +232,7 @@ class HmacImpl extends Transform {
231232

232233
const alg = hmac.toLowerCase();
233234
this.#algorithm = alg;
234-
const blockSize = (alg === "sha512" || alg === "sha384") ? 128 : 64;
235+
const blockSize = getHashBlockSize(alg);
235236
const keySize = keyData.length;
236237

237238
let bufKey: Buffer;

ext/node/polyfills/internal/crypto/util.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import { notImplemented } from "ext:deno_node/_utils.ts";
88
import { Buffer } from "node:buffer";
99
import {
10+
ERR_CRYPTO_INVALID_DIGEST,
1011
ERR_INVALID_ARG_TYPE,
1112
hideStackFrames,
1213
} from "ext:deno_node/internal/errors.ts";
@@ -86,6 +87,33 @@ export function getCiphers(): string[] {
8687
return supportedCiphers;
8788
}
8889

90+
const hashBlockSizes: Record<string, number> = {
91+
md5: 64,
92+
rmd160: 64,
93+
ripemd160: 64,
94+
sha1: 64,
95+
sha224: 64,
96+
sha256: 64,
97+
sha384: 128,
98+
sha512: 128,
99+
"sha512-224": 128,
100+
"sha512-256": 128,
101+
"sha3-224": 144,
102+
"sha3-256": 136,
103+
"sha3-384": 104,
104+
"sha3-512": 72,
105+
blake2b512: 128,
106+
blake2s256: 64,
107+
};
108+
109+
export function getHashBlockSize(algorithm: string): number {
110+
const blockSize = hashBlockSizes[algorithm];
111+
if (blockSize === undefined) {
112+
throw new ERR_CRYPTO_INVALID_DIGEST(algorithm);
113+
}
114+
return blockSize;
115+
}
116+
89117
export function getCipherInfo(
90118
nameOrNid: string | number,
91119
options?: { keyLength?: number; ivLength?: number },
@@ -242,6 +270,7 @@ export default {
242270
getCiphers,
243271
getCipherInfo,
244272
getCurves,
273+
getHashBlockSize,
245274
getOpenSSLSecLevel,
246275
secureHeapUsed,
247276
setEngine,

tests/unit_node/crypto/crypto_hash_test.ts

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { createHash, createHmac, getHashes, hash } from "node:crypto";
33
import { Buffer } from "node:buffer";
44
import { Readable } from "node:stream";
5-
import { assert, assertEquals } from "@std/assert";
5+
import { assert, assertEquals, assertThrows } from "@std/assert";
66

77
// https://github.com/denoland/deno/issues/18140
88
Deno.test({
@@ -15,6 +15,26 @@ Deno.test({
1515
},
1616
});
1717

18+
Deno.test({
19+
name: "[node/crypto] createHmac sha512-224",
20+
fn() {
21+
assertEquals(
22+
createHmac("sha512-224", "secret").update("hello").digest("hex"),
23+
"27ade3215d20a0e939a1ff98f91052148e85f2ece87d926d6a2c1aad",
24+
);
25+
},
26+
});
27+
28+
Deno.test({
29+
name: "[node/crypto] createHmac sha512-256",
30+
fn() {
31+
assertEquals(
32+
createHmac("sha512-256", "secret").update("hello").digest("hex"),
33+
"e1a285d0317f7cce89acb5642fb6e82fc16d14ab588b0a5abcc7c20ea748594e",
34+
);
35+
},
36+
});
37+
1838
Deno.test({
1939
name: "[node/crypto] createHash digest",
2040
fn() {
@@ -159,3 +179,74 @@ Deno.test("[node/crypto.createHmac] should not print deprecation warning", async
159179
const decodedStderr = new TextDecoder().decode(stderr).trim();
160180
assertEquals(decodedStderr, "");
161181
});
182+
183+
Deno.test({
184+
name: "[node/crypto] createHmac sha3-224",
185+
fn() {
186+
assertEquals(
187+
createHmac("sha3-224", "secret").update("hello").digest("hex"),
188+
"d078791e9bf080c2139f883ac65033d4b5b75bbdb4088c494d0b6a14",
189+
);
190+
},
191+
});
192+
193+
Deno.test({
194+
name: "[node/crypto] createHmac sha3-256",
195+
fn() {
196+
assertEquals(
197+
createHmac("sha3-256", "secret").update("hello").digest("hex"),
198+
"850ae61707b3e60d4e45548c4facfda415d301712641fd11535cf395d9e2d7fe",
199+
);
200+
},
201+
});
202+
203+
Deno.test({
204+
name: "[node/crypto] createHmac sha3-384",
205+
fn() {
206+
assertEquals(
207+
createHmac("sha3-384", "secret").update("hello").digest("hex"),
208+
"e24e0dc664132644a6740071af5a05622edffea8afacf0a4060111961bc9148f23c001b6f7d7e79a44b9896b1f00cd85",
209+
);
210+
},
211+
});
212+
213+
Deno.test({
214+
name: "[node/crypto] createHmac sha3-512",
215+
fn() {
216+
assertEquals(
217+
createHmac("sha3-512", "secret").update("hello").digest("hex"),
218+
"bc07c2dfc0295b420662bda474eb8db11b0389822e13da56cf9991f467f2f6c713c481aa8663900ecaee310bf2f226eaa5c2d1345dfebee990658bd529a9c504",
219+
);
220+
},
221+
});
222+
223+
Deno.test({
224+
name: "[node/crypto] createHmac blake2b512",
225+
fn() {
226+
assertEquals(
227+
createHmac("blake2b512", "secret").update("hello").digest("hex"),
228+
"59d8e60d8f7f54753ab7b823b11f20879c4db732e5b56a0da5559d10b2c2b7ac37d47474b668725b661178359ad71c189597108dd2d94ca051697fbc24b6d7ad",
229+
);
230+
},
231+
});
232+
233+
Deno.test({
234+
name: "[node/crypto] createHmac blake2s256",
235+
fn() {
236+
assertEquals(
237+
createHmac("blake2s256", "secret").update("hello").digest("hex"),
238+
"56f9d5d171c31a9481d1949743ddd370209f7c666ba8bb6872067ad70398d9ce",
239+
);
240+
},
241+
});
242+
243+
Deno.test({
244+
name: "[node/crypto] createHmac unknown algorithm throws",
245+
fn() {
246+
assertThrows(
247+
() => createHmac("unknown-algorithm", "secret"),
248+
TypeError,
249+
"Invalid digest: unknown-algorithm",
250+
);
251+
},
252+
});

0 commit comments

Comments
 (0)