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

Figure out in-tree crypto story #14655

Closed
brson opened this issue Jun 4, 2014 · 67 comments
Closed

Figure out in-tree crypto story #14655

brson opened this issue Jun 4, 2014 · 67 comments

Comments

@brson
Copy link
Contributor

brson commented Jun 4, 2014

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.

@brson brson added the A-libs label Jun 4, 2014
@emberian
Copy link
Member

emberian commented Jun 4, 2014

There's some pure-Rust work on https://github.com/DaGenix/rust-crypto. http://nacl.cr.yp.to/ is probably among the most trustworthy libraries at this point, but hasn't been (to my knowledge) widely deployed.

@emberian
Copy link
Member

emberian commented Jun 4, 2014

(http://cr.yp.to/highspeed/coolnacl-20120725.pdf)

@emberian
Copy link
Member

emberian commented Jun 4, 2014

@emberian
Copy link
Member

emberian commented Jun 4, 2014

Oh, and I almost forgot about https://github.com/dnaq/sodiumoxide, which is an initial attempt at binding libsodium

@DaGenix
Copy link

DaGenix commented Jun 5, 2014

Is the goal of the crypto library to provide rust interfaces to a wide set of commonly used algorithms? If so, I don't think NaCL / libsodium are a great fit since I don't believe they include algorithms such as MD5 or TLS.

@wsddn
Copy link

wsddn commented Jun 5, 2014

For just making things secure NaCL seems to be the go to library, but it only supports certain cryptographic primitives which make it not at all useful for a library that wants to provide general cryptographic code. It is not designed to be a general purpose one stop shop cryptographic library. For example it will be impossible to create a standards complying TLS implementation with NaCL because it does not provide AES CBC.

Some cryptographic functions that NaCL does not support:

  • Some AES modes (CBC, CFB, GCM)
  • ChaCha20 (Salsa20 and XSalsa20 are provided, ChaCha20 is just a slight tweak on Salsa20 for greater speed and possibly security)
  • RSA
  • Elliptical Curves (NIST / Brainpool, the NIST curves are controversial though)
  • ECDSA
  • DSA
  • Diffie-Hellman key exchange (NaCL provides curve25519 which is a curve used in Elliptical Curve Diffie Hellman)
  • MD5 hashing (although is providing a universally shunned hash system a good idea?)
  • SHA1

For what its worth Go implements most of their cryptographic code in Go (however Adam Langley has admitted that they have not mitigated timing attacks in their crypto/rsa package).

@Ayrx
Copy link

Ayrx commented Jun 5, 2014

FWIW, I am contributor to the cryptography library for Python. You can consider taking the approach we did here and design a "pluggable" API that bindings existing C libraries. For a general purpose crypto library, NaCL is almost definitely not a good fit because common algorithms aren't present in it. While there has been much bad press about OpenSSL lately, it is really the most viable library to wrap since it is available on all common platforms and almost certainly already installed on Linux distros. The current scrutiny on it should do well to turn up security bugs as well. Our API also allows other C libraries to be used (we bind commoncrypto on OS X as well, and I have PolarSSL bindings in the works.)

If designed well, I can see the potential Rust crypto library at first being dependent on C bindings but eventually gets seamlessly replaced by Rust code without much backwards incompatibility.

@sdevlin
Copy link

sdevlin commented Jun 5, 2014

I highly recommend you package something like NaCl as a high-level crypto interface - call it "crypto/box" or similar. This is the package you want the vast majority of application developers to use.

Other specific protocols should similarly be packaged in high-level interfaces when it makes sense to provide them, e.g. "crypto/tls".

While a lower-level set of primitives is necessary for protocol implementers, documentation and naming conventions should steer people away from them. Call this package "crypto/low-level" or "crypto/arcane" or something like that.

@taoeffect
Copy link

This Rust crypto library should be mentioned (surprised it hasn't been): ClearCrypt

@emberian
Copy link
Member

emberian commented Jun 5, 2014

ClearCrypt is not a general-purpose crypto library but an implementation of
an encryption protocol

On Thu, Jun 5, 2014 at 10:04 AM, Greg Slepak [email protected]
wrote:

This Rust crypto library should be mentioned (surprised it hasn't been):
ClearCrypt https://github.com/clearcrypt/clearcrypt


Reply to this email directly or view it on GitHub
#14655 (comment).

http://octayn.net/

@taoeffect
Copy link

@cmr: ClearCrypt contains many parts of a general-purpose crypto library, similar to how OpenSSL does (though it's an implementation of the SSL/TLS protocol).

@emberian
Copy link
Member

emberian commented Jun 5, 2014

It doesn't now, and since it won't have the mess of supported ciphers etc
that TLS does, I doubt it will (and it shouldn't!).

On Thu, Jun 5, 2014 at 10:14 AM, Greg Slepak [email protected]
wrote:

@cmr https://github.com/cmr: ClearCrypt contains many parts of a
general-purpose crypto library, similar to how OpenSSL does (though it's an
implementation of the SSL/TLS protocol).


Reply to this email directly or view it on GitHub
#14655 (comment).

http://octayn.net/

@taoeffect
Copy link

Right, it's a WIP, I just wanted to mention it. I hope I didn't offend you by doing so. ;)

@erickt
Copy link
Contributor

erickt commented Jun 5, 2014

We do also have the https://github.com/sfackler/rust-openssl bindings, maintained by @sfackler and myself.

@taoeffect
Copy link

My current opinion is that we should not distribute any crypto written in Rust, but that distributing bindings to well-regarded crypto is fine.

I would also like to point out the silliness of inventing a safe programming language only to encourage writing bindings back to C. HT to @dchest for phrasing that so well.

@seanmonstar
Copy link
Contributor

The "sillyness" comes from new crypto requiring audits by cyptographers. The Rust team doesn't have any dedicated at the moment. So it's "safer" to use already-audited code in C.

@taoeffect
Copy link

The "sillyness" comes from new crypto requiring audits by cyptographers. The Rust team doesn't have any dedicated at the moment. So it's "safer" to use already-audited code in C.

Uh huh. And which code would that be?

@samal-rasmussen
Copy link

The "sillyness" comes from new crypto requiring audits by cyptographers. The Rust team doesn't have > any dedicated at the moment. So it's "safer" to use already-audited code in C.

Uh huh. And which code would that be?

Hopefully LibreSSL in the not so distant future?

@thestinger
Copy link
Contributor

LibreSSL is only going to be portable if and when OpenBSD starts receiving funding for it, and there's not a great history of OpenBSD projects receiving funding.

@glandium
Copy link
Contributor

glandium commented Jun 6, 2014

While there has been much bad press about OpenSSL lately, it is really the most viable library to wrap since it is available on all common platforms and almost certainly already installed on Linux distros.

NSS would fit the cross-platform bill too. It's used in Firefox, after all.

My current opinion is that we should not distribute any crypto written in Rust

I can understand why for some things, but then choosing OpenSSL at this point would make most people wonder what's the point of Rust after all.
Anyways, I don't see why not implement things like digests in rust straight away (and they are already in rust-crypto, for that matter, I've been using Sha1, Md5 and Hmac from there). Sure, that would be redundant with whatever library whose bindings would be distributed, but so could be said of a lot of things in the standard library, as being redundant with the system libc.

@thestinger
Copy link
Contributor

Most of the flaws in the most recent OpenSSL security advisory are not related to memory safety.

@taoeffect
Copy link

I can understand why for some things, but then choosing OpenSSL at this point would make most people wonder what's the point of Rust after all.

Just to put it on the record, I am one of those people. 👍

@taoeffect
Copy link

Also, sorry to be off-topic, but @glandium, have you realized that your "randomly generated" GitHub profile picture is flipping all of us off? ;)

@ciphergoth
Copy link
Contributor

SUPERCOP includes many highly optimized implementations of a wide variety of crypto primitives. The trouble is that it is absolutely not designed to make them available to programming languages, only to benchmark them. Using them is hard work! I wrote this tool which builds a shared library out of SUPERCOP primitives - it was not straightforward:

http://hg.opensource.lshift.net/bletchley-primitives/file/tip

@tarcieri
Copy link
Contributor

In a perfect world, I think Rust would provide an abstract, high-level API for encryption backed by multiple "providers" ala the Java Cryptography Architecture:

http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#Design

This approach would allow Rust to have a cryptography story without actually having to vendor or otherwise ship actual encryption code as part of the core distribution.

Instead, ship the multi-provider API as part of core Rust, and developers can plug in the provider modules that are appropriate to a particular purpose.

@taoeffect
Copy link

In a perfect world, I think Rust would provide an abstract, high-level API for encryption backed by multiple "providers" ala the Java Cryptography Architecture

@tarcieri That's a good idea. Seems like the right approach. 👍

@ciphergoth
Copy link
Contributor

In what way is crypto different from other algorithms provided in standard libraries, that crypto needs a provider architecture but other algorithms don't? I think JCA exists because of legal problems at the time with directly shipping crypto libraries, not some technical reason.

@tarcieri
Copy link
Contributor

In what way is crypto different from other algorithms provided in standard libraries

Agility around algorithms is more important in crypto than it is with your average data structure. A multi-provider architecture lets you supply a wider range of algorithms than are available in a single library under a single API, and likewise swap out bad algorithms for good ones in the future.

@ciphergoth
Copy link
Contributor

I can see the advantages of being able to naturally express things like "this block cipher used in counter mode provides a stream cipher" but that seems like an application for subtyping/trait implementation rather than for a provider architecture. Can you give an example of the kind of scenario where you're glad you used a provider architecture?

@tarcieri
Copy link
Contributor

I made a remark about this issue in my talk at Mozilla SF in December 2014 and I just wanted to clarify.

My remark was specifically that Rust should not have an in-tree crypto story, and it highlighted this issue.

This comes with some caveats. My intended point was about implementing ciphers (and crypto-protocols built on them) in-tree, and saying I thought that was a bad idea. My analogy was to Ruby's OpenSSL extension, which is a binding to OpenSSL that is an intractable part of the standard library. There is an effort underway to rip OpenSSL out of the Ruby standard library and move it into an out-of-tree external package.

Rust has various in-tree APIs for hash functions (e.g. std::hash) and I think these are non-controversial and totally fine. In fact I think std::hash::Hasher is great and one of the other remarks I made in my talk is I totally want to see more traits like this.

tl;dr: hash functions are fine, but please leave encryption ciphers and public-key digital signature algorithms (and especially crypto protocols!) to out-of-tree libraries developed by crypto experts.

@ciphergoth
Copy link
Contributor

Say a little more about why hash functions are an exception? Thanks!

@tarcieri
Copy link
Contributor

First, there is one hash function you absolutely do want in the standard library: something like SipHash to use as the basis of a (hashDoS-resistant) hashing function:

http://doc.rust-lang.org/0.11.0/collections/hash/sip/fn.hash.html

Without a cryptographically secure hash function like SipHash, any time an attacker provides the data to be put into e.g. a HashMap, they can potentially collide the buckets the data is placed into, intentionally causing poor algorithmic performance, DoSing the application. This is hashDoS.

Secondly, having hash functions in the standard library also gets you around the bootstrapping problem of how to verify artifacts in the package manager for the language itself.

@Diggsey
Copy link
Contributor

Diggsey commented Jan 24, 2015

It's very easy verify that a custom hash implementation is correct, especially in rust where you don't have to worry about memory safety as much. Checking an entire protocol or cipher is much more difficult, because there are so many possible execution paths.

@thestinger
Copy link
Contributor

Modern block ciphers and stream ciphers both tend to be incredibly simple, and there aren't multiple execution paths in general. It's not significantly different from hashes.

@thestinger
Copy link
Contributor

@tarcieri: Having a secure random number generator for the hash seeds and other use cases means having a stream cipher implementation too.

@tarcieri
Copy link
Contributor

@thestinger you need an API for getting cryptographic randomness, but you only need to use it once at the time the program starts. Once you have the key for SipHash seeded you can reuse the same key for all hashing operations globally. I say this specifically in regard to hashDoS.

@ciphergoth
Copy link
Contributor

Totally support SipHash. But I'm not sure I see the point of including other hash functions. Without a public key signature scheme, you can only verify hashes you already hold, which seems pretty limiting for the applications you set out.

A secure random number generator does seem desirable, but it's a very tricky proposition—it's very platform dependent, it's likely to depend on a good stream cipher and a good hash function, and if there's any platform on which you find you need to do your own entropy management you'll end up in deep water fast. I'm not sure it's a good feature to try to standardize for the 1.0 release.

@ciphergoth
Copy link
Contributor

Also small terminological note: SipHash is a PRF, not a message digest function like SHA-2/Blake2.

@tarcieri
Copy link
Contributor

It's not a hash function, it's a PRF? Really? Next you'll be telling me it's not a block cipher, it's a PRP 😉

Anyway, I think your point was that people shouldn't be using SipHash for anything other than the hash function driving e.g. a HashMap data structure, in which case, yes, that's true.

SipHash is definitely not fungible with e.g. SHA-2/Blake2 and people shouldn't be using it unless they know what they're doing.

@thestinger
Copy link
Contributor

@ciphergoth: SipHash is useless without a seed, so the OS requirements are the same for both SipHash and a CSPRNG... the requirements are there on every platform Rust supports.

@thestinger
Copy link
Contributor

@ciphergoth: A stream cipher is trivially a CSPRNG. There's nothing else that's required. You need to retrieve an initial seed from the operating system, as you do for any kind of DoS secure hashing scheme. Re-seeding it is optional and can actually hurt rather than helping. Not providing a fast CSPRNG means that people are going to use an insecure RNG for cases where they should not... the absence of the feature is a security vulnerability in practice.

http://blog.cr.yp.to/20140205-entropy.html

@tarcieri
Copy link
Contributor

@ciphergoth re: verifying artifacts, what you said is true, however even with just hash functions you can decompose the dependencies into a Merkle tree, so for example a bootstrapping tool can pull in all of its subresources and confirm their integrity, with each of them pinned to specific digests.

With something like that, rustc bootstrap could have cryptographic integrity.

@ciphergoth
Copy link
Contributor

If all the platforms you need to run on can provide a good seed then I take it all back, including an RNG is very desirable.

I still feel there's a very strong presumption against including things in 1.0, since if you leave something out and it was a mistake you can include it later, but if you put it in or give it the wrong API you are in big trouble. Since Rust has a good dependency management story it doesn't seem like a big problem to use that to get hold of the functions you need.

@thestinger
Copy link
Contributor

If all the platforms you need to run on can provide a good seed then I take it all back, including an RNG is very desirable.

A seed is obviously needed for SipHash to be worth anything so I don't understand the distinction you're making.

@thestinger
Copy link
Contributor

Since Rust has a good dependency management story

It really doesn't. The most that can be said is that it has one. It's awful at doing proper reproducible releases and is yet another insecure packager manager without a package signing story or proper system integration. Of course, you can't expect much when compiler snapshots are built on third party cloud infrastructure. Each Xen vulnerability leaves Rust's compiler snapshots wide open to attacks from anything else on those machines.

@tshepang
Copy link
Member

OT: @thestinger I would be keen to read a detailed blog post by you containing all Rust-related issues you have. You notice a lot, and the one about package signing is quite interesting.

@tarcieri
Copy link
Contributor

@tshepang FWIW I made an issue about that here: rust-lang/crates.io#75

@ciphergoth
Copy link
Contributor

Are you saying that the issues you raise with Crate are a reason to put things in-tree?

@tarcieri
Copy link
Contributor

@ciphergoth no, I already gave my rationale for that above (see rustc bootstrap and subresource integrity)

@ciphergoth
Copy link
Contributor

Can you describe the sort of scenario you're thinking of in more detail? The hash of some other resource is included in the Rust sources themselves—what sort of resource do you have in mind and at what stage is it fetched? Also note that you currently have to have Python installed to build rustc; at a pinch you could use a hash function built into Python as a bootstrapping aid. I don't yet see a compelling enough picture to overcome the leave-things-out presumption, but it's very possible you're right and I'm just not seeing the whole picture.

@tarcieri
Copy link
Contributor

I was really making a more general statement about the utility. I don't have some master plan mapped out in my head.

@ciphergoth
Copy link
Contributor

I think it would probably be safe to add the hash function to the sources in the same change that makes use of it.

@tarcieri
Copy link
Contributor

Sure, my point wasn't that hash functions should be included right now, merely that they should be "allowed"

FWIW, SHA256 already appears to be in the rustc sources:

http://doc.rust-lang.org/rustc/util/sha2/struct.Sha256.html

@ciphergoth
Copy link
Contributor

Oh interesting, thanks! It's used here as part of a mangling strategy for symbols and crate names.

https://github.com/rust-lang/rust/blob/master/src/librustc_trans/back/link.rs#L75

I share your sense that I'm less alarmed at seeing a hash function in the sources than pretty much any other cryptographic primitive!

@tarcieri
Copy link
Contributor

Hmm, I see that Rust vendors a Rust implementation of ChaCha20 for use as a PRNG:

https://github.com/rust-lang/rust/blob/master/src/librand/chacha.rs

Hard to say how I feel about that. I'm curious if anyone knows if that gets exposed with the name "secure" on it anywhere, or how the key is generated?

This is all I could find on it:

https://github.com/rust-lang/rust/wiki/Lib-rand

@steveklabnik
Copy link
Member

I'm pulling a massive triage effort to get us ready for 1.0. As part of this, I'm moving stuff that's wishlist-like to the RFCs repo, as that's where major new things should get discussed/prioritized.

This issue has been moved to the RFCs repo: rust-lang/rfcs#766

@l0kod
Copy link
Contributor

l0kod commented Feb 8, 2015

cc rust-lang/cargo#1281

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