dryoc/lib.rs
1//! # dryoc: Don't Roll Your Own Cryptoâ„¢[^1]
2//!
3//! dryoc is a pure-Rust, general-purpose cryptography library. It implements
4//! many [libsodium](https://libsodium.gitbook.io/doc/)-compatible APIs and wire
5//! formats, so supported operations can interoperate with libsodium across
6//! languages.
7//!
8//! dryoc provides a libsodium-like Classic API and a typed Rustaceous API. The
9//! Rustaceous types make key, nonce, and output sizes explicit; the Classic API
10//! eases migration from libsodium. Both APIs use the same implementations and
11//! can be used together.
12//!
13//! This crate uses the Rust 2024 edition. The minimum supported Rust version
14//! (MSRV) is **Rust 1.89** or newer.
15//!
16//! ## Features
17//!
18//! * Pure Rust, with no hidden C libraries
19//! * Limited use of unsafe code[^2]
20//! * Typed Rustaceous APIs for keys, nonces, and outputs
21//! * Classic and Rustaceous APIs for many libsodium operations
22//! * Protected memory handling (`mprotect()` + `mlock()`, along with Windows
23//! equivalents) on stable Rust for Unix and Windows targets, enabled by
24//! default with the `protected` feature
25//! * Password-hash string helpers enabled by default with the `base64` feature
26//! * [Serde](https://serde.rs/) support (with `features = ["serde"]`)
27//! * [wincode](https://crates.io/crates/wincode) support for direct binary
28//! serialization of Rustaceous box types (with `features = ["wincode"]`)
29//! * [_Portable_ SIMD](https://doc.rust-lang.org/std/simd/index.html)
30//! implementations on nightly, with `features = ["simd_backend", "nightly"]`:
31//! * Blake2b (used by generic hashing, password hashing, and key derivation)
32//! * Argon2 block mixing (used by password hashing)
33//! * Salsa20 (used by XSalsa20-Poly1305 secretbox)
34//! * Poly1305 (used by one-time authentication and secret boxes), except on
35//! AArch64 where dryoc keeps the soft backend because the portable-SIMD
36//! path is slower there
37//! * [curve25519-dalek](https://github.com/dalek-cryptography/curve25519-dalek)
38//! (used by public/private key functions) selects its own serial or x86_64
39//! vector backend at build time
40//! * [SHA2](https://github.com/RustCrypto/hashes/tree/master/sha2) (used for
41//! SHA-256 and SHA-512 hashing and seeded box key generation) includes an
42//! AVX2 backend
43//! * [SHA3](https://github.com/RustCrypto/hashes/tree/master/sha3) (used for
44//! SHA-3 hashing)
45//! * [ChaCha20](https://github.com/RustCrypto/stream-ciphers/tree/master/chacha20)
46//! (used by streaming interface) includes SIMD implementations for NEON,
47//! AVX2, and SSE2
48//!
49//! The `simd_backend` and `nightly` features enable dryoc's portable SIMD
50//! backends. CPU-specific dependency backends and local benchmarking may also
51//! benefit from target-specific `RUSTFLAGS`:
52//! * For AVX2 set `RUSTFLAGS=-Ctarget-cpu=haswell -Ctarget-feature=+avx2`
53//! * For SSE2 set `RUSTFLAGS=-Ctarget-feature=+sse2`
54//! * For NEON set `RUSTFLAGS=-Ctarget-feature=+neon`
55//! * For local Apple Silicon benchmarks, use `RUSTFLAGS=-Ctarget-cpu=native`.
56//! NEON is part of the AArch64 macOS baseline target, so adding
57//! `-Ctarget-feature=+neon` is not expected to change native results.
58//!
59//! The Curve25519 backend is selected by `curve25519-dalek`, not by dryoc's
60//! `simd_backend` feature.
61//!
62//! Poly1305 is a special exception on AArch64: even with `simd_backend` and
63//! `nightly` enabled, dryoc uses the soft Poly1305 backend because profiling
64//! shows the portable-SIMD implementation is slower on that architecture.
65//!
66//! See [BENCHMARKS.md](https://github.com/brndnmtthws/dryoc/blob/main/BENCHMARKS.md)
67//! for side-by-side software and SIMD benchmark results.
68//!
69//! ## APIs
70//!
71//! The _Classic_ API closely follows libsodium's functions and types. The
72//! _Rustaceous_ API wraps the same operations in Rust types.
73//!
74//! ## Error handling
75//!
76//! Fallible cryptographic operations return [`Error`]. Its structured variants
77//! let callers distinguish authentication failures, invalid lengths or values,
78//! malformed encodings, invalid keys, protected-memory failures, and invalid
79//! operation state.
80//!
81//! Prefer the Rustaceous API for new code. Use the Classic API when porting
82//! libsodium code or when its byte-array interface is a better fit.
83//!
84//! Rustaceous functions sometimes require an explicit output type. Each module
85//! provides type aliases for its common key, nonce, and output types. The
86//! Classic API instead uses fixed-size byte arrays and byte slices.
87//!
88//! | Feature | Rustaceous API | Classic API | Reference |
89//! |-|-|-|-|
90//! | Public-key authenticated boxes | [`DryocBox`](dryocbox) | [`crypto_box`](classic::crypto_box) | [Link](https://libsodium.gitbook.io/doc/public-key_cryptography/authenticated_encryption) |
91//! | Secret-key authenticated boxes | [`DryocSecretBox`](dryocsecretbox) | [`crypto_secretbox`](classic::crypto_secretbox) | [Link](https://libsodium.gitbook.io/doc/secret-key_cryptography/secretbox) |
92//! | ChaCha20-Poly1305-IETF authenticated encryption | [`chacha20poly1305_ietf`](dryocaead::chacha20poly1305_ietf) | [`crypto_aead_chacha20poly1305_ietf`](classic::crypto_aead_chacha20poly1305_ietf) | [Link](https://doc.libsodium.org/secret-key_cryptography/aead/chacha20-poly1305/ietf_chacha20-poly1305_construction) |
93//! | Authenticated encryption with additional data | [`DryocAead`](dryocaead) | [`crypto_aead_xchacha20poly1305_ietf`](classic::crypto_aead_xchacha20poly1305_ietf) | [Link](https://doc.libsodium.org/secret-key_cryptography/aead/chacha20-poly1305/xchacha20-poly1305_construction) |
94//! | Streaming encryption | [`DryocStream`](dryocstream) | [`crypto_secretstream_xchacha20poly1305`](classic::crypto_secretstream_xchacha20poly1305) | [Link](https://libsodium.gitbook.io/doc/secret-key_cryptography/secretstream) |
95//! | Generic hashing and keyed hashing | [`GenericHash`](generichash) | [`crypto_generichash`](classic::crypto_generichash) | [Link](https://doc.libsodium.org/hashing/generic_hashing) |
96//! | SHA-2 hashing | [`Sha256`](sha256::Sha256), [`Sha512`](sha512::Sha512) | [`crypto_hash`](classic::crypto_hash) | [Link](https://doc.libsodium.org/advanced/sha-2_hash_function) |
97//! | SHA-3 hashing | [`Sha3256`](sha3::Sha3256), [`Sha3512`](sha3::Sha3512) | [`crypto_hash`](classic::crypto_hash) | [Link](https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf) |
98//! | Secret-key authentication | [`Auth`](auth) | [`crypto_auth`](classic::crypto_auth) | [Link](https://doc.libsodium.org/secret-key_cryptography/secret-key_authentication) |
99//! | Direct HMAC authentication | [`Hmac`](hmac) | [`crypto_auth_hmacsha256`](classic::crypto_auth_hmacsha256), [`crypto_auth_hmacsha512`](classic::crypto_auth_hmacsha512), [`crypto_auth_hmacsha512256`](classic::crypto_auth_hmacsha512256) | [Link](https://doc.libsodium.org/secret-key_cryptography/secret-key_authentication) |
100//! | One-time authentication | [`OnetimeAuth`](onetimeauth) | [`crypto_onetimeauth`](classic::crypto_onetimeauth) | [Link](https://doc.libsodium.org/advanced/poly1305) |
101//! | Key derivation | [`Kdf`](kdf) | [`crypto_kdf`](classic::crypto_kdf) | [Link](https://doc.libsodium.org/key_derivation) |
102//! | HKDF key derivation | [`Hkdf`](hkdf) | [`crypto_kdf`](classic::crypto_kdf) | [Link](https://doc.libsodium.org/key_derivation/hkdf) |
103//! | Key exchange | [`Session`](kx) | [`crypto_kx`](classic::crypto_kx) | [Link](https://doc.libsodium.org/key_exchange) |
104//! | Public-key signatures | [`SigningKeyPair`](sign) | [`crypto_sign`](classic::crypto_sign) | [Link](https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures) |
105//! | Password hashing | [`PwHash`](pwhash) | [`crypto_pwhash`](classic::crypto_pwhash) | [Link](https://libsodium.gitbook.io/doc/password_hashing/default_phf) |
106//! | Protected memory[^4] | [protected] | N/A | [Link](https://doc.libsodium.org/memory_management) |
107//! | Short-input hashing | N/A | [`crypto_shorthash`](classic::crypto_shorthash) | [Link](https://libsodium.gitbook.io/doc/hashing/short-input_hashing) |
108//!
109//! ## Using Serde
110//!
111//! This crate includes optional [Serde](https://serde.rs/) support which can be
112//! enabled with the `serde` feature flag. When enabled, the
113//! [`Serialize`](https://docs.rs/serde/latest/serde/trait.Serialize.html) and
114//! [`Deserialize`](https://docs.rs/serde/latest/serde/trait.Deserialize.html) traits are provided
115//! for data structures.
116//!
117//! ## Using wincode
118//!
119//! This crate includes optional [wincode](https://crates.io/crates/wincode)
120//! support which can be enabled with the `wincode` feature flag. When enabled,
121//! [`wincode::SchemaWrite`](https://docs.rs/wincode/latest/wincode/trait.SchemaWrite.html) and
122//! [`wincode::SchemaRead`](https://docs.rs/wincode/latest/wincode/trait.SchemaRead.html) are
123//! provided for supported Rustaceous box types, including
124//! [`DryocBox`](dryocbox::DryocBox),
125//! [`DryocSecretBox`](dryocsecretbox::DryocSecretBox), and
126//! [`AeadBox`](dryocaead::AeadBox).
127//!
128//! ## Unsafe code
129//!
130//! Non-test `unsafe` code is limited to these areas:
131//!
132//! | Area | Feature gate | Why `unsafe` is required |
133//! |-|-|-|
134//! | `src/types.rs` fixed-size byte views | Always available | Converts validated byte slices and vectors into `[u8; N]` references without copying. Each cast is guarded by a length check or an exact-size wrapper invariant. |
135//! | `src/dryocbox.rs`, `src/dryocsecretbox.rs`, and `src/dryocaead.rs` wincode impls | `wincode` | Implements `unsafe` wincode schema traits for the Rustaceous box wire formats, including both AEAD nonce sizes. The implementations write and read initialized fields in the same order. |
136//! | `src/blake2b/blake2b_soft.rs` and `src/blake2b/blake2b_simd.rs` parameter blocks | Always available for the soft backend; `simd_backend,nightly` for SIMD | Views a `repr(C, packed)` BLAKE2b parameter block as bytes so the initialization vector is mixed exactly as specified. The parameter type contains only initialized byte fields. |
137//! | `src/protected.rs` protected memory | `protected` on Unix/Windows | Calls OS APIs such as `mlock`, `mprotect`, `VirtualLock`, and `VirtualProtect`, implements page-aligned guarded heap buffers, and exposes exact-size byte-array views over protected heap buffers. |
138//! | `src/classic/salsa20_simd.rs` Salsa20 SIMD backend | `simd_backend,nightly` | Performs little-endian unaligned in-place and buffer-to-buffer word XOR in 256-byte chunks, plus volatile zeroization of cached SIMD lanes containing derived key material. |
139//!
140//! Test-only unsafe code is used for libsodium and Argon2 compatibility checks
141//! and protected-memory platform probes; it is not part of the runtime crate
142//! API.
143//!
144//! ## Security notes
145//!
146//! dryoc has not undergone a third-party security audit. Its compatibility
147//! tests, Rust types, and limited use of unsafe code reduce some classes of
148//! defects, but do not guarantee that an application is secure. Applications
149//! must still follow the documented key and nonce rules, protect secret
150//! material, handle errors, and choose primitives appropriate for their
151//! protocol.
152//!
153//! ## Acknowledgements
154//!
155//! Thanks to the authors and contributors of [NaCl](https://nacl.cr.yp.to/) and
156//! [libsodium](https://github.com/jedisct1/libsodium).
157//!
158//! [^1]: Not actually trademarked.
159//!
160//! [^2]: The protected memory features described in the [protected] mod are
161//! available on Unix and Windows targets with the default `protected` feature.
162//! Unsupported targets do not expose the protected-memory API. These features
163//! require custom memory allocation, system calls, and pointer arithmetic,
164//! which are unsafe in Rust. Some optional SIMD code, including
165//! dependency-provided SIMD implementations and small internal helpers, may
166//! contain unsafe code. See the unsafe code section above for the non-test
167//! unsafe inventory in this crate.
168//!
169//! [^4]: Available on Unix and Windows targets with the `protected` feature
170//! flag enabled. The `protected` feature is enabled by default.
171
172#![cfg_attr(feature = "nightly", feature(allocator_api, doc_cfg))]
173#![cfg_attr(
174 all(feature = "simd_backend", feature = "nightly"),
175 feature(portable_simd)
176)]
177#![cfg_attr(all(test, feature = "nightly"), feature(test))]
178#[macro_use]
179mod error;
180#[cfg(any(all(feature = "protected", any(unix, windows)), all(doc, not(doctest))))]
181#[cfg_attr(all(feature = "nightly", doc), doc(cfg(feature = "protected")))]
182#[macro_use]
183pub mod protected;
184
185mod argon2;
186mod blake2b;
187#[cfg(feature = "serde")]
188mod bytes_serde;
189mod poly1305;
190mod scalarmult_curve25519;
191mod siphash24;
192
193pub mod classic {
194 //! # Classic API
195 //!
196 //! The Classic API follows libsodium's interface closely. Use it to port
197 //! libsodium code or when fixed-size byte arrays and byte slices are a
198 //! better fit than the Rustaceous types.
199 mod crypto_auth_hmac_impl;
200 mod crypto_box_impl;
201 mod crypto_secretbox_impl;
202 mod generichash_blake2b;
203 #[cfg(all(feature = "simd_backend", feature = "nightly"))]
204 mod salsa20_simd;
205
206 pub mod crypto_aead_chacha20poly1305_ietf;
207 pub mod crypto_aead_xchacha20poly1305_ietf;
208 pub mod crypto_auth;
209 pub mod crypto_auth_hmacsha256;
210 pub mod crypto_auth_hmacsha512;
211 pub mod crypto_auth_hmacsha512256;
212 pub mod crypto_box;
213 /// # Core cryptography functions
214 pub mod crypto_core;
215 pub mod crypto_generichash;
216 /// Hash functions
217 pub mod crypto_hash;
218 pub mod crypto_kdf;
219 pub mod crypto_kx;
220 pub mod crypto_onetimeauth;
221 pub mod crypto_pwhash;
222 pub mod crypto_secretbox;
223 pub mod crypto_secretstream_xchacha20poly1305;
224 pub mod crypto_shorthash;
225 pub mod crypto_sign;
226 pub mod crypto_sign_ed25519;
227}
228
229pub mod auth;
230/// # Constant value definitions
231pub mod constants;
232pub mod dryocaead;
233pub mod dryocbox;
234pub mod dryocsecretbox;
235pub mod dryocstream;
236pub mod generichash;
237pub mod hkdf;
238pub mod hmac;
239pub mod kdf;
240pub mod keypair;
241pub mod kx;
242pub mod onetimeauth;
243pub mod precalc;
244pub mod pwhash;
245/// # Random number generation utilities
246pub mod rng;
247pub mod sha256;
248pub mod sha3;
249pub mod sha512;
250pub mod sign;
251/// # Base type definitions
252pub mod types;
253/// # Various utility functions
254pub mod utils;
255
256pub use error::{Error, ErrorContext, LengthConstraint, ValueConstraint};
257
258#[cfg(test)]
259mod tests {
260
261 #[test]
262 fn test_randombytes_buf() {
263 use crate::rng::*;
264 let r = randombytes_buf(5);
265 assert_eq!(r.len(), 5);
266 let sum = r.into_iter().fold(0u64, |acc, n| acc + n as u64);
267 assert_ne!(sum, 0);
268 }
269}