Open dpc opened 3 months ago
(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 returnbool
.
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
returnbool
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.
Thanks. BTW. From the top of my head: if password_in_request.ct_ne(&password_in_the_config).into() {
works just fine.
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
.
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:
for usual reasons.
I open https://docs.rs/subtle/ , I can see
ConstantTimeEq
and it is clear I should usect_eq
. But then ... why is it returningChoice
? Am I supposed to call.into()
on it? It seems so... ? But why can'tct_eq
returnbool
right away by doing that.into()
under the hood? Unclear.So, it seems to me that the documentation can be improved in two ways:
Choice
explain why: Why does it exist, why can'tct_eq
just returnbool
.