enc

package
v0.28.0 Latest Latest
Warning

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

Go to latest
Published: Jun 30, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package enc implements wick's encrypted-fields layer: a per-user AES-256-GCM cipher that lets credentials and other sensitive values flow between an LLM and a connector without ever appearing as plaintext in the LLM's context window or in audit logs.

The wire format is a single token with a fixed prefix:

wick_enc_<base64url(nonce ‖ AES-256-GCM(plaintext, nonce, derived_key))>

The 32-byte derived key is per-user — HKDF(master_key, salt=user_uuid, info="wick-enc") — so a token issued for user A cannot be decrypted when user B replays it.

Two operation modes:

  • Mask(data, values, user) — replaces every occurrence of each plaintext value in data with its wick_enc_ token, sharing one token per identical plaintext within the same call so the LLM does not mistake duplicates for distinct credentials.
  • Unmask(data, user) — inverse: scans data for wick_enc_ tokens and replaces each with its plaintext.

Disabled() reports whether WICK_ENC_DISABLE is set — when true, callers should skip mask/unmask and pass values through unchanged.

Index

Constants

View Source
const MasterPrefix = "wick_cenc_"

MasterPrefix marks a config-encrypted token (at-rest, master-key keyed, no per-user salt). Distinct from Prefix so the wrong decrypt path can't pick it up — Mask/Unmask scan only for Prefix.

View Source
const Prefix = "wick_enc_"

Prefix marks an encrypted token in user-visible payloads. The string is intentionally distinct from any other format wick or common upstream APIs emit, so a substring scan is unambiguous.

Variables

View Source
var ErrNotToken = errors.New("enc: not a wick_enc_ token")

ErrNotToken signals that DecryptValue saw something that does not carry the wick_enc_ prefix. Callers that scan free-form text for embedded tokens use IsToken first; this error is for direct callers that expected a token.

Functions

func IsMasterToken added in v0.6.1

func IsMasterToken(s string) bool

IsMasterToken reports whether s carries the wick_cenc_ prefix used for at-rest config encryption. Distinct from IsToken so callers can pick the right decrypt path (master vs per-user).

func IsToken

func IsToken(s string) bool

IsToken reports whether s begins with the wick_enc_ prefix. Cheap — callers can use it to skip the work of decoding when they're not sure what they're holding.

Types

type Service

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

Service wraps the master key + the per-user key derivation. One instance is shared across the process; methods are safe to call concurrently.

func New

func New(masterKeyHex string) (*Service, error)

New constructs a Service from a hex-encoded 32-byte master key. An empty key (or one of the wrong length) returns an error so the boot path can fail loudly rather than silently disabling encryption.

When WICK_ENC_DISABLE=true is set in the environment, the returned Service is valid but Disabled() returns true; callers MUST short- circuit on that flag rather than letting empty/zero crypto run.

func (*Service) DecryptMaster added in v0.6.1

func (s *Service) DecryptMaster(token string) (string, error)

DecryptMaster reverses EncryptMaster. Returns ErrNotToken when the input lacks the wick_cenc_ prefix. The error is opaque on auth/decrypt failure (typically: master key was rotated since the token was written).

func (*Service) DecryptValue

func (s *Service) DecryptValue(token, userUUID string) (string, error)

DecryptValue reverses EncryptValue. Returns ErrNotToken when the input lacks the wick_enc_ prefix and an opaque error when the token is malformed or the key is wrong (e.g. cross-user replay).

func (*Service) Disabled

func (s *Service) Disabled() bool

Disabled reports whether encryption is opt-out via the env var. When true, Mask/Unmask return data unchanged and EncryptValue/DecryptValue refuse to operate.

func (*Service) EncryptMaster added in v0.6.1

func (s *Service) EncryptMaster(plain string) (string, error)

EncryptMaster produces a wick_cenc_ token bound to the master key (no per-user salt). Used for at-rest config encryption: admin pastes plaintext into a `secret`-tagged config row, the configs service stores the token, and DecryptMaster restores the plaintext when the row is read back into the cache.

Disabled service is a programmer error — the configs layer must not call this when Disabled() is true. Returns an error rather than silently passing through.

func (*Service) EncryptValue

func (s *Service) EncryptValue(plain, userUUID string) (string, error)

EncryptValue produces one wick_enc_ token for the given plaintext. Returns the original string when the service is disabled. No length floor — admin opted in (manual UI) or tagged the field as secret/encrypt (auto-mask), so short values are honored either way. Pick distinct, non-generic values for sensitive fields to avoid false-positive substring hits during the auto-mask scan.

func (*Service) Mask

func (s *Service) Mask(data string, values []string, userUUID string) string

Mask replaces every occurrence of every value in `values` inside `data` with its wick_enc_ token. Identical values receive identical tokens within one call so the LLM does not mistake duplicates for distinct credentials. When the service is disabled, returns data unchanged.

func (*Service) MaskIgnoreCase

func (s *Service) MaskIgnoreCase(data string, values []string, userUUID string) string

MaskIgnoreCase is the case-insensitive variant of Mask. Every case variant of a keyword maps to one token derived from the keyword's configured spelling, so the LLM gets that spelling back on decrypt.

func (*Service) Unmask

func (s *Service) Unmask(data, userUUID string) (string, error)

Unmask scans data for wick_enc_ tokens and replaces each with its plaintext. Returns an error when ANY token fails to decrypt (typically: the key was rotated since the token was issued, or the token was issued for a different user). Tokens are de-duplicated so repeated occurrences only pay decryption cost once.

When the service is disabled, returns data unchanged with no error.

Jump to

Keyboard shortcuts

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