Inroduction
What is SARE?
SARE (Safe At Rest Encryption) is a hybrid post-quantum encryption system designed to protect data against both classical and quantum attacks.
Unlike traditional encryption tools that rely on a single algorithm (e.g., RSA or AES), SARE combines classical algorithms like X25519 and Ed25519 with post-quantum algorithms like Kyber768, using a hybrid scheme. Even if one algorithm is broken in the future, your data remains secure.
Why SARE Matters
Quantum computers threaten the foundations of classical cryptography. Algorithms like RSA and ECC will be breakable once sufficiently powerful quantum machines exist.
Post-quantum algorithms are young and may still have vulnerabilities. SARE adopts a belt-and-suspenders approach: both classical and post-quantum schemes are used in parallel, giving robust protection today and forward-security tomorrow.
Key Features
- Hybrid Key Encapsulation (KEM): Diffie–Hellman + PQ KEM to derive shared secrets.
- Hybrid Signatures: Files are signed with both elliptic curves and PQ schemes; both signatures must validate.
- File-Level Encryption: Files include headers, metadata, ciphertext, and optional signatures.
- Master Seed: Single 128-byte seed derives all private keys.
- Validation Certificates: Prove that your public keys are valid.
- Revocation Certificates: Revoke compromised or obsolete keys.
- Modular & Extensible: Swap or add encryption, signing, or KDF algorithms without rewriting core logic.
- High-Level API via
sare-lib
: Makes it easy to integrate SARE into Rust applications. - CLI (
sare-cli
): Command-line interface for encryption, decryption, signing, and key management. - Security-Focused: Uses well-vetted, audited algorithms.
Project Layout
The SARE repository has three main components:
sare-core - low-level cryptography primitives
sare-lib - high-level library for file encryption and handling
sare-cli - command-line interface for everyday use
sare-core
is low-level and intended to be used throughsare-lib
. Developers should exercise caution if working directly with it.sare-lib
provides the main library API and handles file formatting, encryption, and key management.sare-cli
provides CLI commands for everyday tasks: encrypt, decrypt, sign, manage keys and recipients.
Installation and Usage
SARE can be used as a CLI tool or integrated into your Rust projects via sare-lib
.
To get started and install / use SARE please read the Getting Started Page
Who is SARE For?
- End users: Encrypt and sign files with long-term security.
- Developers: Integrate hybrid PQ crypto into Rust applications.
- Researchers: Experiment with hybrid cryptography in real-world settings.
Roadmap
- Parallelized encryption/decryption for large files.
- Additional post-quantum algorithms and signature schemes.
- Key revocation workflows in the CLI.
- Keyserver implementations for sharing keys.
- Security audits and performance benchmarks.
License
- Code: MIT + Apache 2.0
- Books, guides, and documentation: CC BY 4.0
Getting Started with SARE
This section will help you quickly install SARE, learn the basics of the CLI, and explore examples using the sare-lib
library.
Installation
Learn how to install sare-cli
and sare-lib
in your environment.
Quickstart with CLI
See how to encrypt, decrypt, sign, and manage keys using the command-line interface.
Sare Lib Examples
Explore examples demonstrating file encryption, decryption, and signing with sare-lib
.
Installation
Installing SARE CLI from Source
You can build SARE CLI directly from source. This is useful if you want the latest development version or need to tweak the code:
git clone https://github.com/SareProject/sare
cd sare
cargo build --release
The resulting binary will be located at:
target/release/sare-cli
You can then move it to a directory in your PATH for easier access:
mv target/release/sare-cli /usr/local/bin/sare-cli
Installation Using Cargo
For a simpler installation, you can install the latest released version directly from crates.io:
cargo install sare-cli
After installation, the sare-cli
command will be available globally in your terminal.
Using SARE Lib in a Rust Project
To use SARE as a library in your Rust projects, add it to your dependencies in Cargo.toml
:
[dependencies]
sare-lib = "0.1"
Using Cargo to Add the Dependency
Alternatively, you can add sare-lib
directly using Cargo:
cargo add sare-lib
This will automatically update your Cargo.toml
and fetch the library from crates.io, making it ready for use in your project.
Quick Start with SARE CLI
SARE CLI is a command-line tool to manage keys, encrypt/decrypt files, and sign/verify files using hybrid post-quantum + classical cryptography.
Note: The CLI is fully functional, but some options (KDF customization, revocation broadcast) are not yet implemented. Defaults are used for now.
1. Generate a Master Key
sare-cli masterkey generate
This generates a new master key and creates:
- Validation Certificate: Confirms your public keys are valid for a specified period.
- Revocation Certificate: Can be published if your key is compromised.
Optional flags such as
--hybrid-kem-algorithm
or--hybrid-sign-algorithm
are present in the CLI but not fully functional yet.
List available master keys:
sare-cli masterkey list
Remove a master key:
sare-cli masterkey remove <masterkey_id>
Export info about a master key:
sare-cli masterkey export <masterkey_id>
2. Add or Manage Recipients
Add a recipient (so you can encrypt files for them):
sare-cli recipient add <path-to-public-key.pem>
Remove a recipient:
sare-cli recipient remove <recipient_id>
List all recipients:
sare-cli recipient list
3. Encrypt and Decrypt Files
Asymmetric Encryption
Encrypt a file for a recipient:
sare-cli encrypt asymmetric <input_file> <output_file> --recipient <recipient_id>
Decrypt a file:
sare-cli decrypt <input_file> <output_file> --masterkey-id <masterkey_id>
Note: Currently, KDF and algorithm options are fixed and cannot be modified.
Symmetric Encryption
Encrypt a file symmetrically:
sare-cli encrypt symmetric <input_file> <output_file>
Decrypt:
sare-cli decrypt <input_file> <output_file>
4. Sign and Verify Files
Generate a signature for a file:
sare-cli signature generate <input_file> <sign_file> --masterkey-id <masterkey_id>
Verify a signature:
sare-cli signature verify <sign_file> <input_file>
5. Revocation Certificates
Generate a new revocation certificate (replaces old):
sare-cli revocation new --reason compromised --masterkey-id <masterkey_id>
List revocation certificates:
sare-cli revocation list
Note:
revocation broadcast
is not implemented yet because keyserver support is pending.
Example Usage of SARE Lib
Encrypting and Decrypting Files
SARE Lib allows you to encrypt and decrypt files using either symmetric (passphrase-based) or asymmetric (public/private key-based) methods. Below are examples for both approaches.
Symmetric Encryption
Use symmetric encryption when you want to protect a file using just a passphrase. This is fast and simple for personal use or sharing with a small group.
#![allow(unused)] fn main() { use sare_lib::{encryption::Encryptor, keys::{EncryptionAlgorithm, RECOMMENDED_PKDF_PARAMS}}; use secrecy::SecretVec; use std::fs::File; let input_file = File::open("message.txt")?; let mut output_file = File::create("message.enc")?; let passphrase = SecretVec::new(b"supersecret".to_vec()); // Generate key derivation function (KDF) using recommended parameters let pkdf = Encryptor::get_pkdf(&passphrase, RECOMMENDED_PKDF_PARAMS, 1); // Encrypt the file symmetrically using XChaCha20-Poly1305 AEAD Encryptor::encrypt_with_passphrase(&mut input_file, &mut output_file, pkdf, EncryptionAlgorithm::XCHACHA20POLY1305)?; }
Symmetric Decryption
To access your encrypted data, provide the same passphrase used during encryption.
#![allow(unused)] fn main() { use sare_lib::encryption::Decryptor; use secrecy::SecretVec; use std::fs::File; let mut input_file = File::open("message.enc")?; let mut output_file = File::create("message_decrypted.txt")?; let passphrase = SecretVec::new(b"supersecret".to_vec()); Decryptor::decrypt_with_passphrase(passphrase, &mut input_file, &mut output_file)?; }
Asymmetric Encryption
For secure sharing with others, use asymmetric encryption. You encrypt with the recipient’s public key, and only they can decrypt with their private key.
#![allow(unused)] fn main() { use sare_lib::{encryption::Encryptor, keys::{MasterKey, SharedPublicKey, EncryptionAlgorithm}}; use std::fs::File; let input_file = File::open("document.txt")?; let mut output_file = File::create("document.enc")?; // Load master key and recipient public key let master_key = MasterKey::load("MASTER_KEY.pem")?; let recipient_key = SharedPublicKey::from_pem(std::fs::read_to_string("recipient.pem")?)?; let encryptor = Encryptor::new(master_key); encryptor.encrypt_with_recipient(&mut input_file, &mut output_file, &recipient_key, EncryptionAlgorithm::XCHACHA20POLY1305)?; }
Asymmetric Decryption
The recipient can decrypt the file using their master key. SARE Lib also allows you to detect and verify any attached signatures automatically.
#![allow(unused)] fn main() { use sare_lib::encryption::Decryptor; use std::fs::File; // Load your master key let master_key = MasterKey::load("MASTER_KEY.pem")?; let decryptor = Decryptor::new(master_key); let mut input_file = File::open("document.enc")?; let mut output_file = File::create("document_decrypted.txt")?; // Decrypt the file let signature = decryptor.decrypt_with_recipient(&mut input_file, &mut output_file)?; if let Some(sig) = signature { println!("Signature attached: {:?}", sig.fullchain_fingerprint); } }
Signing and Verifying
SARE allows you to create detached signatures, ensuring that your files can be verified without modifying the original content.
Detached Signature
#![allow(unused)] fn main() { use sare_lib::signing::Signing; use std::fs; let master_key = MasterKey::load("MASTER_KEY.pem")?; let signer = Signing::new(master_key); let message = fs::read("report.txt")?; let signature = signer.sign_detached(&message); fs::write("report.sig", signature.encode_with_magic_byte())?; }
Verifying a Detached Signature
Verification ensures the integrity and authenticity of a file by comparing it with the signature.
#![allow(unused)] fn main() { use sare_lib::signing::Signing; use sare_lib::format::signature::SignatureHeaderFormat; use std::fs; let signed_file = fs::read("report.sig")?; let original_file = fs::read("report.txt")?; let signature_header = SignatureHeaderFormat::decode_with_magic_byte(&signed_file)?; let is_valid = Signing::verify_detached(&signature_header, &original_file)?; println!("Signature valid: {}", is_valid); }
Master Key Management
Master keys are central to SARE's security. They allow you to manage encryption, signing, and validation certificates.
Generate a Master Key
#![allow(unused)] fn main() { use sare_lib::keys::{MasterKey, HybridKEMAlgorithm, HybridSignAlgorithm}; let master_key = MasterKey::generate( HybridKEMAlgorithm::default(), HybridSignAlgorithm::default() ); // Export the master key (optionally encrypted with a passphrase) master_key.export(Some("supersecret".as_bytes().to_vec().into()), &mut std::fs::File::create("MASTER_KEY.pem")?)?; // Export public key master_key.export_public(&mut std::fs::File::create("PUB_KEY.pem")?)?; }
Inspect a Master Key
You can inspect master keys to verify fingerprints or recover mnemonic seeds.
#![allow(unused)] fn main() { let master_key = MasterKey::load("MASTER_KEY.pem")?; println!("Master Key Fingerprint: {:?}", master_key.get_fullchain_public_fingerprint()); println!("Mnemonic Seed: {}", master_key.to_mnemonic().expose_secret()); }
Revoke a Master Key
If a key is compromised or no longer needed, create a revocation certificate to signal that it should not be used.
#![allow(unused)] fn main() { use sare_lib::{certificate::Certificate, format::certificate::Issuer, format::certificate::RevocationReason}; let master_key = MasterKey::load("MASTER_KEY.pem")?; let issuer = Issuer::new("Your Name", "your@email.com"); let revocation_cert = Certificate::new_revocation(master_key, 1682611200, issuer, RevocationReason::NoReasonSpecified); revocation_cert.export(std::fs::File::create("REVOC_KEY.asc")?)?; }
Recipient Management
Recipients represent the people you share encrypted files with. SARE makes it easy to add, export, and verify recipient keys.
#![allow(unused)] fn main() { use sare_lib::keys::SharedPublicKey; // Add a recipient let recipient_key = SharedPublicKey::from_pem(std::fs::read_to_string("recipient.pem")?)?; recipient_key.export(std::fs::File::create("RECIPIENT.pem")?)?; // Load and list recipients let recipient_key = SharedPublicKey::from_pem(std::fs::read_to_string("RECIPIENT.pem")?)?; println!("Recipient fingerprint: {:?}", recipient_key.fullchain_public_key.calculate_fingerprint()); }
Technical Reference
This section provides a deep dive into the internal structure and cryptographic foundations of SARE.
It is intended for developers and security researchers who want to understand how SARE works under the hood, integrate it into their own applications, or audit its design.
SARE is split into three layers:
- sare-core: Low-level cryptographic operations and file format handling.
- sare-lib: High-level library built on top of
sare-core
to make integration easy. - sare-cli: A command-line interface that demonstrates and exposes SARE’s features.
Contents
-
SARE File Format
Describes how encrypted files are structured, including metadata, nonces, checksums, and signatures. -
Cryptographic Primitives
The algorithms and operations that form the foundation of SARE, including hybrid KEM, hybrid signatures, and KDFs. -
Certificates
Validation and revocation certificates, their structure, and their role in the trust model. -
SareDB
A CLI-only JSON database for managing keys and recipients. Not part of the library but used insare-cli
.
Design Notes
- Self-describing encryption: Metadata contains everything needed to decrypt.
- Hybrid classical + post-quantum: Ensures security both today and in a future with large-scale quantum computers.
- Clear separation of layers:
sare-core
provides primitives,sare-lib
simplifies usage, andsare-cli
offers practical workflows.
For detailed information, follow the links in each section.
File Formatting in SARE
SARE defines its own structured formats for both encrypted files and signature files, providing consistency, versioning, and support for cryptographic metadata. This ensures that files can be properly decoded, verified, and decrypted across different SARE implementations.
Encrypted Files Format
Encrypted files in SARE are not just raw ciphertext—they include a structured header containing all metadata necessary for decryption and verification.
Structure
-
Magic bytes:
A predefined sequence to identify the file as a SARE-encrypted message. -
Version:
Each file includes a version number to allow backward and forward compatibility. The current SARE version is embedded in the header. -
Encryption metadata:
This metadata is part of the file header and includes:-
The symmetric encryption algorithm used (e.g., XChaCha20-Poly1305 for files).
-
Nonces for stream encryption.
-
Optional PKDF metadata if password-based encryption is used.
-
Optional KEM metadata if asymmetric encryption is used, describing the key encapsulation and shared secrets.
-
Encoding and Decoding
-
The header is encoded in binary.
-
The metadata is BSON-serialized, allowing easy extension while keeping the structure machine-readable.
-
During decryption, SARE reads the header, extracts metadata, derives the encryption key (via PKDF or HybridKEM + HKDF), and then decrypts the file content.
Note: Encrypted files are strictly binary-encoded. PEM/ASCII-armoring is not used for encrypted files.
Signature Files Format
Signature files in SARE store cryptographic signatures independently of encrypted content. They follow a structured, self-contained format.
Structure
-
Magic bytes:
Each signature file starts withSARESIGN
to identify it as a SARE signature. -
Versioning:
Au32
version number is included to support backward and forward compatibility. -
Signature metadata:
Metadata includes:-
EC and post-quantum (PQ) algorithms used.
-
Optional cryptographic metadata, such as public keys and algorithm parameters.
-
-
Signature content:
-
Public keys (EC and PQ)
-
The message itself (optional;
None
for detached signatures) -
EC and PQ signature values
-
Full-chain fingerprint for verification
-
Encoding and Decoding
-
Signature files can be encoded in binary (via BSON) or as PEM-encoded files:
-
Binary encoding is standard.
-
PEM encoding provides ASCII-armored files, though SARE CLI currently does not implement the armor option.
-
-
Methods:
-
encode_with_magic_byte()
/decode_with_magic_byte()
handle the header and magic bytes. -
encode_bson()
/decode_bson()
handle metadata serialization. -
encode_pem()
/decode_pem()
allow ASCII-armored serialization.
-
Notes
-
Certificates in SARE use the same BSON-encoded signature format but are documented separately.
-
Detached and attached signatures are supported; the presence of
message
indicates an attached signature.
This design ensures that both encrypted files and signature files are self-describing, versioned, and extensible while remaining secure and compatible across SARE implementations.
Cryptographic Primitives
Cryptographic primitives are the building blocks of secure systems.
They include encryption algorithms, signature schemes, key exchange methods, and key derivation functions.
SARE combines classical elliptic-curve cryptography with post-quantum algorithms to provide long-term security.
Symmetric Cryptography
Symmetric algorithms are used for encrypting file contents and wrapping keys.
They are efficient and secure, even in the post-quantum era.
- XChaCha20-Poly1305 — AEAD algorithm for streaming encryption with confidentiality and integrity.
- AES-256-GCM — AEAD alternative based on AES.
- AES-256 Key Wrap (AES-KW) — Used to wrap (encrypt) symmetric keys securely.
Each encrypted file includes a unique nonce in its metadata to prevent key/nonce reuse attacks.
Asymmetric Cryptography
Asymmetric primitives are used for exchanging keys, verifying identities, and creating digital signatures.
-
Classical algorithms:
Ed25519
(signatures)X25519
(key exchange)
-
Post-quantum algorithms:
Dilithium3
(signatures)Kyber
(key encapsulation mechanism)
Hybrid KEM
SARE’s Hybrid KEM combines:
- A classical Diffie-Hellman exchange (
X25519
) - A post-quantum KEM (
Kyber
)
This produces two shared secrets.
SARE then uses HKDF to derive a final symmetric key by hashing the concatenation of both secrets.
This ensures security against both classical and quantum adversaries.
Read more →
Hybrid Signatures
When signing data, SARE generates two signatures:
- One classical (
Ed25519
) - One post-quantum (
Dilithium3
)
Both signatures must verify successfully.
This ensures trust even if one algorithm is broken in the future.
Read more →
Key Derivation Functions (KDFs)
Key derivation is central to SARE:
- HKDF: Derives symmetric keys from shared secrets in Hybrid KEM.
- PKDF: Derives keys from user passphrases when encrypting with a password.
Each derived key is tied to a salt and algorithm identifier, preventing reuse across contexts.
Read more →
Randomness & Nonces
Every encryption uses secure randomness:
- Nonces ensure ciphertext uniqueness.
- Salts in KDFs prevent rainbow-table attacks.
The randomness source is the system’s cryptographically secure RNG.
Summary
Primitive Type | Algorithm(s) Used | Purpose |
---|---|---|
Symmetric | XChaCha20-Poly1305, AES | File encryption, AEAD |
Key Wrapping | AES-KW | Encrypting symmetric keys |
Asymmetric (class.) | X25519, Ed25519 | DH exchange, digital signatures |
Asymmetric (PQ) | Kyber, Dilithium3 | PQ KEM, PQ signatures |
KDFs | HKDF, PKDF | Deriving keys from secrets or passphrases |
These primitives form the secure foundation for SARE’s encryption, signatures, and certificate model.
Hybrid KEM (Key Encapsulation Mechanism)
SARE uses a Hybrid Key Encapsulation Mechanism (KEM) to securely derive encryption keys for asymmetric file encryption. The hybrid approach combines a classical Diffie-Hellman key exchange with a post-quantum KEM, ensuring robust security even against future quantum attacks.
The hybrid KEM generates two independent shared secrets that are later combined and processed to produce a single symmetric encryption key for AEAD encryption.
Supported Algorithms
Currently, SARE supports the following hybrid KEM algorithms:
-
Classical DH:
X25519
-
Post-Quantum KEM:
Kyber768
Each hybrid KEM consists of a classical DH component and a post-quantum KEM component. Additional algorithms can be added as needed.
Shared Secret Generation
-
Classical DH Shared Secret
-
Generated using the sender’s DH keypair and the recipient’s DH public key.
-
In sare-core:
DiffieHellman::calculate_shared_key() → ss1
.
-
-
Post-Quantum KEM Shared Secret
-
Generated using the sender’s KEM keypair and the recipient’s KEM public key.
-
In sare-core:
Decapsulation::decapsulate() → ss2
.
-
These two secrets are independent and form the basis of the final symmetric key derivation.
Encryption Key Derivation with HKDF
SARE combines the two shared secrets as follows in sare-lib:
combined_ss = ss1 || ss2
Then it derives the final encryption key using HKDF-SHA256:
encryption_key = HKDF(combined_ss, salt, info)
-
combined_ss
– Concatenation of the two shared secrets. -
salt
– Randomly generated per encryption session. -
info
– Optional contextual info (can beNone
). -
encryption_key
– Final key used for AEAD encryption.
This design ensures that the compromise of one component does not expose the encryption key, providing post-quantum resilience for encrypted files.
Hybrid Signatures
Hybrid Signatures in SARE combine a classical digital signature with a post-quantum signature to ensure long-term integrity and non-repudiation of files.
The rationale for using a hybrid approach is to future-proof signatures against quantum attacks while maintaining compatibility with current cryptographic standards. By combining classical and post-quantum signatures, SARE ensures that a file remains verifiable even if one algorithm is later broken.
How Hybrid Signatures Work
When a file is signed in SARE:
-
Classical Signature Generation
-
Typically uses
Ed25519
. -
Signs the SHA3-256 checksum of the file or message.
-
-
Post-Quantum Signature Generation
-
Uses a PQ signature algorithm (e.g.,
Dilithium
orFalcon
, depending on configuration). -
Also signs the same file checksum.
-
Both signatures are generated independently but stored together.
Verification Rule:
-
A file is only considered authentic if both signatures verify correctly.
-
Failure of either signature invalidates the file’s integrity.
Signature Formatting
SARE stores signatures in a structured format included in the file header:
SignatureFormat {
ec_signature: Vec<u8>, // e.g., Ed25519
pq_signature: Vec<u8>, // e.g., Dilithium
fullchain_fingerprint: [u8; 32], // Identifier for the keychain used
signature_metadata: Option<...>, // Additional metadata such as version, key ID
}
-
ec_signature
– The bytes of the classical signature. -
pq_signature
– The bytes of the post-quantum signature. -
fullchain_fingerprint
– Fingerprint of the signer’s keychain to identify which key generated the signature. -
signature_metadata
– Optional metadata that may include algorithm versioning or key identifiers.
End Result:
-
When a file is encrypted or signed, the hybrid signature is attached to the file header.
-
Tools like the CLI will verify both signatures and report validity.
Master Keys
A Master Key in SARE is the root secret that deterministically derives all cryptographic keys (encryption, signing, hybrid, etc.). Its security relies on the master seed, which must be stored securely.
Master Seed
-
The master seed is a high-entropy secret, stored as a
SecretVec<u8>
. -
Generated via a cryptographically secure RNG.
-
Used to deterministically derive all hybrid KEM/Sign keypairs.
Master Key Storage Formats
Secret Key Format (SecretKeyFormat
)
#![allow(unused)] fn main() { #[derive(Serialize, Deserialize)] pub struct SecretKeyFormat { pub ec_algorithm: ECAlgorithm, pub pq_algorithm: PQAlgorithm, pub dh_algorithm: DHAlgorithm, pub kem_algorithm: KEMAlgorithm, #[serde(with = "secret_vec_serde")] pub master_seed: SecretVec<u8>, #[serde(skip_serializing_if = "Option::is_none", flatten)] pub encryption_metadata: Option<EncryptionMetadataFormat>, } }
-
master_seed: the root secret (raw or encrypted).
-
encryption_metadata: optional; only present if the seed is encrypted with a password. Contains either:
-
pkdf_metadata
– information about the password-based key derivation function (algorithm, salt) -
kem_metadata
– for hybrid KEM-based wrapping of the seed (optional).
-
Key points:
-
If
encryption_metadata.pkdf_metadata
is present, SARE will attempt to decrypt the seed using AES Key Wrap with the key derived via the PKDF. -
If
encryption_metadata.pkdf_metadata
is absent, the seed is raw and used directly.
BSON Representation
- Stored as a standard BSON document:
{
"ec_algorithm": "EC_ALGO_NAME",
"pq_algorithm": "PQ_ALGO_NAME",
"dh_algorithm": "DH_ALGO_NAME",
"kem_algorithm": "KEM_ALGO_NAME",
"master_seed": "<raw or encrypted bytes>",
"encryption_metadata": {
"pkdf_metadata": {
"pkdf_algorithm": "PBKDF2 | Argon2 | ...",
"pkdf_salt": "<salt bytes>"
},
"kem_metadata": { ... } // optional
}
}
-
The
encryption_metadata
field is optional. -
Raw seeds omit
encryption_metadata
.
PEM Representation
- The entire BSON (raw or encrypted) is Base64-encoded into PEM:
-----BEGIN SARE MASTER KEY-----
<base64-encoded BSON or encrypted seed>
-----END SARE MASTER KEY-----
- Can be imported/exported via CLI or programmatic interfaces.
Encrypted Master Keys
-
Password Key Derivation
-
If a password is provided, SARE uses the PKDF algorithm specified in
pkdf_metadata
to derive an AES-KW key. -
Example PKDFs: PBKDF2, Argon2.
-
-
AES Key Wrap
- The derived key encrypts (wraps) the master seed, producing a protected
master_seed
inSecretKeyFormat
.
- The derived key encrypts (wraps) the master seed, producing a protected
-
Optional KEM Wrapping
- For hybrid setups,
kem_metadata
can store a KEM-based encrypted seed instead of or in addition to PKDF.
- For hybrid setups,
-
Decryption Logic
-
If
encryption_metadata.pkdf_metadata
exists, SARE derives the AES-KW key and unwraps the seed. -
Otherwise, the seed is treated as raw.
-
Fingerprint Calculation
- The fingerprint is SHA256 over the
master_seed
bytes:
#![allow(unused)] fn main() { impl SecretKeyFormat { pub fn calculate_fingerprint(master_seed: SecretVec<u8>) -> Vec<u8> { let mut hasher = Sha256::new(); hasher.update(master_seed.expose_secret()); let fingerprint: [u8; 32] = hasher.finalize().into(); fingerprint[..=16].to_vec() } } }
- Used to uniquely identify the master key without exposing the seed.
FullChain Public Keys
A FullChain Public Key in SARE combines both signature and encryption public keys into a single, exportable structure. It is used to verify signatures and encrypt data for the holder of the corresponding master key.
Structure
The full chain contains two main components:
#![allow(unused)] fn main() { #[derive(Serialize, Deserialize, Clone)] pub struct FullChainPublicKeyFormat { pub signature_public_key: SignaturePublicKeyFormat, pub encryption_public_key: EncryptionPublicKeyFormat, } }
Signature Public Key (SignaturePublicKeyFormat
)
- Combines classical elliptic-curve (EC) and post-quantum (PQ) algorithms:
#![allow(unused)] fn main() { pub struct SignaturePublicKeyFormat { pub ec_algorithm: ECAlgorithm, pub pq_algorithm: PQAlgorithm, pub ec_public_key: Vec<u8>, pub pq_public_key: Vec<u8>, } }
- Both EC and PQ signatures must verify successfully for a message to be trusted.
Encryption Public Key (EncryptionPublicKeyFormat
)
- Combines Diffie-Hellman (DH) and hybrid KEM algorithms:
#![allow(unused)] fn main() { pub struct EncryptionPublicKeyFormat { pub dh_algorithm: DHAlgorithm, pub kem_algorithm: KEMAlgorithm, pub dh_public_key: Vec<u8>, pub kem_public_key: Vec<u8>, } }
- Used for hybrid KEM-based key agreement to encrypt secrets for this key holder.
Export Formats
BSON
- The full chain can be encoded as BSON:
{
"signature_public_key": {
"ec_algorithm": "EC_ALGO",
"pq_algorithm": "PQ_ALGO",
"ec_public_key": "<bytes>",
"pq_public_key": "<bytes>"
},
"encryption_public_key": {
"dh_algorithm": "DH_ALGO",
"kem_algorithm": "KEM_ALGO",
"dh_public_key": "<bytes>",
"kem_public_key": "<bytes>"
}
}
PEM
- Encoded as a standard PEM block:
-----BEGIN SARE FULLCHAIN PUBLIC KEY-----
<base64-encoded BSON>
-----END SARE FULLCHAIN PUBLIC KEY-----
Fingerprint
The fingerprint uniquely identifies a full chain public key and is derived deterministically from all contained public key components.
#![allow(unused)] fn main() { impl FullChainPublicKeyFormat { pub fn calculate_fingerprint(&self) -> [u8; 32] { let mut hasher = Sha256::new(); // EC signature component hasher.update(self.signature_public_key.ec_algorithm.to_string().as_bytes()); hasher.update(&self.signature_public_key.ec_public_key); // PQ signature component hasher.update(self.signature_public_key.pq_algorithm.to_string().as_bytes()); hasher.update(&self.signature_public_key.pq_public_key); // DH encryption component hasher.update(self.encryption_public_key.dh_algorithm.to_string().as_bytes()); hasher.update(&self.encryption_public_key.dh_public_key); // KEM encryption component hasher.update(self.encryption_public_key.kem_algorithm.to_string().as_bytes()); hasher.update(&self.encryption_public_key.kem_public_key); let fingerprint: [u8; 32] = hasher.finalize().into(); fingerprint } } }
Notes:
-
Uses SHA-256 over all algorithm identifiers and public key bytes.
-
Ensures unique identification of each full chain public key.
-
Safe to share publicly, as it contains only public information.
Encryption and Decryption in SARE
SARE provides both symmetric and asymmetric encryption mechanisms to protect data, combining modern cryptographic primitives with flexible key management.
Underlying Algorithms
Currently, SARE supports the following primary algorithms:
-
XChaCha20-Poly1305: Used for symmetric encryption of file contents. Provides strong authenticated encryption with a large nonce space.
-
AES-256 Key Wrap (AES-KW): Used for securely wrapping smaller cryptographic keys, ensuring confidentiality and integrity of key material.
Other algorithms such as AES-GCM are listed but not implemented yet.
Key Derivation for Encryption
SARE separates the encryption algorithm from the key derivation process, allowing flexibility and additional security measures:
-
Symmetric encryption from passwords:
A passphrase is converted into a cryptographic key using a password-based key derivation function (PKDF). This ensures that even weak passwords are transformed into keys that are safe for encryption. -
Asymmetric encryption for recipients:
Using a Hybrid Key Encapsulation Mechanism (HybridKEM), SARE generates two shared secrets between the sender and the recipient. These secrets are combined and expanded via an HKDF to produce the final symmetric encryption key.Note: Even in asymmetric scenarios, the underlying encryption algorithm remains symmetric (e.g., XChaCha20-Poly1305), providing efficiency and post-quantum security from the key exchange.
Encryption Metadata and File Headers
Encrypted files in SARE are not just raw ciphertext—they include structured metadata to support decryption, verification, and key management:
-
Encryption metadata includes:
-
The algorithm used for encrypting the file (e.g., XChaCha20-Poly1305).
-
Nonces for stream encryption.
-
Optional key encapsulation metadata (for asymmetric encryption).
-
Optional PKDF metadata (for password-based encryption).
-
-
File header:
Every encrypted file contains a header that embeds this encryption metadata along with other metadata, such as digital signatures or comments. This allows SARE to fully describe the encrypted content and recover the key material without requiring external parameters.
The encryption metadata is a defined format within the header but has its own documentation for further details.
Encrypting and Decrypting Data
-
Symmetric encryption (e.g., with a passphrase) involves:
-
Deriving a key via PKDF.
-
Initializing an
Encryptor
with the derived key and the chosen algorithm. -
Writing the structured file header, followed by the encrypted content.
-
-
Asymmetric encryption (e.g., for a recipient) involves:
-
Generating shared secrets via HybridKEM.
-
Deriving a symmetric encryption key via HKDF.
-
Encrypting the file content using XChaCha20-Poly1305.
-
Embedding key encapsulation and encryption metadata into the file header.
-
-
Decryption mirrors these processes:
-
Reading and decoding the file header to obtain metadata.
-
Recovering the encryption key (via PKDF or HybridKEM + HKDF).
-
Decrypting the content with the chosen symmetric algorithm.
-
This design ensures that SARE encrypted files are self-describing, secure against modern attacks, and compatible with both password-based and recipient-based key management workflows.
Key Derivation Functions (KDFs) in SARE
In SARE, cryptographic keys are derived systematically to ensure security and uniqueness across different algorithms and use cases. Two main categories of KDFs are employed: HKDF for general key derivation and password-based KDFs (PKDFs) for deriving keys from user-supplied secrets like passwords.
HKDF-Based Key Derivation
SARE uses the HMAC-based Key Derivation Function (HKDF) to expand secret material into cryptographic keys. The specific hash function used depends on the desired key size:
- 32-byte keys (256-bit): Use SHA-256.
- 64-byte keys (512-bit): Use SHA-512.
Each HKDF derivation includes algorithm-specific magic bytes to ensure that even if the same input material is used across multiple algorithms, the resulting keys are unique. These magic bytes are prepended or mixed into the input seed when deriving keys for different algorithms.
Example usage:
Key size: 32 bytes → SHA-256 HKDF
Magic bytes: [25, 85, 210, 14] (for Ed25519, for instance)
Key size: 64 bytes → SHA-512 HKDF
Magic bytes: [104, 7, 0, 0] (for Kyber768, for instance)
This mechanism guarantees that each derived key is tied not only to the input seed but also to the cryptographic algorithm and context, preventing key collisions.
Password-Based Key Derivation (PKDF)
For symmetric encryption or key wrapping, SARE derives keys from passwords using scrypt. This function applies configurable parameters to increase computational cost and memory usage, defending against brute-force attacks.
Typical flow:
- Generate a random salt (8 bytes by default).
- Apply scrypt with specified parameters
(N, r, p)
to the password and salt. - Extract a key of the required length.
Scrypt ensures that even weak passwords produce keys resistant to offline attacks, and the salt guarantees that identical passwords produce different keys.
Example parameters:
N = 2^5 = 32
r = 8
p = 1
Derived keys from PKDFs can then be safely used for:
- Symmetric encryption
- Key wrapping for secure storage
- Hybrid cryptographic constructions alongside HKDF-derived keys
Summary
- HKDF: Produces algorithm-specific keys using magic bytes, keyed on SHA-256 or SHA-512 depending on the output size.
- PKDF (scrypt): Converts passwords into cryptographic keys, incorporating salt and computationally intensive parameters to protect against brute-force attacks.
- All derived keys are unique per algorithm and purpose due to the combination of input material, salt, and magic bytes.
Certificates in SARE
SARE uses certificates to provide verifiable proof about public keys and their status. Certificates in SARE are self-contained, cryptographically signed documents that are BSON-encoded and stored in PEM format in SARE CLI.
Types of Certificates
SARE currently supports two main types of certificates:
1. Validation Certificates
-
These certificates are attached to a full-chain public key.
-
They indicate that a particular public key is valid and can be trusted within a SARE network.
-
Validation certificates include:
-
Issuer information (name and email)
-
Expiry date (optional)
-
Full-chain public key fingerprint (ensures the certificate is linked to a specific key)
-
-
Validation certificates are signed by a SARE master key to ensure authenticity.
2. Revocation Certificates
-
Used to indicate that a previously valid public key or certificate is no longer trustworthy.
-
Revocation certificates include:
-
Revocation date
-
Revocation reason (e.g.,
Compromised
orNoReasonSpecified
) -
Full-chain fingerprint of the revoked public key
-
-
Revocation certificates are also signed with a SARE master key to prevent tampering.
Certificate Structure
All SARE certificates consist of:
-
Issuer Metadata:
-
name
: the name of the issuer -
email
: the email of the issuer
-
-
Optional Expiry Date:
- For validation certificates, defines when the certificate should no longer be considered valid
-
Certificate Type (via
CertificateType
enum):-
Validation: contains
ValidationCertificateFormat
with the full-chain public key fingerprint -
Revocation: contains
RevocationCertificateFormat
with revocation details
-
-
Signature:
-
Every certificate is cryptographically signed by the issuing master key.
-
SARE uses its internal
SignatureHeaderFormat
to encode the signature alongside the certificate data.
-
Encoding and Storage
-
Certificates are BSON-encoded, allowing structured storage of metadata and cryptographic information.
-
For portability and interoperability, certificates are stored in PEM format in SARE CLI. The PEM tag depends on the type:
-
Validation certificates:
SARE VALIDATION CERTIFICATE
-
Revocation certificates:
SARE REVOCATION CERTIFICATE
-
-
PEM format provides ASCII-armoring, making the certificates easy to transport, copy, and distribute.
Certificate Operations
SARE provides utilities to handle certificates:
-
Creation:
-
new_validation()
— create a validation certificate attached to a public key -
new_revocation()
— create a revocation certificate specifying the revocation reason
-
-
Export:
- Certificates can be exported as PEM files to any writable stream
-
Import:
- PEM-encoded certificates can be imported and decoded into a SARE certificate object
-
Verification:
- All certificates can be verified cryptographically using the attached signature
-
Accessing Data:
- The certificate’s revocation or validation details can be accessed via helper methods
Notes
-
Both validation and revocation certificates are signed and verifiable, ensuring authenticity and integrity.
-
While SARE CLI uses PEM format for certificates, the underlying representation is BSON-encoded, consistent with other SARE formats like encrypted files and signatures.
-
Certificates are self-contained and portable, making them suitable for secure key management and revocation in a SARE environment.
SareDB in SARE-CLI
SareDB
is a command-line specific component of SARE. It is not part of the core SARE library (sare-lib
) and exists purely to facilitate local management of keys and recipients in SARE CLI.
⚠️ Note:
SareDB
is in an early stage and may evolve significantly in future versions.
Purpose
SareDB
is designed to act as a lightweight, local database for storing:
-
Master key associations
-
Links a master key identifier to associated keys and revocation certificates.
-
Each association is stored as a
SareDBAssociatedKey
object containing:-
public_key_id
— the associated public key ID -
revocation_certificate_id
— the linked revocation certificate ID
-
-
-
Recipients
-
Tracks known recipients to simplify encryption workflows.
-
Stored as
SareDBRecipient
objects with:-
fullchain_fingerprint
— the recipient’s key fingerprint -
Optional
comment
-
date_added
timestamp
-
-
Structure and Storage
-
Internally,
SareDB
uses twoHashMap
s:-
key_associations
: maps a master key ID to its associated key information. -
recipients
: maps a recipient identifier to recipient metadata.
-
-
The database is serialized and stored as a JSON file in the SARE directory, making it human-readable and easy to inspect.
-
version
field allows for future upgrades or migrations to the database format.
Functionality
SareDB
provides the following operations:
-
Adding and updating keys
add_key_association(master_key_id, associated_key)
inserts or updates a master key association.
-
Adding recipients
add_recipient(recipient_id, recipient)
adds a new recipient to the database.
-
Retrieving information
-
get_key_association(master_key_id)
returns an associated key if it exists. -
list_recipients()
returns all stored recipients.
-
-
Persistence
-
import_from_json_file()
loads the database from JSON or returns an empty database if the file does not exist. -
save_to_json_file()
writes the current database to JSON for persistence between CLI sessions.
-
Notes
-
SareDB
is primarily intended for local, per-user storage. It is not a cryptographically secure or distributed database. -
Since SARE CLI is still under active development, the structure, storage format, and supported fields may change. Users should not rely on
SareDB
as a stable long-term API.
Keep The Project Alive ❤️
Support Sare's Development
Sare is an open-source project driven by community contributions and support. If you find Sare valuable and would like to contribute to its continued development and improvement, consider making a donation. Your support helps us maintain and enhance Sare for the benefit of all users.
Cryptocurrency Donations
You can support us by making donations in various cryptocurrencies. Your contributions help support ongoing development, and ensure the sustainability of the project.
-
Monero (XMR):
8AF4Lybz7QwiucdYW2szsgiqTHdBp5kjZSSRm6ddzd5363S6n4jixpkACGMLx5JWZnUR5MnGF7cMoidjppruAvLvMe2ovHZ
-
Bitcoin (BTC):
bc1qdzdlytujxn3l02vdt90xx5pkqlezxpuucs6fmm
-
Ethereum (ETH):
0x9E00DC6bE0d07bDB5Ff8B62593a0193913c9B595
-
Bitcoin Cash (BCH):
qzmxuv82j9n2zlxkylrz882yk9e50wvzz5a6hqy2dc
-
Dash:
XamhGMK5XM1wPKqSiF8HACJsToVmW4jMGL
-
Dogecoin (DOGE):
DBEaZAbo5tDk7LuXd7pCkhQMa2h8kBgVbS
-
Litecoin (LTC):
ltc1qrex5xq3px5qn9vjplfkmvzf7sweks3r4skxe5k
-
Matic (MATIC):
0x9E00DC6bE0d07bDB5Ff8B62593a0193913c9B595
-
TON (Free TON):
EQAjMitBSLjcl4DwthElddvuRSW3N-Dvd0HX-RkGMUVsC9sT
-
TRON (TRX):
TUT762nFQQRoXvDe1Z72p3kKH9uY3XZCg9
-
Zcash (ZEC):
t1WbpyRF7sXidefAzA5Vb922dsR3PLe9bRZ
-
Stellar (XLM):
GDT7GJS6U3N2CCWNQAORW2EJ2XFDCUGXOGZXEMGKOP6ILQ77ZIPN3ET4
-
Cosmos (ATOM):
cosmos1pwu953l57000n9hleerzm3hzaclldhpxf86l32
-
Solana (SOL):
5TT1URTgmnXziXXS1avgV4uF7Dwj5f3MNHLPcZtQKVk9
-
Ravencoin (RVN):
RLN8CqRzgDajY77Sd3xYREVLheTYEb7rWc
Your contributions are highly appreciated, and they play a crucial role in the ongoing development of Sare. Thank you for supporting the project!