GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — doc,test: clarify timingSafeEqual semantics by tniessen · Pull Request #43228 · nodejs/node

Conversation

@tniessen

@tniessen tniessen commented May 28, 2022

Copy link
Copy Markdown
Member

Example of a false positive:

const a = new Float32Array(10).fill(NaN);
a.every((x, i) => a[i] === x)  // false
crypto.timingSafeEqual(a, a)  // true

Example of a false negative:

const p0 = new Float32Array(10).fill(0);
const m0 = new Float32Array(10).fill(-0);
p0.every((x, i) => m0[i] === x)  // true
crypto.timingSafeEqual(p0, m0)  // false

(We should probably consider doc-deprecating this or at least we should be more careful about what TypedArrays we allow elsewhere.)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@tniessen tniessen added crypto Issues and PRs related to the crypto subsystem. security Issues and PRs related to security. labels May 28, 2022
@tniessen
tniessen requested a review from Trott May 28, 2022 10:30
@nodejs-github-bot nodejs-github-bot added the doc Issues and PRs related to Node.js documentation. label May 28, 2022
@Trott

Trott commented May 28, 2022

Copy link
Copy Markdown
Member

Should we add the false positive and false negative as a test (maybe in the known_issues directory?) so that we know to update the docs if it ever gets changed/fixed?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mscdex

mscdex commented May 28, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

I don't understand the problem here. timingSafeEqual() compares bytes, so the results seem expected to me.

The two examples given have to do with the larger "problem" of JavaScript equality operator behavior (NaN !== NaN and 0 === -0) rather than any gotcha with timingSafeEqual(). You can run into these same problems outside of this crypto context because they're language issues.

On a related note, you could use Object.is() instead, which should give you the equality checking you're looking for.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tniessen

tniessen commented May 28, 2022

Copy link
Copy Markdown
Member Author

timingSafeEqual() compares bytes

@mscdex The current documentation does not explicitly say so, and that's exactly what this PR is trying to address.

because they're language issues.

This would apply to any language that implements a subset of IEE 754.

On a related note, you could use Object.is() instead, which should give you the equality checking you're looking for.

Sure, but this function is specifically for constant-time comparisons, which Object.is() does not implement.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@mscdex

mscdex commented May 28, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

The current documentation does not explicitly say so, and that's exactly what this PR is trying to address.

Perhaps we should say exactly that then, as the current language this PR adds doesn't make that obvious IMO. Something like "This method compares the underlying bytes that represent any typed array or Buffer."

Sure, but this function is specifically for constant-time comparisons, which Object.is() does not implement.

I was referring to the equality checks inside the .every() callbacks.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tniessen
tniessen force-pushed the doc-crypto-timingsafeequal-floats branch from 289bf9e to 6569cdc Compare May 28, 2022 15:06
@tniessen tniessen changed the title doc: warn about using timingSafeEqual with floats doc,test: clarify timingSafeEqual semantics May 28, 2022
@tniessen
tniessen force-pushed the doc-crypto-timingsafeequal-floats branch from 6569cdc to 2f626d3 Compare May 28, 2022 15:07
@tniessen

tniessen commented May 28, 2022

Copy link
Copy Markdown
Member Author

Added a test and reworded to closer match JS's understanding of equal versus same.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

mscdex
mscdex reviewed May 28, 2022
View reviewed changes
Comment thread doc/api/crypto.md Outdated

@mscdex mscdex May 28, 2022

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

What I meant before was adding the note about "underlying bytes" instead of adding this text. If we state we're comparing the underlying bytes, then this text isn't very useful and makes things more confusing.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@bnoordhuis bnoordhuis May 28, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

I agree. I'd just leave it at "compares bytes" and give it one or two examples. 0 vs. -0 is probably the easiest to understand but different NaNs could work too, e.g.:

const x = new BigInt64Array(["0x7ff0000000000001", "0xfff0000000000001"])
const a = new Float64Array(x.buffer)
const b = new Float64Array([NaN, NaN])
Number.isNaN(a[0]) // true
Number.isNaN(a[1]) // true
crypto.timingSafeEqual(a, b) // false

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@tniessen tniessen May 28, 2022

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

On a related note, you could use Object.is() instead, which should give you the equality checking you're looking for.

Then I guess this earlier comment wasn't correct? Object.is() is true, unlike timingSafeEqual.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@mscdex mscdex May 28, 2022

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Then I guess this earlier comment wasn't correct? Object.is() is true, unlike timingSafeEqual.

As I said:

I was referring to the equality checks inside the .every() callbacks.

To clarify further:

Object.is(0, -0) === false // so of course `timingSafeEqual()` returns `false`
Object.is(NaN, NaN) === true // so of course `timingSafeEqual()` returns `true`

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@tniessen tniessen May 28, 2022

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

@mscdex Your comment appears to imply some (obvious) connection between Object.is() and timingSafeEqual(), but @bnoordhuis' example seems to contradict that:

const a = new Float64Array(new BigInt64Array([0x7ff0000000000001n]).buffer);
const b = new Float64Array(new BigInt64Array([0xfff0000000000001n]).buffer);
Object.is(a[0], b[0]); // true
crypto.timingSafeEqual(a, b); // false

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@Trott

Trott commented May 28, 2022

Copy link
Copy Markdown
Member

LGTM but pinging some other folks on these questions:

  • Is the documentation as clear and concise on this as we can make it?
  • Should the testing note that this is a surprising feature? Is it really a bug and should be in known_issues? Or is this expected behavior, should not change, and the test is in the right place?

@nodejs/documentation @nodejs/crypto @nodejs/testing

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tniessen
tniessen force-pushed the doc-crypto-timingsafeequal-floats branch from 2f626d3 to ad12313 Compare May 28, 2022 15:33
@tniessen

tniessen commented May 28, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

@mscdex Reworded again and removed most of the text as requested.

Edit: Reworded and extended again since this does not match Object.is() semantics.

@Trott I wouldn't consider it a bug, just a very unusual and permissive function signature... for example, comparing a Float64Array to a Uint32Array also seems unusual (and probably unintentional).

Edit: As @bnoordhuis pointed out, the semantics are neither equality nor same value. Accepting Float(32|64)Array seems questionable to me.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tniessen
doc,test: clarify timingSafeEqual semantics
20e007c
@tniessen
tniessen force-pushed the doc-crypto-timingsafeequal-floats branch from ad12313 to 20e007c Compare May 28, 2022 16:42
mscdex
mscdex reviewed May 28, 2022
View reviewed changes
Comment thread doc/api/crypto.md
entry, such as `Uint16Array`, the result will be computed using the platform
byte order.

<strong class="critical">When both of the inputs are `Float32Array`s or

@mscdex mscdex May 28, 2022

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

This section is still incorrect and misleading. If the float/double values are the same, then timingSafeEqual() will return true. If the values differ, then timingSafeEqual() will return false.

0 and -0 are different values. The fact that the === operator treats them as being equal is a language "issue", much like how == can return true for two different value types due to type coercion.

timingSafeEqual() is doing the correct and expected comparison here.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@tniessen tniessen May 28, 2022

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Which part is incorrect? The test that's added in this PR demonstrates that timingSafeEqual() can return false even when Object.is() returns true.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@tniessen tniessen Jun 6, 2022

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

ping @mscdex

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
aymen94
aymen94 approved these changes May 30, 2022
View reviewed changes
@tniessen tniessen added the review wanted PRs that need review. label Jun 1, 2022
@tniessen

tniessen commented Jun 20, 2022

Copy link
Copy Markdown
Member Author

ping @mscdex @nodejs/documentation @nodejs/crypto

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

bnoordhuis
bnoordhuis approved these changes Jun 20, 2022
View reviewed changes
@tniessen tniessen added request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. author ready PRs with CI started, the required approvals, and no outstanding review comments. labels Jun 20, 2022
@github-actions github-actions Bot removed the request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. label Jun 20, 2022
@nodejs-github-bot

This comment was marked as outdated.

Sign in to view
@github-actions github-actions Bot mentioned this pull request Jun 21, 2022
CI Reliability 2022-06-21 nodejs/reliability#307
Open
33 tasks
Trott
Trott approved these changes Jun 21, 2022
View reviewed changes
@nodejs-github-bot

nodejs-github-bot commented Jun 21, 2022

Copy link
Copy Markdown
Collaborator

CI: https://ci.nodejs.org/job/node-test-pull-request/44774/

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tniessen tniessen added the commit-queue PRs queued for automated landing through the Commit Queue. label Jun 21, 2022
@nodejs-github-bot nodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Jun 21, 2022
@nodejs-github-bot
nodejs-github-bot merged commit 800cff1 into nodejs:main Jun 21, 2022
@nodejs-github-bot

nodejs-github-bot commented Jun 21, 2022

Copy link
Copy Markdown
Collaborator

Landed in 800cff1

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

This was referenced Jun 22, 2022
CI Reliability 2022-06-22 nodejs/reliability#308
Open
CI Reliability 2022-06-23 nodejs/reliability#309
Open
CI Reliability 2022-06-24 nodejs/reliability#310
Open
This was referenced Jun 25, 2022
CI Reliability 2022-06-25 nodejs/reliability#311
Open
CI Reliability 2022-06-26 nodejs/reliability#312
Open
targos pushed a commit that referenced this pull request Jul 12, 2022
@tniessen @targos
doc,test: clarify timingSafeEqual semantics
462e526
PR-URL: #43228
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Rich Trott <[email protected]>
@targos targos mentioned this pull request Jul 12, 2022
v18.6.0 release proposal #43789
Merged
targos pushed a commit that referenced this pull request Jul 20, 2022
@tniessen @targos
doc,test: clarify timingSafeEqual semantics
da098ef
PR-URL: #43228
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Rich Trott <[email protected]>
targos pushed a commit that referenced this pull request Jul 31, 2022
@tniessen @targos
doc,test: clarify timingSafeEqual semantics
7be07c7
PR-URL: #43228
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Rich Trott <[email protected]>
@targos targos mentioned this pull request Aug 3, 2022
v16.17.0 release proposal #44098
Merged
guangwong pushed a commit to noslate-project/node that referenced this pull request Oct 10, 2022
@tniessen @guangwong
doc,test: clarify timingSafeEqual semantics
95cf67e
PR-URL: nodejs/node#43228
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Rich Trott <[email protected]>
@coderabbitai coderabbitai Bot mentioned this pull request Jul 31, 2026
feat(090): fecha implementacao da fase 1 de papeis globais FarenRavirar/artificio#234
Merged
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@bnoordhuis bnoordhuis bnoordhuis approved these changes
@Trott Trott Trott approved these changes
+2 more reviewers
@mscdex mscdex mscdex left review comments
@aymen94 aymen94 aymen94 approved these changes
Reviewers whose approvals may not affect merge requirements

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

author ready PRs with CI started, the required approvals, and no outstanding review comments. crypto Issues and PRs related to the crypto subsystem. doc Issues and PRs related to Node.js documentation. review wanted PRs that need review. security Issues and PRs related to security.

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

6 participants

@tniessen @Trott @mscdex @nodejs-github-bot @bnoordhuis @aymen94
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.