Skip to main content

crypto/
crypto.rs

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