1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
//! # Authenticated Encryption (AEAD)
//!
//! > 💡 This is a hacspec representation of the [HPKE RFC].
//! > The text is mostly verbatim from the RFC with changes where required.
//! > It demonstrates the possibilities of hacspec for specifications.
//!
//! - [`Seal(key, nonce, aad, pt)`](`AeadSeal`): Encrypt and authenticate plaintext
//! `pt` with associated data `aad` using symmetric key `key` and nonce
//! `nonce`, yielding ciphertext and tag `ct`. This function
//! can raise a [`MessageLimitReachedError`](`HpkeError::MessageLimitReachedError`) upon failure.
//! - [`Open(key, nonce, aad, ct)`](`AeadOpen`): Decrypt ciphertext and tag `ct` using
//! associated data `aad` with symmetric key `key` and nonce `nonce`,
//! returning plaintext message `pt`. This function can raise an
//! [`OpenError`](`HpkeError::OpenError`) or [`MessageLimitReachedError`](`HpkeError::MessageLimitReachedError`) upon failure.
//! - [`Nk`]: The length in bytes of a key for this algorithm.
//! - [`Nn`]: The length in bytes of a nonce for this algorithm.
//! - [`Nt`]: The length in bytes of the authentication tag for this algorithm.
//!
//! ## Security Requirements on an AEAD
//!
//! All AEADs MUST be IND-CCA2-secure, as is currently true for all AEADs
//! listed in [`AEAD`].
//!
//! [hpke rfc]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-hpke/
//! [publication queue]: https://www.rfc-editor.org/current_queue.php
#![allow(
non_camel_case_types,
non_snake_case,
unused_imports,
non_upper_case_globals
)]
#[cfg(feature = "evercrypt")]
use evercrypt_cryptolib::*;
#[cfg(not(feature = "evercrypt"))]
use hacspec_cryptolib::*;
use hacspec_lib::*;
use hpke_errors::*;
type CryptoResult = Result<ByteSeq, CryptoError>;
type AeadAlgResult = Result<AeadAlgorithm, HpkeError>;
/// ## Authenticated Encryption with Associated Data (AEAD) Functions
///
/// The `0xFFFF` AEAD ID is reserved for applications which only use the Export
/// interface; see HPKE for more details.
///
/// | Value | AEAD | Nk | Nn | Nt | Reference |
/// | :----- | :--------------- | :-- | :-- | :-- | :-------- |
/// | 0x0000 | (reserved) | N/A | N/A | N/A | N/A |
/// | 0x0001 | AES-128-GCM | 16 | 12 | 16 | [GCM] |
/// | 0x0002 | AES-256-GCM | 32 | 12 | 16 | [GCM] |
/// | 0x0003 | ChaCha20Poly1305 | 32 | 12 | 16 | [RFC8439] |
/// | 0xFFFF | Export-only | N/A | N/A | N/A | RFCXXXX |
///
/// The "HPKE AEAD Identifiers" registry lists identifiers for authenticated
/// encryption with associated data (AEAD) algorithms defined for use with HPKE.
/// These identifiers are two-byte values, so the maximum possible value is
/// 0xFFFF = 65535.
///
/// Template:
///
/// * Value: The two-byte identifier for the algorithm
/// * AEAD: The name of the algorithm
/// * Nk: The length in bytes of a key for this algorithm
/// * Nn: The length in bytes of a nonce for this algorithm
/// * Nt: The length in bytes of an authentication tag for this algorithm
/// * Reference: Where this algorithm is defined
///
/// [GCM]: https://doi.org/10.6028/nist.sp.800-38d
/// [RFC8439]: https://www.rfc-editor.org/info/rfc8439
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum AEAD {
/// 0x0001
AES_128_GCM,
/// 0x0002
AES_256_GCM,
/// 0x0003
ChaCha20Poly1305,
/// 0xFFFF
Export_only,
}
/// The length in bytes of a key for this algorithm.
///
/// See [`AEAD`] for details.
pub fn Nk(aead_id: AEAD) -> usize {
match aead_id {
AEAD::AES_128_GCM => 16,
AEAD::AES_256_GCM => 32,
AEAD::ChaCha20Poly1305 => 32,
AEAD::Export_only => 0,
}
}
/// The length in bytes of the authentication tag for this algorithm.
///
/// See [`AEAD`] for details.
pub fn Nt(aead_id: AEAD) -> usize {
match aead_id {
AEAD::AES_128_GCM => 16,
AEAD::AES_256_GCM => 16,
AEAD::ChaCha20Poly1305 => 16,
AEAD::Export_only => 0,
}
}
/// The length in bytes of a nonce for this algorithm.
///
/// See [`AEAD`] for details.
pub fn Nn(aead_id: AEAD) -> usize {
match aead_id {
AEAD::AES_128_GCM => 12,
AEAD::AES_256_GCM => 12,
AEAD::ChaCha20Poly1305 => 12,
AEAD::Export_only => 0,
}
}
/// An AEAD key is a sequence of bytes.
pub type Key = ByteSeq;
/// An AEAD nonce is a sequence of bytes.
pub type Nonce = ByteSeq;
fn alg_for_aead(aead_id: AEAD) -> AeadAlgResult {
match aead_id {
AEAD::AES_128_GCM => AeadAlgResult::Ok(AeadAlgorithm::Aes128Gcm),
AEAD::AES_256_GCM => AeadAlgResult::Ok(AeadAlgorithm::Aes256Gcm),
AEAD::ChaCha20Poly1305 => AeadAlgResult::Ok(AeadAlgorithm::Chacha20Poly1305),
AEAD::Export_only => AeadAlgResult::Err(HpkeError::UnsupportedAlgorithm),
}
}
/// Encrypt and authenticate plaintext `pt` with associated data `aad` using
/// symmetric key `key` and nonce `nonce`, yielding ciphertext and tag `ct`.
/// This function can raise a [`MessageLimitReachedError`](`HpkeError::MessageLimitReachedError`) upon failure.
pub fn AeadSeal(
aead_id: AEAD,
key: &Key,
nonce: &Nonce,
aad: &Seq<U8>,
pt: &Seq<U8>,
) -> HpkeByteSeqResult {
let algorithm = alg_for_aead(aead_id)?;
match aead_encrypt(&algorithm, key, nonce, pt, aad) {
CryptoResult::Ok(ct) => HpkeByteSeqResult::Ok(ct),
CryptoResult::Err(_) => HpkeByteSeqResult::Err(HpkeError::CryptoError),
}
}
/// Decrypt ciphertext and tag `ct` using
/// associated data `aad` with symmetric key `key` and nonce `nonce`,
/// returning plaintext message `pt`. This function can raise an
/// [`OpenError`](`HpkeError::OpenError`) or [`MessageLimitReachedError`](`HpkeError::MessageLimitReachedError`) upon failure.
pub fn AeadOpen(
aead_id: AEAD,
key: &Key,
nonce: &Nonce,
aad: &ByteSeq,
ct: &ByteSeq,
) -> HpkeByteSeqResult {
let algorithm = alg_for_aead(aead_id)?;
match aead_decrypt(&algorithm, key, nonce, ct, aad) {
CryptoResult::Ok(pt) => HpkeByteSeqResult::Ok(pt),
CryptoResult::Err(_) => HpkeByteSeqResult::Err(HpkeError::CryptoError),
}
}