crypto

package
v1.3.4 Latest Latest
Warning

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

Go to latest
Published: May 4, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package crypto provides envelope encryption (AES-256-GCM, per-record DEK) for sensitive data such as secret headers and webhook secrets.

The Key Encryption Key (KEK) is loaded from the SPARROW_ENCRYPTION_KEY environment variable (64 hex chars = 32 bytes). This is required -- the server will not start without it.

Envelope Encryption

Each Encrypt call generates a random 256-bit Data Encryption Key (DEK), encrypts the plaintext with the DEK, then wraps (encrypts) the DEK with the KEK. This enables efficient key rotation: re-wrap every DEK with the new KEK without touching the (potentially large) data.

Backward Compatibility

Decrypt auto-detects envelope-encrypted data (version prefix 0x01). If the prefix is absent, it falls back to legacy direct AES-256-GCM decryption so that data encrypted before the envelope migration is still readable.

When no encryption key is configured, any attempt to encrypt or decrypt returns ErrNoEncryptionKey.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoEncryptionKey = errors.New("crypto: encryption key not configured (set SPARROW_ENCRYPTION_KEY)")

ErrNoEncryptionKey is returned when encryption/decryption is attempted without a configured encryption key.

Functions

func GenerateKey added in v0.5.0

func GenerateKey() (string, []byte, error)

GenerateKey generates a cryptographically random 32-byte key and returns it as a 64-character hex string suitable for SPARROW_ENCRYPTION_KEY. This is primarily used in tests; production deployments should generate keys externally via: openssl rand -hex 32

func IsEnvelopeEncrypted added in v0.5.0

func IsEnvelopeEncrypted(ciphertext []byte) bool

IsEnvelopeEncrypted reports whether ciphertext appears to be envelope-encrypted. It checks the version byte and structural validity without attempting decryption.

func ParseKey

func ParseKey(raw string) ([]byte, error)

ParseKey decodes a 64-character hex string into a 32-byte key suitable for NewService. Returns nil if raw is empty.

Types

type Service

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

Service provides encrypt/decrypt operations using envelope encryption (per-record DEK wrapped with a KEK). A nil *Service or one created without a key is valid — calls return ErrNoEncryptionKey.

func NewService

func NewService(key []byte) (*Service, error)

NewService creates a new crypto service from a 32-byte AES-256 key (the KEK). Pass nil to create a no-op service that returns ErrNoEncryptionKey on use.

func (*Service) Decrypt

func (s *Service) Decrypt(ciphertext []byte) ([]byte, error)

Decrypt decrypts ciphertext, auto-detecting the format:

  • Envelope format (version 0x01 prefix): uses envelope decryption
  • Legacy format (no prefix): falls back to direct AES-256-GCM

This ensures backward compatibility during migration from direct to envelope encryption.

func (*Service) DecryptJSON

func (s *Service) DecryptJSON(ciphertext []byte, v any) error

DecryptJSON decrypts ciphertext (auto-detecting format) and unmarshals into v.

func (*Service) DecryptString added in v0.5.0

func (s *Service) DecryptString(ciphertext []byte) (string, error)

DecryptString decrypts ciphertext back to a plaintext string. Returns "" if the input is nil/empty.

func (*Service) Enabled

func (s *Service) Enabled() bool

Enabled reports whether the service has an encryption key configured.

func (*Service) Encrypt

func (s *Service) Encrypt(plaintext []byte) ([]byte, error)

Encrypt encrypts plaintext using envelope encryption (per-record DEK). New data is always written in envelope format.

func (*Service) EncryptJSON

func (s *Service) EncryptJSON(v any) ([]byte, error)

EncryptJSON marshals v to JSON, then encrypts using envelope encryption.

func (*Service) EncryptString added in v0.5.0

func (s *Service) EncryptString(plaintext string) ([]byte, error)

EncryptString encrypts a plaintext string and returns the ciphertext bytes. Returns nil if the input is empty.

func (*Service) EnvelopeDecrypt added in v0.5.0

func (s *Service) EnvelopeDecrypt(ciphertext []byte) ([]byte, error)

EnvelopeDecrypt decrypts data produced by EnvelopeEncrypt. It unwraps the DEK using the KEK, then decrypts the data with the DEK.

func (*Service) EnvelopeEncrypt added in v0.5.0

func (s *Service) EnvelopeEncrypt(plaintext []byte) ([]byte, error)

EnvelopeEncrypt encrypts plaintext using envelope encryption:

  1. Generates a random 256-bit DEK (Data Encryption Key)
  2. Encrypts the plaintext with the DEK using AES-256-GCM
  3. Encrypts (wraps) the DEK with the KEK (Key Encryption Key, held by Service)

Wire format:

[0x01] [edek_len:2 LE] [encrypted_dek:edek_len] [data_nonce:12] [data_ciphertext+tag]

Jump to

Keyboard shortcuts

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