# yb-core
**Named blobs on a YubiKey, encrypted and signed by it, from Rust.**
[](https://crates.io/crates/yb-core)
[](https://docs.rs/yb-core)
[](https://github.com/douzebis/yb/blob/main/LICENSES/MIT.txt)
yb-core keeps small files (secrets, keys, a password database) in a
YubiKey 5's PIV data objects: about 50 KB in all, under names you
choose. Each blob can be encrypted with a key that never leaves the
YubiKey, or derived by it, and is signed or sealed by it, so that
tampering is detected before use.
It is the library under the [`yb`](https://crates.io/crates/yb) command
and libyubiblob, its C interface.
## Guarantees
Each one is documented, and checked by regression tests against emulated
YubiKeys ([the invariants](https://github.com/douzebis/yb/tree/main/docs/invariants)):
| **Interrupted writes lose nothing** | A YubiKey pulled out, or its memory full, mid-write: the previous version stays. |
| **Several programs, one YubiKey** | Operations take the card's lock, and their outcome is that of running them one at a time. |
| **Tampering is detected before use** | A blob altered on the YubiKey is refused before it is decrypted or returned. |
| **Reading never writes** | Listing and fetching change nothing on the YubiKey. |
| **The management key is never lost** | Changing it is interruption-safe, and it is held in memory that is wiped after use. |
## Features
- **Two kinds of store:**
- **legacy:** P-256 ECDH and AES-256-GCM, with ECDSA signatures;
- **post-quantum:** symmetric keys derived by the YubiKey's FIDO2
application (`hmac-secret`), one touch per blob.
- **Blobs** of any content, compressed when it helps (brotli or xz),
listed with their sizes and modification times.
- **PINs only when needed:** listing needs none; writing and decrypting
need the PIN.
- **Snapshots and conditional writes:** read the store once, and write
only if a blob is still as you last saw it.
- **Testing without a YubiKey:** `VirtualPiv`, a simulated YubiKey in
memory (feature `virtual-piv`).
## Example
The YubiKey must first be set up with `yb format --post-quantum` (from
the [`yb`](https://crates.io/crates/yb) command), with its FIDO2 PIN
set.
```rust,no_run
use yb_core::{orchestrator, store::Store, Compression, Context, ContextOptions, OutputOptions};
fn main() -> anyhow::Result<()> {
let mut ctx = Context::new(
ContextOptions::default(),
Box::new(|| Ok(None)), // no PIV PIN: not used by a post-quantum store
Box::new(|_, _| Ok(None)), // the only YubiKey connected
OutputOptions::default(),
)?;
ctx.fido2_pin_fn = Box::new(|| Ok(std::env::var("YB_PIN").ok()));
ctx.on_touch = Box::new(|| eprintln!("Touch your YubiKey…"));
let mut store = Store::from_device(&ctx.reader, ctx.piv.as_ref())?;
let descriptor = store.descriptor().cloned().expect("a post-quantum store");
let session = ctx.post_quantum_session()?; // asks for the FIDO2 PIN, once
let protection = session.protection(&ctx, &descriptor);
// Store a blob, encrypted and sealed: one touch.
let stored = orchestrator::store_blob_with(
&mut store,
ctx.piv.as_ref(),
&protection,
"greeting",
b"Hello, YubiKey!",
true, // encrypted
Compression::Auto,
None, // the management key: the protection unwraps the store's copy
)?;
assert!(stored, "the store is full");
// List: no PIN, no touch.
for blob in orchestrator::list_blobs(&store) {
println!("{}: {} bytes", blob.name, blob.plain_size);
}
// Fetch: its seal checked, then decrypted: one touch.
let data = orchestrator::fetch_blob_with(&store, &protection, "greeting")?;
assert_eq!(data.as_deref(), Some(&b"Hello, YubiKey!"[..]));
Ok(())
}
```
Legacy stores (`yb format`, no touch), removal, snapshots and the other
operations: see [the documentation](https://docs.rs/yb-core).
## Building
yb-core links two system libraries, found with `pkg-config`:
| Debian, Ubuntu | `libpcsclite-dev` | `libfido2-dev` |
| Fedora | `pcsc-lite-devel` | `libfido2-devel` |
| Arch | `pcsclite` | `libfido2` |
| macOS (Homebrew) | built in | `libfido2` |
| NixOS | `pcsclite` | `libfido2` |
At run time, PC/SC's daemon (`pcscd`) must be running on Linux. On
Windows, only legacy stores are supported, without libfido2.
## Which crate?
- **[`yb`](https://crates.io/crates/yb):** the command (`yb store`,
`yb fetch`, `yb ls`…), to set up a YubiKey and manage its blobs.
- **yb-core:** this library, for Rust programs.
- **[`yubiblob`](https://crates.io/crates/yubiblob):** libyubiblob, the
same store for C and C++ programs (used by
[KeePassYB](https://github.com/douzebis/keepassyb), a KeePassXC with
its database on a YubiKey).
More: [the storage format](https://github.com/douzebis/yb/blob/main/docs/YBLOB_FORMAT.md),
[the changelog](https://github.com/douzebis/yb/blob/main/CHANGELOG.md).
## License
MIT.