-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Implement PBKDF2, Scrypt, and HMAC #8989
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
Conversation
x = x | (lhs[i] ^ rhs[i]); | ||
} | ||
|
||
return x == Zero::zero(); |
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 believe this line could just be x.is_zero()
.
Just want to say, these are awesome! |
Seconding @alexcrichton; these are awesome! |
Things like |
LLVM added |
Thanks for the reviews and feedback! I'll make sure to address all the comments. |
Can we get a crypto expert to review this code (perhaps someone on the Moz security team)? As a point of comparison, Adam Langley, a world-renowned crypto expert, has written all the Go crypto code. I do not consider myself qualified to review this properly. Until we have thorough review on this, I would like a huge disclaimer saying "EXPERIMENTAL; USE AT YOUR OWN RISK". |
(Putting |
I'm still working on getting all the comments addressed. I'll add in an experimental warning. Just in the extremely unlikely case that a security expert is looking at the pull request and thinking about doing an in-depth review, although I would love such a review, my update to the pull request will change things that would probably invalidate such a review. I agree I got too clever with the fixed_time_eq method. There is no point in having it be generic - I'll remove that. A FixedTimeEq trait with a macro probably could work, but I'm not aware of any need for such a method except for u8s. Adding #[inline(never)] wouldn't hurt, but it wouldn't solve the most severe problem - the concern that LLVM adds an optimization in the future that is clever enough to compile the method to faster, non-constant time code. I looked into marking the method with the new no-opt LLVM function attribute. However, there are some issues with that:
So, given all of that, I think the most conservative approach might be to just re-write the method using asm!(). Doing this guarantees that LLVM won't apply an optimization that breaks the constant-time property. Its a pretty simple method so its not all that much work or code. It could always be replaced with a pure-Rust implementation if the no-opt flag for LLVM turns out to fit this use case and if it can't be, as I said, its a tiny amount of asm code. The method as it stands in the original pull request is basically the same as the similar function from Go. I'll try to do a survey other other crypto libraries to see what else is out there. Thoughts? |
static MAX_MEM: u32 = 1 << 30; | ||
|
||
// The salsa20/8 core function. | ||
fn salsa20_8(input: &[u8], output: &mut [u8]) { |
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 think it would be better if whole salsa20 family is provided at crypto/salsa20.rs in future.
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.
If Salsa20 were implemented, this function would definitely make more sense there. Since this is a private function, it can easily be moved later. Since I'm not attempting to implement more than the tiny bit of Salsa20 that is necessary for Scrypt, I think it makes sense to leave it here for now since seeing a file name salsa20.rs would be a bit confusing at the current time..
I think optnone attribute was introduced to avoid misoptimization bugs and not intended for security purposes, per se. |
Also, we may verify correctness (not including side-channels) of crypto blocks (e.g. salsa20_8 cipher) using ECRYPT framework like original salsa20 did. |
This function compares two vectors using a fixed number of operations. This method should be used wherever an adversary might time how long a comparison takes and derive useful information from that.
I emailed the author of the optnone patches for LLVM who said that the purpose of the patches is to disable optimizations for certain functions to help with debugging. The optnone option won't disable all optimizations, even when finished. Specifically, inter-procedural optimizations will still be done. Its a bit unclear to me if that would risk breaking the constant time property of the function. Anyway, its not really feasible to analyze it all that much deeper at the current time since the patches haven't been completed yet. I don't think that we need to assume that any implementation is vulnerable. However, any implementation that passes through LLVM's optimization passes may be. I'll post a re-based version of these patches shortly that re-implements the fixed_time_eq function using assembly which should guarantee that LLVM's optimizer won't get in the way, even without optnone. |
Rebased the commit to address all comments (except as noted below). If I didn't address anything, it's something I missed so please point it out to me so I can fixup my changes! I consider this to be basically an RFC state - I want to get more feedback, but even in the unlikely case that everything looks great, please don't r+ since I want to run more tests to make sure that everything is working. Notes:
|
Oh, I also re-wrote the fixed_time_eq() function in assembly using asm!() for both x86 and ARM which should guarantee that the function won't be turned into a non-fixed time function by an LLVM optimization pass. I tested on x86_64 and ARM. I didn't test on 32-bit x86, but I believe it should work there too. I don't think there are any other architectures that Rust currently compiles for. |
Wow, thanks a lot! On optnone, sanxiyn corrected it above but I just misread his comment. sorry for confusion! I now think assembly is the right way to do it safely. |
} | ||
|
||
#[cfg(test)] | ||
#[cfg(test)] |
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.
Just to be sure it gets removed? :P
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.
Lol. Better safe than sorry!
@DaGenix Well there's some level of mips support, but I'm not sure if it even works right now since I don't think anyone builds or tests it. |
FWIW, the recommendation from the Mozilla security engineers I've talked to is that Rust not implement any crypto primitives and instead delegate to NSS or OpenSSL. |
@pcwalton: we can tag functions as OpenSSL isn't GPL-compatible, so it would rule out static linking for many users, and with NSS they would be responsible for making the NSS source available (as with LGPL). |
While this is an impressive piece of code, people much smarter that me warn against reimplementing crypto, and the current consensus on the team is that we should not do it. This would be great material for an external Rust package, for users who understand the tradeoffs, but I'm not comfortable maintaining hand-rolled crypto, nor exposing users to it in the standard distribution. Thanks for your patience and effort @DaGenix. Closing. |
feat(lint): add default_iter_empty close rust-lang#8915 This PR adds `default_iter_empty` lint. This lint checks `std::iter::Empty::default()` and replace with `std::iter::empty()`. Thank you in advance. --- changelog: add `default_instead_of_iter_empty` lint.
With Rust getting more mature, its only a matter of time until someone decides to store passwords with an application written in it (if that hasn't happened already). If someone is going to store a password, its important to protect it against offline brute force attacks. Rust already has some Digest implementations, but they are all exceptionally poor choices to encrypt a password since they are designed to run very quickly and are easily attacked with brute force methods using GPUs. The three major functions to securely store a password are PBKDF2, Scrypt, and Bcrypt. This pull request implements the first two of those. Scrypt is the most secure and is based off of PBKDF2. PBKDF2 is a standard. Bcrypt is less secure than Scrypt and isn't really a standard, so I didn't implement that function at this time. PBKDF2 requires a Pseudo Random Function to work which is generally an HMAC, so I implemented a Mac trait (Message Authentication Code) and the HMAC struct that implements that trait. I also added a new method to the Digest trait, output_bytes(), which does basically the same thing as the existing output_bits() method, but is generally more convenient to use.
I didn't implement any benchmarks for the new functions since Key Derivation Functions are slow by design and Rust's benchmarking functions expect each iteration to be very fast. So, the benchmark would have to test exceptionally weak parameter values to work at all which would mean that the benchmark would be testing configurations that no one should really be running in practice.