# Blindplane
**Enterprise control without surrendering your users' plaintext.**
Blindplane is an embeddable Rust security library for products that need
encrypted data, organization-wide administration, and auditable access. It lets
authorized users and tenant administrators share controlled visibility while
the relay that stores and routes the data remains unable to decrypt it.
Clients encrypt records and audit events, sign every protected object, and
enforce administrator-signed grants, policies, and revocation state. The relay
can validate, store, index, and return those objects without holding a key that
opens their protected content.
> **Prototype, not audited.** Blindplane implements cryptographic primitives
> directly from their specifications and tests them against published vectors
> and established implementations. That is not a substitute for an independent
> security audit. Do not use this project for production secrets.
## Why Blindplane
- **Embed it in an existing product.** Keep your own identity, UI, storage, and
business logic instead of adopting a complete security platform.
- **Give enterprises real control.** Administrators can grant scoped access,
enable or disable capabilities, rotate role keys, and revoke future access.
- **Preserve user visibility.** A user can inspect their own encrypted activity;
an authorized tenant administrator can inspect activity across the tenant.
- **Keep the service provider blind.** Storage and routing code can verify
authenticity and monotonic updates without receiving decryption keys.
Typical integrations include enterprise MCP and agent controls, encrypted audit
trails, protected SaaS fields, and internal tools that must offer administrative
oversight without making the hosting layer a universal plaintext reader.
## How it works
A sealed record contains:
- an AEAD-encrypted payload under a fresh object secret;
- an HPKE envelope for each recipient;
- a commitment to the object secret;
- blind-index tokens for selected equality lookups;
- an Ed25519 signature over the canonical record encoding.
The enterprise access layer adds:
- principals for users, administrators, devices, and services;
- administrator-signed role-key grants with explicit scope and expiry;
- default-deny policies for MCP servers, tools, skills, and CLI access;
- signed revocation epochs for future authorization and key rotation;
- encrypted audit events readable by the owning user and tenant administrators.
The relay validates structure, signatures, route context, and monotonic
versions. It cannot decrypt payloads or recipient envelopes because the
server-side crates expose no decryption key type.
```text
client relay client
|----------------------------->| validate, store, index |
| |----------------------------->|
| | verify, open |
```
## What the relay can see
Blindplane does not hide all metadata. The relay sees:
- tenant, object, field, epoch, version, and schema identifiers;
- ciphertext length;
- recipient identifiers and access changes;
- grant subjects, scopes, permissions, expiry, and policy capability names;
- equality and frequency within each blind-index scope;
- access patterns.
The caller must decide whether those leaks are acceptable for its data model.
## Workspace crates
| `blindplane-crypto` | Cryptographic primitives and simple high-level helpers |
| `blindplane-wire` | Canonical record encoding and validation; no decryption API |
| `blindplane-core` | Client-side sealing, opening, rekeying, and blind indexes |
| `blindplane-access` | Signed grants, capability policies, revocation, and encrypted audit events |
| `blindplane-relay` | Framework-neutral in-memory relay |
| `blindplane-blazingly` | Typed Blazingly API for records and signed access objects |
| `blindplane-cli` | Key generation and end-to-end self-check |
The shipped crypto, wire, core, access, and relay crates have no third-party
runtime dependencies. Their development dependencies are used only for tests.
## Protect a record
```rust
use blindplane_core::{Author, RecipientKeypair, fastest_payload_suite, open, seal};
use blindplane_wire::RecordContext;
let author = Author::generate()?;
let alice = RecipientKeypair::generate("alice", 1)?;
let record = seal(
&author,
RecordContext {
tenant: "acme".into(),
object_id: "patient-42".into(),
field: "diagnosis".into(),
epoch: 1,
version: 1,
schema_version: 1,
},
b"the relay never sees this",
&[alice.recipient()],
vec![],
fastest_payload_suite(),
)?;
// `record.encode()` is sent to a relay for validation and storage.
let plaintext = open(&record, &alice, author.public_key())?;
assert_eq!(plaintext.as_bytes(), b"the relay never sees this");
# Ok::<(), Box<dyn std::error::Error>>(())
```
Run the complete local self-check:
```bash
cargo run -p blindplane-cli -- selfcheck
```
## Add enterprise access
`blindplane-access` is application-neutral. Your service keeps responsibility
for identity onboarding, storage, UI, and provider adapters. Blindplane provides
the canonical signed objects and cryptographic enforcement layer:
- a personal audit role opens one subject's stream;
- a tenant audit role opens every stream sealed to that role;
- administrators receive the tenant role through signed grants;
- capability decisions are available only after issuer, subject, time,
revision, and revocation checks pass;
- policy evaluation is exact-name and default-deny.
The runnable example issues grants and policy, seals one request for a user and
tenant administrator, and opens it as both recipients:
```bash
cargo run -p blindplane-access --example enterprise_access
```
An agent platform such as GrantTap/Nodvox can map MCP servers, tools, skills,
and usage events onto this API. Blindplane itself stays independent of any
particular agent, model provider, or identity system.
## HTTP examples
The Blazingly example runs a complete seal, store, search, fetch, and open
flow through the adapter:
```bash
cargo run -p blindplane-blazingly --example sealed_api
```
The framework-neutral relay is also exposed through a small Axum adapter:
```bash
cargo run -p blindplane-relay --example axum_relay
```
The Blazingly adapter represents records and signed grants, policies, and
revocation states as base64 inside typed JSON models. The Axum example accepts
canonical record bytes directly. This is an adapter choice; the relay itself is
independent of either wire shape.
## Feature flags and targets
`blindplane-crypto` enables `std` and `accel` by default.
- `std` enables operating-system entropy and heap-backed helpers.
- `accel` enables runtime-selected CPU instruction paths and implies `std`.
- `--no-default-features --features std` uses portable cryptographic paths.
- `--no-default-features` builds the allocation-free `no_std` core with
caller-supplied keys and entropy.
The portable `std` build still uses a small reviewed FFI block to request
entropy from the operating system. The freestanding `no_std` build contains no
unsafe code.
The core can be checked for WebAssembly without a separate implementation:
```bash
cargo build --target wasm32-unknown-unknown \
-p blindplane-crypto --no-default-features
```
A browser binding must supply secure entropy for key generation and should run
Argon2id outside the UI thread.
## Security properties
- Secret-dependent branches and memory addresses are treated as defects.
- Secret comparisons use constant-time masked operations.
- AEAD opening authenticates before releasing plaintext.
- Failed opening clears the destination buffer.
- AES-GCM is available only where supported CPU instructions are present;
there is no table-based software AES fallback.
- Ed25519 verification rejects non-canonical scalars and small-order keys.
- Records use a canonical binary encoding before signing.
- Recipient public keys must be pinned through a trusted channel.
- Access objects are domain-separated and verified with a pinned issuer key.
- Policy evaluation fails closed before trust, time, revision, and epoch checks.
- Audit content is encrypted for a user role and tenant-administrator role.
- A persisted signed chain head detects rollback for one client history.
## Current limitations
- The project has not received an independent security audit.
- The included relay store is in memory and is not a production database.
- Identity-provider login, recovery, device enrolment, and issuer-key onboarding
are integration responsibilities and are not included.
- A modified endpoint can bypass a locally embedded policy verifier. MDM,
attestation, code signing, and gateway enforcement require separate controls.
- Offline clients learn revocation only after refreshing signed state or when a
short-lived grant expires.
- Tenant administrators intentionally receive access to audit content sealed to
the tenant audit role.
- The per-client rollback head does not provide cross-client fork consistency.
- Password-derived vault data remains subject to offline guessing if an
attacker obtains the encrypted blob.
- Revocation prevents future access after rekeying but cannot revoke plaintext
a former recipient already obtained.
- AES-256-GCM currently requires AArch64 crypto extensions; other targets use
ChaCha20-Poly1305.
## Verification
```bash
cargo fmt --all --check
cargo test --workspace --all-targets --locked
cargo test --workspace --doc --locked
cargo test -p blindplane-crypto \
--no-default-features --features std --locked
cargo check -p blindplane-crypto --no-default-features --locked
cargo check -p blindplane-access --no-default-features --locked
cargo clippy --workspace --all-targets --locked -- -D warnings
```
The crypto test suite includes RFC, FIPS, and NIST vectors, negative tests,
split-call streaming tests, and byte-for-byte interoperability checks against
independent implementations.
## License
MIT OR Apache-2.0.