Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Create DataView with correct byteLength in timingSafeEqual #3208

Merged
merged 4 commits into from
Feb 21, 2023
Merged

fix: Create DataView with correct byteLength in timingSafeEqual #3208

merged 4 commits into from
Feb 21, 2023

Conversation

kamilogorek
Copy link
Contributor

@kamilogorek kamilogorek commented Feb 17, 2023

The example presented in #3207 uses argontwo, which under the hood returns Uint8Array which memory buffer is taken directly from a WASM instance, making original b.getUint8(i) access out of bounds for 2nd argument to timingSafeEqual.

ref: https://deno.land/x/[email protected]/wasm/mod.ts?source#L14
ref: https://deno.land/x/[email protected]/mod.ts?source#L126

Fixes #3207

Note#1: I use SharedArrayBuffer for cleaner assertions.
Note#2: changed names of 2 tests, because VS Code integration deduplicates tests with the same name.

@@ -12,10 +12,10 @@ export function timingSafeEqual(
return false;
}
if (!(a instanceof DataView)) {
a = new DataView(ArrayBuffer.isView(a) ? a.buffer : a);
a = new DataView(ArrayBuffer.isView(a) ? a.buffer : a, 0, a.byteLength);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks fine when a is an ArrayBuffer, but the second argument seems to need to be a.byteOffset when a is a TypedArray.

Especially the example given in #3207 doesn't return true with this change

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch. Added the test to cover it as well.

Copy link
Contributor Author

@kamilogorek kamilogorek Feb 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested original case as well to double-check:

import { hash } from "https://deno.land/x/argontwo/mod.ts";
import { encode, decode } from "https://deno.land/std/encoding/base64url.ts";
import { timingSafeEqual } from "../../deno/deno_std/node/crypto.ts";

let x = hash("bong", decode("4ereginClY4QuqtT2j-8_g"));
let dec = decode("QAEyt51JgnxV8sc0wVKv63OcLO5BAzqFooCxXAnuBUo");

console.log(timingSafeEqual(dec, x)); // true

Deno.test({
name: "[timingSafeEqual] - Uint8Array w. different buffer sizes (a > b)",
fn() {
const a = new SharedArrayBuffer(4);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor point, but do we need to use SharedArrayBuffer here? How about ArrayBuffer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ArrayBuffer is a transferable object, so we won't be able to create Uint8Array after manipulating it with the DataView. And we do want to do that, to make Uint8Array a specific slice of the buffer for the purpose of these specific tests.

@kt3k
Copy link
Member

kt3k commented Feb 20, 2023

@kamilogorek Thanks for looking into this! I left a few comments

Copy link
Member

@kt3k kt3k left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks!

const va = new DataView(a);
va.setUint8(1, 212);
va.setUint8(2, 213);
const ua = new Uint8Array(a, 1, 2);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@kt3k kt3k merged commit bfde22f into denoland:main Feb 21, 2023
@kamilogorek kamilogorek deleted the timing-safe-equal-byte-length branch February 21, 2023 08:58
@bartlomieju
Copy link
Member

@kt3k I believe this API might have been copied into ext/node in the Deno repo and if so should be updated as well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

timingSafeEqual: RangeError: Offset is outside the bounds of the DataView
3 participants