Documentation
¶
Overview ¶
Per-principal CEK derivation via HKDF.
Each org/user gets a unique 256-bit Content Encryption Key derived from:
CEK = HKDF-SHA256(master_key, principal_id)
This ensures:
- Different orgs can't read each other's databases
- Master key compromise + principal ID needed to derive any CEK
- Key rotation: re-derive all CEKs from new master, re-encrypt databases
Package sqlite provides an encrypted SQLite driver for Hanzo.
It is dual-backend and registers the database/sql driver name "sqlite" under BOTH build configurations, exposing the same public API either way:
- CGO (//go:build cgo) → mattn/go-sqlite3 + SQLCipher: page-level AES-256 encryption at rest. This is the production engine. Build with CGO_ENABLED=1 -tags "sqlcipher sqlite_fts5".
- !CGO (//go:build !cgo) → modernc.org/sqlite (pure Go): NO encryption. Used only for CGO-off CI (test + lint) and local dev. Demanding a key on this backend is a hard error — it never silently stores plaintext.
Because the "sqlite" driver name is registered under both tags, any code doing `_ "github.com/hanzoai/sqlite"` + `sql.Open("sqlite", dsn)` (e.g. Hanzo IAM's xorm engine) compiles and runs in CGO-off CI and runs encrypted in the CGO production build — one import, one driver name, two backends.
The encryption key, replication mode, threshold config, and per-principal CEK derivation (cek.go, threshold.go) are pure Go and live in tag-neutral files; only the database/sql driver registration and the connect-time pragma application differ by build tag (driver_cgo.go / driver_nocgo.go).
Threshold write attestation for multi-party SQLite.
Each party runs a node with a full replica. Write operations require t-of-n parties to sign the write before it's committed. Reads are local.
Use case: MPC wallet shard storage, DEX trade approvals, multi-sig transaction authorization in trading platforms.
Index ¶
- Variables
- func DSN(path string, rawKey []byte) string
- func DeriveKey(masterKey []byte, principalType PrincipalType, principalID string) ([]byte, error)
- func EncryptionAvailable() bool
- func OpenDB(path string, rawKey []byte) (*sql.DB, error)
- type Config
- type DB
- type Mode
- type Option
- func WithCRDT(nodeID, listen string, peers []string) Option
- func WithKey(passphrase string) Option
- func WithPeers(peers []string) Option
- func WithPrincipalKey(masterKey []byte, principalType PrincipalType, principalID string) Option
- func WithRaft(nodeID, listen string, peers []string) Option
- func WithRawKey(key []byte) Option
- func WithThreshold(t, n int, signingKey ed25519.PrivateKey) Option
- type PrincipalType
- type ThresholdManager
- func (tm *ThresholdManager) Attest(proposalID [32]byte, nodeID string, signature []byte) error
- func (tm *ThresholdManager) CleanExpired() int
- func (tm *ThresholdManager) Pending() int
- func (tm *ThresholdManager) Propose(sql string, params []any) ([32]byte, error)
- func (tm *ThresholdManager) RegisterPeer(nodeID string, pubKey ed25519.PublicKey)
- func (tm *ThresholdManager) SetCommitFunc(fn func(string, []any) error)
- type WriteProposal
Constants ¶
This section is empty.
Variables ¶
var ( ErrThresholdNotMet = errors.New("sqlite: threshold attestations not met") ErrDuplicateSigner = errors.New("sqlite: duplicate signer") ErrInvalidSig = errors.New("sqlite: invalid attestation signature") ErrSessionExpired = errors.New("sqlite: attestation session expired") )
ErrEncryptionUnavailable is returned when an encryption key is supplied to a backend that cannot encrypt. Never returned by the CGO backend.
Functions ¶
func DSN ¶ added in v0.1.2
DSN builds a canonical IAM SQLite DSN for the active (CGO/mattn/SQLCipher) backend.
When rawKey is non-nil it is emitted as SQLCipher's native `key=x'HEX'` URI parameter, which SQLCipher applies inside sqlite3_open_v2 — before mattn's pragma battery — making the connection reopen-safe. The DSN consequently CONTAINS the key; callers MUST NOT log it.
rawKey must be exactly 32 bytes when non-nil (validated by Open; OpenDB trusts its caller). A nil key yields an unencrypted DSN for the global/dev/test engine.
func DeriveKey ¶
func DeriveKey(masterKey []byte, principalType PrincipalType, principalID string) ([]byte, error)
DeriveKey derives a 256-bit CEK for a principal from a master key using HKDF-SHA256.
masterKey: 32-byte master encryption key (from KMS) principalType: "org" or "user" principalID: unique identifier (org slug, user ID)
The info string is "{principalType}:{principalID}" ensuring domain separation.
func EncryptionAvailable ¶ added in v0.1.2
func EncryptionAvailable() bool
EncryptionAvailable reports that this build's backend can encrypt at rest.
It returns true for the CGO backend, which is a BACKEND-capability flag, not a proof that libsqlcipher is actually linked: a CGO build WITHOUT the codec links plain sqlite and silently no-ops the key (writes plaintext). The production Dockerfile links libsqlcipher; the package's encryption-proof test verifies real ciphertext at runtime so a mis-linked build fails CI instead of shipping plaintext.
func OpenDB ¶ added in v0.1.2
OpenDB opens *path* as a database/sql DB on the CGO/SQLCipher backend with the given raw 256-bit key. It is the entry point for callers that need a *sql.DB (e.g. to hand to xorm.NewEngineWithDB). A nil key opens unencrypted. The returned DB is NOT pinged here; the caller (or Open) pings.
Types ¶
type Config ¶
type Config struct {
// Encryption
RawKey []byte // raw 256-bit key (skips KDF); nil means unencrypted
// Replication
Mode Mode
NodeID string
Listen string // bind address for replication
Peers []string // peer addresses
// Threshold mode
Threshold int // t value (signatures required)
Parties int // n value (total parties)
SigningKey ed25519.PrivateKey // this node's signing key
// contains filtered or unexported fields
}
Config for opening a database.
type DB ¶
DB wraps sql.DB with replication and encryption.
type Option ¶
type Option func(*Config)
Option configures a database.
func WithKey ¶
WithKey derives a raw 256-bit key from a passphrase via SHA-256 and configures sqlcipher to use it directly (skipping KDF).
func WithPrincipalKey ¶
func WithPrincipalKey(masterKey []byte, principalType PrincipalType, principalID string) Option
WithPrincipalKey derives a CEK and configures the database to use it. This is the primary API for per-org and per-user encryption.
func WithRawKey ¶
WithRawKey sets a raw 256-bit encryption key (skips KDF).
func WithThreshold ¶
func WithThreshold(t, n int, signingKey ed25519.PrivateKey) Option
WithThreshold enables multi-party threshold attestation for writes.
type PrincipalType ¶
type PrincipalType string
PrincipalType identifies the type of principal for CEK derivation.
const ( PrincipalOrg PrincipalType = "org" PrincipalUser PrincipalType = "user" )
type ThresholdManager ¶
type ThresholdManager struct {
// contains filtered or unexported fields
}
ThresholdManager coordinates multi-party write attestation.
func NewThresholdManager ¶
func NewThresholdManager(threshold, parties int, nodeID string, signingKey ed25519.PrivateKey) *ThresholdManager
NewThresholdManager creates a threshold write coordinator.
func (*ThresholdManager) Attest ¶
func (tm *ThresholdManager) Attest(proposalID [32]byte, nodeID string, signature []byte) error
Attest adds a peer's attestation to a pending proposal.
func (*ThresholdManager) CleanExpired ¶
func (tm *ThresholdManager) CleanExpired() int
CleanExpired removes expired proposals.
func (*ThresholdManager) Pending ¶
func (tm *ThresholdManager) Pending() int
Pending returns the number of pending proposals.
func (*ThresholdManager) Propose ¶
func (tm *ThresholdManager) Propose(sql string, params []any) ([32]byte, error)
Propose creates a new write proposal. Returns the proposal ID.
func (*ThresholdManager) RegisterPeer ¶
func (tm *ThresholdManager) RegisterPeer(nodeID string, pubKey ed25519.PublicKey)
RegisterPeer adds a peer's public key for attestation verification.
func (*ThresholdManager) SetCommitFunc ¶
func (tm *ThresholdManager) SetCommitFunc(fn func(string, []any) error)
SetCommitFunc sets the function called when threshold is met.
type WriteProposal ¶
type WriteProposal struct {
ID [32]byte // SHA-256 of the SQL + params
SQL string
Params []any
Proposer string // node ID of proposer
CreatedAt time.Time
ExpiresAt time.Time
// contains filtered or unexported fields
}
WriteProposal is a proposed write that needs t-of-n attestations.