wolf_crypto/
lib.rs

1//! Safe bindings to wolfSSL's `wolfcrypt`
2//!
3//! This crate provides a well-tested, type-safe, zero-cost interface for wolfSSL's software
4//! cryptographic module `wolfcrypt`. It leverages Rust's type system to ensure correct usage
5//! of cryptographic primitives at compile-time.
6//!
7//! # Safety
8//!
9//! This crate uses Rust's type system and ownership model to prevent common cryptographic
10//! mistakes. However, this library cannot ensure you use the provided cryptographic primitives
11//! correctly in the broader context of your application to ensure overall security.
12//!
13//! # Performance
14//!
15//! The bindings are designed to be zero-cost, allowing direct use of the highly optimized
16//! `wolfcrypt` implementations without additional runtime overhead.
17//!
18//! The majority of the future performance improvements will be in enabling further hardware
19//! acceleration in the underlying `wolf-crypto-sys` crate.
20//!
21//! # Stability
22//!
23//! This library is currently in alpha. As such, there is no guarantee of API stability
24//! across any update. This crate follows semantic versioning.
25
26#![cfg_attr(docsrs, feature(doc_cfg))]
27#![cfg_attr(not(any(test, feature = "std")), no_std)]
28#![warn(
29    clippy::pedantic,
30    clippy::nursery,
31    clippy::all
32)]
33// requirements for lower level things, these are all checked, just not checked in the unsafe
34// api.
35#![allow(clippy::cast_possible_truncation)]
36// stupid lint IMO
37#![allow(clippy::module_name_repetitions)]
38// always checked in safe api
39#![allow(clippy::cast_possible_wrap)]
40#![allow(clippy::cast_lossless)]
41// this devalues things which actually require the must-use attribute
42#![allow(clippy::must_use_candidate)]
43// I am passing something which is 32 bits, so either half the size (more frequently) or the same
44// size as the reference. This lint needs to be more context aware as this is just bad.
45#![allow(clippy::needless_pass_by_value)]
46// I don't care for the assertion in my panic API where I am checking if OK. This is just for
47// more controlled error messages. Again, should be disabled
48#![allow(clippy::manual_assert)]
49// I don't need a linter lecturing me on performance
50#![allow(clippy::inline_always)]
51// I am doing constant time bitwise hacks
52#![allow(clippy::cast_sign_loss)]
53// for debug assertions
54#![allow(clippy::used_underscore_binding)]
55// why does clippy not look at the difference in size between variants or, just the impact
56// one variant has on the total size? Like this lint is somewhat aimed at performance optimization,
57// yet where it is giving me these warnings the size of Ok and Err are equivalent.
58#![allow(clippy::result_large_err)]
59// I may just want to be cautious.
60#![allow(clippy::redundant_pub_crate)]
61#![allow(clippy::similar_names)]
62
63#![warn(missing_docs)]
64
65#[cfg(any(test, feature = "alloc"))]
66extern crate alloc;
67
68#[cfg(test)]
69extern crate std;
70
71extern crate core;
72
73#[macro_use]
74mod macros;
75
76mod ptr;
77pub mod buf;
78pub mod opaque_res;
79mod sealed;
80
81// TODO: FURTHER TESTING.
82// pub mod random;
83pub mod aes;
84pub mod hash;
85mod error;
86
87non_fips! { // unfortunate
88    pub mod chacha;
89}
90
91pub mod aead;
92pub mod mac;
93pub(crate) mod ct;
94pub mod kdf;
95
96pub use ct::ct_eq;
97
98pub mod hex {
99    //! Constant-Time Hex Encoding and Decoding
100
101    pub use super::ct::HexError;
102
103    pub use super::ct::hex_encode as encode_into;
104    pub use super::ct::hex_encode_str as encode_str;
105    pub use super::ct::hex_decode as decode_into;
106
107    alloc! {
108        pub use super::ct::hex_encode_alloc as encode;
109        pub use super::ct::hex_decode_alloc as decode;
110    }
111}
112
113pub use error::Unspecified;
114pub use error::MakeOpaque;
115
116#[cfg(not(target_pointer_width = "32"))]
117#[inline]
118#[must_use]
119pub(crate) const fn const_can_cast_u32<const S: usize>() -> bool {
120    const_lte::<S, { u32::MAX }>()
121}
122
123#[cfg(not(target_pointer_width = "32"))]
124#[inline]
125#[must_use]
126pub(crate) const fn can_cast_u32(len: usize) -> bool {
127    len <= (u32::MAX as usize)
128}
129
130#[cfg(target_pointer_width = "32")]
131#[inline]
132#[must_use]
133pub(crate) const fn const_can_cast_u32<const S: usize>() -> bool {
134    true
135}
136
137#[cfg(target_pointer_width = "32")]
138#[inline]
139#[must_use]
140pub(crate) const fn can_cast_u32(_len: usize) -> bool {
141    true
142}
143
144#[inline]
145#[must_use]
146pub(crate) const fn const_can_cast_i32<const S: usize>() -> bool {
147    const_lte::<S, { i32::MAX as u32 }>()
148}
149
150#[inline]
151#[must_use]
152pub(crate) const fn can_cast_i32(len: usize) -> bool {
153    len <= (i32::MAX as usize)
154}
155
156#[must_use]
157pub(crate) const fn const_lte<const L: usize, const MAX: u32>() -> bool {
158    L <= (MAX as usize)
159}
160
161#[cfg_attr(not(feature = "allow-non-fips"), allow(dead_code))]
162#[must_use]
163pub(crate) const fn const_gte<const L: usize, const MIN: usize>() -> bool {
164    L >= MIN
165}
166
167#[allow(dead_code)]
168#[inline]
169#[must_use]
170pub(crate) const fn lte<const MAX: usize>(value: usize) -> bool {
171    value <= MAX
172}
173
174#[cfg_attr(not(feature = "allow-non-fips"), allow(dead_code))]
175#[inline]
176#[must_use]
177pub(crate) const fn gte<const MIN: usize>(value: usize) -> bool {
178    value >= MIN
179}
180
181#[cfg(not(target_pointer_width = "32"))]
182#[inline]
183#[must_use]
184pub(crate) const fn to_u32(num: usize) -> Option<u32> {
185    if can_cast_u32(num) {
186        Some(num as u32)
187    } else {
188        None
189    }
190}
191
192#[cfg(target_pointer_width = "32")]
193#[inline]
194#[must_use]
195pub(crate) const fn to_u32(num: usize) -> Option<u32> {
196    Some(num as u32)
197}
198
199/// Marker Trait for Algorithms and Configurations which are FIPS compliant.
200pub trait Fips: sealed::FipsSealed {}
201
202/// Ensure the Provided Type is in FIPS scope.
203///
204/// This is a simple no-op, allowing to guard against non-fips compliant algorithms and
205/// configurations at compilation time.
206///
207/// # Example
208///
209/// ```
210/// use wolf_crypto::mac::hmac::{Hmac, Sha256, algo::Hash};
211/// use wolf_crypto::ensure_fips;
212///
213/// macro_rules! fips_hmac {
214///     ($algo:ty, $($key:tt)*) => {{
215///         ensure_fips::<Hmac<$algo>>();
216///         Hmac::<$algo>::new($($key)*)
217///     }}
218/// }
219///
220/// let mut mac = fips_hmac!(Sha256, [42; 32]);
221/// ```
222///
223/// ```compile_fail
224/// # use wolf_crypto::mac::hmac::{Hmac, Md5, algo::Hash};
225/// # use wolf_crypto::ensure_fips;
226/// #
227/// # macro_rules! fips_hmac {
228/// #     ($algo:ty, $($key:tt)*) => {{
229/// #         ensure_fips::<Hmac<$algo>>();
230/// #         Hmac::<$algo>::new($($key)*)
231/// #     }}
232/// # }
233/// let mut mac = fips_hmac!(Md5, [42; 16]); // does not compile!
234/// ```
235pub const fn ensure_fips<F: Fips>() {}