mirror of
https://github.com/denoland/deno.git
synced 2025-09-26 12:19:12 +00:00

Some checks are pending
ci / test release macos-aarch64 (push) Blocked by required conditions
ci / bench release linux-x86_64 (push) Blocked by required conditions
ci / lint debug linux-x86_64 (push) Blocked by required conditions
ci / lint debug macos-x86_64 (push) Blocked by required conditions
ci / lint debug windows-x86_64 (push) Blocked by required conditions
ci / test debug linux-x86_64 (push) Blocked by required conditions
ci / test release linux-x86_64 (push) Blocked by required conditions
ci / test debug macos-x86_64 (push) Blocked by required conditions
ci / test release macos-x86_64 (push) Blocked by required conditions
ci / test debug windows-x86_64 (push) Blocked by required conditions
ci / test release windows-x86_64 (push) Blocked by required conditions
ci / build libs (push) Blocked by required conditions
ci / pre-build (push) Waiting to run
ci / test debug linux-aarch64 (push) Blocked by required conditions
ci / test release linux-aarch64 (push) Blocked by required conditions
ci / test debug macos-aarch64 (push) Blocked by required conditions
ci / publish canary (push) Blocked by required conditions
Fixes #30759
The buffer validation is based on Node.js implementation:
591ba692bf/src/crypto/crypto_util.h (L467-L472)
75 lines
2 KiB
TypeScript
75 lines
2 KiB
TypeScript
// Copyright 2018-2025 the Deno authors. MIT license.
|
|
|
|
// TODO(petamoriken): enable prefer-primordials for node polyfills
|
|
// deno-lint-ignore-file prefer-primordials
|
|
|
|
import { Buffer } from "node:buffer";
|
|
import {
|
|
ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH,
|
|
ERR_INVALID_ARG_TYPE,
|
|
} from "ext:deno_node/internal/errors.ts";
|
|
import { core } from "ext:core/mod.js";
|
|
|
|
const {
|
|
isAnyArrayBuffer,
|
|
isArrayBufferView,
|
|
} = core;
|
|
|
|
function validateBuffer(
|
|
buf: unknown,
|
|
name: string,
|
|
): asserts buf is ArrayBufferLike | ArrayBufferView {
|
|
if (!isAnyArrayBuffer(buf) && !isArrayBufferView(buf)) {
|
|
throw new ERR_INVALID_ARG_TYPE(
|
|
name,
|
|
["Buffer", "ArrayBuffer", "TypedArray", "DataView"],
|
|
buf,
|
|
);
|
|
}
|
|
}
|
|
|
|
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
|
|
* cannot gain information about the platform. */
|
|
function stdTimingSafeEqual(
|
|
a: ArrayBufferView | ArrayBufferLike | DataView,
|
|
b: ArrayBufferView | ArrayBufferLike | DataView,
|
|
): boolean {
|
|
if (a.byteLength !== b.byteLength) {
|
|
throw new ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH();
|
|
}
|
|
if (!(a instanceof DataView)) {
|
|
a = toDataView(a);
|
|
}
|
|
if (!(b instanceof DataView)) {
|
|
b = toDataView(b);
|
|
}
|
|
const length = a.byteLength;
|
|
let out = 0;
|
|
let i = -1;
|
|
while (++i < length) {
|
|
out |= a.getUint8(i) ^ b.getUint8(i);
|
|
}
|
|
return out === 0;
|
|
}
|
|
|
|
export const timingSafeEqual = (
|
|
buf1: Buffer | DataView | ArrayBuffer,
|
|
buf2: Buffer | DataView | ArrayBuffer,
|
|
): boolean => {
|
|
validateBuffer(buf1, "buf1");
|
|
validateBuffer(buf2, "buf2");
|
|
if (buf1 instanceof Buffer) {
|
|
buf1 = new DataView(buf1.buffer, buf1.byteOffset, buf1.byteLength);
|
|
}
|
|
if (buf2 instanceof Buffer) {
|
|
buf2 = new DataView(buf2.buffer, buf2.byteOffset, buf2.byteLength);
|
|
}
|
|
return stdTimingSafeEqual(buf1, buf2);
|
|
};
|