apppass

package
v0.2.26 Latest Latest
Warning

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

Go to latest
Published: Sep 8, 2026 License: MPL-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package apppass is the app-password mechanism the stateful personalities share: argon2id hashing in PHC form, constant-time verification, a dummy verify that hides account existence, two generators (a grouped token and a BIP-39 word phrase), and a verified-login cache. The IMAP head (chassis/server/personality/imap) and the calendar head (chassis/server/personality/calendar) authenticate the same way, so one password minted for a persona can open both — the product decides whether the credential is shared by passing the same value to both account ops.

Index

Constants

View Source
const WordPasswordDefaultWords = 5

WordPasswordDefaultWords is the default word count for GenerateWordPassword: 5 × 11 bits = 55 bits, enough that an offline attack on the argon2id hash is measured in millennia while the phrase stays typable on a phone. Four words (44 bits) is defensible only because the head throttles LOGIN; six (66 bits) costs one more word.

Variables

View Source
var (
	// ErrBadHash is returned when a stored hash is not a PHC argon2id string
	// this package produced.
	ErrBadHash = errors.New("apppass: malformed password hash")
)

Functions

func GeneratePassword

func GeneratePassword() string

GeneratePassword returns a fresh random password in four-character groups ("xxxx-xxxx-xxxx-xxxx-xxxx-xxxx", ~116 bits) for the `password=""` path of the account ops. It is returned to the caller exactly once and only its hash is stored.

func GenerateWordPassword

func GenerateWordPassword(n int) string

GenerateWordPassword returns n words from the BIP-39 list joined by hyphens ("river-galaxy-bamboo-orbit-velvet"). n < 1 uses the default. Each word is one unbiased 11-bit draw from crypto/rand: 65536 is a multiple of 2048, so the modulo introduces no bias. Returned to the caller exactly once by the account ops; only its hash is stored.

func HashPassword

func HashPassword(password string) (string, error)

HashPassword returns a PHC-formatted argon2id string ($argon2id$v=19$m=…,t=…,p=…$<salt>$<hash>, base64 without padding) for storage in an accounts table (imap_accounts.pw_hash, calendar_accounts.pw_hash).

func LoginKey

func LoginKey(username, pwHash, password string) string

LoginKey is the cache key for one verified triple.

func VerifyDummy

func VerifyDummy(password string) bool

VerifyDummy burns one argon2id verify against a fixed hash so a LOGIN for an unknown username costs the same as one for a known username (no account-existence timing oracle). The result is always false.

func VerifyPassword

func VerifyPassword(phc, password string) (bool, error)

VerifyPassword reports whether password matches the PHC hash. The comparison is constant-time; parameters are read from the hash so a later cost bump verifies old rows unchanged. A malformed hash is an error (never a silent false-negative that hides a corrupt row).

Types

type LoginCache

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

LoginCache remembers recently verified (username, hash, password) triples so a desktop client's 5–10 parallel LOGINs per wake — or a CalDAV client's dozens of Basic-authenticated requests per refresh — cost one argon2id verify, not one each. The key is a hash of all three, so a rotated password (new pw_hash) misses by construction, and a stale entry can only ever admit a password that was correct for that hash.

func NewLoginCache

func NewLoginCache(ttl time.Duration, max int) *LoginCache

NewLoginCache builds a cache holding at most max entries for ttl each.

func (*LoginCache) Hit

func (c *LoginCache) Hit(key string) bool

Hit reports whether key was verified within the TTL.

func (*LoginCache) Put

func (c *LoginCache) Put(key string)

Put records a verified key.

func (*LoginCache) SetClock

func (c *LoginCache) SetClock(now func() time.Time)

SetClock pins the cache's clock (tests).

Jump to

Keyboard shortcuts

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