mirror of
https://github.com/denoland/std.git
synced 2024-11-21 20:50:22 +00:00
d102a10235
* refactor: import from `@std/assert` * update
62 lines
1.9 KiB
TypeScript
62 lines
1.9 KiB
TypeScript
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
|
// This module is browser compatible.
|
|
|
|
function toDataView(
|
|
value: ArrayBufferView | ArrayBufferLike | DataView,
|
|
): DataView {
|
|
if (value instanceof DataView) {
|
|
return value;
|
|
}
|
|
return ArrayBuffer.isView(value)
|
|
? new DataView(value.buffer, value.byteOffset, value.byteLength)
|
|
: new DataView(value);
|
|
}
|
|
|
|
/**
|
|
* When checking the values of cryptographic hashes are equal, default
|
|
* comparisons can be susceptible to timing based attacks, where attacker is
|
|
* able to find out information about the host system by repeatedly checking
|
|
* response times to equality comparisons of values.
|
|
*
|
|
* It is likely some form of timing safe equality will make its way to the
|
|
* WebCrypto standard (see:
|
|
* {@link https://github.com/w3c/webcrypto/issues/270 | w3c/webcrypto#270}), but until
|
|
* that time, `timingSafeEqual()` is provided:
|
|
*
|
|
* @example Usage
|
|
* ```ts
|
|
* import { timingSafeEqual } from "@std/crypto/timing-safe-equal";
|
|
* import { assert } from "@std/assert";
|
|
*
|
|
* const a = await crypto.subtle.digest(
|
|
* "SHA-384",
|
|
* new TextEncoder().encode("hello world"),
|
|
* );
|
|
* const b = await crypto.subtle.digest(
|
|
* "SHA-384",
|
|
* new TextEncoder().encode("hello world"),
|
|
* );
|
|
*
|
|
* assert(timingSafeEqual(a, b));
|
|
* ```
|
|
*
|
|
* @param a The first value to compare.
|
|
* @param b The second value to compare.
|
|
* @returns `true` if the values are equal, otherwise `false`.
|
|
*/
|
|
export function timingSafeEqual(
|
|
a: ArrayBufferView | ArrayBufferLike | DataView,
|
|
b: ArrayBufferView | ArrayBufferLike | DataView,
|
|
): boolean {
|
|
if (a.byteLength !== b.byteLength) return false;
|
|
const dataViewA = toDataView(a);
|
|
const dataViewB = toDataView(b);
|
|
const length = a.byteLength;
|
|
let out = 0;
|
|
let i = -1;
|
|
while (++i < length) {
|
|
out |= dataViewA.getUint8(i) ^ dataViewB.getUint8(i);
|
|
}
|
|
return out === 0;
|
|
}
|