evidence 0.1.0

Type-level tags for cryptographic primitives
Documentation
//! AES-GCM encryption implementation.

use alloc::vec::Vec;

use super::EncryptionPrimitive;
use aes_gcm::aead::{Aead, AeadCore, KeyInit, OsRng};
use hybrid_array::{Array, typenum::U12};

/// AES-256-GCM AEAD primitive (256-bit key, 96-bit nonce).
#[derive(Debug, Clone, Copy)]
pub enum Aes256Gcm {}

#[allow(clippy::expect_used)] // AEAD encrypt is infallible; nonce size is type-level guaranteed
impl EncryptionPrimitive for Aes256Gcm {
    type Key = aes_gcm::Key<aes_gcm::Aes256Gcm>;
    type NonceSize = U12;
    type Error = aes_gcm::Error;

    fn encrypt(key: &Self::Key, plaintext: &[u8]) -> (Vec<u8>, Array<u8, Self::NonceSize>) {
        let cipher = aes_gcm::Aes256Gcm::new(key);
        let nonce = aes_gcm::Aes256Gcm::generate_nonce(&mut OsRng);
        let ciphertext = cipher
            .encrypt(&nonce, plaintext)
            .expect("encryption should not fail");

        let nonce_array = Array::try_from(nonce.as_slice()).expect("nonce size matches NonceSize");
        (ciphertext, nonce_array)
    }

    fn encrypt_with_nonce(
        key: &Self::Key,
        nonce: &Array<u8, Self::NonceSize>,
        plaintext: &[u8],
    ) -> Vec<u8> {
        let cipher = aes_gcm::Aes256Gcm::new(key);
        let nonce = aes_gcm::Nonce::from_slice(nonce.as_slice());
        cipher
            .encrypt(nonce, plaintext)
            .expect("encryption should not fail")
    }

    fn decrypt(
        key: &Self::Key,
        nonce: &Array<u8, Self::NonceSize>,
        ciphertext: &[u8],
    ) -> Result<Vec<u8>, Self::Error> {
        let cipher = aes_gcm::Aes256Gcm::new(key);
        let nonce = aes_gcm::Nonce::from_slice(nonce.as_slice());
        cipher.decrypt(nonce, ciphertext)
    }
}

/// AES-128-GCM AEAD primitive (128-bit key, 96-bit nonce).
#[derive(Debug, Clone, Copy)]
pub enum Aes128Gcm {}

#[allow(clippy::expect_used)] // AEAD encrypt is infallible; nonce size is type-level guaranteed
impl EncryptionPrimitive for Aes128Gcm {
    type Key = aes_gcm::Key<aes_gcm::Aes128Gcm>;
    type NonceSize = U12;
    type Error = aes_gcm::Error;

    fn encrypt(key: &Self::Key, plaintext: &[u8]) -> (Vec<u8>, Array<u8, Self::NonceSize>) {
        let cipher = aes_gcm::Aes128Gcm::new(key);
        let nonce = aes_gcm::Aes128Gcm::generate_nonce(&mut OsRng);
        let ciphertext = cipher
            .encrypt(&nonce, plaintext)
            .expect("encryption should not fail");

        let nonce_array = Array::try_from(nonce.as_slice()).expect("nonce size matches NonceSize");
        (ciphertext, nonce_array)
    }

    fn encrypt_with_nonce(
        key: &Self::Key,
        nonce: &Array<u8, Self::NonceSize>,
        plaintext: &[u8],
    ) -> Vec<u8> {
        let cipher = aes_gcm::Aes128Gcm::new(key);
        let nonce = aes_gcm::Nonce::from_slice(nonce.as_slice());
        cipher
            .encrypt(nonce, plaintext)
            .expect("encryption should not fail")
    }

    fn decrypt(
        key: &Self::Key,
        nonce: &Array<u8, Self::NonceSize>,
        ciphertext: &[u8],
    ) -> Result<Vec<u8>, Self::Error> {
        let cipher = aes_gcm::Aes128Gcm::new(key);
        let nonce = aes_gcm::Nonce::from_slice(nonce.as_slice());
        cipher.decrypt(nonce, ciphertext)
    }
}