-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Figure out in-tree crypto story #766
Comments
PolarSSL will be relicensed from GPL to Apache, making it an alternative to OpenSSL. |
It's worth mentioning that LLVM cannot create branchless constant time code, so either one should link libraries with assembly imeplementations, or else pursue another compiler option, like https://github.com/klutzy/nadeko perhaps. See https://moderncrypto.org/mail-archive/curves/2015/000463.html and https://moderncrypto.org/mail-archive/curves/2015/000466.html |
There is a simpler question worth addressing too : Is cryptographic key material copyable? Apperently no : rust-lang/rust#20631 We should zero out cryptographic keys when they're dropped, ensuring that LLVM does not optimize it away, as done in sodiumoxide via libsodium : https://github.com/dnaq/sodiumoxide/blob/master/src/newtype_macros.rs It follows that types containig crpyographic keys must have a drop method that zeros them, and therefore cannot be copyable. It follows that keys will use move semantics, so.. Is it correct that a move will drop what is being moved from? In practice, we'll commonly use pointers anyways since key material is at least 16 bytes long, but this seemed worth clarifying. As an aside, we should call |
We should maybe build just a framework for cryptographic crates rather than trying to pack all the cryptographic algorithms into one big crate, so just the basic traits, etc. for handling key material, digests, stream cyphers, block cyphers, boxes, etc. but not the actual algorithms. |
@burdges I'm currently exploring that idea, starting with hash functions because they're the simplest. I have implementations for these traits in the same crate, which act as a kind of adapter to the actual crypto libraries, which can be swapped similar to rust-native-tls. So it's not the crypto library that needs a dependency on the "framework" crate, as you call it, but the framework crate has a dependency on a single crypto library--which one depends on your cargo features. The end result is similar in that there is a common API, anyone who codes against it can use any implementation, and low-level implementations don't need to live in the same crate. |
Isn't that slightly more complicated than making the algorithms depend on the framework crate? Anyways, there are many crypto algorithm that would benefit from a common base that provides constant time operations. I donno if those should simply be added to core ala #1814 or should be the start of a crypto crate, maybe starting with https://github.com/valarauca/consistenttime or something similar, like |
I've made a write up of nadeko's issues. It isn't constant time, and really does not solve the core issues with being constant time. There is a very high level of AST manipulation and understanding of intent that goes into making something constant time. I truely believe we cannot just have it opt in. I like the idea of a crypto frame work. Exposing a handful of functions:
This will make crypt-library authors jobs a lot easier. |
Let's keep two things separate. The first is "under" the implementations of crypto primitives and the second is "on top" of them:
|
I said "framework" because: There are a bunch of useful traits in https://github.com/DaGenix/rust-crypto/tree/master/src for things like hash digests, stream ciphers, encryption and decryption with stream cipher, ctr modes, etc. In principle, one could build upon those, except some design decisions there seem questionably disjoint from Why no in-place operation of stream ciphers? I'd imagine that's just an omission. Should stream ciphers act as iterators though? I donno. If so, should appropriate stream ciphers like ChaCha20 use general purpose iterator machinery for seeking and/or translation from an iterator that operates in blocks. Should digests input stuff that's Answering these questions publicly, and/or adjusting traits to do these things, seems important, as otherwise every hash function or cipher developer need to think about these question themselves. It's true constant-time operations are a step below this traits "framework" stuff, but they are similar in that anyone writing crypto primitives needs to think about them if they are not being done right elsewhere. |
I see your point of saving crypto library implementors from reinventing the wheel all the time. That's a major benefit of such a "framework". While a library implementor could use both the outward-facing traits and the low-level helpers, the crypto user should better not be able to access the low-level stuff directly, so it should at least be in a separate module. And I argue it should be in a separate crate because not all crypto libraries really need it. There are quite many which are actually just wrappers of some C library (OpenSSL, BoringSSL, libsodium), so they wouldn't need the constant-time operations in Rust. Instead, they are based on other (common) low-level things like libc, some FFI generator or something like that. And they work under the same high-level traits as the crypto APIs implemented in Rust itself. And I agree that it's good to answer these questions publicly. Maybe, the API/traits and the lower-level functions are two separate discussions, though, because there are different stakeholders. And probably neither of the discussions belongs into this thread, but I would have many details to discuss already :-) including iterators in cipher APIs. You name rust-crypto as a base that could be adapted. Have you also looked at others? This topic has been discussed in the #rust-crypto IRC a few weeks back and it seemed to me that ring's API is more well-regarded. |
A few constant time building blocks sound small compared to say pulling in an extra hash function, much less AES and RSA, like every existing crypto library does. Aren't those I'd say leave any "stakeholders" who want uber-safety to using ring and sodiumoxide. Those projects make a range of safety decisions, including evaluating if the Rust code is mature enough to replace solid C code. Rust is not lacking in foot gun free crypto libraries. Rust is weaker on flexible building blocks though: We want to simplify building a separate crate to provide a crypto primitive, without needing to dig too deeply into rustc or LLVM. Right now, people send pull requests to rust-crypto, but that project should not be responsible for everyone's pet cipher or hash function. I suppose just breaking rust-crypto in a crypto-current and crypto-legacy crates would require exposing enough building blocks that new ciphers and hash functions need not send pull requests. We want to simplify using such crates in protocols, including unconventional protocols involving stuff like blind signatures, Axolotl, elligator, semi-private keys, mixnets, ECQV, post-quantum, etc. We should not worry about public-key algorithms right now, as stand alone crates do those well enough, but the symmetric crypto should not stand in the way when people when do unusual asymmetric stuff. Applications are increasingly needing these unconventional usages. If you insist on avoiding all foot guns, then either important new things get built in languages like Go, or else everyone maintains their own private fork of the crypto library. And I doubt you'll do as good a job of being foot gun free as ring anyways. In this vein, curve25519-dalek is the right approach to doing a public key library. All the mathematical submodules are well documented and exported. Fixed-size arrays are used everywhere with the help of the arrayref crate, so no slices. etc. |
This approach makes less sense to me than having a single set of traits multiple crypto libraries can target. It would require that libraries which want to buy into a common crypto core be rewritten to use those traits, but to me, that's the "right answer", as opposed to trying to make a one-size-fits-all wrapper to the divergent APIs present in existing crypto libraries. As @burdges noted, there are already some good traits which could be extracted for this purpose in rust-crypto. As a former JCA user, it was, like many Java things, an extremely overcomplicated and bad abstraction (the entire Java crypto ecosystem is the stuff of nightmares). It had somewhat noble goals, but from a practical perspective was a giant pain to work with. I would prefer an approach that leans on Rust's type system more, with simple abstractions built on common traits, and no need to lean on cargo features: just include the crates with the algorithms you want, all built on a common set of traits, and everything just works. I think this approach could potentially still enable things like "ask for a named instance of a cipher at runtime" That way, crappy algorithms people shouldn't be using can be spun out into separate crates, complete with appropriate "caveat emptor" warnings for their users. |
There are now a litany of incompatible Rust libraries for memory protected secret storage: If nothing else, it seems like something else that could benefit from a common trait.
libsodium does more than that: it adds guard pages at the beginning and end of the region using Another popular approach is to use a master key-encrypting-key (KEK), storing all secrets encrypted in memory, and using the KEK to decrypt them on demand for a particular operation. All that said, this really looks to me like another case that can benefit from a common trait, and depending on your paranoia level you can pick the exact strategy/crate you want to safeguard your keys/other secrets. |
FYI, the design of ring's API has pretty much nothing to do with BoringSSL's. ring avoids modeling everything using traits because we do things that Rust's traits don't support (yet). Surprisingly, many of the unusual things we do in ring actually have reasonable explanations that are readily available to anybody who asks the ring developers about them. |
First, I agree that a common set of traits would be the nicer solution. It comes with many advantages. For example, a higher-level library like one of the many JWT libraries (https://github.com/mikkyang/rust-jwt/blob/96fd54b36ad631352e46a33565fd20dd4e26b6e3/src/crypt.rs) could only depend on "something that computes a HMAC for me", without choosing a crypto implementation for its user (possibly messing up their build). But, like @briansmith, I have found some things you can't do with traits, yet. Especially when I compare it to the cargo-feature-switching solution, there are some downsides. But I see these as a technical challenges, and maybe we can solve them (now already) to build such a set of common traits. So to be more concrete: Traits can't be the return type of a function, yet. As an example, consider ring's Another issue: I would like a global function (again I'm using hashing as the example) that just does the simplest job without even letting the user choose an algorithm, e.g., Related issue: It would be great if the implementations were easily exchangeable for basic use cases. (If the common library could reference the implementation, this would be done with a build flag.) I imagine this could be achieved if all crypto libraries followed a similar structure. A user who wants extreme exchangeability (not really necessary, but it shows the point) could use (@briansmith Why does ring call it |
This is a particularly interesting case: I like the ergonomics of how ring's Having a common
IMO "digest" as the output of a hash function is the correct term. |
This was done mostly to distinguish it from
A KDF's output isn't a digest of any message, so it doesn't make sense to use |
@briansmith makes sense. BLAKE2b was probably my specific concern, but its |
It's still a good point, because hashing is only the example here.
I also like the And there are other return values that are definitely not fixed size, like ciphertexts. But if there is no other way, we could have something like a Currently, I still have the solution with the associated
I agree, it's the right term for the result. But the module is also named |
In
OpenSSL seems to also prefer the term "digest," e.g. <openssl/digest.h>. See also java.security.MessageDigest. See also PKCS#11, e.g. I also agree that Regarding whether digests should implement |
I'm not familiar with This is all well for ring and other libraries, because they have to work in these environments. Among the goals of common API traits should be usability and misuse resistance, though. And that doeesn't go very far without vectors, The current plan would make ring and other crypto libraries depend on this API crate, and thus transitively depend on
If there is a solution that allows ring to compile in
sodiumoxide/rust_sodium seem to go the other way round (http://docs.maidsafe.net/rust_sodium/master/rust_sodium/crypto/hash/sha256/struct.Digest.html) and apparently implement everything they possibly can (even What is your motivation not to have at least the more useful trait implementations in ring?
|
My goal in ring is to make it unnecessary for ring users to compare digests for equality and then make it impossible for them to do so. Thus all timing attacks will be averted. |
Wouldn't that imply that your |
You are probably right that the "make it impossible for them to do so" part of my goal is unreasonable because the entire point of the |
... and advertise it / make it the default API / make it the easiest to use
I begin to think that hashing might not be the best example to use all the time. It's just the one that I analysed first because it's the simplest kind of API. But there are many cases where people use hashes for non-crypto purposes and hence they use them in ways that would be unsound for crypto purposes. HMAC/AEAD/... are probably only used for actual security-critical purposes, so I'm going to look at those next. In the HMAC case: doesn't Could there be any cases where the HMAC digest needs to be sent over the wire, saved on disk or stored in a database? Maybe this discussion should move somewhere where crypto API design is discussed -- and this thread should be about whether to include any crypto (API, implementation, traits, ...) into the standard library or rust-lang-nursery. |
Right. We need a way to output an HMAC value so that it can be serialized, and because HMAC uses the same key for verification and signing, one can (ab)use
I agree that that this discussion is probably getting ahead of the actual issue that is supposed to be discussed here. Regarding what's actually supposed to be discussed here, I think there is so much great work being done now in a variety of crates that we should just shelve this issue, let people continue to do that great work throughout 2017, and revisit the issue when it's time to build the 2018 roadmap. |
A trait's associated type cannot by used to determine the return type of this function @Philipp91 ? |
I'm not exactly sure what you mean by "this function", but it certainly can be used like this: https://github.com/Philipp91/rust-crypto-api/blob/c5662d5e05f8586dcfea4839ff2403601179d715/src/hash/mod.rs#L25 |
Yup. I just miss understood something you wrote up thread then. |
Issue by brson
Wednesday Jun 04, 2014 at 22:05 GMT
For earlier discussion, see rust-lang/rust#14655
This issue was labelled with: A-libs in the Rust repository
We've previously made the decision not to distribute any crypto with Rust at all, but this is probably not tenable since crypto is used everywhere. My current opinion is that we should not distribute any crypto written in Rust, but that distributing bindings to well-regarded crypto is fine.
Figure out a strategy here, build consensus, then start implementing a robust crypto library out of tree, with the goal of merging into the main distribution someday. There are some existing efforts along these lines that should be evaluated for this purpose.
The text was updated successfully, but these errors were encountered: