paserk/lib.rs
1//! Platform-Agnostic Serialized Keys (PASERK) for PASETO.
2//!
3//! PASERK is a standard format for serializing keys used with PASETO tokens.
4//! This crate provides a type-safe, idiomatic Rust implementation of the
5//! PASERK specification.
6//!
7//! # Quick Start
8//!
9//! ```rust
10//! use paserk::core::types::PaserkLocal;
11//! use paserk::core::version::K4;
12//!
13//! // Create a PASERK key from raw bytes
14//! let key_bytes: [u8; 32] = [0u8; 32];
15//! let paserk_key = PaserkLocal::<K4>::from(key_bytes);
16//!
17//! // Serialize to PASERK string format
18//! let paserk_string = paserk_key.to_string();
19//! assert!(paserk_string.starts_with("k4.local."));
20//!
21//! // Parse a PASERK string back to a key
22//! let parsed = PaserkLocal::<K4>::try_from(paserk_string.as_str());
23//! assert!(parsed.is_ok());
24//! ```
25//!
26//! # PASERK Types
27//!
28//! All PASERK key types are implemented for all versions (K1-K4):
29//!
30//! | Type | Format | Description | K1 | K2 | K3 | K4 |
31//! |------|--------|-------------|----|----|----|----|
32//! | `local` | `k{v}.local.{data}` | Symmetric encryption key | ✅ | ✅ | ✅ | ✅ |
33//! | `public` | `k{v}.public.{data}` | Public verification key | ✅ | ✅ | ✅ | ✅ |
34//! | `secret` | `k{v}.secret.{data}` | Secret signing key | N/A¹ | ✅ | ✅ | ✅ |
35//! | `lid` | `k{v}.lid.{data}` | Local key identifier | ✅ | ✅ | ✅ | ✅ |
36//! | `pid` | `k{v}.pid.{data}` | Public key identifier | ✅ | ✅ | ✅ | ✅ |
37//! | `sid` | `k{v}.sid.{data}` | Secret key identifier | N/A¹ | ✅ | ✅ | ✅ |
38//! | `local-wrap` | `k{v}.local-wrap.pie.{data}` | PIE-wrapped symmetric key | ✅ | ✅ | ✅ | ✅ |
39//! | `secret-wrap` | `k{v}.secret-wrap.pie.{data}` | PIE-wrapped secret key | N/A¹ | ✅ | ✅ | ✅ |
40//! | `local-pw` | `k{v}.local-pw.{data}` | Password-wrapped symmetric key | ✅ | ✅ | ✅ | ✅ |
41//! | `secret-pw` | `k{v}.secret-pw.{data}` | Password-wrapped secret key | N/A¹ | ✅ | ✅ | ✅ |
42//! | `seal` | `k{v}.seal.{data}` | PKE-encrypted symmetric key | ✅ | ✅ | ✅ | ✅ |
43//!
44//! ¹ K1 uses RSA which has no separate secret key type in PASETO V1.
45//!
46//! # Versions
47//!
48//! PASERK supports four versions, corresponding to PASETO versions:
49//!
50//! | Version | Algorithms | Status |
51//! |---------|------------|--------|
52//! | **K1** | RSA + AES-CTR + HMAC-SHA384 | ⚠️ **Deprecated** (see warning below) |
53//! | **K2** | Ed25519 + `XChaCha20` + `BLAKE2b` | ✅ Fully implemented |
54//! | **K3** | P-384 + AES-CTR + HMAC-SHA384 | ✅ Fully implemented |
55//! | **K4** | Ed25519 + `XChaCha20` + `BLAKE2b` | ✅ Fully implemented (Recommended) |
56//!
57//! # ⚠️ Security Warning: K1 (RSA) Vulnerability
58//!
59//! **The `k1-insecure` feature uses the `rsa` crate which is vulnerable to
60//! [RUSTSEC-2023-0071] (Marvin Attack), a timing side-channel attack that
61//! could enable private key recovery.**
62//!
63//! - **Do not use K1 for new projects.** Use [`K4`] instead.
64//! - K1 support is provided only for legacy PASETO V1 interoperability.
65//! - The feature has been renamed from `k1` to `k1-insecure` to require explicit opt-in.
66//! - K1 types will emit deprecation warnings when used.
67//!
68//! [RUSTSEC-2023-0071]: https://rustsec.org/advisories/RUSTSEC-2023-0071
69//!
70//! # Features
71//!
72//! Enable specific versions with feature flags:
73//!
74//! ```toml
75//! [dependencies]
76//! paserk = { version = "0.1", features = ["k4"] } # K4 only (default, recommended)
77//! paserk = { version = "0.1", features = ["k2", "k4"] } # K2 and K4
78//! paserk = { version = "0.1", features = ["all-versions"] } # All versions
79//! # paserk = { version = "0.1", features = ["k1-insecure"] } # K1 (⚠️ see security warning)
80//! ```
81//!
82//! # Cryptographic Operations
83//!
84//! ## Key Wrapping (PIE Protocol)
85//!
86//! | Version | Encryption | Authentication |
87//! |---------|------------|----------------|
88//! | K1/K3 | AES-256-CTR | HMAC-SHA384 (48-byte tag) |
89//! | K2/K4 | `XChaCha20` | `BLAKE2b` (32-byte tag) |
90//!
91//! ## Password-Based Key Wrapping (PBKW)
92//!
93//! | Version | KDF | Encryption | Authentication |
94//! |---------|-----|------------|----------------|
95//! | K1/K3 | PBKDF2-SHA384 | AES-256-CTR | HMAC-SHA384 |
96//! | K2/K4 | Argon2id | `XChaCha20` | `BLAKE2b` |
97//!
98//! ## Public Key Encryption (Seal)
99//!
100//! | Version | Key Exchange | Encryption | Authentication |
101//! |---------|--------------|------------|----------------|
102//! | K1 | RSA-4096 KEM | AES-256-CTR | HMAC-SHA384 |
103//! | K2/K4 | X25519 ECDH | `XChaCha20` | `BLAKE2b` |
104//! | K3 | P-384 ECDH | AES-256-CTR | HMAC-SHA384 |
105//!
106//! # Security
107//!
108//! This crate follows security best practices:
109//!
110//! - Key material is zeroized on drop
111//! - Debug output redacts sensitive key material
112//! - Constant-time comparison for secret keys
113//! - No unsafe code (`#![forbid(unsafe_code)]`)
114//! - Authenticated encryption prevents tampering
115//!
116//! # Modules
117//!
118//! - [`core`] - Core types and operations
119//! - [`prelude`] - Ergonomic imports (requires `prelude` feature)
120//!
121//! # Builder Patterns
122//!
123//! The `prelude` module provides fluent builder APIs for password-based wrapping:
124//!
125//! ```rust
126//! use paserk::prelude::*;
127//!
128//! # fn main() -> Result<(), paserk::PaserkError> {
129//! let key = PaserkLocal::<K4>::from([0x42u8; 32]);
130//!
131//! // Use preset security profiles
132//! let wrapped = LocalPwBuilder::<K4>::moderate()
133//! .try_wrap(&key, b"password")?;
134//!
135//! // Or customize parameters
136//! let wrapped = LocalPwBuilder::<K4>::new()
137//! .memory_kib(128 * 1024)
138//! .iterations(3)
139//! .parallelism(2)
140//! .try_wrap(&key, b"password")?;
141//! # Ok(())
142//! # }
143//! ```
144
145pub mod core;
146
147#[cfg(feature = "prelude")]
148pub mod prelude;
149
150// Re-export commonly used items at crate root
151pub use core::error::{PaserkError, PaserkResult};
152#[allow(deprecated)]
153pub use core::version::{PaserkVersion, K1, K2, K3, K4};
154
155// Re-export types based on enabled version features
156#[cfg(feature = "k4")]
157pub use core::types::{
158 PaserkLocal, PaserkLocalId, PaserkLocalPw, PaserkLocalWrap, PaserkPublic, PaserkPublicId,
159 PaserkSeal, PaserkSecret, PaserkSecretId, PaserkSecretPw, PaserkSecretWrap,
160};
161
162// Re-export wrap protocol markers
163pub use core::operations::wrap::{Pie, WrapProtocol};
164
165// Re-export PBKW parameters
166#[cfg(any(feature = "k2", feature = "k4"))]
167pub use core::operations::pbkw::Argon2Params;
168
169// Version-specific type aliases for when only one version is enabled
170#[cfg(all(
171 feature = "k4",
172 not(any(feature = "k1-insecure", feature = "k2", feature = "k3"))
173))]
174pub mod types {
175 //! Convenient type aliases for K4 (default version).
176
177 use super::core::operations::wrap::Pie;
178 use super::core::types;
179 use super::K4;
180
181 /// Symmetric key for K4.
182 pub type LocalKey = types::PaserkLocal<K4>;
183 /// Public key for K4.
184 pub type PublicKey = types::PaserkPublic<K4>;
185 /// Secret key for K4.
186 pub type SecretKey = types::PaserkSecret<K4>;
187 /// Local key ID for K4.
188 pub type LocalKeyId = types::PaserkLocalId<K4>;
189 /// Public key ID for K4.
190 pub type PublicKeyId = types::PaserkPublicId<K4>;
191 /// Secret key ID for K4.
192 pub type SecretKeyId = types::PaserkSecretId<K4>;
193 /// Wrapped local key for K4.
194 pub type LocalKeyWrap = types::PaserkLocalWrap<K4, Pie>;
195 /// Wrapped secret key for K4.
196 pub type SecretKeyWrap = types::PaserkSecretWrap<K4, Pie>;
197 /// Password-wrapped local key for K4.
198 pub type LocalKeyPw = types::PaserkLocalPw<K4>;
199 /// Password-wrapped secret key for K4.
200 pub type SecretKeyPw = types::PaserkSecretPw<K4>;
201 /// Sealed (PKE-encrypted) local key for K4.
202 pub type SealedKey = types::PaserkSeal<K4>;
203}