Skip to main content

crypto/
crypto.rs

1//! Pure Rust cryptography with `no_std` support and hardware / SIMD acceleration
2//! for `x86_64` and `aarch64` (and sometimes WASM).
3//!
4//! # ⚠️ Warning
5//!
6//! This crate has **not** undergone a third-party security audit or formal
7//! cryptographic review yet. Use at your own risk.
8
9#[cfg(feature = "alloc")]
10extern crate alloc;
11
12#[cfg(feature = "alloc")]
13use alloc::vec::Vec;
14
15pub mod aes;
16#[cfg(feature = "alloc")]
17pub mod argon2;
18pub mod blake2;
19pub mod chacha;
20pub mod curve25519;
21pub mod hkdf;
22pub mod hmac;
23pub mod mldsa;
24pub mod mlkem;
25pub mod poly1305;
26pub mod sha2;
27pub mod sha3;
28pub mod xwing;
29
30mod bytes;
31
32#[cfg(feature = "alloc")]
33pub mod encoding;
34pub mod p256;
35pub mod pbkdf2;
36pub use bytes::{Bytes, Hash, Tag};
37
38const MAX_HASH_BLOCK_SIZE: usize = 128;
39
40////////////////////////////////////////////////////////////////////////////////////////////////////
41/// Errors
42////////////////////////////////////////////////////////////////////////////////////////////////////
43
44// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
45// pub enum Error {
46//     Hkdf(HkdfError),
47//     Aead(AeadError),
48//     EllipticCurve(EllipticCurveError),
49// }
50
51// impl core::fmt::Display for Error {
52//     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
53//         match self {
54//             Error::Hkdf(err) => write!(f, "{err}"),
55//             Error::Aead(err) => write!(f, "{err}"),
56//             Error::EllipticCurve(err) => write!(f, "{err}"),
57//         }
58//     }
59// }
60
61// #[cfg(feature = "std")]
62// impl std::error::Error for Error {}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub enum AeadError {
66    InvalidKey,
67    InvalidNonce,
68    InvalidCiphertext,
69}
70
71impl core::fmt::Display for AeadError {
72    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
73        match self {
74            AeadError::InvalidKey => write!(f, "key is not valid"),
75            AeadError::InvalidNonce => write!(f, "nonce is not valid"),
76            AeadError::InvalidCiphertext => write!(f, "ciphertext is not valid"),
77        }
78    }
79}
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82pub enum EllipticCurveError {
83    InvalidKey,
84    Unspecified,
85    InvalidSignature,
86}
87
88impl core::fmt::Display for EllipticCurveError {
89    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
90        match self {
91            EllipticCurveError::InvalidKey => write!(f, "key is not valid"),
92            EllipticCurveError::Unspecified => write!(f, "unknown error"),
93            EllipticCurveError::InvalidSignature => write!(f, "signature is not valid"),
94        }
95    }
96}
97
98#[cfg(feature = "std")]
99impl std::error::Error for EllipticCurveError {}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq)]
102pub enum HkdfError {
103    PrkIsTooShort(usize),
104    OutputIsTooLong,
105}
106
107impl core::fmt::Display for HkdfError {
108    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
109        match self {
110            HkdfError::PrkIsTooShort(_) => write!(f, "PRK is too short"),
111            HkdfError::OutputIsTooLong => {
112                write!(f, "HKDF output length exceeds RFC 5869 limit (255 * Hash's output size)")
113            }
114        }
115    }
116}
117
118#[cfg(feature = "std")]
119impl std::error::Error for HkdfError {}
120
121////////////////////////////////////////////////////////////////////////////////////////////////////
122/// Traits
123////////////////////////////////////////////////////////////////////////////////////////////////////
124
125pub trait StreamCipher: Sized {
126    fn xor_keystream(&mut self, in_out: &mut [u8]);
127}
128
129pub trait Aead: Sized {
130    const TAG_SIZE: usize;
131    const NONCE_SIZE: usize;
132
133    fn encrypt_in_place(&self, in_out: &mut [u8], nonce: &[u8], aad: &[u8]) -> Tag;
134
135    fn decrypt_in_place(&self, in_out: &mut [u8], nonce: &[u8], aad: &[u8], tag: &[u8]) -> Result<(), AeadError>;
136
137    #[cfg(feature = "alloc")]
138    fn encrypt(&self, plaintext: &[u8], nonce: &[u8], aad: &[u8]) -> Vec<u8> {
139        let mut ciphertext = Vec::with_capacity(plaintext.len() + Self::TAG_SIZE);
140        ciphertext.extend_from_slice(plaintext);
141
142        let tag = self.encrypt_in_place(&mut ciphertext, nonce, aad);
143        ciphertext.extend_from_slice(tag.as_ref());
144
145        return ciphertext;
146    }
147
148    #[cfg(feature = "alloc")]
149    fn decrypt(&self, ciphertext: &[u8], nonce: &[u8], aad: &[u8]) -> Result<Vec<u8>, AeadError> {
150        if ciphertext.len() < Self::TAG_SIZE {
151            return Err(AeadError::InvalidCiphertext);
152        }
153
154        let plaintext_length = ciphertext.len() - Self::TAG_SIZE;
155        let mut plaintext = Vec::with_capacity(plaintext_length);
156        plaintext.extend_from_slice(&ciphertext[..plaintext_length]);
157
158        self.decrypt_in_place(&mut plaintext, &nonce, aad, &ciphertext[plaintext_length..])?;
159
160        return Ok(plaintext);
161    }
162}
163
164#[cfg(feature = "zeroize")]
165pub trait Zeroize: zeroize::Zeroize {}
166#[cfg(feature = "zeroize")]
167impl<T: zeroize::Zeroize> Zeroize for T {}
168
169#[cfg(not(feature = "zeroize"))]
170pub trait Zeroize {}
171#[cfg(not(feature = "zeroize"))]
172impl<T> Zeroize for T {}
173
174pub trait Hasher: Sized + Clone + Zeroize {
175    /// The internal block size of the hash function
176    const BLOCK_SIZE: usize;
177    /// The output size of the hash function
178    const OUTPUT_SIZE: usize;
179
180    fn new() -> Self;
181    fn update(&mut self, data: &[u8]);
182    fn sum(self) -> Hash;
183
184    #[inline]
185    fn hash(data: &[u8]) -> Hash {
186        let mut hasher = Self::new();
187        hasher.update(data);
188        return hasher.sum();
189    }
190}
191
192pub trait Xof: Sized + Send + Sync {
193    fn absorb(&mut self, data: &[u8]);
194    fn squeeze(&mut self, out: &mut [u8]);
195}