# 🔮 Sage **Sage** is a lightweight cryptographic library built with Rust that layers [age](https://github.com/FiloSottile/age) encryption and [minisign](https://jedisct1.github.io/minisign/) signatures to enable **signed encryption** — ensuring both confidentiality **and** authenticity. Sage signs a message before encryption and again after encryption, verifying both layers on decryption. This offers **end-to-end message integrity, trust, and non-repudiation**. ## 🚀 Features - 🔐 Encryption with age - ✍️ Dual minisign signatures (before and after encryption) - ✅ Signature verification on both layers during decryption - 📦 Easy key serialization and identity management ## 🌱 Getting Started ### Generate a New Identity ```rust let id = sage::Identity::new(); let persona = id.public(); ``` - `Identity`: holds your private encryption and signing keys. - `Persona`: a tuple of `(age_public_key, minisign_public_key)` for sharing public keys. ### Encrypt and Sign ```rust let message = b"Hello, secure world!"; let recipient = persona.enc_key().unwrap(); // Recipient's age public key let ciphertext = id.encrypt(message, &recipient); ``` ### Verify and Decrypt ```rust let sender_pk = persona.sign_key().unwrap(); // Sender's minisign public key match id.decrypt(&ciphertext, &sender_pk) { Ok(msg) => { println!("Decrypted: {}", String::from_utf8_lossy(&msg.payload)); println!("Signed at timestamp: {}", msg.timestamp); } Err(err) => eprintln!("Failed to decrypt: {:?}", err), } ``` ## 📁 Saving & Loading Identities ```rust id.save("my_keys/"); let loaded = sage::Identity::try_load("my_keys/").unwrap(); ``` - Saves two files: `age.key` and `sign.key` ## 🔍 How It Works ### Encryption Flow 1. **Sign the plaintext** with minisign and add meta information (timestamp) 2. **Encrypt** the signed payload using age 3. **Sign the encrypted blob** with minisign again ### Decryption Flow 1. **Verify the outer signature** (authenticity of ciphertext) 2. **Decrypt** using the age identity 3. **Verify the inner signature** (authenticity of plaintext) 4. **Extract** message and timestamp ## 🙏 Credits - [age](https://github.com/FiloSottile/age) by Filippo Valsorda - [minisign](https://jedisct1.github.io/minisign/) by Frank Denis (jedisct1)