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

Add a simple example for aead #526

Closed
wants to merge 6 commits into from

Conversation

jaysonsantos
Copy link

Hi, I've added this to try to help newcomers (like me) when using a cryptography library to avoid common errors and to have something to run ASAP.
Let me know if I wrote some BS and if this is the rigt place to put it.

Copy link
Contributor

@Philipp91 Philipp91 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I very very much appreciate you adding a code sample for what is probably the most important part of the ring API. Thank you!

Note that Brian plans on changing the API around (#436), though I don't know when. This might require changes to the code sample in the future, but that's fine, I guess.

Also, the way you (don't) use the output_size return value shows once again how confusing the current API is.

src/aead/aead.rs Outdated
@@ -25,6 +25,82 @@
//! [AEAD]: http://www-cse.ucsd.edu/~mihir/papers/oem.html
//! [`crypto.cipher.AEAD`]: https://golang.org/pkg/crypto/cipher/#AEAD

//!
//! **Example (if you don't know what you are doing, read this first)**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could explain what AEAD is (i.e. what most people need when they need "encryption"). To tell people "this is the right place for you if you believed you just wanted to encrypt."

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please follow the template used in ring::signature's module-level documentation. In particular, this should be:

//! # Example

No need for the "if you don't know what you are doing…" comment.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a suggestion for a start line?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't try to explain what an AEAD is in this example. We already try to do that and link to a paper about it above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This module is what you need when you want to encrypt something symmetrically (using the same secret key for encryption and decryption). Instead of using unauthenticated encryption (AES-ECB, AES-CBC, AES-CTR and the like), you probably want to use authenticated encryption (aka. AEAD) as implemented in this module -- unless you know what you are doing.

The text deliberately mentions the things that it replaces (ECB, CBC) because experiments I conducted (with Rust/crypto beginners) have showed that people search for those (on the web and in the documentation) and find other implementations, so mentioning these helps potential ring users find what they thought they needed.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scope of this PR is to add an example. If we want to add documentation beyond the example then let's do it as a separate PR. In particular, I don't want to expand the scope of what's required of @jaysonsantos way beyond what he originally was intending.

src/aead/aead.rs Outdated
//! // The password will be used to generate a key and it is normally used when
//! // it is generated by the user. If you need a key which will be stored in a file you
//! // generate it directly.
//! let password = b"nice password";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should make it exceedingly clear that the password should not be hard-coded and this is here only because it's sample code. Maybe change it to `b"DO NOT hard-code passwords, this is just an example".

src/aead/aead.rs Outdated
//!
//! // Usually the salt has some random data and something that relates to the user
//! // like an username and it must be 8 bytes (64 bits)
//! let salt = [0, 1, 2, 3, 4, 5, 6, 7];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same: hard-code or not?

src/aead/aead.rs Outdated
//! // like an username and it must be 8 bytes (64 bits)
//! let salt = [0, 1, 2, 3, 4, 5, 6, 7];
//!
//! // Keys must have 32 bytes and if you want to use an user password for it you have
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: a user

src/aead/aead.rs Outdated
//! // to use an algorithm to derive it (in this case pbkdf2).
//! let mut key = [0; 32];
//! derive(&HMAC_SHA256, 100, &salt, &password[..], &mut key);
//!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd cut off the example here (move the part above elsewhere) and show how to generate a random key here, instead. Many users of other libraries (not ring) fail to generate random keys and hard-code something instead.

Next to the line where the generation happens, you can then explain that the key can also be derived from the user's password or sth. like that and then point to the part of the code above (moved to a second code-block here or to the pbkdf2 module).

Added benefit: this code sample becomes shorter (it's a bit too long and users might skip it for that reason).

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @Philipp91. I don't think we should teach people how to derive a key from a password in this example. This example scheme is actually not as secure as we'd like it to be w.r.t. the nonce handling anyway.

I agree with @Philipp91 that you can just generate a random key in the example, with a comment that indicates that that part of the example is unrealistic.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was a problem when I started playing with crypto algos and would be nice to say that the password can be converted into keys using derive. Do you think it is worth it to remove thinking that it is a common problem users find when using cryptography for the first time?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Brian wrote:

I don't think we should teach people how to derive a key from a password in this example. This example scheme is actually not as secure as we'd like it to be w.r.t. the nonce handling.

I can't find that comment anymore here. Without understaind his exact reasons (again, I'm not a crypto expert, so I can't judge), I'd say the example code shouldn't demonstrate the derivation if it's not safe.

OTOH: Yes, it is a common problem, and it's common to derive a secret from a password and then encrypt something with it. So eventually, this (upper) part of the sample code will be relevant -- don't throw it away. I hope that ring will soon offer a safe solution to do that? Maybe it has to do with nonce-misuse-resistant ciphers? #413

Once the key derivation sample becomes relevant, it can be debated whether it should be placed here or elsewhere. Either way, I think it should not be in this same block of code.

src/aead/aead.rs Outdated
//!
//! // The input/output variable need some space to store the tag which will have the
//! // signature
//! println!("Tag len {}", CHACHA20_POLY1305.tag_len());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this line?

src/aead/aead.rs Outdated
//! }
//!
//! // Opening key used to decrypt data
//! let opening_key = OpeningKey::new(&CHACHA20_POLY1305, &key).unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is counter-intuitive to initialize the OpeningKey here -- it should be moved behind all the encryption code. In real-world code, this would be in a different function.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I didn't follow here. Do you think I should move it even being an example thing?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be in line 95, because after line 94 you can (mentally or actually) draw a line -- that's where the encryption is complete. The OpeningKey is not needed for the encryption operation, so it should be below that "line".

src/aead/aead.rs Outdated
//! // The input/output variable need some space to store the tag which will have the
//! // signature
//! println!("Tag len {}", CHACHA20_POLY1305.tag_len());
//! for _ in 0..CHACHA20_POLY1305.tag_len() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

`in_out.resize(in_out.len() + CHACHA20_POLY1305.tag_len(), 0u8);

//! // Encrypt data into in_out variable
//! let output_size = seal_in_place(&sealing_key, &nonce, &additional_data, &mut in_out,
//! CHACHA20_POLY1305.tag_len()).unwrap();
//!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use output_size here to .truncate() the ciphertext, which is now in in_out.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't I lose the tag? I thought it had the signed data.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tag's length is not guaranteed to be out_suffix_capacity. So it might be that you resize() the vector from 80 to 100 to make room for the tag, but then it turns out the tag is only 15 long, so your ciphertext is 95. That's the number returned from seal_in_place.

I don't know if that difference actually ever occurs -- it might well be that output_size always matches the size of the vector, so a .truncate() call wouldn't do anything at all. Nevertheless, that's how the API is designed (if I understand it correctly, that is).

So now, AFAIK you wouldn't loose the tag, it's included in that size. Just try out, if the decryption fails, something went wrong, otherwise it's correct.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

//! // Random data must be used only once per encryption and ideally if you encrypt blocks
//! // it should be generated on per block see an example of poorly generated nonces
//! // where a new nonce is generated at every few pixels at
//! // https://github.com/jaysonsantos/bad-encryption-example
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be true (I'm not a crypto expert), but the explanation is too hard to understand.

I reckon average users wouldn't encrypt every pixel of an image individually, though (as you seem to do here https://github.com/jaysonsantos/bad-encryption-example/blob/master/src/main.rs#L69), but rather the whole thing at once. Similarly, they would encrypt an entire text at once, and not the individual characters. And average users don't have "blocks", they just have their data. So the only explanation needed here is: "Never reuse a nonce, that is, always generate a fresh nonce (e.g. with rand.fill()) for every seal_in_place call you make."

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea of encrypting pixel by pixel is to have a visual analogy of what would happen if you encrypt many files/something else using the same nonce, I think it illustrates well what could happen because if you are not using with cryptography stuff you simply think that as it is not the secret itself you could keep reusing it

@coveralls
Copy link

coveralls commented Apr 28, 2017

Coverage Status

Coverage remained the same at 95.325% when pulling ab4ffb93327eff4af64b0b2a4c97e00c2ee13ab2 on rusty-platter:aead-example into 60867f2 on briansmith:master.

Copy link
Owner

@briansmith briansmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I deleted the earlier comment about removing the derivation part because I thought it was just "pending".

You can't use PBKDF2 to derive a key from a password and then use that key for AEAD operations without having a secure way to generate nonces. (I don't want to encourage people to use random nonces with these algorithms.)

src/aead/aead.rs Outdated
@@ -25,6 +25,82 @@
//! [AEAD]: http://www-cse.ucsd.edu/~mihir/papers/oem.html
//! [`crypto.cipher.AEAD`]: https://golang.org/pkg/crypto/cipher/#AEAD

//!
//! **Example (if you don't know what you are doing, read this first)**
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please follow the template used in ring::signature's module-level documentation. In particular, this should be:

//! # Example

No need for the "if you don't know what you are doing…" comment.

src/aead/aead.rs Outdated
//! // to use an algorithm to derive it (in this case pbkdf2).
//! let mut key = [0; 32];
//! derive(&HMAC_SHA256, 100, &salt, &password[..], &mut key);
//!
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @Philipp91. I don't think we should teach people how to derive a key from a password in this example. This example scheme is actually not as secure as we'd like it to be w.r.t. the nonce handling anyway.

I agree with @Philipp91 that you can just generate a random key in the example, with a comment that indicates that that part of the example is unrealistic.

src/aead/aead.rs Outdated
@@ -25,6 +25,82 @@
//! [AEAD]: http://www-cse.ucsd.edu/~mihir/papers/oem.html
//! [`crypto.cipher.AEAD`]: https://golang.org/pkg/crypto/cipher/#AEAD

//!
//! **Example (if you don't know what you are doing, read this first)**
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't try to explain what an AEAD is in this example. We already try to do that and link to a paper about it above.

@briansmith
Copy link
Owner

First, thanks for doing this!

I accidentally submitted some of my draft feedback earlier than I intended to, so then I had to submit more before I intended to. I will review this carefully in a few days.

@coveralls
Copy link

coveralls commented Apr 28, 2017

Coverage Status

Coverage remained the same at 95.325% when pulling e61a5f84cf727c5c793b77db223813b32977e856 on rusty-platter:aead-example into 60867f2 on briansmith:master.

@jaysonsantos
Copy link
Author

jaysonsantos commented Apr 29, 2017

@briansmith

You can't use PBKDF2 to derive a key from a password and then use that key for AEAD operations without having a secure way to generate nonces. (I don't want to encourage people to use random nonces with these algorithms.)

I changed it in my code but could you explain why this is a problem? If you derive from a password and generate nonces with SystemRandom isn't it enough? And it seems it is a common thing to do when creating keys from passwords.

@jaysonsantos
Copy link
Author

jaysonsantos commented Apr 29, 2017

I also changed the header to # Example but it will render it literally instead of a and I couldn't find the difference from this to signature's or pbkdf2's docs

@coveralls
Copy link

coveralls commented Apr 29, 2017

Coverage Status

Coverage remained the same at 95.325% when pulling 20c9835364bdbfce80abe3f002037e336e4d13e0 on rusty-platter:aead-example into 60867f2 on briansmith:master.

@briansmith
Copy link
Owner

generate nonces with SystemRandom isn't it enoug

The nonces here are only 96 bits, which means random nonce collision probability is 1/2**48 assuming a perfect PRNG. Some people may be OK with that, but I don't want to advocate for something like that in the ring examples.

@coveralls
Copy link

coveralls commented Apr 30, 2017

Coverage Status

Coverage remained the same at 95.325% when pulling acf91661d1a0f822b0066500c788fe29c6ffbb86 on rusty-platter:aead-example into 60867f2 on briansmith:master.

src/aead/aead.rs Outdated
//!
//! // Usually the salt has some random data and something that relates to the user
//! // like a username and it must be 8 bytes (64 bits)
//! let salt = [0, 1, 2, 3, 4, 5, 6, 7];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This variable is unused since 20c9835364bdbfce80abe3f002037e336e4d13e0.

@coveralls
Copy link

coveralls commented May 11, 2017

Coverage Status

Coverage decreased (-0.6%) to 94.761% when pulling a604ebe27955f4d3b5fa36d197bd6cb5a9b9dc04 on rusty-platter:aead-example into 60867f2 on briansmith:master.

src/aead/aead.rs Outdated
//!extern crate ring;
//!
//!use ring::aead::*;
//!use ring::rand::SystemRandom;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, I missed this before. You need something like use ring::rand::{SystemRandom, SecureRandom}; to avoid build failures.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is true, i saw some buildings that passed and I thought it was working.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And actually, cargo test works on my machine, I will try to figure out before changing it.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably will need the thing @isonmad suggested if/when you rebase it on the current master.

@jaysonsantos
Copy link
Author

I just rebased it with upstream's master

@coveralls
Copy link

coveralls commented May 13, 2017

Coverage Status

Changes Unknown when pulling dc23d0a on rusty-platter:aead-example into ** on briansmith:master**.

@coveralls
Copy link

coveralls commented May 13, 2017

Coverage Status

Coverage remained the same at 95.481% when pulling dc23d0a on rusty-platter:aead-example into 0124565 on briansmith:master.

@ghost
Copy link

ghost commented May 15, 2017

Sorry, I didn't see this, and submitted #536.

@ghost
Copy link

ghost commented May 15, 2017

Why are you using CHACHA20_POLY1305 not one of the AES_GCM variants? Are they suspected to be compromised?

@jaysonsantos
Copy link
Author

@cedenday

Why are you using CHACHA20_POLY1305 not one of the AES_GCM variants? Are they suspected to be compromised?
Because is the one I was using at the time and it is faster on systems that don't have processor instructions for AES.

@ghost
Copy link

ghost commented Jun 10, 2017

@briansmith What is blocking the acceptance of this pull request?

@briansmith
Copy link
Owner

@briansmith What is blocking the acceptance of this pull request?

The AEAD API is getting replaced real soon now, which will obsolete this. Sorry.

@briansmith briansmith closed this Sep 25, 2017
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

Successfully merging this pull request may close these issues.

5 participants