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

The documentation should show an example of typical correct usage #122

Open
dpc opened this issue Jun 18, 2024 · 3 comments
Open

The documentation should show an example of typical correct usage #122

dpc opened this issue Jun 18, 2024 · 3 comments

Comments

@dpc
Copy link

dpc commented Jun 18, 2024

While it might seem obvious to people familiar with this crate, I am actually confused how to use this crate after just landing on it looking for a constant comparison crate.

What I want to do is:

if password_in_request != password_in_the_config {
   bail!("Wrong password");
}

for usual reasons.

I open https://docs.rs/subtle/ , I can see ConstantTimeEq and it is clear I should use ct_eq. But then ... why is it returning Choice? Am I supposed to call .into() on it? It seems so... ? But why can't ct_eq return bool right away by doing that .into() under the hood? Unclear.

So, it seems to me that the documentation can be improved in two ways:

  • Please add an idiomatic example on a front page of a correct usage. It will take one short paragraph and give an immediate answer to developers that are just looking for a solution.
  • Please somewhere early in the documentation of Choice explain why: Why does it exist, why can't ct_eq just return bool.
@hackerbirds
Copy link

(Disclaimer: I never contributed to the crate, I merely use it and I want to help)

Why does [Choice] exist, why can't ct_eq just return bool.

When using bool, the compiler can sometimes find optimizations for it and make your operations/branch conditions not constant-time. subtle works by using Choice is a wrapper struct around a fake bool (Choice is just a u8 that can be 1 or 0) that tries to make sure the compiler won't optimize it back into a bool. Choice implements bit operations etc the same way a bool does.

Why can't ct_eq return bool right away by doing that .into() under the hood? Unclear.

You don't always want to convert back into bool directly. You might still need to do extra constant-time operations after calling ct_eq().

For example, say you're checking both a username and a password: (username_in_request.ct_ne(&username_in_the_config)) | (password_in_request.ct_ne(&password_in_the_config)). You're doing two constant-time equality checks (one for the username, one for the password), and they both return Choice, but the OR "|" also needs to be constant time, so you have to do Choice | Choice, which gives you yet another Choice. Only after you're done doing all that, you then convert back that last Choice into a bool.

Am I supposed to call .into() on it?

In your case, I think yes you can call .into() to convert back into bool after you're done doing your constant-time checks.

Assuming your passwords are say byte arrays &[u8], which implement ConstantTimeEq, something like this should work (Warning, I didn't test it):

if bool::from(password_in_request.ct_ne(&password_in_the_config)) {
   bail!("Wrong password");
}

However, after you convert into a bool, you stop being in "constant-time land", so be careful, because you may also need to use Choice elsewhere in your code, in which case converting back to bool can make things not constant-time anymore.


Please add an idiomatic example on a front page of a correct usage. It will take one short paragraph and give an immediate answer to developers that are just looking for a solution.

I think it would be a good idea to have examples and better explanations. Maybe I'll try making a PR for it. OTOH it's easy to use that crate incorrectly, and simply throwing an example that everyone will copy-paste without understanding what the crate does will probably cause problems.

@dpc
Copy link
Author

dpc commented Jul 4, 2024

Thanks. BTW. From the top of my head: if password_in_request.ct_ne(&password_in_the_config).into() { works just fine.

@hackerbirds
Copy link

Yeah, you can write .into(). I just wrote bool::from as a personal preference because it makes it more explicit that you're using a bool instead of Choice.

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

No branches or pull requests

2 participants