summaryrefslogtreecommitdiff
path: root/ext/node/polyfills/internal_binding/_timingSafeEqual.ts
diff options
context:
space:
mode:
Diffstat (limited to 'ext/node/polyfills/internal_binding/_timingSafeEqual.ts')
-rw-r--r--ext/node/polyfills/internal_binding/_timingSafeEqual.ts43
1 files changed, 43 insertions, 0 deletions
diff --git a/ext/node/polyfills/internal_binding/_timingSafeEqual.ts b/ext/node/polyfills/internal_binding/_timingSafeEqual.ts
new file mode 100644
index 000000000..9002300d1
--- /dev/null
+++ b/ext/node/polyfills/internal_binding/_timingSafeEqual.ts
@@ -0,0 +1,43 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+import { Buffer } from "internal:deno_node/polyfills/buffer.ts";
+
+function assert(cond) {
+ if (!cond) {
+ throw new Error("assertion failed");
+ }
+}
+
+/** 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) {
+ return false;
+ }
+ if (!(a instanceof DataView)) {
+ a = new DataView(ArrayBuffer.isView(a) ? a.buffer : a);
+ }
+ if (!(b instanceof DataView)) {
+ b = new DataView(ArrayBuffer.isView(b) ? b.buffer : b);
+ }
+ assert(a instanceof DataView);
+ assert(b instanceof DataView);
+ 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 = (
+ 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);
+ return stdTimingSafeEqual(a, b);
+};