crypt

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 3, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package crypt seals the per-device secrets a storage backend must retain on Apple's behalf with AES-256-GCM under a named key from a secrets.Provider.

Why

The check-in protocol hands the server an UnlockToken in TokenUpdate and a BootstrapToken in SetBootstrapToken, and the push certificate store holds private keys; a copy of the database alone must not expose them. Phase 4 of the plan of record adds this package (decision record 0013): a Keyring with one active key and any number of retired ones, additional authenticated data that binds every blob to its table, column, and row id so a ciphertext cannot be moved to another row, and a Strict mode that refuses plaintext rows. The key name travels in the ciphertext header, which lets an operator rotate by naming a new active key while keeping the retired key in the accepted list until every stored value has been rewrapped.

Which columns are sealed, and the Rewrap that walks them, live in the SQL backends through sqlcommon. This package knows only bytes, keys, and AAD.

References

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoKeyring is returned when Seal or Open is called on a nil Keyring.
	ErrNoKeyring = errors.New("crypt: no keyring configured")
	// ErrUnknownKey is returned when a header names a key the ring does not hold.
	ErrUnknownKey = errors.New("crypt: ciphertext uses an unknown key")
	// ErrTampered is returned when authentication fails, including a wrong AAD.
	ErrTampered = errors.New("crypt: authentication failed")
	// ErrUnsealed is returned by strict callers that meet a value without the header.
	ErrUnsealed = errors.New("crypt: value is not sealed")
	// ErrWeakKey is returned when a provider supplies fewer than 16 bytes of key material.
	ErrWeakKey = errors.New("crypt: key material shorter than 16 bytes")
	// ErrBadFormat is returned for input that is not a well formed sealed value.
	ErrBadFormat = errors.New("crypt: malformed ciphertext")
	// ErrNoActive is returned when Keys.Active is empty.
	ErrNoActive = errors.New("crypt: no active key name")
)

Sentinel errors returned by this package. Callers should test them with errors.Is because the returned values may carry extra context.

Functions

func AAD

func AAD(purpose, rowID string) []byte

AAD builds the associated data that binds a value to its table column and row, as purpose, a NUL byte, then rowID. Moving a sealed value to another column or row therefore fails to open.

func IsSealed

func IsSealed(b []byte) bool

IsSealed reports whether b starts with the sealed value header.

func KeyName

func KeyName(b []byte) (string, bool)

KeyName returns the key name in a sealed header without decrypting. It reports ok as false when b is not sealed or the header is malformed.

Types

type Keyring

type Keyring struct {
	// contains filtered or unexported fields
}

Keyring holds the derived AEAD for each key name. It is safe for concurrent use once constructed.

func NewKeyring

func NewKeyring(ctx context.Context, o Options) (*Keyring, error)

NewKeyring fetches every named key from the provider once, so a provider failure is a construction error rather than a surprise at the first Seal. Provider bytes are normalised to a 32 byte AES key with HKDF over SHA-256, salted with the key name, so two names backed by the same material still yield distinct keys.

func (*Keyring) Active

func (k *Keyring) Active() string

Active returns the name of the key Seal uses.

func (*Keyring) Open

func (k *Keyring) Open(ciphertext, aad []byte) (plaintext []byte, keyName string, err error)

Open decrypts a sealed value and reports which key name it used. It returns ErrBadFormat for input that is not sealed or is too short, ErrUnknownKey when the header names a key the ring does not hold, and ErrTampered when authentication fails, which includes a wrong aad.

func (*Keyring) Seal

func (k *Keyring) Seal(plaintext, aad []byte) ([]byte, error)

Seal encrypts plaintext under the active key and returns the sealed value: magic, key name length, key name, nonce, then the AES-GCM output including its tag. Empty plaintext is allowed and yields a sealed empty value. The aad is authenticated but not stored; Open must be given the same bytes.

func (*Keyring) Strict

func (k *Keyring) Strict() bool

Strict reports whether callers should refuse unsealed values.

type Keys

type Keys struct {
	// Active is the key name every Seal uses.
	Active string
	// Accepted lists retired key names Open still honours.
	Accepted []string
	// Strict makes callers refuse unsealed values (set once Rewrap has run everywhere).
	Strict bool
}

Keys names the active key and the retired keys still accepted on read.

type Options

type Options struct {
	// Keys names the keys to fetch.
	Keys Keys
	// Provider supplies the raw key material for each name.
	Provider secrets.Provider
}

Options configures NewKeyring.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL