native-ossl
native-ossl is an idiomatic Rust wrapper around the OpenSSL 3.x C library. It exposes
the full EVP_* cryptographic API — hashing, symmetric encryption, MAC, asymmetric keys,
key derivation, randomness, X.509, and TLS — through safe, zero-copy Rust types.
What it provides
- Digests — streaming SHA-2, SHA-3, SHAKE (XOF), SM3 via
DigestAlg+DigestCtx - Symmetric encryption — AES-GCM, AES-CBC, ChaCha20-Poly1305, and more via
CipherAlg - MAC — HMAC, CMAC, KMAC via
MacAlg+MacCtx - Asymmetric keys — RSA, ECDSA, Ed25519, X25519, ML-KEM, ML-DSA via
Pkey<T> - Key derivation — HKDF, PBKDF2, scrypt via typed builders; raw
KdfCtxfor anything else - Randomness —
Rand::fillfor simple use;RandCtxfor seeded DRBG hierarchies - X.509 — certificate parsing, building, and self-signing via
X509andX509Builder - TLS — full TLS 1.2 / 1.3 client and server via
SslCtxandSsl - Library contexts — FIPS-provider isolation via
LibCtx
What it does not do
- Does not require OpenSSL headers at runtime; bindings are generated by
bindgenat build time against the system’s installed headers. - Does not ship its own copy of OpenSSL; it links the system library dynamically.
- Does not expose deprecated OpenSSL 1.x APIs (
ENGINE,BN_*arithmetic, legacy cipher names, etc.). - Does not provide async I/O;
Sslis synchronous. Async wrappers are a separate concern and can be built on top of the BIO layer.
Minimum requirements
| Requirement | Version |
|---|---|
| OpenSSL | 3.5.0 or later |
| Rust | 1.77 or later |
bindgen (build dep) | 0.72 or later |
pkg-config | system |
The build script enforces the OpenSSL version at compile time. If an older library is found, the build fails with a clear diagnostic message.
Quick example
#![allow(unused)]
fn main() {
use native_ossl::digest::DigestAlg;
// Fetch the algorithm descriptor once — it is Send + Sync and can be shared.
let sha256 = DigestAlg::fetch(c"SHA2-256", None)?;
assert_eq!(sha256.output_len(), 32);
// Stream arbitrary data through a stateful context.
let mut ctx = sha256.new_context()?;
ctx.update(b"hello, ")?;
ctx.update(b"world")?;
let mut out = [0u8; 32];
ctx.finish(&mut out)?;
println!("{}", hex::encode(out));
}
Crate layout
native-ossl/ workspace root
├── native-ossl-sys/ raw FFI (bindgen output, unsafe only)
├── native-ossl/ safe Rust wrappers (public API)
└── examples/
└── encrypt-demo/ hybrid RSA-OAEP + AES-256-GCM demo
All public API lives in native-ossl. The native-ossl-sys crate is an implementation
detail; callers never import it directly.