Encrypt with AEAD
Recipe | Crates | Categories |
---|---|---|
aes-gcm-siv | ||
aes-gcm | ||
ChaCha20Poly1305 |
For more algorithms, see Rust Crypto AEADs: aes-gcm-siv, aes-gcm, chacha20poly1305
aes-gcm-siv
Pure Rust implementation of the AES-GCM-SIV Misuse-Resistant Authenticated Encryption Cipher (RFC 8452) with optional architecture-specific hardware acceleration.
use aes_gcm_siv::Aes256GcmSiv; use aes_gcm_siv::Key; use aes_gcm_siv::Nonce; use aes_gcm_siv::aead::Aead; use aes_gcm_siv::aead::KeyInit; use aes_gcm_siv::aead::OsRng; use aes_gcm_siv::aead::Payload; // AES-GCM-SIV (Misuse-Resistant Authenticated Encryption Cipher). // // "Authenticated Encryption" is a scheme that simultaneously assures the data // confidentiality (the encrypted message is impossible to understand without // the knowledge of a secret key) and authenticity (it is unforgeable) // https://en.wikipedia.org/wiki/Authenticated_encryption // Authenticated encryption with associated data (AEAD) is a variant of AE that // allows the message to include "associated data" (AD). AD is additional // non-confidential information, which integrity is protected (i.e., it is // readable, but tampering with it will be detected). A typical example is the // header of a network packet that contains its destination address. To properly // route the packet, all intermediate nodes in the message path need to know the // destination, but for security reasons they cannot possess the secret key. // See // https://codahale.com/towards-a-safer-footgun/ // https://www.imperialviolet.org/2017/05/14/aesgcmsiv.html fn main() -> Result<(), aes_gcm_siv::Error> { // Generate a random 256-bit key let key: Key<Aes256GcmSiv> = Aes256GcmSiv::generate_key(&mut OsRng); // Generate a random 96-bit nonce. // A nonce is an arbitrary (often random) number that can be used just once // in a cryptographic communication. let nonce = Nonce::from_slice(b"unique nonce"); let cipher: Aes256GcmSiv = Aes256GcmSiv::new(&key); // Encrypt the given plaintext payload, and return the resulting ciphertext // as a vector of bytes. let plaintext = b"Secret message"; let associated_data = b"Header"; let ciphertext: Vec<u8> = cipher.encrypt( nonce, Payload { msg: plaintext, aad: associated_data, // AD stays unencrypted... }, )?; println!("Ciphertext: {:?}", ciphertext); // Decrypt. // Failure to pass the same AD that was used during encryption will cause // decryption to fail let decrypted_ciphertext = cipher.decrypt( nonce, Payload { msg: ciphertext.as_ref(), aad: associated_data, }, )?; println!( "Decrypted Ciphertext: {}", String::from_utf8(decrypted_ciphertext.clone()).unwrap() ); assert_eq!(plaintext, decrypted_ciphertext.as_slice()); Ok(()) }
aes-gcm
Pure Rust implementation of the AES-GCM (Galois/Counter Mode) Authenticated Encryption with Associated Data (AEAD) Cipher with optional architecture-specific hardware acceleration.
// Algorithm use aes_gcm::Aes256Gcm; // Use Aes128Gcm or Aes256Gcm, respectively // Cryptokey use aes_gcm::Key; // A nonce is an arbitrary (often random) number // that must be used just once // in a cryptographic communication. use aes_gcm::Nonce; // Trait that provides `encrypt` and `decrypt` use aes_gcm::aead::Aead; // Trait that provides `generate_key` use aes_gcm::aead::KeyInit; // The operating-system's random data source use aes_gcm::aead::OsRng; fn main() { // Generate a random 256-bit key let key: Key<Aes256Gcm> = Aes256Gcm::generate_key(&mut OsRng); // Generate a random 96-bit nonce. let nonce = Nonce::from_slice(b"unique nonce"); // Create the cipher... let cipher = Aes256Gcm::new(&key); let plaintext = b"Secret message"; // ...that will encrypt the secret message. // To authenticate additional Associated Data, // apply the same method than in the AES-GCM-SIV example let ciphertext = cipher .encrypt(nonce, plaintext.as_ref()) .expect("encryption failure!"); println!("Ciphertext: {:?}", ciphertext); let decrypted_ciphertext = cipher .decrypt(nonce, ciphertext.as_ref()) .expect("decryption failure!"); assert_eq!(plaintext, decrypted_ciphertext.as_slice()); println!( "Decrypted Ciphertext: {}", String::from_utf8(decrypted_ciphertext).unwrap() ); }
ChaCha20Poly1305
Pure Rust implementation of the ChaCha20Poly1305 Authenticated Encryption with Additional Data Cipher (RFC 8439) with optional architecture-specific hardware acceleration. Also contains implementations of the XChaCha20Poly1305 extended nonce variant of ChaCha20Poly1305, and the reduced-round ChaCha8Poly1305 and ChaCha12Poly1305 lightweight variants.
// Trait that provides in-place stateless AEAD. use chacha20poly1305::AeadInPlace; // Algorithm use chacha20poly1305::ChaCha20Poly1305; // Cryptographic key use chacha20poly1305::Key; // A nonce is an arbitrary (often random) number // that must be used just once // in a cryptographic communication. use chacha20poly1305::Nonce; // use chacha20poly1305::Tag; // Trait that provides `generate_nonce` use chacha20poly1305::aead::AeadCore; // Trait that provides `encrypt` and `decrypt` // use chacha20poly1305::aead::Aead; // Trait that provides `generate_key`, etc use chacha20poly1305::aead::KeyInit; // A random number generator that retrieves randomness from the operating // system use chacha20poly1305::aead::OsRng; // Trait for securely erasing values from memory use zeroize::Zeroize; // An Authenticated Encryption with Associated Data (AEAD) cipher, // based on the ChaCha20 stream cipher and Poly1305 universal hash function. // ChaCha20Poly1305 is notable for being simple and fast when implemented in // pure software. fn encrypt_then_decrypt() { // Example plaintext to encrypt let mut plaintext: Vec<u8> = b"This is a secret message.".to_vec(); // Create a key. // Use a cryptographically secure Random Number Generator let mut key: Key = ChaCha20Poly1305::generate_key(&mut OsRng); // Generate a nonce. // Nonces MUST be unique for each encryption with the same key. let mut nonce: Nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng); let mut ciphertext = plaintext.to_vec(); let tag: Tag; // --- Encryption --- { // Create an instance of the cipher let cipher = ChaCha20Poly1305::new(&key); // Encrypt in-place, replacing the plaintext contents with ciphertext, // and returning the authentication tag. // In-place encryption eliminates `alloc` requirements. tag = cipher .encrypt_in_place_detached(&nonce, b"", &mut ciphertext) .unwrap(); println!("Ciphertext: {:x?}", ciphertext); println!("Tag: {:x?}", tag); } // --- Decryption --- { // Create a cipher instance for decryption let cipher_dec = ChaCha20Poly1305::new(&key); // Decrypt the message in-place, returning an error in the event // the provided authentication tag does not match the given ciphertext // (i.e. ciphertext is modified/unauthentic) let mut decrypted_plaintext = ciphertext.clone(); let decrypted_result = cipher_dec.decrypt_in_place_detached( &nonce, b"", // No associated_data in this example &mut decrypted_plaintext, // Buffer &tag, ); match decrypted_result { Ok(_) => { println!( "Decrypted plaintext: {}", String::from_utf8_lossy(&decrypted_plaintext) ); } Err(e) => { eprintln!("Decryption error: {}", e); } } // Check if decryption was successful assert_eq!(decrypted_plaintext, plaintext); } // --- Example using an incorrect tag --- { let mut bad_tag = tag; bad_tag[0] ^= 1; // Corrupt the tag let cipher_bad = ChaCha20Poly1305::new(&key); let mut decrypted_plaintext_bad_tag = ciphertext.clone(); let decrypted_result_bad_tag = cipher_bad.decrypt_in_place_detached( &nonce, b"", &mut decrypted_plaintext_bad_tag, &bad_tag, ); match decrypted_result_bad_tag { Ok(_) => { println!( "Decryption with bad tag succeeded (this should not happen!)" ); } Err(e) => { println!("Decryption with bad tag failed as expected: {}", e); // This is the expected behavior } } } // Fill all sensitive fields with zeroes plaintext.zeroize(); key.zeroize(); nonce.zeroize(); ciphertext.zeroize(); } // --- Example with associated data (AAD) --- fn aad() { let mut plaintext = Vec::from(b"This is a secret message."); let aad = b"Associated Data"; // Create an instance of the cipher (with a new key) let mut key = ChaCha20Poly1305::generate_key(&mut OsRng); let cipher_aad = ChaCha20Poly1305::new(&key); let mut nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng); let mut ciphertext_aad = plaintext.to_vec(); let tag_aad = cipher_aad .encrypt_in_place_detached(&nonce, aad, &mut ciphertext_aad) .unwrap(); println!("Ciphertext with AAD: {:x?}", ciphertext_aad); println!("Tag with AAD: {:x?}", tag_aad); let mut decrypted_plaintext_aad = ciphertext_aad.clone(); let decrypted_result_aad = cipher_aad.decrypt_in_place_detached( &nonce, aad, &mut decrypted_plaintext_aad, &tag_aad, ); match decrypted_result_aad { Ok(_) => { println!( "Decrypted plaintext with AAD: {}", String::from_utf8_lossy(&decrypted_plaintext_aad) ); } Err(e) => { eprintln!("Decryption error with AAD: {}", e); } } plaintext.zeroize(); key.zeroize(); nonce.zeroize(); ciphertext_aad.zeroize(); } fn main() { encrypt_then_decrypt(); aad(); }