Encrypt with AEAD
Recipe | Crates | Categories |
---|---|---|
aes-gcm-siv | ||
aes-gcm | ||
ChaCha20Poly1305 |
"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) - see 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.
AEAD is commonly used in secure communication protocols like TLS (Transport Layer Security). See also:
aes-gcm-siv
aes-gcm-siv
⮳ is a pure Rust implementation of the AES-GCM-SIV Misuse-Resistant Authenticated Encryption Cipher (RFC 8452) with optional architecture-specific hardware acceleration.
AES-GCM-SIV (Advanced Encryption Standard - Galois/Counter Mode - Synthetic Initialization Vector) is a mode of operation for AES that provides nonce misuse resistance. This means it can securely handle situations where a cryptographic nonce (a number used only once) might be reused accidentally.
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). 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
aes-gcm
⮳ is a 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
chacha20poly1305
⮳ is a 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(); }
For more algorithms, see Rust Crypto AEADs: aes-gcm-siv, aes-gcm, chacha20poly1305.
Related Topics
- Encryption.
- Hashing.