crypt

package
v1.8.0 Latest Latest
Warning

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

Go to latest
Published: Sep 12, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package crypt encrypts and decrypts tracked dotfiles with age.

A repository file with the .crypt suffix holds an ASCII-armored age ciphertext. The recipient is derived from the configured identity, so a single private key is all that has to be set up. The identity file itself may be passphrase-protected (age -p); the passphrase is taken from the environment or asked for on the terminal.

Index

Constants

View Source
const (
	EnvAgeIdentity   = "DMAN_AGE_IDENTITY"
	EnvAgePassphrase = "DMAN_AGE_PASSPHRASE"
)

Environment variables that override the config file.

Variables

View Source
var ErrNoKey = errors.New("no encryption key configured")

ErrNoKey is returned when no identity is configured. Callers treat it as "encryption is not set up on this machine" and skip encrypted files.

View Source
var ReadPassphrase = func(prompt string) ([]byte, error) {
	if p, ok := os.LookupEnv(EnvAgePassphrase); ok {
		return []byte(p), nil
	}
	tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
	if err != nil {
		return nil, fmt.Errorf("identity file is passphrase-protected; set %s or run interactively", EnvAgePassphrase)
	}
	defer func() { _ = tty.Close() }()

	if _, err := fmt.Fprint(tty, prompt); err != nil {
		return nil, err
	}
	pass, err := term.ReadPassword(tty.Fd())
	_, _ = fmt.Fprintln(tty)
	if err != nil {
		return nil, fmt.Errorf("read passphrase: %w", err)
	}
	return pass, nil
}

ReadPassphrase asks for the passphrase of a protected identity file. It prefers EnvAgePassphrase and otherwise reads from the controlling terminal without echo. Tests replace it.

Functions

func IsEncrypted

func IsEncrypted(data []byte) bool

IsEncrypted reports whether data looks like an age file, armored or not.

Types

type Codec

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

Codec encrypts with the recipient derived from an identity file and decrypts with every identity in it. A nil *Codec is valid and reports ErrNoKey from every method, so callers can carry "no key" without branching.

func New

func New(opts Options) (*Codec, error)

New resolves the identity path (environment over config) and returns a Codec. It returns ErrNoKey when nothing is configured. A configured but missing identity file is reported as an error, not as ErrNoKey: that is a misconfiguration the user should see. Parsing the identity, and any passphrase prompt, is deferred to first use.

func (*Codec) Decrypt

func (c *Codec) Decrypt(ciphertext []byte) ([]byte, error)

Decrypt returns the plaintext of an armored or binary age ciphertext.

func (*Codec) Encrypt

func (c *Codec) Encrypt(plaintext []byte) ([]byte, error)

Encrypt returns the armored ciphertext of plaintext for the codec's recipient. Every call produces different bytes; compare plaintext, never ciphertext.

func (*Codec) Path

func (c *Codec) Path() string

Path returns the identity file the codec was built from.

func (*Codec) Unlock

func (c *Codec) Unlock() error

Unlock loads the identities now instead of on first use. Browse calls it before the TUI takes over the terminal so a passphrase prompt is not drawn into the alternate screen.

type Options

type Options struct {
	// Identity is the path to the age identity file. Tilde expansion is the
	// caller's job.
	Identity string
}

Options are the encryption settings from the config file, before the environment is applied.

Jump to

Keyboard shortcuts

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