Skip to content

Commit

Permalink
doc,test: clarify timingSafeEqual semantics
Browse files Browse the repository at this point in the history
  • Loading branch information
tniessen committed May 28, 2022
1 parent 0818b52 commit 2f626d3
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 2 deletions.
17 changes: 15 additions & 2 deletions doc/api/crypto.md
Original file line number Diff line number Diff line change
Expand Up @@ -5443,8 +5443,11 @@ changes:
* `b` {ArrayBuffer|Buffer|TypedArray|DataView}
* Returns: {boolean}

This function is based on a constant-time algorithm.
Returns true if `a` is equal to `b`, without leaking timing information that
This function compares the underlying bytes that represent the given
`ArrayBuffer`, `TypedArray`, or `DataView` instances using a constant-time
algorithm.

It returns true if `a` is equal to `b`, without leaking timing information that
would allow an attacker to guess one of the values. This is suitable for
comparing HMAC digests or secret values like authentication cookies or
[capability urls](https://www.w3.org/TR/capability-urls/).
Expand All @@ -5453,6 +5456,15 @@ comparing HMAC digests or secret values like authentication cookies or
must have the same byte length. An error is thrown if `a` and `b` have
different byte lengths.

This function does not compare the elements of `a` and `b` directly. Instead, it
compares the bitwise representations of `a` and `b`. If `a` and `b` are
instances of the same `TypedArray` class, this is equivalent to an element-wise
[SameValue comparison][].

<strong class="critical">In particular, this function does not follow the usual
definition of equality for floating-point numbers when `a` or `b` is a
`Float32Array` or a `Float64Array`.</strong>

If at least one of `a` and `b` is a `TypedArray` with more than one byte per
entry, such as `Uint16Array`, the result will be computed using the platform
byte order.
Expand Down Expand Up @@ -6104,6 +6116,7 @@ See the [list of SSL OP Flags][] for details.
[RFC 4122]: https://www.rfc-editor.org/rfc/rfc4122.txt
[RFC 5208]: https://www.rfc-editor.org/rfc/rfc5208.txt
[RFC 5280]: https://www.rfc-editor.org/rfc/rfc5280.txt
[SameValue comparison]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness
[Web Crypto API documentation]: webcrypto.md
[`BN_is_prime_ex`]: https://www.openssl.org/docs/man1.1.1/man3/BN_is_prime_ex.html
[`Buffer`]: buffer.md
Expand Down
22 changes: 22 additions & 0 deletions test/sequential/test-crypto-timing-safe-equal.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,28 @@ assert.strictEqual(
}
}

{
// timingSafeEqual has SameValue semantics, not equality semantics, when the
// inputs are floating-point numbers.

const cmp = (fn) => (a, b) => a.every((x, i) => fn(x, b[i]));
const eq = cmp((a, b) => a === b);
const is = cmp(Object.is);

// NaN !== NaN, but Object.is(NaN, NaN) === true.
const a = new Float32Array(10).fill(NaN);
assert.strictEqual(eq(a, a), false);
assert.strictEqual(is(a, a), true);
assert.strictEqual(crypto.timingSafeEqual(a, a), true);

// 0 === -0, but Object.is(0, -0) === false.
const pos0 = new Float64Array(10).fill(0);
const neg0 = new Float64Array(10).fill(-0);
assert.strictEqual(eq(pos0, neg0), true);
assert.strictEqual(is(pos0, neg0), false);
assert.strictEqual(crypto.timingSafeEqual(pos0, neg0), false);
}

assert.throws(
() => crypto.timingSafeEqual(Buffer.from([1, 2, 3]), Buffer.from([1, 2])),
{
Expand Down

0 comments on commit 2f626d3

Please sign in to comment.