fix(ext/node): timingSafeEqual account for AB byteOffset (#26292)

Fixes https://github.com/denoland/deno/issues/26276
This commit is contained in:
Divy Srivastava 2024-10-16 14:27:28 +05:30 committed by GitHub
parent 661882f10d
commit 21fa953f32
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 21 additions and 10 deletions

View File

@ -5,10 +5,11 @@
import { Buffer } from "node:buffer";
function assert(cond) {
if (!cond) {
throw new Error("assertion failed");
function toDataView(ab: ArrayBufferLike | ArrayBufferView): DataView {
if (ArrayBuffer.isView(ab)) {
return new DataView(ab.buffer, ab.byteOffset, ab.byteLength);
}
return new DataView(ab);
}
/** Compare to array buffers or data views in a way that timing based attacks
@ -21,13 +22,11 @@ function stdTimingSafeEqual(
return false;
}
if (!(a instanceof DataView)) {
a = new DataView(ArrayBuffer.isView(a) ? a.buffer : a);
a = toDataView(a);
}
if (!(b instanceof DataView)) {
b = new DataView(ArrayBuffer.isView(b) ? b.buffer : b);
b = toDataView(b);
}
assert(a instanceof DataView);
assert(b instanceof DataView);
const length = a.byteLength;
let out = 0;
let i = -1;
@ -41,7 +40,11 @@ export const timingSafeEqual = (
a: Buffer | DataView | ArrayBuffer,
b: Buffer | DataView | ArrayBuffer,
): boolean => {
if (a instanceof Buffer) a = new DataView(a.buffer);
if (a instanceof Buffer) b = new DataView(a.buffer);
if (a instanceof Buffer) {
a = new DataView(a.buffer, a.byteOffset, a.byteLength);
}
if (b instanceof Buffer) {
b = new DataView(b.buffer, b.byteOffset, b.byteLength);
}
return stdTimingSafeEqual(a, b);
};

View File

@ -1,5 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { randomFillSync, randomUUID } from "node:crypto";
import { randomFillSync, randomUUID, timingSafeEqual } from "node:crypto";
import { Buffer } from "node:buffer";
import { assert, assertEquals } from "../../unit/test_util.ts";
import { assertNotEquals } from "@std/assert";
@ -28,3 +29,10 @@ Deno.test("[node/crypto.randomFillSync] array buffer view", () => {
assertEquals(buf.subarray(0, 8), new Uint8Array(8));
assertEquals(buf.subarray(24, 32), new Uint8Array(8));
});
Deno.test("[node/crypto.timingSafeEqual] compares equal Buffer with different byteOffset", () => {
const a = Buffer.from([212, 213]);
const b = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 212, 213]).subarray(8);
assert(timingSafeEqual(a, b));
});