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 p256;
40pub mod p384;
41pub mod pbkdf2;
42pub mod rsa;
43pub(crate) use bytes::Bytes;
44pub use bytes::Hash;
45#[cfg(feature = "random")]
46pub use random::{random_bytes, random_fill};
47
48const MAX_HASH_BLOCK_SIZE: usize = 136;
49
50////////////////////////////////////////////////////////////////////////////////////////////////////
51/// Errors
52////////////////////////////////////////////////////////////////////////////////////////////////////
53
54// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
55// pub enum Error {
56//     Hkdf(HkdfError),
57//     Aead(AeadError),
58//     EllipticCurve(EllipticCurveError),
59// }
60
61// impl core::fmt::Display for Error {
62//     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
63//         match self {
64//             Error::Hkdf(err) => write!(f, "{err}"),
65//             Error::Aead(err) => write!(f, "{err}"),
66//             Error::EllipticCurve(err) => write!(f, "{err}"),
67//         }
68//     }
69// }
70
71// #[cfg(feature = "std")]
72// impl std::error::Error for Error {}
73
74#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75pub enum AeadError {
76    InvalidKey,
77    InvalidNonce,
78    InvalidCiphertext,
79}
80
81impl core::fmt::Display for AeadError {
82    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
83        match self {
84            AeadError::InvalidKey => write!(f, "key is not valid"),
85            AeadError::InvalidNonce => write!(f, "nonce is not valid"),
86            AeadError::InvalidCiphertext => write!(f, "ciphertext is not valid"),
87        }
88    }
89}
90
91#[cfg(feature = "std")]
92impl std::error::Error for AeadError {}
93
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95pub enum EllipticCurveError {
96    InvalidKey,
97    Unspecified,
98    InvalidSignature,
99}
100
101impl core::fmt::Display for EllipticCurveError {
102    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
103        match self {
104            EllipticCurveError::InvalidKey => write!(f, "key is not valid"),
105            EllipticCurveError::Unspecified => write!(f, "unknown error"),
106            EllipticCurveError::InvalidSignature => write!(f, "signature is not valid"),
107        }
108    }
109}
110
111#[cfg(feature = "std")]
112impl std::error::Error for EllipticCurveError {}
113
114#[derive(Debug, Clone, Copy, PartialEq, Eq)]
115pub enum RsaError {
116    InvalidKey,
117    InvalidSignature,
118    NotSupported,
119    Unspecified,
120}
121
122impl core::fmt::Display for RsaError {
123    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
124        match self {
125            RsaError::InvalidKey => write!(f, "key is not valid"),
126            RsaError::InvalidSignature => write!(f, "signature is not valid"),
127            RsaError::NotSupported => write!(f, "key size not supported"),
128            RsaError::Unspecified => write!(f, "unknown error"),
129        }
130    }
131}
132
133#[cfg(feature = "std")]
134impl std::error::Error for RsaError {}
135
136#[derive(Debug, Clone, Copy, PartialEq, Eq)]
137pub enum HkdfError {
138    PrkIsTooShort(usize),
139    OutputIsTooLong,
140}
141
142impl core::fmt::Display for HkdfError {
143    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
144        match self {
145            HkdfError::PrkIsTooShort(_) => write!(f, "PRK is too short"),
146            HkdfError::OutputIsTooLong => {
147                write!(f, "HKDF output length exceeds RFC 5869 limit (255 * Hash's output size)")
148            }
149        }
150    }
151}
152
153#[cfg(feature = "std")]
154impl std::error::Error for HkdfError {}
155
156////////////////////////////////////////////////////////////////////////////////////////////////////
157/// Traits
158////////////////////////////////////////////////////////////////////////////////////////////////////
159
160pub trait StreamCipher {
161    fn xor_keystream(&mut self, in_out: &mut [u8]);
162}
163
164pub trait Aead {
165    const TAG_SIZE: usize;
166    const NONCE_SIZE: usize;
167
168    fn encrypt_in_place(&self, in_out: &mut [u8], nonce: &[u8], aad: &[u8]) -> Hash;
169
170    fn decrypt_in_place(&self, in_out: &mut [u8], nonce: &[u8], aad: &[u8], tag: &[u8]) -> Result<(), AeadError>;
171
172    #[cfg(feature = "alloc")]
173    fn encrypt(&self, plaintext: &[u8], nonce: &[u8], aad: &[u8]) -> Vec<u8> {
174        let mut ciphertext = Vec::with_capacity(plaintext.len() + Self::TAG_SIZE);
175        ciphertext.extend_from_slice(plaintext);
176
177        let tag = self.encrypt_in_place(&mut ciphertext, nonce, aad);
178        ciphertext.extend_from_slice(tag.as_ref());
179
180        return ciphertext;
181    }
182
183    #[cfg(feature = "alloc")]
184    fn decrypt(&self, ciphertext: &[u8], nonce: &[u8], aad: &[u8]) -> Result<Vec<u8>, AeadError> {
185        if ciphertext.len() < Self::TAG_SIZE {
186            return Err(AeadError::InvalidCiphertext);
187        }
188
189        let plaintext_length = ciphertext.len() - Self::TAG_SIZE;
190        let mut plaintext = Vec::with_capacity(plaintext_length);
191        plaintext.extend_from_slice(&ciphertext[..plaintext_length]);
192
193        self.decrypt_in_place(&mut plaintext, &nonce, aad, &ciphertext[plaintext_length..])?;
194
195        return Ok(plaintext);
196    }
197}
198
199#[cfg(feature = "zeroize")]
200pub trait Zeroize: zeroize::Zeroize {}
201#[cfg(feature = "zeroize")]
202impl<T: zeroize::Zeroize> Zeroize for T {}
203
204#[cfg(not(feature = "zeroize"))]
205pub trait Zeroize {}
206#[cfg(not(feature = "zeroize"))]
207impl<T> Zeroize for T {}
208
209pub trait Hasher: Clone + Zeroize {
210    /// The internal block size of the hash function
211    const BLOCK_SIZE: usize;
212    /// The output size of the hash function
213    const OUTPUT_SIZE: usize;
214
215    fn new() -> Self;
216    fn update(&mut self, data: &[u8]);
217    fn sum(self) -> Hash;
218
219    #[inline]
220    fn hash(data: &[u8]) -> Hash {
221        let mut hasher = Self::new();
222        hasher.update(data);
223        return hasher.sum();
224    }
225}
226
227pub trait Xof: Send + Sync {
228    fn absorb(&mut self, data: &[u8]);
229    fn squeeze(&mut self, out: &mut [u8]);
230}