The library behind dove — client-side-encrypted, expiring file sharing from a cloud you own.
dove-core is the whole engine with the terminal peeled off: the AES-256-GCM
container format, the S3 + access-gate transfer, the provisioner, and the
config → backend registry. It does no I/O to a terminal — it takes resolved
inputs and reports progress through a callback — so the dove
CLI, a desktop app, and any other front-end
drive the exact same audited code. Encryption keys never leave the library;
share hands back a finished link, never raw key material.
cargo add dove-coreEverything routes through one Transfer seam. Resolve the active backend from
the local config and share a file — no key material or terminal output crosses
the boundary:
use dove_core::{resolve, config::Registry, progress::Silent, transfer::ShareRequest};
use std::time::Duration;
fn main() -> dove_core::error::Result<()> {
// The active backend from ~/.config/dove — a self-hosted S3 + gate, or a
// discovered plugin. Building it is I/O-free; only use touches the network.
let registry = Registry::load()?;
let backend = resolve(®istry)?;
let share = backend.share(
ShareRequest {
path: "report.pdf".into(),
expires: Duration::from_secs(3 * 24 * 3600),
encrypt: true,
downloads: Some(1), // one-time link
pin: Some("4917".into()), // second factor, folded into the key
from: Some("Ada".into()),
message: None,
},
&Silent, // swap in your own `Progress` impl to drive a UI
)?;
// Hand this out. The decryption key rides its `#fragment` and never reaches
// a server; recipients decrypt in a browser or with `dove get`.
println!("{}", share.link);
Ok(())
}Transfer also gives you get, list, revoke, and status. Provisioning
(dove_core::provision) stands up the backing infrastructure in your own cloud;
it, too, reports through Progress and never prompts.
crypto— the chunked AES-256-GCM container (per-file nonce prefix, per-chunk counter, counter + terminal-flag in the AAD to reject reorder, truncation, and tampering). Byte-compatible with WebCrypto, so a browser decrypts exactly what this crate wrote (locked bytests/browser_crypto_compat.rs). Plus PBKDF2 PIN derivation, MAC'd share/request ids, and the E2E metadata blob.transfer— theTransfertrait and the built-inSelfHostedbackend (your S3 bucket, optional DynamoDB + access-gate for encrypted, download-limited, PIN-able links).factory—resolve: dispatch to the built-in backend, or discover adove-<kind>plugin binary, or fail legibly.config— a named-backend registry with an active pointer.provision— non-interactive provisioning of the S3 / DynamoDB / gate Lambda / CloudFront stack in an account you own.request— file requests: mint a PIN-gated link and collect a file someone else encrypts on their device and uploads to you.error— a typed error enum consumers can match on (needs a PIN, locked, gone, integrity failure, …).
The full design and threat model live in docs/DESIGN.md; the
file-request feature in docs/REQUEST.md. The dove CLI that
wraps this library is at boomctl/dove.
Core, gate, provisioning, and embedded-page follow-up work is tracked in the agent-ready OSS build list. Hosted-service and desktop plans are explicitly out of scope.
dove-core is co-built with Claude
(Anthropic's Claude Code) working alongside its author, and is a sibling to
git-ark.