Documentation
¶
Overview ¶
Package crypto implements the SyncMyEnv key hierarchy on vetted libraries only (age, x/crypto) — no custom primitives.
master password ──argon2id──▶ KEK₁ ─┐
├─ XChaCha20-Poly1305 ─▶ vault identity
recovery key ─────hkdf─────▶ KEK₂ ─┘ (age hybrid: ML-KEM-768 + X25519)
│
vault recipient (public key)
│
the daemon seals every revision to the recipient
Sealing needs only the public recipient, so the daemon can run unattended without holding any secret. Opening (history, restore, share) needs the identity, which is only ever unwrapped in memory.
The hybrid key is post-quantum: ciphertext synced today stays safe even if someone stores it and waits for a quantum computer.
Index ¶
Constants ¶
const MaxPlaintext = 1 << 20
MaxPlaintext bounds what we'll seal/open. Env files are tiny; anything bigger is almost certainly a mistake (or an attack on memory).
const MinPasswordLen = 12
MinPasswordLen for the vault master password.
Variables ¶
var ( ErrWrongPassword = errors.New("wrong master password") ErrWrongRecovery = errors.New("recovery key doesn't match this vault") ErrCorrupt = errors.New("key file is corrupt or was tampered with") ErrWeakPassword = fmt.Errorf("master password must be at least %d characters", MinPasswordLen) )
var DefaultArgon = ArgonParams{Memory: 64 * 1024, Time: 3, Threads: 4}
DefaultArgon: 64 MiB, 3 passes, 4 lanes (~0.2–0.5s on a laptop).
var ErrBadRecoveryKey = errors.New("invalid recovery key — check for typos")
ErrBadRecoveryKey means the key is malformed or mistyped.
var ErrTooLarge = errors.New("crypto: data too large")
ErrTooLarge is returned for plaintexts or ciphertexts above MaxPlaintext.
Functions ¶
func Fingerprint ¶
Fingerprint is a short, human-comparable ID for a (very long) PQ recipient, e.g. "5c1e:9a07:33d2:fb18". Compare it across machines to be sure you're talking about the same vault.
Types ¶
type ArgonParams ¶
type ArgonParams struct {
Memory uint32 `json:"m"` // KiB
Time uint32 `json:"t"`
Threads uint8 `json:"p"`
}
ArgonParams are stored per key file, so they can be raised later without breaking existing vaults.
type KeyFile ¶
type KeyFile struct {
Version int `json:"version"`
Recipient string `json:"recipient"`
CreatedAt time.Time `json:"created_at"`
Password *Wrapped `json:"password"`
Recovery *Wrapped `json:"recovery"`
}
KeyFile is what's stored at ~/.syncmyenv/keys.json and (later) synced to remotes for new-device recovery. It contains no plaintext secret.
func NewKeyFile ¶
func NewKeyFile(k *VaultKey, password string, rk RecoveryKey) (*KeyFile, error)
NewKeyFile wraps k under both the master password and the recovery key.
func (*KeyFile) SetPassword ¶
SetPassword (re)wraps k under a new master password. The recovery key and all sealed data are unaffected.
func (*KeyFile) UnlockWithPassword ¶
UnlockWithPassword unwraps the vault key with the master password.
func (*KeyFile) UnlockWithRecovery ¶
func (f *KeyFile) UnlockWithRecovery(rk RecoveryKey) (*VaultKey, error)
UnlockWithRecovery unwraps the vault key with the recovery key.
type RecoveryKey ¶
type RecoveryKey [30]byte
A recovery key is 240 random bits + a 16-bit checksum, written in Crockford base32 (no I, L, O, U) as 13 groups of 4:
SME1-7QK2-M4XW-…-R9TD
The checksum catches typos before we burn an unlock attempt.
func NewRecoveryKey ¶
func NewRecoveryKey() (RecoveryKey, error)
NewRecoveryKey returns a fresh random recovery key.
func ParseRecoveryKey ¶
func ParseRecoveryKey(s string) (RecoveryKey, error)
ParseRecoveryKey accepts any case, spaces or dashes, and Crockford look-alikes (I/L→1, O→0).
func (RecoveryKey) String ¶
func (k RecoveryKey) String() string
type VaultKey ¶
type VaultKey struct {
// contains filtered or unexported fields
}
VaultKey is the vault's secret identity. Keep it in memory only.
func NewVaultKey ¶
NewVaultKey generates a fresh post-quantum hybrid vault key.
func (*VaultKey) CertifyDevice ¶
CertifyDevice vouches for a device signing key. Only holders of the vault key can produce (or check) a certificate — the server can't, even though it knows the public recipient. This is what stops a malicious server from forging log entries: sealing to the recipient is public, certifying isn't.
func (*VaultKey) MAC ¶
MAC is a keyed hash for change detection and dedup. Never store a bare hash of a secret: short .env values would be brute-forceable offline.
func (*VaultKey) VerifyDeviceCert ¶
VerifyDeviceCert checks a certificate made by CertifyDevice.