Skip to main content

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
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//! Dryoc's portable SIMD backends require a nightly Rust toolchain and
50//! `--features simd_backend,nightly`. `simd_backend` selects the SIMD code;
51//! `nightly` enables Rust's unstable `portable_simd` API.
52//!
53//! The Curve25519 backend is selected by `curve25519-dalek`, not by dryoc's
54//! `simd_backend` feature.
55//!
56//! Poly1305 is a special exception on AArch64: even with `simd_backend` and
57//! `nightly` enabled, dryoc uses the soft Poly1305 backend because profiling
58//! shows the portable-SIMD implementation is slower on that architecture.
59//!
60//! See [BENCHMARKS.md](https://github.com/brndnmtthws/dryoc/blob/main/BENCHMARKS.md)
61//! for side-by-side software and SIMD benchmark results.
62//!
63//! ## APIs
64//!
65//! The _Classic_ API closely follows libsodium's functions and types. The
66//! _Rustaceous_ API wraps the same operations in Rust types.
67//!
68//! ## Error handling
69//!
70//! Fallible cryptographic operations return [`Error`]. Its structured variants
71//! let callers distinguish authentication failures, invalid lengths or values,
72//! malformed encodings, invalid keys, protected-memory failures, and invalid
73//! operation state.
74//!
75//! Prefer the Rustaceous API for new code. Use the Classic API when porting
76//! libsodium code or when its byte-array interface is a better fit.
77//!
78//! Rustaceous functions sometimes require an explicit output type. Each module
79//! provides type aliases for its common key, nonce, and output types. The
80//! Classic API instead uses fixed-size byte arrays and byte slices.
81//!
82//! | Feature | Rustaceous API | Classic API | Reference |
83//! |-|-|-|-|
84//! | Public-key authenticated boxes | [`DryocBox`](dryocbox) | [`crypto_box`](classic::crypto_box) | [Link](https://libsodium.gitbook.io/doc/public-key_cryptography/authenticated_encryption) |
85//! | Secret-key authenticated boxes | [`DryocSecretBox`](dryocsecretbox) | [`crypto_secretbox`](classic::crypto_secretbox) | [Link](https://libsodium.gitbook.io/doc/secret-key_cryptography/secretbox) |
86//! | 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) |
87//! | 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) |
88//! | Streaming encryption | [`DryocStream`](dryocstream) | [`crypto_secretstream_xchacha20poly1305`](classic::crypto_secretstream_xchacha20poly1305) | [Link](https://libsodium.gitbook.io/doc/secret-key_cryptography/secretstream) |
89//! | Generic hashing and keyed hashing | [`GenericHash`](generichash) | [`crypto_generichash`](classic::crypto_generichash) | [Link](https://doc.libsodium.org/hashing/generic_hashing) |
90//! | SHA-2 hashing | [`Sha256`](sha256::Sha256), [`Sha512`](sha512::Sha512) | [`crypto_hash`](classic::crypto_hash) | [Link](https://doc.libsodium.org/advanced/sha-2_hash_function) |
91//! | 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) |
92//! | Secret-key authentication | [`Auth`](auth) | [`crypto_auth`](classic::crypto_auth) | [Link](https://doc.libsodium.org/secret-key_cryptography/secret-key_authentication) |
93//! | 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) |
94//! | One-time authentication | [`OnetimeAuth`](onetimeauth) | [`crypto_onetimeauth`](classic::crypto_onetimeauth) | [Link](https://doc.libsodium.org/advanced/poly1305) |
95//! | Key derivation | [`Kdf`](kdf) | [`crypto_kdf`](classic::crypto_kdf) | [Link](https://doc.libsodium.org/key_derivation) |
96//! | HKDF key derivation | [`Hkdf`](hkdf) | [`crypto_kdf`](classic::crypto_kdf) | [Link](https://doc.libsodium.org/key_derivation/hkdf) |
97//! | Key exchange | [`Session`](kx) | [`crypto_kx`](classic::crypto_kx) | [Link](https://doc.libsodium.org/key_exchange) |
98//! | Public-key signatures | [`SigningKeyPair`](sign) | [`crypto_sign`](classic::crypto_sign) | [Link](https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures) |
99//! | Password hashing | [`PwHash`](pwhash) | [`crypto_pwhash`](classic::crypto_pwhash) | [Link](https://libsodium.gitbook.io/doc/password_hashing/default_phf) |
100//! | Protected memory[^4] | [protected] | N/A | [Link](https://doc.libsodium.org/memory_management) |
101//! | Short-input hashing | N/A | [`crypto_shorthash`](classic::crypto_shorthash) | [Link](https://libsodium.gitbook.io/doc/hashing/short-input_hashing) |
102//!
103//! ## Using Serde
104//!
105//! This crate includes optional [Serde](https://serde.rs/) support which can be
106//! enabled with the `serde` feature flag. When enabled, the
107//! [`Serialize`](https://docs.rs/serde/latest/serde/trait.Serialize.html) and
108//! [`Deserialize`](https://docs.rs/serde/latest/serde/trait.Deserialize.html) traits are provided
109//! for data structures.
110//!
111//! ## Using wincode
112//!
113//! This crate includes optional [wincode](https://crates.io/crates/wincode)
114//! support which can be enabled with the `wincode` feature flag. When enabled,
115//! [`wincode::SchemaWrite`](https://docs.rs/wincode/latest/wincode/trait.SchemaWrite.html) and
116//! [`wincode::SchemaRead`](https://docs.rs/wincode/latest/wincode/trait.SchemaRead.html) are
117//! provided for supported Rustaceous box types, including
118//! [`DryocBox`](dryocbox::DryocBox),
119//! [`DryocSecretBox`](dryocsecretbox::DryocSecretBox), and
120//! [`AeadBox`](dryocaead::AeadBox).
121//!
122//! ## Unsafe code
123//!
124//! Non-test `unsafe` code is limited to these areas:
125//!
126//! | Area | Feature gate | Why `unsafe` is required |
127//! |-|-|-|
128//! | `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. |
129//! | `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. |
130//! | `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. |
131//! | `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. |
132//! | `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. |
133//!
134//! Test-only unsafe code is used for libsodium and Argon2 compatibility checks
135//! and protected-memory platform probes; it is not part of the runtime crate
136//! API.
137//!
138//! ## Security notes
139//!
140//! dryoc has not undergone a third-party security audit. Its compatibility
141//! tests, Rust types, and limited use of unsafe code reduce some classes of
142//! defects, but do not guarantee that an application is secure. Applications
143//! must still follow the documented key and nonce rules, protect secret
144//! material, handle errors, and choose primitives appropriate for their
145//! protocol.
146//!
147//! ## Acknowledgements
148//!
149//! Thanks to the authors and contributors of [NaCl](https://nacl.cr.yp.to/) and
150//! [libsodium](https://github.com/jedisct1/libsodium).
151//!
152//! [^1]: Not actually trademarked.
153//!
154//! [^2]: The protected memory features described in the [protected] mod are
155//! available on Unix and Windows targets with the default `protected` feature.
156//! Unsupported targets do not expose the protected-memory API. These features
157//! require custom memory allocation, system calls, and pointer arithmetic,
158//! which are unsafe in Rust. Some optional SIMD code, including
159//! dependency-provided SIMD implementations and small internal helpers, may
160//! contain unsafe code. See the unsafe code section above for the non-test
161//! unsafe inventory in this crate.
162//!
163//! [^4]: Available on Unix and Windows targets with the `protected` feature
164//! flag enabled. The `protected` feature is enabled by default.
165
166#![cfg_attr(feature = "nightly", feature(allocator_api, doc_cfg))]
167#![cfg_attr(
168    all(feature = "simd_backend", feature = "nightly"),
169    feature(portable_simd)
170)]
171#![cfg_attr(all(test, feature = "nightly"), feature(test))]
172#[macro_use]
173mod error;
174#[cfg(any(all(feature = "protected", any(unix, windows)), all(doc, not(doctest))))]
175#[cfg_attr(all(feature = "nightly", doc), doc(cfg(feature = "protected")))]
176#[macro_use]
177pub mod protected;
178
179mod argon2;
180mod blake2b;
181#[cfg(feature = "serde")]
182mod bytes_serde;
183mod poly1305;
184mod scalarmult_curve25519;
185mod siphash24;
186
187pub mod classic {
188    //! # Classic API
189    //!
190    //! The Classic API follows libsodium's interface closely. Use it to port
191    //! libsodium code or when fixed-size byte arrays and byte slices are a
192    //! better fit than the Rustaceous types.
193    mod crypto_auth_hmac_impl;
194    mod crypto_box_impl;
195    mod crypto_secretbox_impl;
196    mod generichash_blake2b;
197    #[cfg(all(feature = "simd_backend", feature = "nightly"))]
198    mod salsa20_simd;
199
200    pub mod crypto_aead_chacha20poly1305_ietf;
201    pub mod crypto_aead_xchacha20poly1305_ietf;
202    pub mod crypto_auth;
203    pub mod crypto_auth_hmacsha256;
204    pub mod crypto_auth_hmacsha512;
205    pub mod crypto_auth_hmacsha512256;
206    pub mod crypto_box;
207    /// # Core cryptography functions
208    pub mod crypto_core;
209    pub mod crypto_generichash;
210    /// Hash functions
211    pub mod crypto_hash;
212    pub mod crypto_kdf;
213    pub mod crypto_kx;
214    pub mod crypto_onetimeauth;
215    pub mod crypto_pwhash;
216    pub mod crypto_secretbox;
217    pub mod crypto_secretstream_xchacha20poly1305;
218    pub mod crypto_shorthash;
219    pub mod crypto_sign;
220    pub mod crypto_sign_ed25519;
221}
222
223pub mod auth;
224/// # Constant value definitions
225pub mod constants;
226pub mod dryocaead;
227pub mod dryocbox;
228pub mod dryocsecretbox;
229pub mod dryocstream;
230pub mod generichash;
231pub mod hkdf;
232pub mod hmac;
233pub mod kdf;
234pub mod keypair;
235pub mod kx;
236pub mod onetimeauth;
237pub mod precalc;
238pub mod pwhash;
239/// # Random number generation utilities
240pub mod rng;
241pub mod sha256;
242pub mod sha3;
243pub mod sha512;
244pub mod sign;
245/// # Base type definitions
246pub mod types;
247/// # Various utility functions
248pub mod utils;
249
250pub use error::{Error, ErrorContext, LengthConstraint, ValueConstraint};
251
252#[cfg(test)]
253mod tests {
254
255    #[test]
256    fn test_randombytes_buf() {
257        use crate::rng::*;
258        let r = randombytes_buf(5);
259        assert_eq!(r.len(), 5);
260        let sum = r.into_iter().fold(0u64, |acc, n| acc + n as u64);
261        assert_ne!(sum, 0);
262    }
263}