use ring::aead;
#[allow(dead_code)]
pub mod transform_kind {
pub const NONE: u8 = 0x00;
pub const AES128_GMAC: u8 = 0x01;
pub const AES128_GCM: u8 = 0x02;
pub const AES256_GMAC: u8 = 0x03;
pub const AES256_GCM: u8 = 0x04;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Suite {
Aes128Gcm,
Aes256Gcm,
HmacSha256,
}
impl Suite {
#[must_use]
pub const fn key_len(self) -> usize {
match self {
Self::Aes128Gcm => 16,
Self::Aes256Gcm | Self::HmacSha256 => 32,
}
}
#[must_use]
pub(crate) fn algorithm(self) -> Option<&'static aead::Algorithm> {
match self {
Self::Aes128Gcm => Some(&aead::AES_128_GCM),
Self::Aes256Gcm => Some(&aead::AES_256_GCM),
Self::HmacSha256 => None,
}
}
#[must_use]
pub const fn is_aead(self) -> bool {
matches!(self, Self::Aes128Gcm | Self::Aes256Gcm)
}
#[must_use]
pub fn transform_kind_id(self) -> u8 {
match self {
Self::Aes128Gcm => transform_kind::AES128_GCM, Self::Aes256Gcm => transform_kind::AES256_GCM, Self::HmacSha256 => transform_kind::AES128_GMAC, }
}
#[must_use]
pub fn transform_kind(self) -> [u8; 4] {
[0, 0, 0, self.transform_kind_id()]
}
#[must_use]
pub fn from_transform_kind_id(id: u8) -> Option<Self> {
match id {
transform_kind::AES128_GMAC => Some(Self::HmacSha256),
transform_kind::AES128_GCM => Some(Self::Aes128Gcm),
transform_kind::AES256_GCM => Some(Self::Aes256Gcm),
_ => None,
}
}
#[must_use]
pub const fn max_encrypts(self) -> u64 {
1u64 << 48
}
}
impl Default for Suite {
fn default() -> Self {
Self::Aes128Gcm
}
}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::unwrap_used)]
mod tests {
use super::*;
#[test]
fn spec_constants_match_table_79() {
assert_eq!(transform_kind::NONE, 0x00);
assert_eq!(transform_kind::AES128_GMAC, 0x01);
assert_eq!(transform_kind::AES128_GCM, 0x02);
assert_eq!(transform_kind::AES256_GMAC, 0x03);
assert_eq!(transform_kind::AES256_GCM, 0x04);
}
#[test]
fn aes128_gcm_uses_spec_id_2() {
assert_eq!(Suite::Aes128Gcm.transform_kind_id(), 0x02);
assert_eq!(Suite::Aes128Gcm.transform_kind(), [0, 0, 0, 0x02]);
}
#[test]
fn aes256_gcm_uses_spec_id_4() {
assert_eq!(Suite::Aes256Gcm.transform_kind_id(), 0x04);
assert_eq!(Suite::Aes256Gcm.transform_kind(), [0, 0, 0, 0x04]);
}
#[test]
fn hmac_sha256_uses_aes128_gmac_slot() {
assert_eq!(Suite::HmacSha256.transform_kind_id(), 0x01);
}
#[test]
fn from_id_roundtrip_for_all_supported() {
assert_eq!(Suite::from_transform_kind_id(0x01), Some(Suite::HmacSha256));
assert_eq!(Suite::from_transform_kind_id(0x02), Some(Suite::Aes128Gcm));
assert_eq!(Suite::from_transform_kind_id(0x04), Some(Suite::Aes256Gcm));
}
#[test]
fn from_id_rejects_unsupported() {
assert!(Suite::from_transform_kind_id(0x00).is_none());
assert!(Suite::from_transform_kind_id(0x03).is_none());
assert!(Suite::from_transform_kind_id(0x99).is_none());
}
#[test]
fn each_suite_roundtrips_id() {
for s in [Suite::Aes128Gcm, Suite::Aes256Gcm, Suite::HmacSha256] {
let id = s.transform_kind_id();
assert_eq!(Suite::from_transform_kind_id(id), Some(s));
}
}
}