Expand description
Platform-Agnostic Serialized Keys (PASERK) for PASETO.
PASERK is a standard format for serializing keys used with PASETO tokens. This crate provides a type-safe, idiomatic Rust implementation of the PASERK specification.
§Quick Start
use paserk::core::types::PaserkLocal;
use paserk::core::version::K4;
// Create a PASERK key from raw bytes
let key_bytes: [u8; 32] = [0u8; 32];
let paserk_key = PaserkLocal::<K4>::from(key_bytes);
// Serialize to PASERK string format
let paserk_string = paserk_key.to_string();
assert!(paserk_string.starts_with("k4.local."));
// Parse a PASERK string back to a key
let parsed = PaserkLocal::<K4>::try_from(paserk_string.as_str());
assert!(parsed.is_ok());§PASERK Types
All PASERK key types are implemented for all versions (K1-K4):
| Type | Format | Description | K1 | K2 | K3 | K4 |
|---|---|---|---|---|---|---|
local | k{v}.local.{data} | Symmetric encryption key | ✅ | ✅ | ✅ | ✅ |
public | k{v}.public.{data} | Public verification key | ✅ | ✅ | ✅ | ✅ |
secret | k{v}.secret.{data} | Secret signing key | N/A¹ | ✅ | ✅ | ✅ |
lid | k{v}.lid.{data} | Local key identifier | ✅ | ✅ | ✅ | ✅ |
pid | k{v}.pid.{data} | Public key identifier | ✅ | ✅ | ✅ | ✅ |
sid | k{v}.sid.{data} | Secret key identifier | N/A¹ | ✅ | ✅ | ✅ |
local-wrap | k{v}.local-wrap.pie.{data} | PIE-wrapped symmetric key | ✅ | ✅ | ✅ | ✅ |
secret-wrap | k{v}.secret-wrap.pie.{data} | PIE-wrapped secret key | N/A¹ | ✅ | ✅ | ✅ |
local-pw | k{v}.local-pw.{data} | Password-wrapped symmetric key | ✅ | ✅ | ✅ | ✅ |
secret-pw | k{v}.secret-pw.{data} | Password-wrapped secret key | N/A¹ | ✅ | ✅ | ✅ |
seal | k{v}.seal.{data} | PKE-encrypted symmetric key | ✅ | ✅ | ✅ | ✅ |
¹ K1 uses RSA which has no separate secret key type in PASETO V1.
§Versions
PASERK supports four versions, corresponding to PASETO versions:
| Version | Algorithms | Status |
|---|---|---|
| K1 | RSA + AES-CTR + HMAC-SHA384 | ⚠️ Deprecated (see warning below) |
| K2 | Ed25519 + XChaCha20 + BLAKE2b | ✅ Fully implemented |
| K3 | P-384 + AES-CTR + HMAC-SHA384 | ✅ Fully implemented |
| K4 | Ed25519 + XChaCha20 + BLAKE2b | ✅ Fully implemented (Recommended) |
§⚠️ Security Warning: K1 (RSA) Vulnerability
The k1-insecure feature uses the rsa crate which is vulnerable to
RUSTSEC-2023-0071 (Marvin Attack), a timing side-channel attack that
could enable private key recovery.
- Do not use K1 for new projects. Use
K4instead. - K1 support is provided only for legacy PASETO V1 interoperability.
- The feature has been renamed from
k1tok1-insecureto require explicit opt-in. - K1 types will emit deprecation warnings when used.
§Features
Enable specific versions with feature flags:
[dependencies]
paserk = { version = "0.1", features = ["k4"] } # K4 only (default, recommended)
paserk = { version = "0.1", features = ["k2", "k4"] } # K2 and K4
paserk = { version = "0.1", features = ["all-versions"] } # All versions
# paserk = { version = "0.1", features = ["k1-insecure"] } # K1 (⚠️ see security warning)§Cryptographic Operations
§Key Wrapping (PIE Protocol)
| Version | Encryption | Authentication |
|---|---|---|
| K1/K3 | AES-256-CTR | HMAC-SHA384 (48-byte tag) |
| K2/K4 | XChaCha20 | BLAKE2b (32-byte tag) |
§Password-Based Key Wrapping (PBKW)
| Version | KDF | Encryption | Authentication |
|---|---|---|---|
| K1/K3 | PBKDF2-SHA384 | AES-256-CTR | HMAC-SHA384 |
| K2/K4 | Argon2id | XChaCha20 | BLAKE2b |
§Public Key Encryption (Seal)
| Version | Key Exchange | Encryption | Authentication |
|---|---|---|---|
| K1 | RSA-4096 KEM | AES-256-CTR | HMAC-SHA384 |
| K2/K4 | X25519 ECDH | XChaCha20 | BLAKE2b |
| K3 | P-384 ECDH | AES-256-CTR | HMAC-SHA384 |
§Security
This crate follows security best practices:
- Key material is zeroized on drop
- Debug output redacts sensitive key material
- Constant-time comparison for secret keys
- No unsafe code (
#![forbid(unsafe_code)]) - Authenticated encryption prevents tampering
§Modules
§Builder Patterns
The prelude module provides fluent builder APIs for password-based wrapping:
use paserk::prelude::*;
let key = PaserkLocal::<K4>::from([0x42u8; 32]);
// Use preset security profiles
let wrapped = LocalPwBuilder::<K4>::moderate()
.try_wrap(&key, b"password")?;
// Or customize parameters
let wrapped = LocalPwBuilder::<K4>::new()
.memory_kib(128 * 1024)
.iterations(3)
.parallelism(2)
.try_wrap(&key, b"password")?;Re-exports§
pub use core::error::PaserkError;pub use core::error::PaserkResult;pub use core::version::PaserkVersion;pub use core::version::K1;Deprecated pub use core::version::K2;pub use core::version::K3;pub use core::version::K4;pub use core::types::PaserkLocal;pub use core::types::PaserkLocalId;pub use core::types::PaserkLocalPw;pub use core::types::PaserkLocalWrap;pub use core::types::PaserkPublic;pub use core::types::PaserkPublicId;pub use core::types::PaserkSeal;pub use core::types::PaserkSecret;pub use core::types::PaserkSecretId;pub use core::types::PaserkSecretPw;pub use core::types::PaserkSecretWrap;pub use core::operations::wrap::Pie;pub use core::operations::wrap::WrapProtocol;pub use core::operations::pbkw::Argon2Params;