citadel_types/crypto/
mod.rs

1//! # Cryptographic Types and Utilities
2//!
3//! This module provides core cryptographic types and utilities for the Citadel Protocol,
4//! including secure memory management, algorithm selection, and parameter configuration.
5//!
6//! ## Key Components
7//!
8//! ### Secure Memory Management
9//!
10//! The module provides `SecBuffer` for secure handling of sensitive data:
11//!
12//! ```rust
13//! use citadel_types::crypto::SecBuffer;
14//!
15//! // Create a secure buffer
16//! let mut buffer = SecBuffer::empty();
17//!
18//! // Work with the buffer securely
19//! {
20//!     let mut handle = buffer.handle();
21//!     handle.extend_from_slice(b"sensitive data");
22//! } // Memory is locked when handle is dropped
23//! ```
24//!
25//! ### Cryptographic Parameters
26//!
27//! Configure cryptographic algorithms and security levels:
28//!
29//! ```rust
30//! use citadel_types::crypto::{KemAlgorithm, EncryptionAlgorithm, SecurityLevel};
31//!
32//! // Create parameters
33//! let params = KemAlgorithm::Kyber
34//!     + EncryptionAlgorithm::ChaCha20Poly_1305;
35//!
36//! // Set security level
37//! let level = SecurityLevel::High;
38//! ```
39//!
40//! ### Algorithm Selection
41//!
42//! Supported algorithms include:
43//!
44//! - KEM (Key Encapsulation Mechanism)
45//!   - Kyber (1024)
46//! - Encryption
47//!   - ChaCha20-Poly1305
48//!   - AES-GCM
49//!   - Ascon
50//! - Signatures
51//!   - Falcon
52//!
53//! ## Security Considerations
54//!
55//! - All sensitive data should be stored in `SecBuffer`
56//! - Use appropriate security levels for your use case
57//! - Consider perfect secrecy mode for maximum security
58//! - Properly handle algorithm selection based on requirements
59
60use crate::utils;
61use crate::utils::validate_crypto_params;
62use bytes::{Bytes, BytesMut};
63use packed_struct::derive::{PackedStruct, PrimitiveEnum_u8};
64use packed_struct::{PackedStruct, PrimitiveEnum};
65use serde::{Deserialize, Deserializer, Serialize, Serializer};
66use std::fmt::{Debug, Formatter};
67use std::ops::{Add, Deref, DerefMut};
68use strum::{EnumCount, ParseError};
69use uuid::Uuid;
70
71pub const LARGEST_NONCE_LEN: usize = KYBER_NONCE_LENGTH_BYTES;
72
73pub const CHA_CHA_NONCE_LENGTH_BYTES: usize = 12;
74pub const ASCON_NONCE_LENGTH_BYTES: usize = 16;
75pub const AES_GCM_NONCE_LENGTH_BYTES: usize = 12;
76pub const KYBER_NONCE_LENGTH_BYTES: usize = 32;
77
78pub const KEM_ALGORITHM_COUNT: u8 = KemAlgorithm::COUNT as u8;
79
80impl From<CryptoParameters> for u8 {
81    fn from(val: CryptoParameters) -> Self {
82        let bytes: [u8; 1] = val.pack().unwrap();
83        bytes[0]
84    }
85}
86
87pub trait AlgorithmsExt:
88    strum::IntoEnumIterator + for<'a> TryFrom<&'a str> + Debug + PrimitiveEnum<Primitive = u8>
89{
90    fn list() -> Vec<Self> {
91        Self::iter().collect()
92    }
93
94    fn try_from_str<R: AsRef<str>>(t: R) -> Result<Self, ParseError> {
95        Self::try_from(t.as_ref()).map_err(|_| ParseError::VariantNotFound)
96    }
97
98    fn names() -> Vec<String> {
99        Self::iter()
100            .map(|r| format!("{r:?}").to_lowercase())
101            .collect()
102    }
103
104    fn from_u8(input: u8) -> Option<Self> {
105        Self::from_primitive(input)
106    }
107
108    fn as_u8(&self) -> u8 {
109        self.to_primitive()
110    }
111
112    fn set_crypto_param(&self, params: &mut CryptoParameters);
113}
114
115pub fn add_inner<L: AlgorithmsExt, R: AlgorithmsExt>(lhs: L, rhs: R) -> CryptoParameters {
116    let mut ret = CryptoParameters::default();
117    lhs.set_crypto_param(&mut ret);
118    rhs.set_crypto_param(&mut ret);
119    ret
120}
121
122#[derive(Copy, Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Default)]
123pub enum SecrecyMode {
124    /// Slowest, but ensures each packet gets encrypted with a unique symmetrical key
125    Perfect,
126    /// Fastest. Meant for high-throughput environments. Each message will attempt to get re-keyed, but if not possible, will use the most recent symmetrical key
127    #[default]
128    BestEffort,
129}
130
131impl TryFrom<u8> for SecrecyMode {
132    type Error = crate::errors::Error;
133
134    fn try_from(value: u8) -> Result<Self, Self::Error> {
135        match value {
136            0 => Ok(Self::Perfect),
137            1 => Ok(Self::BestEffort),
138            _ => Err(Self::Error::Other(format!(
139                "Cannot cast `{}` into SecrecyMode",
140                value
141            ))),
142        }
143    }
144}
145
146/// A memory-secure wrapper for shipping around Bytes
147pub struct SecBuffer {
148    pub inner: BytesMut,
149}
150
151impl SecBuffer {
152    /// Creates an unlocked, empty buffer
153    pub fn empty() -> Self {
154        Self::with_capacity(0)
155    }
156
157    pub fn with_capacity(cap: usize) -> Self {
158        Self::from(BytesMut::with_capacity(cap))
159    }
160
161    /// Returns the inner element without dropping the memory
162    pub fn into_buffer(mut self) -> BytesMut {
163        self.unlock();
164        std::mem::take(&mut self.inner)
165    }
166
167    /// For accessing the inner element
168    pub fn handle(&mut self) -> SecureBufMutHandle {
169        SecureBufMutHandle::new(self)
170    }
171
172    /// returns the length of the buffer
173    pub fn len(&self) -> usize {
174        self.inner.len()
175    }
176
177    fn lock(&self) {
178        unsafe { utils::mem::mlock(self.slice().as_ptr(), self.inner.len()) }
179    }
180
181    fn unlock(&self) {
182        unsafe { utils::mem::munlock(self.slice().as_ptr(), self.inner.len()) }
183    }
184
185    fn zeroize(&mut self) {
186        unsafe { utils::mem::zeroize(self.slice().as_ptr(), self.inner.len()) }
187    }
188
189    fn slice(&self) -> &[u8] {
190        &self.inner[..]
191    }
192
193    pub fn reserve(&mut self, additional: usize) {
194        self.inner.reserve(additional)
195    }
196
197    pub fn is_empty(&self) -> bool {
198        self.len() == 0
199    }
200}
201
202pub struct SecureBufMutHandle<'a> {
203    inner: &'a mut SecBuffer,
204}
205
206impl<'a> SecureBufMutHandle<'a> {
207    fn new(inner: &'a mut SecBuffer) -> SecureBufMutHandle<'a> {
208        inner.unlock();
209        Self { inner }
210    }
211}
212
213impl Deref for SecureBufMutHandle<'_> {
214    type Target = BytesMut;
215
216    fn deref(&self) -> &Self::Target {
217        &self.inner.inner
218    }
219}
220
221impl DerefMut for SecureBufMutHandle<'_> {
222    fn deref_mut(&mut self) -> &mut Self::Target {
223        &mut self.inner.inner
224    }
225}
226
227impl Drop for SecureBufMutHandle<'_> {
228    fn drop(&mut self) {
229        self.inner.lock()
230    }
231}
232
233impl AsRef<[u8]> for SecBuffer {
234    fn as_ref(&self) -> &[u8] {
235        &self.inner[..]
236    }
237}
238
239impl AsMut<[u8]> for SecBuffer {
240    fn as_mut(&mut self) -> &mut [u8] {
241        self.inner.as_mut()
242    }
243}
244
245impl From<Vec<u8>> for SecBuffer {
246    fn from(inner: Vec<u8>) -> Self {
247        Self::from(BytesMut::from(Bytes::from(inner)))
248    }
249}
250
251impl From<BytesMut> for SecBuffer {
252    fn from(inner: BytesMut) -> Self {
253        let this = Self { inner };
254        this.lock();
255        this
256    }
257}
258
259impl<const N: usize> From<[u8; N]> for SecBuffer {
260    fn from(this: [u8; N]) -> Self {
261        Self::from(&this as &[u8])
262    }
263}
264
265impl From<&[u8]> for SecBuffer {
266    fn from(this: &[u8]) -> Self {
267        Self::from(BytesMut::from(this))
268    }
269}
270
271impl From<&str> for SecBuffer {
272    fn from(this: &str) -> Self {
273        Self::from(BytesMut::from(this))
274    }
275}
276
277impl Drop for SecBuffer {
278    fn drop(&mut self) {
279        self.unlock();
280        self.zeroize();
281    }
282}
283
284impl Debug for SecBuffer {
285    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
286        write!(f, "***SECRET***")
287    }
288}
289
290impl<T: AsRef<[u8]>> PartialEq<T> for SecBuffer {
291    fn eq(&self, other: &T) -> bool {
292        // Constant time comparison to prevent timing attacks
293        let this = self.as_ref();
294        let other = other.as_ref();
295        utils::const_time_compare(this, other)
296    }
297}
298
299impl Clone for SecBuffer {
300    fn clone(&self) -> Self {
301        self.unlock();
302        let ret = SecBuffer::from(self.inner.clone());
303        self.lock();
304        ret
305    }
306}
307
308impl Serialize for SecBuffer {
309    fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
310    where
311        S: Serializer,
312    {
313        self.unlock();
314        let ret = self.inner.serialize(serializer);
315        self.lock();
316        ret
317    }
318}
319
320impl<'de> Deserialize<'de> for SecBuffer {
321    fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
322    where
323        D: Deserializer<'de>,
324    {
325        Ok(Self::from(BytesMut::deserialize(deserializer)?))
326    }
327}
328
329impl SecurityLevel {
330    /// Returns byte representation of self
331    pub fn value(self) -> u8 {
332        match self {
333            SecurityLevel::Standard => 0,
334            SecurityLevel::Reinforced => 1,
335            SecurityLevel::High => 2,
336            SecurityLevel::Ultra => 3,
337            SecurityLevel::Extreme => 4,
338            SecurityLevel::Custom(val) => val,
339        }
340    }
341
342    /// Possibly returns the security_level given an input value
343    pub fn for_value(val: usize) -> Option<Self> {
344        Some(SecurityLevel::from(u8::try_from(val).ok()?))
345    }
346}
347
348#[derive(PackedStruct, Default, Serialize, Deserialize, Copy, Clone, Debug)]
349#[packed_struct(bit_numbering = "msb0")]
350pub struct CryptoParameters {
351    #[packed_field(bits = "0..=2", ty = "enum")]
352    pub encryption_algorithm: EncryptionAlgorithm,
353    #[packed_field(bits = "3..=5", ty = "enum")]
354    pub kem_algorithm: KemAlgorithm,
355    #[packed_field(bits = "6..=7", ty = "enum")]
356    pub sig_algorithm: SigAlgorithm,
357}
358
359impl TryFrom<u8> for CryptoParameters {
360    type Error = crate::errors::Error;
361
362    fn try_from(value: u8) -> Result<Self, Self::Error> {
363        let value: [u8; 1] = [value];
364        let this: CryptoParameters = CryptoParameters::unpack(&value)
365            .map_err(|err| crate::errors::Error::Other(err.to_string()))?;
366        validate_crypto_params(&this)?;
367        Ok(this)
368    }
369}
370
371#[derive(
372    PrimitiveEnum_u8,
373    Default,
374    Copy,
375    Clone,
376    Debug,
377    Eq,
378    PartialEq,
379    Serialize,
380    Deserialize,
381    strum::EnumString,
382    strum::EnumIter,
383)]
384pub enum EncryptionAlgorithm {
385    #[default]
386    AES_GCM_256 = 0,
387    ChaCha20Poly_1305 = 1,
388    Kyber = 2,
389    Ascon80pq = 3,
390}
391
392#[derive(
393    PrimitiveEnum_u8,
394    Default,
395    Copy,
396    Clone,
397    Debug,
398    Eq,
399    PartialEq,
400    Serialize,
401    Deserialize,
402    strum::EnumString,
403    strum::EnumIter,
404    strum::EnumCount,
405)]
406pub enum KemAlgorithm {
407    #[strum(ascii_case_insensitive)]
408    #[default]
409    Kyber = 0,
410}
411
412#[derive(
413    PrimitiveEnum_u8,
414    strum::EnumString,
415    strum::EnumIter,
416    Default,
417    Serialize,
418    Deserialize,
419    Copy,
420    Clone,
421    Debug,
422    Eq,
423    PartialEq,
424)]
425pub enum SigAlgorithm {
426    #[default]
427    None = 0,
428    Falcon1024 = 1,
429}
430
431impl AlgorithmsExt for KemAlgorithm {
432    fn set_crypto_param(&self, params: &mut CryptoParameters) {
433        params.kem_algorithm = *self;
434    }
435}
436
437impl AlgorithmsExt for EncryptionAlgorithm {
438    fn set_crypto_param(&self, params: &mut CryptoParameters) {
439        params.encryption_algorithm = *self;
440    }
441}
442
443impl AlgorithmsExt for SigAlgorithm {
444    fn set_crypto_param(&self, params: &mut CryptoParameters) {
445        params.sig_algorithm = *self;
446    }
447}
448
449impl<R: AlgorithmsExt> Add<R> for KemAlgorithm {
450    type Output = CryptoParameters;
451
452    fn add(self, rhs: R) -> Self::Output {
453        add_inner(self, rhs)
454    }
455}
456
457impl<R: AlgorithmsExt> Add<R> for EncryptionAlgorithm {
458    type Output = CryptoParameters;
459
460    fn add(self, rhs: R) -> Self::Output {
461        add_inner(self, rhs)
462    }
463}
464
465impl<R: AlgorithmsExt> Add<R> for SigAlgorithm {
466    type Output = CryptoParameters;
467
468    fn add(self, rhs: R) -> Self::Output {
469        add_inner(self, rhs)
470    }
471}
472
473impl<R: AlgorithmsExt> Add<R> for CryptoParameters {
474    type Output = CryptoParameters;
475
476    fn add(mut self, rhs: R) -> Self::Output {
477        rhs.set_crypto_param(&mut self);
478        self
479    }
480}
481
482impl<T: AlgorithmsExt> From<T> for CryptoParameters {
483    fn from(this: T) -> Self {
484        let mut ret = CryptoParameters::default();
485        this.set_crypto_param(&mut ret);
486        ret
487    }
488}
489
490/// Provides the enumeration for all security levels
491#[derive(Serialize, Deserialize, Copy, Clone, Debug, Default)]
492pub enum SecurityLevel {
493    #[default]
494    Standard,
495    Reinforced,
496    High,
497    Ultra,
498    Extreme,
499    Custom(u8),
500}
501
502impl From<u8> for SecurityLevel {
503    fn from(val: u8) -> Self {
504        match val {
505            0 => SecurityLevel::Standard,
506            1 => SecurityLevel::Reinforced,
507            2 => SecurityLevel::High,
508            3 => SecurityLevel::Ultra,
509            4 => SecurityLevel::Extreme,
510            n => SecurityLevel::Custom(n),
511        }
512    }
513}
514
515#[derive(Serialize, Deserialize, Copy, Clone, Debug, Default)]
516pub enum HeaderObfuscatorSettings {
517    /// Enables header obfuscation to help mitigate some deep packet inspection techniques using a pseudorandom key
518    Enabled,
519    #[default]
520    /// Disables header obfuscation (default)
521    Disabled,
522    /// Enables header obfuscation with a specific key. This value must be symmetric between both endpoints, otherwise the obfuscation will fail
523    EnabledWithKey(u128),
524}
525
526impl From<u128> for HeaderObfuscatorSettings {
527    fn from(val: u128) -> Self {
528        HeaderObfuscatorSettings::EnabledWithKey(val)
529    }
530}
531
532impl From<bool> for HeaderObfuscatorSettings {
533    fn from(value: bool) -> Self {
534        if value {
535            HeaderObfuscatorSettings::Enabled
536        } else {
537            HeaderObfuscatorSettings::Disabled
538        }
539    }
540}
541
542impl From<Uuid> for HeaderObfuscatorSettings {
543    fn from(value: Uuid) -> Self {
544        HeaderObfuscatorSettings::EnabledWithKey(value.as_u128())
545    }
546}
547
548#[cfg(test)]
549mod test {
550    use crate::crypto::SecBuffer;
551
552    #[test]
553    fn test_secbuffer_cmp_same() {
554        let a = SecBuffer::from("Hello");
555        let b = SecBuffer::from("Hello");
556        assert_eq!(a, b);
557    }
558
559    #[test]
560    fn test_secbuffer_cmp_diff() {
561        let a = SecBuffer::from("Hello");
562        let b = SecBuffer::from("World");
563        assert_ne!(a, b);
564    }
565
566    #[test]
567    fn test_secbuffer_cmp_diff2() {
568        let a = SecBuffer::from("Hello");
569        let b = SecBuffer::from("World................");
570        assert_ne!(a, b);
571    }
572
573    #[test]
574    fn test_secbuffer_cmp_diff3() {
575        let a = SecBuffer::from("Hello................");
576        let b = SecBuffer::from("World");
577        assert_ne!(a, b);
578    }
579}