Skip to content

v0.1.0

Release Date: 2026-10-12

Highlights

  • Envelope encryption with rotation that does not touch your data. Data keys are wrapped by provider-held key-encryption keys, so rotating a key-encryption key re-wraps registry records and leaves stored ciphertext alone.
  • Guarded retirement and destruction. A caller-supplied guard can veto, a delay applies, every outcome is audited, and the absence of a guard is a refusal.
  • Erasure by key destruction. Per-subject keys make erasing a subject a key destruction, with completion tracked until every key version that wrapped the subject's keys is gone.
  • A single-host setup in one call. embedded.Open wires a keyring file, a SQLite registry, the lifecycle jobs and the control plane from a directory and a root key. PostgreSQL is supported for shared deployments.

Status

keyforge v0.1.0 has not been externally audited and is not yet recommended for production use. The envelope format and the keyring file format are frozen from this release: a change needs a version bump and new known-answer vectors. See the threat model for what it defends and where it stops.

Overview

keyforge manages the lifecycle of encryption keys for Go applications. It composes standard primitives from the Go standard library and golang.org/x/crypto, implements none of its own, and keeps the code that touches key material to the standard library alone, which a test enforces.

Features

Envelope format

Mode Holds Use
Reference The data key's identifier; the wrapped key is in the registry Rows and values under a purpose or subject
Inline The wrapped key beside the ciphertext Standalone objects such as exports and files

AES-256-GCM through cipher.NewGCMWithRandomNonce, with the header and the caller's context authenticated. A per-key encryption cap holds across replicas and crashes, and data keys move to a new epoch by volume and by age. See Envelope format.

Rotation and recovery

  • Automatic KEK rotation with a sentinel recorded for every version
  • Resumable, idempotent re-wrapping of data keys, safe to run from several workers
  • Rollback to the most recent decrypt-only version
  • Emergency procedures for an exposed key-encryption key or data key
  • Keyring backup acknowledgement and rollback detection

Retirement, destruction and erasure

  • Retirement in steps: request, delay, guard, complete; then destruction behind the guard again
  • Crypto-shredding of a subject with a tombstone, tracked to completion

Providers and stores

Component Included
Provider Keyring file sealed under a root key; in-memory provider for tests
Registry SQLite and PostgreSQL through Ent; in-memory reference store
Scheduler OmniWorkflow: in-memory, durable file store, Temporal, Step Functions

Every provider and every store passes a shared conformance suite.

Operations

  • HTTP control plane; an authorizer is asked before every action and there is no default allow
  • keyforge command line: status, health, verify, rotate, rewrap, rollback, retire, destroy, compromise, datakey, shred, backup ack, keyring inspect, rootkey generate
  • Status report, audit events and a metrics interface with bounded labels

Installation

go get github.com/plexusone/keyforge@v0.1.0
go install github.com/plexusone/keyforge/cmd/keyforge@v0.1.0

Requires Go 1.26.

Quick start

sys, err := embedded.Open(ctx, embedded.Options{
    Dir:  "/var/lib/myapp/keyforge",
    Root: local.FileSource("/etc/keyforge/root.key"),
    Purposes: map[keyforge.Purpose]embedded.PurposeOptions{"session-secrets": {}},
})
if err != nil {
    return err
}
defer sys.Close()

sealed, err := sys.Client.Encrypt(ctx, "session-secrets", []byte("token-value"), []byte("user:42"))
plaintext, _, err := sys.Client.Decrypt(ctx, "session-secrets", sealed, []byte("user:42"))

See Getting started and Operations.

Known limitations

  • The local provider is as safe as the host and its root key source. It is not a hardware module.
  • The root key is not recoverable. Keep two copies, one offline.
  • A restore can undo an erasure. Shreds live in the registry, and keyring backups hold destroyed versions' material. Erasure is complete for the live system only.
  • Restores are done with the process stopped. A keyring replaced under a running process is refused at the next write, but the process keeps its in-memory copy.
  • Writes under a cached key outlive a shred until the cache expires or Purge is called.
  • Inline wraps are not counted per key-encryption key version.
  • Registry backups lose recent data keys. Data written under a key created after the last backup is unreadable after a restore.
  • One process for durable jobs. Several replicas need a shared OmniWorkflow provider.

The complete list is in the threat model.

Dependencies

Module Use
golang.org/x/crypto Standard primitives not in the standard library
entgo.io/ent The SQL registry
modernc.org/sqlite SQLite driver (pure Go)
github.com/jackc/pgx/v5 PostgreSQL driver
github.com/plexusone/omniworkflow Lifecycle job scheduling
github.com/spf13/cobra Command line
github.com/grokify/oscompat File locking, directory sync and permission checks (no dependencies of its own)

The packages that touch key material import only the standard library and oscompat, a dependency-free module for operating-system differences.