Encrypt with AEAD

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

For more algorithms, see Rust Crypto AEADs: aes-gcm-siv, aes-gcm, chacha20poly1305

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

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

aes-gcm aes-gcm-crates.io aes-gcm-github aes-gcm-lib.rs cat-cryptography cat-no-std

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

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();
}