Zero-knowledge secret sharing API built with Rust and Axum. Clients encrypt secrets locally; the server stores only the encrypted blob and never has access to plaintext, passphrases, or keys.
git clone https://github.com/Ryouku/OpenIronShare.git
cd OpenIronShare
docker compose up -dgit clone https://github.com/Ryouku/OpenIronShare.git
cd OpenIronShare
cargo build --release
./target/release/ironshareAPI available at http://localhost:3000.
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
sqlite:./ironshare.db |
SQLite connection string |
IRONSHARE_HOST |
0.0.0.0 |
Bind address |
IRONSHARE_PORT |
3000 |
Server port |
| Method | Endpoint | Description |
|---|---|---|
GET |
/ |
API info |
GET |
/health |
Health check |
GET |
/crypto.js |
Reference crypto implementation |
POST |
/api/secret |
Store encrypted secret |
GET |
/api/secret/:id/check |
Check existence (no view consumed) |
POST |
/api/secret/:id |
Retrieve encrypted secret |
Client: encrypt(plaintext, passphrase) → {ciphertext, iv, salt}
Client: POST /api/secret {ciphertext, iv, salt, ttl_minutes, max_views}
Server: stores encrypted blob → returns {id, expires_at}
Client: POST /api/secret/:id → receives {ciphertext, iv, salt}
Client: decrypt(ciphertext, iv, salt, passphrase) → plaintext
The server cannot decrypt secrets. A wrong passphrase fails silently client-side via AES-GCM authentication.
static/crypto.js is a complete WebCrypto API reference implementation using PBKDF2-SHA256 (600,000 iterations) and AES-256-GCM. Use it directly or port to any language.
// Generate a strong passphrase (~92 bits entropy)
const passphrase = IronCrypto.generatePassphrase();
// Encrypt
const { ciphertext, iv, salt } = await IronCrypto.encrypt("my secret", passphrase);
// Store
const { id } = await fetch("/api/secret", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ ciphertext, iv, salt, max_views: 1, ttl_minutes: 60 })
}).then(r => r.json());
// Retrieve and decrypt
const data = await fetch(`/api/secret/${id}`, { method: "POST" }).then(r => r.json());
const plaintext = await IronCrypto.decrypt(data.ciphertext, data.iv, data.salt, passphrase);ironshare/
├── src/
│ ├── main.rs # Entry point, DB setup, background cleanup
│ ├── handlers.rs # HTTP route handlers
│ ├── models.rs # Request/response types, validation
│ ├── db.rs # Database operations
│ └── config.rs # Environment configuration
├── static/
│ └── crypto.js # Reference crypto implementation
├── migrations/ # SQLite schema migrations
├── tests/ # Integration tests
├── docs/ # Documentation
├── nginx/ # Nginx config example
├── deploy/ # Systemd service and install scripts
├── Dockerfile
└── docker-compose.yml
- Fork and create a feature branch
- Make changes and run
cargo test - Run
cargo fmtandcargo clippy - Open a pull request
See Development Guide for full details.