Encrypt with AEAD

RecipeCratesCategories
aes-gcm-sivaes-gcm-siv aes-gcmcat-cryptography
aes-gcmaes-gcmcat-cryptography
ChaCha20Poly1305chacha20poly1305cat-cryptography

"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 aes-gcm-siv-crates.io aes-gcm-siv-github aes-gcm-siv-lib.rs cat-cryptography cat-no-std

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 aes-gcm-crates.io aes-gcm-github aes-gcm-lib.rs cat-cryptography cat-no-std

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-website chacha20poly1305 chacha20poly1305-crates.io chacha20poly1305-github chacha20poly1305-lib.rs cat-cryptography cat-no-std

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.