Add RFC specs for auth crypt and trust packages

This commit is contained in:
Virgil 2026-03-27 21:45:33 +00:00
parent 60b713114b
commit 82fd4e5267
8 changed files with 1665 additions and 0 deletions

521
specs/auth/RFC.md Normal file
View file

@ -0,0 +1,521 @@
# auth
**Import:** `dappco.re/go/core/crypt/auth`
**Files:** 4
## Types
### `Authenticator`
```go
type Authenticator struct {
medium io.Medium
store SessionStore
hardwareKey HardwareKey // optional hardware key (nil = software only)
challenges map[string]*Challenge // userID -> pending challenge
mu sync.RWMutex // protects challenges map only
challengeTTL time.Duration
sessionTTL time.Duration
}
```
Authenticator manages PGP-based challenge-response authentication.
All user data and keys are persisted through an io.Medium, which may
be backed by disk, memory (MockMedium), or any other storage backend.
Sessions are persisted via a SessionStore (in-memory by default,
optionally SQLite-backed for crash recovery).
An optional HardwareKey can be provided via WithHardwareKey for
hardware-backed cryptographic operations (PKCS#11, YubiKey, etc.).
See auth/hardware.go for the interface definition and integration points.
Usage: create an Authenticator with New(...) and then call Register, Login, or CreateChallenge.
#### Methods
##### `CreateChallenge`
```go
func (a *Authenticator) CreateChallenge(userID string) (*Challenge, error)
```
CreateChallenge generates a cryptographic challenge for the given user.
A random nonce is created and encrypted with the user's PGP public key.
The client must decrypt the nonce and sign it to prove key ownership.
Usage: call CreateChallenge(...) during the package's normal workflow.
##### `DeleteUser`
```go
func (a *Authenticator) DeleteUser(userID string) error
```
DeleteUser removes a user and all associated keys from storage.
The "server" user is protected and cannot be deleted (mirroring the
original TypeScript implementation's safeguard).
Usage: call DeleteUser(...) during the package's normal workflow.
##### `IsRevoked`
```go
func (a *Authenticator) IsRevoked(userID string) bool
```
IsRevoked checks whether a user's key has been revoked by inspecting the
.rev file. Returns true only if the file contains valid revocation JSON
(not the legacy "REVOCATION_PLACEHOLDER" string).
Usage: call IsRevoked(...) during the package's normal workflow.
##### `Login`
```go
func (a *Authenticator) Login(userID, password string) (*Session, error)
```
Login performs password-based authentication as a convenience method.
It verifies the password against the stored hash and, on success,
creates a new session. This bypasses the PGP challenge-response flow.
Hash format detection:
- If a .hash file exists, its content starts with "$argon2id$" and is verified
using constant-time Argon2id comparison.
- Otherwise, falls back to legacy .lthn file with LTHN hash verification.
On successful legacy login, the password is re-hashed with Argon2id and
a .hash file is written (transparent migration).
Usage: call Login(...) for password-based flows when challenge-response is not required.
##### `ReadResponseFile`
```go
func (a *Authenticator) ReadResponseFile(userID, path string) (*Session, error)
```
ReadResponseFile reads a signed response from a file and validates it,
completing the air-gapped authentication flow. The file must contain the
raw PGP signature bytes (armored).
Usage: call ReadResponseFile(...) during the package's normal workflow.
##### `RefreshSession`
```go
func (a *Authenticator) RefreshSession(token string) (*Session, error)
```
RefreshSession extends the expiry of an existing valid session.
Usage: call RefreshSession(...) during the package's normal workflow.
##### `Register`
```go
func (a *Authenticator) Register(username, password string) (*User, error)
```
Register creates a new user account. It hashes the username with LTHN to
produce a userID, generates a PGP keypair (protected by the given password),
and persists the public key, private key, revocation placeholder, password
hash (Argon2id), and encrypted metadata via the Medium.
Usage: call Register(...) during the package's normal workflow.
##### `RevokeKey`
```go
func (a *Authenticator) RevokeKey(userID, password, reason string) error
```
RevokeKey marks a user's key as revoked. It verifies the password first,
writes a JSON revocation record to the .rev file (replacing the placeholder),
and invalidates all sessions for the user.
Usage: call RevokeKey(...) during the package's normal workflow.
##### `RevokeSession`
```go
func (a *Authenticator) RevokeSession(token string) error
```
RevokeSession removes a session, invalidating the token immediately.
Usage: call RevokeSession(...) during the package's normal workflow.
##### `RotateKeyPair`
```go
func (a *Authenticator) RotateKeyPair(userID, oldPassword, newPassword string) (*User, error)
```
RotateKeyPair generates a new PGP keypair for the given user, re-encrypts
their metadata with the new key, updates the password hash, and invalidates
all existing sessions. The caller must provide the current password
(oldPassword) to decrypt existing metadata and the new password (newPassword)
to protect the new keypair.
Usage: call RotateKeyPair(...) during the package's normal workflow.
##### `StartCleanup`
```go
func (a *Authenticator) StartCleanup(ctx context.Context, interval time.Duration)
```
StartCleanup runs a background goroutine that periodically removes expired
sessions from the store. It stops when the context is cancelled.
Usage: call StartCleanup(...) during the package's normal workflow.
##### `ValidateResponse`
```go
func (a *Authenticator) ValidateResponse(userID string, signedNonce []byte) (*Session, error)
```
ValidateResponse verifies a signed nonce from the client. The client must
have decrypted the challenge nonce and signed it with their private key.
On success, a new session is created and returned.
Usage: call ValidateResponse(...) during the package's normal workflow.
##### `ValidateSession`
```go
func (a *Authenticator) ValidateSession(token string) (*Session, error)
```
ValidateSession checks whether a token maps to a valid, non-expired session.
Usage: call ValidateSession(...) during the package's normal workflow.
##### `WriteChallengeFile`
```go
func (a *Authenticator) WriteChallengeFile(userID, path string) error
```
WriteChallengeFile writes an encrypted challenge to a file for air-gapped
(courier) transport. The challenge is created and then its encrypted nonce
is written to the specified path on the Medium.
Usage: call WriteChallengeFile(...) during the package's normal workflow.
### `Challenge`
```go
type Challenge struct {
Nonce []byte `json:"nonce"`
Encrypted string `json:"encrypted"` // PGP-encrypted nonce (armored)
ExpiresAt time.Time `json:"expires_at"`
}
```
Challenge is a PGP-encrypted nonce sent to a client during authentication.
Usage: use Challenge with the other exported helpers in this package.
### `HardwareKey`
```go
type HardwareKey interface {
// Sign produces a cryptographic signature over the given data using the
// hardware-stored private key. The signature format depends on the
// underlying device (e.g. ECDSA, RSA-PSS, EdDSA).
Sign(data []byte) ([]byte, error)
// Decrypt decrypts ciphertext using the hardware-stored private key.
// The ciphertext format must match what the device expects (e.g. RSA-OAEP).
Decrypt(ciphertext []byte) ([]byte, error)
// GetPublicKey returns the PEM or armored public key corresponding to the
// hardware-stored private key.
GetPublicKey() (string, error)
// IsAvailable reports whether the hardware key device is currently
// connected and operational. Callers should check this before attempting
// Sign or Decrypt to provide graceful fallback behaviour.
IsAvailable() bool
}
```
HardwareKey defines the contract for hardware-backed cryptographic operations.
Implementations should wrap PKCS#11 tokens, YubiKeys, TPM modules, or
similar tamper-resistant devices.
All methods must be safe for concurrent use.
Usage: implement HardwareKey and pass it to WithHardwareKey(...) to wire hardware-backed auth into New(...).
### `MemorySessionStore`
```go
type MemorySessionStore struct {
mu sync.RWMutex
sessions map[string]*Session
}
```
MemorySessionStore is an in-memory SessionStore backed by a map.
Usage: use MemorySessionStore with the other exported helpers in this package.
#### Methods
##### `Cleanup`
```go
func (m *MemorySessionStore) Cleanup() (int, error)
```
Cleanup removes all expired sessions and returns the count removed.
Usage: call Cleanup(...) during the package's normal workflow.
##### `Delete`
```go
func (m *MemorySessionStore) Delete(token string) error
```
Delete removes a session by token.
Usage: call Delete(...) during the package's normal workflow.
##### `DeleteByUser`
```go
func (m *MemorySessionStore) DeleteByUser(userID string) error
```
DeleteByUser removes all sessions belonging to the given user.
Usage: call DeleteByUser(...) during the package's normal workflow.
##### `Get`
```go
func (m *MemorySessionStore) Get(token string) (*Session, error)
```
Get retrieves a session by token.
Usage: call Get(...) during the package's normal workflow.
##### `Set`
```go
func (m *MemorySessionStore) Set(session *Session) error
```
Set stores a session, keyed by its token.
Usage: call Set(...) during the package's normal workflow.
### `Option`
```go
type Option func(*Authenticator)
```
Option configures an Authenticator.
Usage: use Option with the other exported helpers in this package.
### `Revocation`
```go
type Revocation struct {
UserID string `json:"user_id"`
Reason string `json:"reason"`
RevokedAt time.Time `json:"revoked_at"`
}
```
Revocation records the details of a revoked user key.
Stored as JSON in the user's .rev file, replacing the legacy placeholder.
Usage: use Revocation with the other exported helpers in this package.
### `SQLiteSessionStore`
```go
type SQLiteSessionStore struct {
mu sync.Mutex
store *store.Store
}
```
SQLiteSessionStore is a SessionStore backed by core/store (SQLite KV).
A mutex serialises all operations because SQLite is single-writer.
Usage: use SQLiteSessionStore with the other exported helpers in this package.
#### Methods
##### `Cleanup`
```go
func (s *SQLiteSessionStore) Cleanup() (int, error)
```
Cleanup removes all expired sessions and returns the count removed.
Usage: call Cleanup(...) during the package's normal workflow.
##### `Close`
```go
func (s *SQLiteSessionStore) Close() error
```
Close closes the underlying SQLite store.
Usage: call Close(...) during the package's normal workflow.
##### `Delete`
```go
func (s *SQLiteSessionStore) Delete(token string) error
```
Delete removes a session by token from SQLite.
Usage: call Delete(...) during the package's normal workflow.
##### `DeleteByUser`
```go
func (s *SQLiteSessionStore) DeleteByUser(userID string) error
```
DeleteByUser removes all sessions belonging to the given user.
Usage: call DeleteByUser(...) during the package's normal workflow.
##### `Get`
```go
func (s *SQLiteSessionStore) Get(token string) (*Session, error)
```
Get retrieves a session by token from SQLite.
Usage: call Get(...) during the package's normal workflow.
##### `Set`
```go
func (s *SQLiteSessionStore) Set(session *Session) error
```
Set stores a session in SQLite, keyed by its token.
Usage: call Set(...) during the package's normal workflow.
### `Session`
```go
type Session struct {
Token string `json:"token"`
UserID string `json:"user_id"`
ExpiresAt time.Time `json:"expires_at"`
}
```
Session represents an authenticated session.
Usage: use Session with the other exported helpers in this package.
### `SessionStore`
```go
type SessionStore interface {
Get(token string) (*Session, error)
Set(session *Session) error
Delete(token string) error
DeleteByUser(userID string) error
Cleanup() (int, error) // Remove expired sessions, return count removed
}
```
SessionStore abstracts session persistence.
Usage: use SessionStore with the other exported helpers in this package.
### `User`
```go
type User struct {
PublicKey string `json:"public_key"`
KeyID string `json:"key_id"`
Fingerprint string `json:"fingerprint"`
PasswordHash string `json:"password_hash"` // Argon2id (new) or LTHN (legacy)
Created time.Time `json:"created"`
LastLogin time.Time `json:"last_login"`
}
```
User represents a registered user with PGP credentials.
Usage: use User with the other exported helpers in this package.
## Functions
### `New`
```go
func New(m io.Medium, opts ...Option) *Authenticator
```
New creates an Authenticator that persists user data via the given Medium.
By default, sessions are stored in memory. Use WithSessionStore to provide
a persistent implementation (e.g. SQLiteSessionStore).
Usage: call New(...) to create a ready-to-use value.
### `NewMemorySessionStore`
```go
func NewMemorySessionStore() *MemorySessionStore
```
NewMemorySessionStore creates a new in-memory session store.
Usage: call NewMemorySessionStore(...) to create a ready-to-use value.
### `NewSQLiteSessionStore`
```go
func NewSQLiteSessionStore(dbPath string) (*SQLiteSessionStore, error)
```
NewSQLiteSessionStore creates a new SQLite-backed session store.
Use ":memory:" for testing or a file path for persistent storage.
Usage: call NewSQLiteSessionStore(...) to create a ready-to-use value.
### `WithChallengeTTL`
```go
func WithChallengeTTL(d time.Duration) Option
```
WithChallengeTTL sets the lifetime of a challenge before it expires.
Usage: pass WithChallengeTTL(...) into the related constructor to adjust the default behaviour.
### `WithHardwareKey`
```go
func WithHardwareKey(hk HardwareKey) Option
```
WithHardwareKey configures the Authenticator to use a hardware key for
cryptographic operations where supported. When set, the Authenticator may
delegate signing, decryption, and public key retrieval to the hardware
device instead of using software PGP keys.
This is a forward-looking option — integration points are documented in
auth.go but not yet wired up.
Usage: pass WithHardwareKey(...) into New(...) to enable a HardwareKey implementation.
### `WithSessionStore`
```go
func WithSessionStore(s SessionStore) Option
```
WithSessionStore sets the SessionStore implementation.
If not provided, an in-memory store is used (sessions lost on restart).
Usage: pass WithSessionStore(...) into the related constructor to adjust the default behaviour.
### `WithSessionTTL`
```go
func WithSessionTTL(d time.Duration) Option
```
WithSessionTTL sets the lifetime of a session before it expires.
Usage: pass WithSessionTTL(...) into the related constructor to adjust the default behaviour.

250
specs/crypt/RFC.md Normal file
View file

@ -0,0 +1,250 @@
# crypt
**Import:** `dappco.re/go/core/crypt/crypt`
**Files:** 6
## Types
None.
## Functions
### `AESGCMDecrypt`
```go
func AESGCMDecrypt(ciphertext, key []byte) ([]byte, error)
```
AESGCMDecrypt decrypts ciphertext encrypted with AESGCMEncrypt.
The key must be 32 bytes. Expects the nonce prepended to the ciphertext.
Usage: call AESGCMDecrypt(...) during the package's normal workflow.
### `AESGCMEncrypt`
```go
func AESGCMEncrypt(plaintext, key []byte) ([]byte, error)
```
AESGCMEncrypt encrypts plaintext using AES-256-GCM.
The key must be 32 bytes. The nonce is randomly generated and prepended
to the ciphertext.
Usage: call AESGCMEncrypt(...) during the package's normal workflow.
### `ChaCha20Decrypt`
```go
func ChaCha20Decrypt(ciphertext, key []byte) ([]byte, error)
```
ChaCha20Decrypt decrypts ciphertext encrypted with ChaCha20Encrypt.
The key must be 32 bytes. Expects the nonce prepended to the ciphertext.
Usage: call ChaCha20Decrypt(...) during the package's normal workflow.
### `ChaCha20Encrypt`
```go
func ChaCha20Encrypt(plaintext, key []byte) ([]byte, error)
```
ChaCha20Encrypt encrypts plaintext using ChaCha20-Poly1305.
The key must be 32 bytes. The nonce is randomly generated and prepended
to the ciphertext.
Usage: call ChaCha20Encrypt(...) during the package's normal workflow.
### `Decrypt`
```go
func Decrypt(ciphertext, passphrase []byte) ([]byte, error)
```
Decrypt decrypts data encrypted with Encrypt.
Expects format: salt (16 bytes) + nonce (24 bytes) + ciphertext.
Usage: call Decrypt(...) during the package's normal workflow.
### `DecryptAES`
```go
func DecryptAES(ciphertext, passphrase []byte) ([]byte, error)
```
DecryptAES decrypts data encrypted with EncryptAES.
Expects format: salt (16 bytes) + nonce (12 bytes) + ciphertext.
Usage: call DecryptAES(...) during the package's normal workflow.
### `DeriveKey`
```go
func DeriveKey(passphrase, salt []byte, keyLen uint32) []byte
```
DeriveKey derives a key from a passphrase using Argon2id with default parameters.
The salt must be argon2SaltLen bytes. keyLen specifies the desired key length.
Usage: call DeriveKey(...) during the package's normal workflow.
### `DeriveKeyScrypt`
```go
func DeriveKeyScrypt(passphrase, salt []byte, keyLen int) ([]byte, error)
```
DeriveKeyScrypt derives a key from a passphrase using scrypt.
Uses recommended parameters: N=32768, r=8, p=1.
Usage: call DeriveKeyScrypt(...) during the package's normal workflow.
### `Encrypt`
```go
func Encrypt(plaintext, passphrase []byte) ([]byte, error)
```
Encrypt encrypts data with a passphrase using ChaCha20-Poly1305.
A random salt is generated and prepended to the output.
Format: salt (16 bytes) + nonce (24 bytes) + ciphertext.
Usage: call Encrypt(...) during the package's normal workflow.
### `EncryptAES`
```go
func EncryptAES(plaintext, passphrase []byte) ([]byte, error)
```
EncryptAES encrypts data using AES-256-GCM with a passphrase.
A random salt is generated and prepended to the output.
Format: salt (16 bytes) + nonce (12 bytes) + ciphertext.
Usage: call EncryptAES(...) during the package's normal workflow.
### `HKDF`
```go
func HKDF(secret, salt, info []byte, keyLen int) ([]byte, error)
```
HKDF derives a key using HKDF-SHA256.
secret is the input keying material, salt is optional (can be nil),
info is optional context, and keyLen is the desired output length.
Usage: call HKDF(...) during the package's normal workflow.
### `HMACSHA256`
```go
func HMACSHA256(message, key []byte) []byte
```
HMACSHA256 computes the HMAC-SHA256 of a message using the given key.
Usage: call HMACSHA256(...) during the package's normal workflow.
### `HMACSHA512`
```go
func HMACSHA512(message, key []byte) []byte
```
HMACSHA512 computes the HMAC-SHA512 of a message using the given key.
Usage: call HMACSHA512(...) during the package's normal workflow.
### `HashBcrypt`
```go
func HashBcrypt(password string, cost int) (string, error)
```
HashBcrypt hashes a password using bcrypt with the given cost.
Cost must be between bcrypt.MinCost and bcrypt.MaxCost.
Usage: call HashBcrypt(...) during the package's normal workflow.
### `HashPassword`
```go
func HashPassword(password string) (string, error)
```
HashPassword hashes a password using Argon2id with default parameters.
Returns a string in the format: $argon2id$v=19$m=65536,t=3,p=4$<base64salt>$<base64hash>
Usage: call HashPassword(...) during the package's normal workflow.
### `SHA256File`
```go
func SHA256File(path string) (string, error)
```
SHA256File computes the SHA-256 checksum of a file and returns it as a hex string.
Usage: call SHA256File(...) during the package's normal workflow.
### `SHA256Sum`
```go
func SHA256Sum(data []byte) string
```
SHA256Sum computes the SHA-256 checksum of data and returns it as a hex string.
Usage: call SHA256Sum(...) during the package's normal workflow.
### `SHA512File`
```go
func SHA512File(path string) (string, error)
```
SHA512File computes the SHA-512 checksum of a file and returns it as a hex string.
Usage: call SHA512File(...) during the package's normal workflow.
### `SHA512Sum`
```go
func SHA512Sum(data []byte) string
```
SHA512Sum computes the SHA-512 checksum of data and returns it as a hex string.
Usage: call SHA512Sum(...) during the package's normal workflow.
### `VerifyBcrypt`
```go
func VerifyBcrypt(password, hash string) (bool, error)
```
VerifyBcrypt verifies a password against a bcrypt hash.
Usage: call VerifyBcrypt(...) during the package's normal workflow.
### `VerifyHMAC`
```go
func VerifyHMAC(message, key, mac []byte, hashFunc func() hash.Hash) bool
```
VerifyHMAC verifies an HMAC using constant-time comparison.
hashFunc should be sha256.New, sha512.New, etc.
Usage: call VerifyHMAC(...) during the package's normal workflow.
### `VerifyPassword`
```go
func VerifyPassword(password, hash string) (bool, error)
```
VerifyPassword verifies a password against an Argon2id hash string.
The hash must be in the format produced by HashPassword.
Usage: call VerifyPassword(...) during the package's normal workflow.

View file

@ -0,0 +1,30 @@
# chachapoly
**Import:** `dappco.re/go/core/crypt/crypt/chachapoly`
**Files:** 1
## Types
None.
## Functions
### `Decrypt`
```go
func Decrypt(ciphertext []byte, key []byte) ([]byte, error)
```
Decrypt decrypts data using ChaCha20-Poly1305.
Usage: call Decrypt(...) during the package's normal workflow.
### `Encrypt`
```go
func Encrypt(plaintext []byte, key []byte) ([]byte, error)
```
Encrypt encrypts data using ChaCha20-Poly1305.
Usage: call Encrypt(...) during the package's normal workflow.

63
specs/crypt/lthn/RFC.md Normal file
View file

@ -0,0 +1,63 @@
# lthn
**Import:** `dappco.re/go/core/crypt/crypt/lthn`
**Files:** 1
## Types
None.
## Functions
### `GetKeyMap`
```go
func GetKeyMap() map[rune]rune
```
GetKeyMap returns the current character substitution map.
Usage: call GetKeyMap(...) during the package's normal workflow.
### `Hash`
```go
func Hash(input string) string
```
Hash computes the LTHN hash of the input string.
The algorithm:
1. Derive a quasi-salt by reversing the input and applying character substitutions
2. Concatenate: input + salt
3. Compute SHA-256 of the concatenated string
4. Return the hex-encoded digest (64 characters, lowercase)
The same input always produces the same hash, enabling verification
without storing a separate salt value.
Usage: call Hash(...) when you need a deterministic content-style digest rather than a password hash.
### `SetKeyMap`
```go
func SetKeyMap(newKeyMap map[rune]rune)
```
SetKeyMap replaces the default character substitution map.
Use this to customize the quasi-salt derivation for specific applications.
Changes affect all subsequent Hash and Verify calls.
Usage: call SetKeyMap(...) during the package's normal workflow.
### `Verify`
```go
func Verify(input string, hash string) bool
```
Verify checks if an input string produces the given hash.
Returns true if Hash(input) equals the provided hash value.
Uses constant-time comparison to prevent timing attacks.
Usage: call Verify(...) during the package's normal workflow.

View file

@ -0,0 +1,69 @@
# openpgp
**Import:** `dappco.re/go/core/crypt/crypt/openpgp`
**Files:** 1
## Types
### `Service`
```go
type Service struct {
core *framework.Core
}
```
Service provides OpenPGP cryptographic operations.
Usage: use Service with the other exported helpers in this package.
#### Methods
##### `CreateKeyPair`
```go
func (s *Service) CreateKeyPair(name, passphrase string) (string, error)
```
CreateKeyPair generates a new RSA-4096 PGP keypair.
Returns the armored private key string.
Usage: call CreateKeyPair(...) during the package's normal workflow.
##### `DecryptPGP`
```go
func (s *Service) DecryptPGP(privateKey, message, passphrase string, opts ...any) (string, error)
```
DecryptPGP decrypts a PGP message using the provided armored private key and passphrase.
Usage: call DecryptPGP(...) during the package's normal workflow.
##### `EncryptPGP`
```go
func (s *Service) EncryptPGP(writer goio.Writer, recipientPath, data string, opts ...any) (string, error)
```
EncryptPGP encrypts data for a recipient identified by their public key (armored string in recipientPath).
The encrypted data is written to the provided writer and also returned as an armored string.
Usage: call EncryptPGP(...) during the package's normal workflow.
##### `HandleIPCEvents`
```go
func (s *Service) HandleIPCEvents(c *framework.Core, msg framework.Message) error
```
HandleIPCEvents handles PGP-related IPC messages.
Usage: call HandleIPCEvents(...) during the package's normal workflow.
## Functions
### `New`
```go
func New(c *framework.Core) (any, error)
```
New creates a new OpenPGP service instance.
Usage: call New(...) to create a ready-to-use value.

77
specs/crypt/pgp/RFC.md Normal file
View file

@ -0,0 +1,77 @@
# pgp
**Import:** `dappco.re/go/core/crypt/crypt/pgp`
**Files:** 1
## Types
### `KeyPair`
```go
type KeyPair struct {
PublicKey string
PrivateKey string
}
```
KeyPair holds armored PGP public and private keys.
Usage: use KeyPair with the other exported helpers in this package.
## Functions
### `CreateKeyPair`
```go
func CreateKeyPair(name, email, password string) (*KeyPair, error)
```
CreateKeyPair generates a new PGP key pair for the given identity.
If password is non-empty, the private key is encrypted with it.
Returns a KeyPair with armored public and private keys.
Usage: call CreateKeyPair(...) during the package's normal workflow.
### `Decrypt`
```go
func Decrypt(data []byte, privateKeyArmor, password string) ([]byte, error)
```
Decrypt decrypts armored PGP data using the given armored private key.
If the private key is encrypted, the password is used to decrypt it first.
Usage: call Decrypt(...) during the package's normal workflow.
### `Encrypt`
```go
func Encrypt(data []byte, publicKeyArmor string) ([]byte, error)
```
Encrypt encrypts data for the recipient identified by their armored public key.
Returns the encrypted data as armored PGP output.
Usage: call Encrypt(...) during the package's normal workflow.
### `Sign`
```go
func Sign(data []byte, privateKeyArmor, password string) ([]byte, error)
```
Sign creates an armored detached signature for the given data using
the armored private key. If the key is encrypted, the password is used
to decrypt it first.
Usage: call Sign(...) during the package's normal workflow.
### `Verify`
```go
func Verify(data, signature []byte, publicKeyArmor string) error
```
Verify verifies an armored detached signature against the given data
and armored public key. Returns nil if the signature is valid.
Usage: call Verify(...) during the package's normal workflow.

56
specs/crypt/rsa/RFC.md Normal file
View file

@ -0,0 +1,56 @@
# rsa
**Import:** `dappco.re/go/core/crypt/crypt/rsa`
**Files:** 1
## Types
### `Service`
```go
type Service struct{}
```
Service provides RSA functionality.
Usage: use Service with the other exported helpers in this package.
#### Methods
##### `Decrypt`
```go
func (s *Service) Decrypt(privateKey, ciphertext, label []byte) ([]byte, error)
```
Decrypt decrypts data with a private key.
Usage: call Decrypt(...) during the package's normal workflow.
##### `Encrypt`
```go
func (s *Service) Encrypt(publicKey, data, label []byte) ([]byte, error)
```
Encrypt encrypts data with a public key.
Usage: call Encrypt(...) during the package's normal workflow.
##### `GenerateKeyPair`
```go
func (s *Service) GenerateKeyPair(bits int) (publicKey, privateKey []byte, err error)
```
GenerateKeyPair creates a new RSA key pair.
Usage: call GenerateKeyPair(...) during the package's normal workflow.
## Functions
### `NewService`
```go
func NewService() *Service
```
NewService creates and returns a new Service instance for performing RSA-related operations.
Usage: call NewService(...) to create a ready-to-use value.

599
specs/trust/RFC.md Normal file
View file

@ -0,0 +1,599 @@
# trust
**Import:** `dappco.re/go/core/crypt/trust`
**Files:** 5
## Types
### `Agent`
```go
type Agent struct {
// Name is the unique identifier for the agent (e.g., "Athena", "Clotho").
Name string
// Tier is the agent's trust level.
Tier Tier
// ScopedRepos limits repo access for Tier 2 agents. Empty means no repo access.
// Tier 3 agents ignore this field (they have access to all repos).
ScopedRepos []string
// RateLimit is the maximum requests per minute. 0 means unlimited.
RateLimit int
// TokenExpiresAt is when the agent's token expires.
TokenExpiresAt time.Time
// CreatedAt is when the agent was registered.
CreatedAt time.Time
}
```
Agent represents an agent identity in the trust system.
Usage: use Agent with the other exported helpers in this package.
### `ApprovalQueue`
```go
type ApprovalQueue struct {
mu sync.RWMutex
requests map[string]*ApprovalRequest
nextID int
}
```
ApprovalQueue manages pending approval requests for NeedsApproval decisions.
Usage: use ApprovalQueue with the other exported helpers in this package.
#### Methods
##### `Approve`
```go
func (q *ApprovalQueue) Approve(id string, reviewedBy string, reason string) error
```
Approve marks a pending request as approved. Returns an error if the
request is not found or is not in pending status.
Usage: call Approve(...) during the package's normal workflow.
##### `Deny`
```go
func (q *ApprovalQueue) Deny(id string, reviewedBy string, reason string) error
```
Deny marks a pending request as denied. Returns an error if the
request is not found or is not in pending status.
Usage: call Deny(...) during the package's normal workflow.
##### `Get`
```go
func (q *ApprovalQueue) Get(id string) *ApprovalRequest
```
Get returns the approval request with the given ID, or nil if not found.
Usage: call Get(...) during the package's normal workflow.
##### `Len`
```go
func (q *ApprovalQueue) Len() int
```
Len returns the total number of requests in the queue.
Usage: call Len(...) during the package's normal workflow.
##### `Pending`
```go
func (q *ApprovalQueue) Pending() []ApprovalRequest
```
Pending returns all requests with ApprovalPending status.
Usage: call Pending(...) during the package's normal workflow.
##### `PendingSeq`
```go
func (q *ApprovalQueue) PendingSeq() iter.Seq[ApprovalRequest]
```
PendingSeq returns an iterator over all requests with ApprovalPending status.
Usage: call PendingSeq(...) during the package's normal workflow.
##### `Submit`
```go
func (q *ApprovalQueue) Submit(agent string, cap Capability, repo string) (string, error)
```
Submit creates a new approval request and returns its ID.
Returns an error if the agent name or capability is empty.
Usage: call Submit(...) during the package's normal workflow.
### `ApprovalRequest`
```go
type ApprovalRequest struct {
// ID is the unique identifier for this request.
ID string
// Agent is the name of the requesting agent.
Agent string
// Cap is the capability being requested.
Cap Capability
// Repo is the optional repo context for repo-scoped capabilities.
Repo string
// Status is the current approval status.
Status ApprovalStatus
// Reason is a human-readable explanation from the reviewer.
Reason string
// RequestedAt is when the request was created.
RequestedAt time.Time
// ReviewedAt is when the request was reviewed (zero if pending).
ReviewedAt time.Time
// ReviewedBy is the name of the admin who reviewed the request.
ReviewedBy string
}
```
ApprovalRequest represents a queued capability approval request.
Usage: use ApprovalRequest with the other exported helpers in this package.
### `ApprovalStatus`
```go
type ApprovalStatus int
```
ApprovalStatus represents the state of an approval request.
Usage: use ApprovalStatus with the other exported helpers in this package.
#### Methods
##### `String`
```go
func (s ApprovalStatus) String() string
```
String returns the human-readable name of the approval status.
Usage: call String(...) during the package's normal workflow.
### `AuditEntry`
```go
type AuditEntry struct {
// Timestamp is when the evaluation occurred.
Timestamp time.Time `json:"timestamp"`
// Agent is the name of the agent being evaluated.
Agent string `json:"agent"`
// Cap is the capability that was evaluated.
Cap Capability `json:"capability"`
// Repo is the repo context (empty if not repo-scoped).
Repo string `json:"repo,omitempty"`
// Decision is the evaluation outcome.
Decision Decision `json:"decision"`
// Reason is the human-readable reason for the decision.
Reason string `json:"reason"`
}
```
AuditEntry records a single policy evaluation for compliance.
Usage: use AuditEntry with the other exported helpers in this package.
### `AuditLog`
```go
type AuditLog struct {
mu sync.Mutex
entries []AuditEntry
writer io.Writer
}
```
AuditLog is an append-only log of policy evaluations.
Usage: use AuditLog with the other exported helpers in this package.
#### Methods
##### `Entries`
```go
func (l *AuditLog) Entries() []AuditEntry
```
Entries returns a snapshot of all audit entries.
Usage: call Entries(...) during the package's normal workflow.
##### `EntriesFor`
```go
func (l *AuditLog) EntriesFor(agent string) []AuditEntry
```
EntriesFor returns all audit entries for a specific agent.
Usage: call EntriesFor(...) during the package's normal workflow.
##### `EntriesForSeq`
```go
func (l *AuditLog) EntriesForSeq(agent string) iter.Seq[AuditEntry]
```
EntriesForSeq returns an iterator over audit entries for a specific agent.
Usage: call EntriesForSeq(...) during the package's normal workflow.
##### `EntriesSeq`
```go
func (l *AuditLog) EntriesSeq() iter.Seq[AuditEntry]
```
EntriesSeq returns an iterator over all audit entries.
Usage: call EntriesSeq(...) during the package's normal workflow.
##### `Len`
```go
func (l *AuditLog) Len() int
```
Len returns the number of entries in the log.
Usage: call Len(...) during the package's normal workflow.
##### `Record`
```go
func (l *AuditLog) Record(result EvalResult, repo string) error
```
Record appends an evaluation result to the audit log.
Usage: call Record(...) during the package's normal workflow.
### `Capability`
```go
type Capability string
```
Capability represents a specific action an agent can perform.
Usage: use Capability with the other exported helpers in this package.
### `Decision`
```go
type Decision int
```
Decision is the result of a policy evaluation.
Usage: use Decision with the other exported helpers in this package.
#### Methods
##### `MarshalJSON`
```go
func (d Decision) MarshalJSON() ([]byte, error)
```
MarshalJSON implements custom JSON encoding for Decision.
Usage: call MarshalJSON(...) during the package's normal workflow.
##### `String`
```go
func (d Decision) String() string
```
String returns the human-readable name of the decision.
Usage: call String(...) during the package's normal workflow.
##### `UnmarshalJSON`
```go
func (d *Decision) UnmarshalJSON(data []byte) error
```
UnmarshalJSON implements custom JSON decoding for Decision.
Usage: call UnmarshalJSON(...) during the package's normal workflow.
### `EvalResult`
```go
type EvalResult struct {
Decision Decision
Agent string
Cap Capability
Reason string
}
```
EvalResult contains the outcome of a capability evaluation.
Usage: use EvalResult with the other exported helpers in this package.
### `PoliciesConfig`
```go
type PoliciesConfig struct {
Policies []PolicyConfig `json:"policies"`
}
```
PoliciesConfig is the top-level configuration containing all tier policies.
Usage: use PoliciesConfig with the other exported helpers in this package.
### `Policy`
```go
type Policy struct {
// Tier is the trust level this policy applies to.
Tier Tier
// Allowed lists the capabilities granted at this tier.
Allowed []Capability
// RequiresApproval lists capabilities that need human/higher-tier approval.
RequiresApproval []Capability
// Denied lists explicitly denied capabilities.
Denied []Capability
}
```
Policy defines the access rules for a given trust tier.
Usage: use Policy with the other exported helpers in this package.
### `PolicyConfig`
```go
type PolicyConfig struct {
Tier int `json:"tier"`
Allowed []string `json:"allowed"`
RequiresApproval []string `json:"requires_approval,omitempty"`
Denied []string `json:"denied,omitempty"`
}
```
PolicyConfig is the JSON-serialisable representation of a trust policy.
Usage: use PolicyConfig with the other exported helpers in this package.
### `PolicyEngine`
```go
type PolicyEngine struct {
registry *Registry
policies map[Tier]*Policy
}
```
PolicyEngine evaluates capability requests against registered policies.
Usage: use PolicyEngine with the other exported helpers in this package.
#### Methods
##### `ApplyPolicies`
```go
func (pe *PolicyEngine) ApplyPolicies(r io.Reader) error
```
ApplyPolicies loads policies from a reader and sets them on the engine,
replacing any existing policies for the same tiers.
Usage: call ApplyPolicies(...) during the package's normal workflow.
##### `ApplyPoliciesFromFile`
```go
func (pe *PolicyEngine) ApplyPoliciesFromFile(path string) error
```
ApplyPoliciesFromFile loads policies from a JSON file and sets them on the engine.
Usage: call ApplyPoliciesFromFile(...) during the package's normal workflow.
##### `Evaluate`
```go
func (pe *PolicyEngine) Evaluate(agentName string, cap Capability, repo string) EvalResult
```
Evaluate checks whether the named agent can perform the given capability.
If the agent has scoped repos and the capability is repo-scoped, the repo
parameter is checked against the agent's allowed repos.
Usage: call Evaluate(...) during the package's normal workflow.
##### `ExportPolicies`
```go
func (pe *PolicyEngine) ExportPolicies(w io.Writer) error
```
ExportPolicies serialises the current policies as JSON to the given writer.
Usage: call ExportPolicies(...) during the package's normal workflow.
##### `GetPolicy`
```go
func (pe *PolicyEngine) GetPolicy(t Tier) *Policy
```
GetPolicy returns the policy for a tier, or nil if none is set.
Usage: call GetPolicy(...) during the package's normal workflow.
##### `SetPolicy`
```go
func (pe *PolicyEngine) SetPolicy(p Policy) error
```
SetPolicy replaces the policy for a given tier.
Usage: call SetPolicy(...) during the package's normal workflow.
### `Registry`
```go
type Registry struct {
mu sync.RWMutex
agents map[string]*Agent
}
```
Registry manages agent identities and their trust tiers.
Usage: use Registry with the other exported helpers in this package.
#### Methods
##### `Get`
```go
func (r *Registry) Get(name string) *Agent
```
Get returns the agent with the given name, or nil if not found.
Usage: call Get(...) during the package's normal workflow.
##### `Len`
```go
func (r *Registry) Len() int
```
Len returns the number of registered agents.
Usage: call Len(...) during the package's normal workflow.
##### `List`
```go
func (r *Registry) List() []Agent
```
List returns all registered agents. The returned slice is a snapshot.
Usage: call List(...) during the package's normal workflow.
##### `ListSeq`
```go
func (r *Registry) ListSeq() iter.Seq[Agent]
```
ListSeq returns an iterator over all registered agents.
Usage: call ListSeq(...) during the package's normal workflow.
##### `Register`
```go
func (r *Registry) Register(agent Agent) error
```
Register adds or updates an agent in the registry.
Returns an error if the agent name is empty or the tier is invalid.
Usage: call Register(...) during the package's normal workflow.
##### `Remove`
```go
func (r *Registry) Remove(name string) bool
```
Remove deletes an agent from the registry.
Usage: call Remove(...) during the package's normal workflow.
### `Tier`
```go
type Tier int
```
Tier represents an agent's trust level in the system.
Usage: use Tier with the other exported helpers in this package.
#### Methods
##### `String`
```go
func (t Tier) String() string
```
String returns the human-readable name of the tier.
Usage: call String(...) during the package's normal workflow.
##### `Valid`
```go
func (t Tier) Valid() bool
```
Valid returns true if the tier is a recognised trust level.
Usage: call Valid(...) during the package's normal workflow.
## Functions
### `LoadPolicies`
```go
func LoadPolicies(r io.Reader) ([]Policy, error)
```
LoadPolicies reads JSON from a reader and returns parsed policies.
Usage: call LoadPolicies(...) during the package's normal workflow.
### `LoadPoliciesFromFile`
```go
func LoadPoliciesFromFile(path string) ([]Policy, error)
```
LoadPoliciesFromFile reads a JSON file and returns parsed policies.
Usage: call LoadPoliciesFromFile(...) during the package's normal workflow.
### `NewApprovalQueue`
```go
func NewApprovalQueue() *ApprovalQueue
```
NewApprovalQueue creates an empty approval queue.
Usage: call NewApprovalQueue(...) to create a ready-to-use value.
### `NewAuditLog`
```go
func NewAuditLog(w io.Writer) *AuditLog
```
NewAuditLog creates an in-memory audit log. If a writer is provided,
each entry is also written as a JSON line to that writer (append-only).
Usage: call NewAuditLog(...) to create a ready-to-use value.
### `NewPolicyEngine`
```go
func NewPolicyEngine(registry *Registry) *PolicyEngine
```
NewPolicyEngine creates a policy engine with the given registry and default policies.
Usage: call NewPolicyEngine(...) to create a ready-to-use value.
### `NewRegistry`
```go
func NewRegistry() *Registry
```
NewRegistry creates an empty agent registry.
Usage: call NewRegistry(...) to create a ready-to-use value.