use serde::{Deserialize, Serialize};
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum CipherSuite {
#[default]
Standard2025 = 0x01,
PostQuantum2030 = 0x02,
Hybrid2028 = 0x03,
GovHighAssurance = 0x04,
LegacyRSA = 0xFF,
}
impl CipherSuite {
#[must_use]
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0x01 => Some(Self::Standard2025),
0x02 => Some(Self::PostQuantum2030),
0x03 => Some(Self::Hybrid2028),
0x04 => Some(Self::GovHighAssurance),
0xFF => Some(Self::LegacyRSA),
_ => None,
}
}
#[must_use]
pub const fn to_u8(self) -> u8 {
self as u8
}
#[must_use]
pub const fn is_secure(&self) -> bool {
!matches!(self, Self::LegacyRSA)
}
#[must_use]
pub const fn is_post_quantum(&self) -> bool {
matches!(self, Self::PostQuantum2030 | Self::Hybrid2028)
}
#[must_use]
pub const fn is_government_approved(&self) -> bool {
matches!(self, Self::GovHighAssurance)
}
#[must_use]
pub const fn is_deprecated(&self) -> bool {
matches!(self, Self::LegacyRSA)
}
#[must_use]
pub const fn signature_size(&self) -> usize {
match self {
Self::Standard2025 => 64, Self::PostQuantum2030 => 3293, Self::Hybrid2028 => 64 + 3293, Self::GovHighAssurance => 96, Self::LegacyRSA => 256, }
}
#[must_use]
pub const fn public_key_size(&self) -> usize {
match self {
Self::Standard2025 => 32, Self::PostQuantum2030 => 1952, Self::Hybrid2028 => 32 + 1952, Self::GovHighAssurance => 97, Self::LegacyRSA => 256, }
}
#[must_use]
pub const fn encryption_key_size(&self) -> usize {
match self {
Self::Standard2025
| Self::PostQuantum2030
| Self::Hybrid2028
| Self::GovHighAssurance => 32,
Self::LegacyRSA => 16, }
}
#[must_use]
pub const fn hash_size(&self) -> usize {
match self {
Self::Standard2025 | Self::PostQuantum2030 | Self::Hybrid2028 | Self::LegacyRSA => 32,
Self::GovHighAssurance => 48, }
}
#[must_use]
pub const fn name(&self) -> &'static str {
match self {
Self::Standard2025 => "Standard2025 (Ed25519 + XChaCha20)",
Self::PostQuantum2030 => "PostQuantum2030 (ML-DSA-65 + ML-KEM-768)",
Self::Hybrid2028 => "Hybrid2028 (Ed25519 + ML-DSA-65)",
Self::GovHighAssurance => "GovHighAssurance (ECDSA P-384 + AES-256)",
Self::LegacyRSA => "LegacyRSA (RSA-2048 + AES-128) [DEPRECATED]",
}
}
#[must_use]
pub const fn signature_algorithm(&self) -> &'static str {
match self {
Self::Standard2025 => "Ed25519",
Self::PostQuantum2030 => "ML-DSA-65 (Dilithium3)",
Self::Hybrid2028 => "Ed25519 + ML-DSA-65",
Self::GovHighAssurance => "ECDSA P-384",
Self::LegacyRSA => "RSA-2048-PKCS1v15",
}
}
#[must_use]
pub const fn encryption_algorithm(&self) -> &'static str {
match self {
Self::Standard2025 => "XChaCha20-Poly1305",
Self::PostQuantum2030 => "ML-KEM-768 + AES-256-GCM",
Self::Hybrid2028 => "X25519 + ML-KEM-768 + AES-256-GCM",
Self::GovHighAssurance => "AES-256-GCM",
Self::LegacyRSA => "AES-128-CBC-HMAC-SHA256",
}
}
#[must_use]
pub const fn hash_algorithm(&self) -> &'static str {
match self {
Self::Standard2025 => "BLAKE3",
Self::PostQuantum2030 | Self::Hybrid2028 => "SHA3-256",
Self::GovHighAssurance => "SHA-384",
Self::LegacyRSA => "SHA-256",
}
}
#[must_use]
pub const fn kdf_algorithm(&self) -> &'static str {
match self {
Self::Standard2025 => "Argon2id",
Self::PostQuantum2030 | Self::Hybrid2028 => "HKDF-SHA3",
Self::GovHighAssurance => "HKDF-SHA384",
Self::LegacyRSA => "PBKDF2-SHA256",
}
}
#[must_use]
pub const fn migration_target(&self) -> Option<Self> {
match self {
Self::LegacyRSA => Some(Self::Standard2025),
Self::Standard2025 => Some(Self::Hybrid2028),
Self::Hybrid2028 => Some(Self::PostQuantum2030),
Self::GovHighAssurance | Self::PostQuantum2030 => None,
}
}
#[must_use]
pub const fn security_level_bits(&self) -> u32 {
match self {
Self::Standard2025 => 128,
Self::PostQuantum2030 | Self::Hybrid2028 | Self::GovHighAssurance => 192,
Self::LegacyRSA => 112, }
}
#[must_use]
pub const fn meets_security_level(&self, min_bits: u32) -> bool {
self.security_level_bits() >= min_bits
}
#[must_use]
pub const fn all() -> &'static [Self] {
&[
Self::Standard2025,
Self::PostQuantum2030,
Self::Hybrid2028,
Self::GovHighAssurance,
Self::LegacyRSA,
]
}
#[must_use]
pub const fn recommended() -> &'static [Self] {
&[
Self::Standard2025,
Self::Hybrid2028,
Self::PostQuantum2030,
Self::GovHighAssurance,
]
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(clippy::struct_excessive_bools)] pub struct CipherCapabilities {
pub suite: CipherSuite,
pub can_sign: bool,
pub can_encrypt: bool,
pub can_derive_keys: bool,
pub has_hw_accel: bool,
}
impl CipherCapabilities {
#[must_use]
pub const fn for_suite(suite: CipherSuite) -> Self {
Self {
suite,
can_sign: true,
can_encrypt: true,
can_derive_keys: true,
has_hw_accel: matches!(
suite,
CipherSuite::Standard2025 | CipherSuite::GovHighAssurance
),
}
}
}
#[cfg(test)]
#[path = "cipher_tests.rs"]
mod tests;