Help us shape the future of Go! Take the 2026 Go Developer Survey

crypt

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 19, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package crypt seals secret columns at rest (decision record 0017): remote repository and proxy passwords, LDAP and mail credentials, webhook secrets, key pair private keys, OIDC secrets and the token signing key.

A sealed value is

magic(4) | version(4, big endian) | key id(4) | nonce(12) | AES-256-GCM ciphertext and tag

Keys are derived from the operator's master key with HKDF-SHA256, one per version, so rotation adds a version instead of replacing the key: values sealed under an older version still open until the store re-seals them (Reseal), and the old master key can then be retired. The key id is a fingerprint of the master key for that version; it turns "the server was started with a different master key" into ErrWrongKey rather than an authentication failure that looks like tampering.

The purpose (which column) and row id (which record) are authenticated but not stored, so a sealed value copied into another row or column fails to open. This is the same design as hostweave's keyring, with a version number in place of a key name because artifactweave has one master key at a time.

Index

Constants

View Source
const Masked = "********"

Masked is what reads return in place of a stored secret. Research 03 and 15 record that Artifactory returns secrets masked rather than in clear; the exact string Artifactory uses is unverified, so this one is artifactweave's.

View Source
const (

	// MinMasterKey is the shortest accepted master key.
	MinMasterKey = 32
)

Variables

View Source
var (
	// ErrWeakKey reports master key material shorter than 32 bytes.
	ErrWeakKey = errors.New("crypt: master key must be at least 32 bytes")
	// ErrNoKeys reports a keyring built from no keys.
	ErrNoKeys = errors.New("crypt: no master key")
	// ErrBadVersion reports a zero or duplicate key version.
	ErrBadVersion = errors.New("crypt: invalid key version")
	// ErrBadFormat reports input that is not a sealed value.
	ErrBadFormat = errors.New("crypt: not a sealed value")
	// ErrUnknownKey reports a value sealed under a version the ring lacks.
	ErrUnknownKey = errors.New("crypt: sealed under an unknown key version")
	// ErrWrongKey reports a value sealed under a different master key for the
	// same version: the configured master key is not the one that sealed it.
	ErrWrongKey = errors.New("crypt: sealed under a different master key")
	// ErrTampered reports failed authentication, including a value moved to
	// another purpose or row.
	ErrTampered = errors.New("crypt: authentication failed")
	// ErrBadPurpose reports an empty purpose.
	ErrBadPurpose = errors.New("crypt: purpose is required")
)

Sentinel errors; callers test them with errors.Is.

Functions

func IsSealed

func IsSealed(b []byte) bool

IsSealed reports whether b has the sealed-value header.

func KeepIfMasked

func KeepIfMasked(incoming, stored string) string

KeepIfMasked resolves an incoming secret on update. Clients such as the Terraform providers and `jf` read a configuration, change a field and send the whole document back; the secret then arrives as Masked and must not overwrite the stored value.

func Mask

func Mask(secret string) string

Mask returns Masked for a set secret and "" for an unset one, so a client can still tell whether a password is configured.

func ParseMasterKey

func ParseMasterKey(s string) ([]byte, error)

ParseMasterKey turns the configured master key (ARTIFACTWEAVE_MASTER_KEY) into key material. Base64 (standard or URL alphabet, padded or not) that decodes to at least 32 bytes is decoded, which is what `openssl rand -base64 32` produces; anything else is used as raw bytes and must itself be at least 32 bytes.

func Version

func Version(sealed []byte) (uint32, error)

Version returns the key version a sealed value names.

Types

type Keyring

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

Keyring seals under its newest version and opens any version it holds. It is safe for concurrent use.

func New

func New(material []byte) (*Keyring, error)

New returns a keyring holding a single version-1 master key.

func NewKeyring

func NewKeyring(keys ...MasterKey) (*Keyring, error)

NewKeyring returns a keyring holding every given version. The highest version seals; all of them open.

func (*Keyring) Active

func (k *Keyring) Active() uint32

Active is the version Seal uses.

func (*Keyring) Open

func (k *Keyring) Open(purpose, rowID string, sealed []byte) ([]byte, error)

Open decrypts a value sealed by Seal with the same purpose and rowID.

func (*Keyring) Reseal

func (k *Keyring) Reseal(purpose, rowID string, sealed []byte) ([]byte, bool, error)

Reseal re-encrypts a value under the active version if it was sealed under an older one, and reports whether it changed. Stores run it over every sealed column after Rotate; once nothing changes, the old master key can be removed from the configuration.

func (*Keyring) Rotate

func (k *Keyring) Rotate(newMaster []byte) (*Keyring, error)

Rotate returns a keyring that seals under newMaster as the next version and still opens every version this one holds. The receiver is unchanged.

func (*Keyring) Seal

func (k *Keyring) Seal(purpose, rowID string, plaintext []byte) ([]byte, error)

Seal encrypts plaintext for one column (purpose) of one record (rowID).

func (*Keyring) Versions

func (k *Keyring) Versions() []uint32

Versions lists the versions the keyring opens, oldest first.

type MasterKey

type MasterKey struct {
	Version  uint32
	Material []byte
}

MasterKey is one version of the operator's master key.

func ParseVersionedKey

func ParseVersionedKey(s string) (MasterKey, error)

ParseVersionedKey reads one configured master key, optionally prefixed with its version as "vN:" (N >= 1); a key without a prefix is version 1. Versions must be stable across restarts because sealed values name the version that sealed them, so rotation adds the next version explicitly: the old key moves to master_key_previous unchanged and the new one is configured as "v2:<key>", then "v3:<key>" at the next rotation. Base64 never contains ':', so the prefix cannot be mistaken for key material.

Jump to

Keyboard shortcuts

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