Documentation
¶
Overview ¶
Package crypto holds envelope encryption for mailbox credentials and password hashing.
Index ¶
- Constants
- Variables
- func Envelope(dekEnc []byte) int
- func GenerateMasterKey(dataDir string) ([]byte, error)
- func HashPassword(password string) (string, error)
- func KEKID(dekEnc []byte) string
- func LoadMasterKey(value, keyFile, dataDir string) ([]byte, error)
- func MasterKeyFile(dataDir string) string
- func MasterKeySource(value, keyFile, dataDir string) string
- func NewDataKey() ([]byte, error)
- func OpenKEK(ctx context.Context, p KeyProvider, legacy LegacyOpener, b Binding, ...) ([]byte, error)
- func SealKEK(ctx context.Context, p KeyProvider, b Binding, plaintext []byte) (secretEnc, dekEnc []byte, err error)
- func VerifyPassword(encoded, password string) bool
- type Binding
- type KeyProvider
- type LegacyOpener
- type MasterKey
- func (m MasterKey) KeyID() string
- func (m MasterKey) OpenLegacy(rowID int64, secretEnc, dekEnc []byte) ([]byte, error)
- func (m MasterKey) Unwrap(_ context.Context, tenantID int64, keyID string, wrapped []byte) ([]byte, error)
- func (m MasterKey) Wrap(_ context.Context, tenantID int64, key []byte) ([]byte, error)
- type TenantKey
Constants ¶
const MasterKeyID = "master"
MasterKeyID is the KeyID of MasterKey.
const MinPasswordLen = 12
MinPasswordLen is the shortest admin password, for first-run setup, a change in the browser and the reset command.
Variables ¶
var ErrDecrypt = errors.New("decrypt failed")
ErrDecrypt means a ciphertext was tampered with, moved between rows, or sealed under another key.
ErrKeyUnavailable means the key provider could not be asked to wrap or unwrap a key (a key service that does not answer, or refuses for a reason other than the key): nothing sealed under a key it holds opens until it answers again, and nothing new is sealed. It is never a wrong key, which is ErrDecrypt.
var ErrNoMasterKey = errors.New("no master key")
ErrNoMasterKey means no key was given, in the environment or a named file, and the data directory has no master.key yet. LoadMasterKey never makes one: whether a new key is safe depends on what the database holds, so the caller decides and calls GenerateMasterKey.
Functions ¶
func Envelope ¶ added in v0.3.0
Envelope reports how a secret was sealed, by its wrapped per-secret key: 1, 2 or 3, and 0 for none (an empty, deleted secret) or one it does not know.
func GenerateMasterKey ¶ added in v0.1.2
GenerateMasterKey makes a new random key and stores it, readable only by the user, as <dataDir>/master.key. It never replaces a file that is already there.
func HashPassword ¶
HashPassword returns an argon2id hash in the standard encoded form.
func KEKID ¶ added in v0.3.0
KEKID is the KEK an envelope-3 copy was sealed under (its KeyProvider's KeyID), "" for any other envelope.
func LoadMasterKey ¶
LoadMasterKey returns the key-encryption key: from the base64 value, else from keyFile, else from <dataDir>/master.key. It returns ErrNoMasterKey when that file does not exist.
func MasterKeyFile ¶ added in v0.1.2
MasterKeyFile is where the key lives when neither the environment nor a named file gives it.
func MasterKeySource ¶ added in v0.1.2
MasterKeySource names where LoadMasterKey reads the key from, for a message to a person.
func NewDataKey ¶ added in v0.3.0
NewDataKey makes a random data key for a tenant.
func OpenKEK ¶ added in v0.3.0
func OpenKEK(ctx context.Context, p KeyProvider, legacy LegacyOpener, b Binding, secretEnc, dekEnc []byte) ([]byte, error)
OpenKEK reverses SealKEK; with legacy, it also opens envelope 1 bound to b.LegacyRow.
func SealKEK ¶ added in v0.3.0
func SealKEK(ctx context.Context, p KeyProvider, b Binding, plaintext []byte) (secretEnc, dekEnc []byte, err error)
SealKEK seals plaintext under a fresh per-secret key that the provider wraps itself (envelope 3), bound to b: for a copy that must stay readable after its tenant's key is gone. The per-secret key is wrapped as tenant b.TenantID's.
func VerifyPassword ¶
VerifyPassword reports whether password matches an encoded hash, in constant time.
Types ¶
type Binding ¶ added in v0.3.0
Binding is what a secret is sealed to: its tenant, its kind ("account", "destination", "setting", "removed") and its row id or name. LegacyRow is the number envelope 1 bound it to, for opening one sealed before tenant keys.
type KeyProvider ¶ added in v0.3.0
type KeyProvider interface {
// KeyID names the KEK new keys are wrapped under; it is stored with each wrapped key,
// so a provider holding several (a rotation) knows which one opens it.
KeyID() string
Wrap(ctx context.Context, tenantID int64, key []byte) ([]byte, error)
// Unwrap returns ErrDecrypt when keyID or the tenant is not the one wrapped. Any other
// error means the provider could not answer (ErrKeyUnavailable).
Unwrap(ctx context.Context, tenantID int64, keyID string, wrapped []byte) ([]byte, error)
}
KeyProvider holds a key-encryption key: it wraps tenants' data keys and unwraps them. tenantID is bound into each wrap, so a wrapped key does not open as another tenant's. ext.KeyProvider is the same contract as a module implements it.
func WithMasterKey ¶ added in v0.3.0
func WithMasterKey(p KeyProvider, master MasterKey) KeyProvider
WithMasterKey is p, the key provider of a module (ext.Module.Keys), with the master key still unwrapping what was wrapped under it before p held the keys: the tenant keys whose kek_id is MasterKeyID, removed mailboxes' envelope-3 copies under it, and envelope 1. Everything else goes to p alone, so a key p wrapped never falls back to the master key. master may be nil (an install that never had one, or has retired it): what was wrapped under the master key is then ErrDecrypt, without asking p.
type LegacyOpener ¶ added in v0.3.0
LegacyOpener opens secrets sealed before tenant keys (envelope 1), with the master key they were sealed under.
type MasterKey ¶ added in v0.3.0
type MasterKey []byte
MasterKey is the KeyProvider of the master key (LoadMasterKey), the KEK of self-host and of the hosted build until a KMS holds it. It also opens envelope 1.
func (MasterKey) OpenLegacy ¶ added in v0.3.0
OpenLegacy implements LegacyOpener.
type TenantKey ¶ added in v0.3.0
type TenantKey struct {
// contains filtered or unexported fields
}
TenantKey is one tenant's unwrapped data key, with what opens the tenant's secrets sealed before it existed. It never leaves the process.
func NewTenantKey ¶ added in v0.3.0
func NewTenantKey(tenantID int64, key []byte, legacy LegacyOpener) TenantKey
NewTenantKey is tenant's data key, unwrapped; legacy may be nil.
func (TenantKey) MAC ¶ added in v0.3.0
MAC is an HMAC of data under a key derived from the tenant's key for label: a fingerprint that ties a stored value to a secret without storing the secret.
func (TenantKey) Open ¶ added in v0.3.0
func (k TenantKey) Open(kind, ref string, legacyRow int64, secretEnc, dekEnc []byte) ([]byte, error)
Open opens a secret of the tenant sealed by Seal under kind and ref, or one sealed before tenant keys (envelope 1) to legacyRow. It returns ErrDecrypt for a wrong key, tenant, kind, row or ciphertext.