encryption

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Dec 7, 2025 License: MIT Imports: 16 Imported by: 0

README

Encryption at Rest Package

Comprehensive data encryption at rest for the EventSourcing framework.

Security Implementation: This package implements SEC-103 (Data Encryption at Rest) from the security roadmap, providing enterprise-grade encryption for events, snapshots, and sensitive data.

Table of Contents

Overview

The encryption package provides:

AES-256-GCM Encryption - Authenticated encryption with associated data ✅ Key Management - Rotation, versioning, and lifecycle management ✅ Field-Level Encryption - Encrypt only sensitive fields ✅ Full Data Encryption - Encrypt entire event payloads ✅ Password-Based Encryption - Argon2id/PBKDF2 key derivation ✅ Key Rotation - Zero-downtime key rotation support ✅ Event Integration - Seamless event encryption/decryption

Why Encrypt at Rest?
Threat Without Encryption With Encryption
Database Breach ❌ All data exposed ✅ Data protected
Backup Theft ❌ Plaintext data ✅ Encrypted backups
Insider Threat ❌ Full access ✅ Key-based access control
Compliance ❌ GDPR/HIPAA violations ✅ Compliance met

Quick Start

1. Basic Encryption
package main

import (
    "github.com/plaenen/eventstore/pkg/security/encryption"
)

func main() {
    // Generate encryption key
    masterKey, _ := encryption.GenerateKey(32)

    // Create encryption service
    service, _ := encryption.NewService(masterKey)

    // Encrypt data
    ciphertext, _ := service.EncryptString("sensitive data")

    // Decrypt data
    plaintext, _ := service.DecryptString(ciphertext)
}
2. Password-Based Encryption
// Generate salt
salt, _ := encryption.GenerateSalt()

// Create service with password
password := "my-secure-password"
service, _ := encryption.NewServiceWithPassword(password, salt)

// Use normally
ciphertext, _ := service.EncryptString("secret")
3. Event Encryption
// Create event encryptor
eventEnc := encryption.NewEventEncryptor(service, nil)

// Encrypt event
encryptedEvent, _ := eventEnc.EncryptEvent(event)

// Decrypt event
decryptedEvent, _ := eventEnc.DecryptEvent(encryptedEvent)

Features

AES-256-GCM Encryption
  • Algorithm: AES-256 in Galois/Counter Mode
  • Authentication: Built-in authentication (AEAD)
  • Nonce: Unique nonce per encryption
  • Key Size: 256-bit (32 bytes) or 128-bit (16 bytes)
config := &encryption.Config{
    Algorithm:     encryption.AlgorithmAES256GCM,
    KeySize:       32,
    KeyDerivation: encryption.KeyDerivationArgon2,
}
Key Derivation Functions

Argon2id (Recommended)

  • Memory-hard function
  • Resistant to GPU/ASIC attacks
  • OWASP recommended
config := encryption.DefaultConfig()
// Argon2Time: 3, Argon2Memory: 64MB, Argon2Threads: 4

PBKDF2-SHA256 (Legacy Support)

  • Compatible with older systems
  • 600,000 iterations (OWASP 2023)
config := &encryption.Config{
    KeyDerivation:    encryption.KeyDerivationPBKDF2,
    PBKDF2Iterations: 600000,
}
Key Management

Features:

  • Key versioning
  • Key rotation
  • Multiple active keys
  • Key metadata export
  • Key lifecycle management
km := service.KeyManager()

// Rotate key
newKeyID, _ := km.RotateKey()

// List all keys
keys := km.ListKeys()

// Get active key
activeKey, _ := km.GetActiveKey()
Event Encryption Modes

Full Encryption:

config := &encryption.EventEncryptionConfig{
    EncryptData: true,
    FieldEncryption: false,
}

Field-Level Encryption:

config := &encryption.EventEncryptionConfig{
    EncryptData: true,
    FieldEncryption: true,
    EncryptedFields: []string{"ssn", "credit_card", "password"},
}

Usage Examples

Example 1: Basic Encryption/Decryption
// Generate key
key, _ := encryption.GenerateKey(32)

// Create cipher
cipher, _ := encryption.NewCipher(key, encryption.DefaultConfig())

// Encrypt
plaintext := []byte("sensitive data")
ciphertext, _ := cipher.Encrypt(plaintext)

// Decrypt
decrypted, _ := cipher.Decrypt(ciphertext)
Example 2: Service with Key Rotation
// Create service
masterKey, _ := encryption.GenerateKey(32)
service, _ := encryption.NewService(masterKey)

// Encrypt with original key
data1 := "old data"
cipher1, _ := service.EncryptString(data1)

// Rotate key
newKeyID, _ := service.RotateKey()

// Encrypt with new key
data2 := "new data"
cipher2, _ := service.EncryptString(data2)

// Both can still be decrypted
old, _ := service.DecryptString(cipher1)  // Works!
new, _ := service.DecryptString(cipher2)  // Works!

// Re-encrypt old data with new key
reEncrypted, _ := service.ReEncrypt(cipher1)
Example 3: Full Event Encryption
// Create encryptor
eventEnc := encryption.NewEventEncryptor(service, &encryption.EventEncryptionConfig{
    EncryptData: true,
    FieldEncryption: false,
})

// Create event
eventData := map[string]interface{}{
    "account_id":   "ACC-123",
    "amount":       1000.0,
    "ssn":          "123-45-6789",
    "credit_card":  "4532-1111-2222-3333",
}
eventDataBytes, _ := json.Marshal(eventData)

event := &domain.Event{
    ID:            "evt-001",
    AggregateID:   "account-123",
    AggregateType: "Account",
    EventType:     "AccountCredited",
    Version:       1,
    Timestamp:     time.Now(),
    Data:          eventDataBytes,
}

// Encrypt (entire payload encrypted)
encrypted, _ := eventEnc.EncryptEvent(event)

// Store encrypted event
// ...

// Decrypt when loading
decrypted, _ := eventEnc.DecryptEvent(encrypted)
Example 4: Field-Level Event Encryption
// Create field-level encryptor
fieldEnc := encryption.NewEventEncryptor(service, &encryption.EventEncryptionConfig{
    EncryptData:     true,
    FieldEncryption: true,
    EncryptedFields: []string{"ssn", "credit_card"},
})

// Create event with mixed sensitive/non-sensitive data
eventData := map[string]interface{}{
    "account_id":   "ACC-123",    // Not encrypted (searchable)
    "amount":       1000.0,       // Not encrypted (searchable)
    "customer_name": "John Doe",  // Not encrypted (searchable)
    "ssn":          "123-45-6789", // ENCRYPTED
    "credit_card":  "4532-1111-2222-3333", // ENCRYPTED
}

// Encrypt (only ssn and credit_card encrypted)
encrypted, _ := fieldEnc.EncryptEvent(event)

// Result: Can still search by account_id, amount, customer_name
// But ssn and credit_card are protected
Example 5: Password-Based Encryption
// Generate salt (store this!)
salt, _ := encryption.GenerateSalt()

// Derive key from password
password := "user-password-123"
key, _ := encryption.DeriveKey(password, salt, encryption.DefaultConfig())

// Create cipher with derived key
cipher, _ := encryption.NewCipher(key, encryption.DefaultConfig())

// Or use service directly
service, _ := encryption.NewServiceWithPassword(password, salt)

Key Management

Key Generation
// Generate AES-256 key (32 bytes)
key256, _ := encryption.GenerateKey(32)

// Generate AES-128 key (16 bytes)
key128, _ := encryption.GenerateKey(16)

// Generate salt for key derivation
salt, _ := encryption.GenerateSalt()
Key Rotation
service, _ := encryption.NewService(masterKey)

// Rotate to new key
newKeyID, _ := service.RotateKey()

// Old data still decrypts (uses old key)
// New data uses new key automatically

// Re-encrypt old data with new key
reEncrypted, _ := service.ReEncrypt(oldCiphertext)
Key Storage

DO:

  • ✅ Store keys in AWS KMS, HashiCorp Vault, or Azure Key Vault
  • ✅ Use environment variables for temporary storage
  • ✅ Encrypt keys at rest
  • ✅ Use separate keys per environment

DON'T:

  • ❌ Store keys in source code
  • ❌ Commit keys to version control
  • ❌ Share keys between environments
  • ❌ Store keys in plaintext files
Integration with Credential Provider
import (
    "github.com/plaenen/eventstore/pkg/security/credentials"
    "github.com/plaenen/eventstore/pkg/security/encryption"
)

// Store encryption key securely
credProvider, _ := credentials.NewSecretProvider(ctx,
    "awskms://arn:aws:secretsmanager:us-east-1:123:secret:encryption-key")

creds, _ := credProvider.GetCredentials(ctx)

// Use the key
service, _ := encryption.NewService([]byte(creds.Token))

Event Encryption

When to Use Full vs Field-Level
Scenario Recommendation
Highly sensitive data (medical records) Full encryption
Mixed sensitive/non-sensitive fields Field-level
Need to search/query events Field-level (encrypt only PII)
Regulatory compliance (HIPAA) Full encryption
Performance-sensitive Field-level
Full Encryption

Pros:

  • Maximum security
  • All data protected
  • Simple configuration

Cons:

  • Cannot search encrypted fields
  • Slightly slower
  • Must decrypt to query

Use When:

  • All data is equally sensitive
  • Compliance requires full encryption
  • Search not needed
Field-Level Encryption

Pros:

  • Granular control
  • Searchable non-sensitive fields
  • Better performance
  • Flexible queries

Cons:

  • More configuration
  • Need to identify sensitive fields
  • Potential for mistakes

Use When:

  • Only some fields are sensitive
  • Need to search/filter events
  • Performance matters

Production Deployment

Deployment Checklist
  • Generate strong master keys (32 bytes)
  • Store keys in secure key management system
  • Use Argon2id for password-based encryption
  • Enable key rotation schedule
  • Configure field-level encryption for searchable data
  • Test encryption/decryption performance
  • Set up key backup and recovery
  • Monitor encryption operations
  • Document key management procedures
  • Train team on security practices
AWS Deployment
// 1. Store master key in AWS Secrets Manager
aws secretsmanager create-secret \
  --name prod/encryption/master-key \
  --secret-binary fileb://master-key.bin

// 2. Use in application
credProvider, _ := credentials.NewSecretProvider(ctx,
    "awsparamstore:///prod/encryption/master-key")

creds, _ := credProvider.GetCredentials(ctx)
service, _ := encryption.NewService([]byte(creds.Token))
Kubernetes Deployment
# Create secret with encryption key
apiVersion: v1
kind: Secret
metadata:
  name: encryption-key
type: Opaque
data:
  master-key: <base64-encoded-key>
---
# Mount in pod
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: app
    env:
    - name: ENCRYPTION_KEY
      valueFrom:
        secretKeyRef:
          name: encryption-key
          key: master-key
// Use in application
keyBase64 := os.Getenv("ENCRYPTION_KEY")
key, _ := base64.StdEncoding.DecodeString(keyBase64)
service, _ := encryption.NewService(key)
Performance Tuning

For Development:

config := encryption.FastConfig()
// Faster key derivation, less secure
// Only use in development!

For Production:

config := encryption.DefaultConfig()
// Secure defaults, slower but safer

Custom Tuning:

config := &encryption.Config{
    Algorithm:     encryption.AlgorithmAES256GCM,
    KeyDerivation: encryption.KeyDerivationArgon2,
    KeySize:       32,
    Argon2Time:    3,    // Iterations
    Argon2Memory:  64 * 1024, // 64 MiB
    Argon2Threads: 4,    // Parallel threads
}

Security Best Practices

✅ DO's
  1. Use Strong Keys

    key, _ := encryption.GenerateKey(32) // AES-256
    
  2. Rotate Keys Regularly

    // Rotate every 90 days
    service.RotateKey()
    
  3. Use Argon2id

    config.KeyDerivation = encryption.KeyDerivationArgon2
    
  4. Store Keys Securely

    • AWS KMS, HashiCorp Vault, Azure Key Vault
    • Never in source code or config files
  5. Encrypt Sensitive Fields

    config.EncryptedFields = []string{"ssn", "credit_card", "password"}
    
  6. Test Recovery Procedures

    • Test key backup/restore
    • Document recovery steps
❌ DON'TS
  1. NEVER Store Keys in Code

    // ❌ BAD
    masterKey := []byte("hardcoded-key-12345")
    
    // ✅ GOOD
    masterKey, _ := loadKeyFromVault()
    
  2. NEVER Skip Key Derivation

    // ❌ BAD - using password directly
    service, _ := encryption.NewService([]byte("password"))
    
    // ✅ GOOD - derive key from password
    key, _ := encryption.DeriveKey("password", salt, config)
    
  3. NEVER Share Keys Between Environments

    • Dev, staging, production must have separate keys
  4. NEVER Use Fast Config in Production

    // ❌ BAD in production
    config := encryption.FastConfig()
    
    // ✅ GOOD
    config := encryption.DefaultConfig()
    
  5. NEVER Ignore Encryption Errors

    // ❌ BAD
    ciphertext, _ := service.Encrypt(data)
    
    // ✅ GOOD
    ciphertext, err := service.Encrypt(data)
    if err != nil {
        log.Fatalf("Encryption failed: %v", err)
    }
    

API Reference

Core Functions
// Key generation
GenerateKey(size int) ([]byte, error)
GenerateSalt() ([]byte, error)
DeriveKey(password string, salt []byte, config *Config) ([]byte, error)

// Cipher creation
NewCipher(key []byte, config *Config) (*Cipher, error)
NewCipherWithPassword(password string, salt []byte, config *Config) (*Cipher, error)

// Service creation
NewService(masterKey []byte) (*Service, error)
NewServiceWithConfig(masterKey []byte, config *Config) (*Service, error)
NewServiceWithPassword(password string, salt []byte) (*Service, error)
Cipher Methods
// Encryption/Decryption
Encrypt(plaintext []byte) ([]byte, error)
Decrypt(ciphertext []byte) ([]byte, error)
EncryptString(plaintext string) (string, error)
DecryptString(ciphertext string) (string, error)

// Key ID management
SetKeyID(keyID string)
KeyID() string
Service Methods
// Encryption/Decryption
Encrypt(plaintext []byte) (string, error)
Decrypt(ciphertext string) ([]byte, error)
EncryptString(plaintext string) (string, error)
DecryptString(ciphertext string) (string, error)

// Key management
RotateKey() (string, error)
ReEncrypt(oldCiphertext string) (string, error)
KeyManager() *KeyManager
EventEncryptor Methods
// Event encryption
EncryptEvent(event *domain.Event) (*domain.Event, error)
DecryptEvent(event *domain.Event) (*domain.Event, error)
EncryptEvents(events []*domain.Event) ([]*domain.Event, error)
DecryptEvents(events []*domain.Event) ([]*domain.Event, error)

Troubleshooting

Common Issues
1. Decryption Failed

Error: decryption failed: message authentication failed

Causes:

  • Wrong encryption key
  • Corrupted ciphertext
  • Modified data

Solution:

// Verify using correct key
key, err := loadCorrectKey()
if err != nil {
    log.Fatal("Failed to load key")
}

// Verify ciphertext format
if !strings.Contains(ciphertext, ":") {
    log.Fatal("Invalid ciphertext format")
}
2. Key Not Found

Error: key {id} not found

Cause: Trying to decrypt with a key that no longer exists

Solution:

// Keep old keys for decryption
// Only remove keys after re-encrypting all data
km.ListKeys() // Verify key exists before removing
3. Performance Issues

Problem: Slow encryption/decryption

Solutions:

// 1. Use fast config for development
config := encryption.FastConfig()

// 2. Reduce Argon2 parameters
config.Argon2Time = 1
config.Argon2Memory = 16 * 1024

// 3. Use field-level encryption instead of full
config.FieldEncryption = true
4. Out of Memory

Problem: High memory usage with Argon2

Solution:

// Reduce memory parameter
config := &encryption.Config{
    KeyDerivation: encryption.KeyDerivationArgon2,
    Argon2Memory:  32 * 1024, // Reduce from 64 MiB to 32 MiB
}

Examples

See the encryption-at-rest example for comprehensive demonstrations including:

  • Basic encryption/decryption
  • Password-based encryption
  • Key rotation
  • Full event encryption
  • Field-level event encryption
  • Key management
  • Performance comparison

Run the example:

cd examples/cmd/security-examples/encryption-at-rest
go run main.go

Security Roadmap

This package implements:

  • SEC-103: Data Encryption at Rest - Complete implementation
    • AES-256-GCM encryption
    • Key management and rotation
    • Field-level encryption
    • Event encryption integration

Related security features:

  • SEC-001: Authentication & Credentials - Secure credential management
  • SEC-002: TLS/Encryption - Encryption in transit
  • 🔲 SEC-003: RBAC - Role-based access control (planned)
  • 🔲 SEC-004: Audit Logging - Security audit trails (planned)

License

Copyright © 2024 EventSourcing Framework

Integration with Credentials Package

The encryption package integrates seamlessly with the credentials package (SEC-001) for secure key storage.

Quick Integration
import (
    "context"
    "github.com/plaenen/eventstore/pkg/security/credentials"
    "github.com/plaenen/eventstore/pkg/security/encryption"
)

// AWS Secrets Manager
provider, _ := credentials.NewSecretProvider(ctx,
    "awsparamstore:///prod/encryption/master-key")

// Create encryption service from credential provider
service, _ := encryption.NewServiceFromCredentialProvider(ctx, provider)

// Use normally
encrypted, _ := service.EncryptString("sensitive data")
Key Storage Best Practices

1. Production: AWS Secrets Manager

# Generate key
openssl rand -base64 32 > master-key.txt

# Store in AWS
aws secretsmanager create-secret \
  --name prod/encryption/master-key \
  --secret-string file://master-key.txt

# Delete local copy
shred -u master-key.txt
// Application code
provider, _ := credentials.NewSecretProvider(ctx,
    "awsparamstore:///prod/encryption/master-key")
service, _ := encryption.NewServiceFromCredentialProvider(ctx, provider)

2. Development: Environment Variables

# Generate and export key
export ENCRYPTION_MASTER_KEY=$(openssl rand -base64 32)
// Application code
provider := credentials.NewEnvTokenProvider("ENCRYPTION_MASTER_KEY", 0)
service, _ := encryption.NewServiceFromCredentialProvider(ctx, provider)

3. Flexible: Chain Provider

// Try production first, fall back to development
provider := credentials.NewChainProvider(
    credentials.NewSecretProvider(ctx, "awsparamstore:///prod/key"),
    credentials.NewEnvTokenProvider("ENCRYPTION_KEY", 0),
)

service, _ := encryption.NewServiceFromCredentialProvider(ctx, provider)
Key Rotation with Credentials
// 1. Load current key
currentProvider, _ := credentials.NewSecretProvider(ctx,
    "awsparamstore:///prod/encryption/master-key")
service, _ := encryption.NewServiceFromCredentialProvider(ctx, currentProvider)

// 2. Load new key
newProvider, _ := credentials.NewSecretProvider(ctx,
    "awsparamstore:///prod/encryption/master-key-v2")
newCreds, _ := newProvider.GetCredentials(ctx)
newKey, _ := encryption.DecodeKey(newCreds.Token)

// 3. Add new key to key manager
km := service.KeyManager()
km.AddKey("master-v2", newKey, true) // Set as active

// 4. Old data still decrypts, new encryptions use new key
Multi-Tenant Key Management
// Get tenant-specific encryption key
func getTenantEncryptionService(ctx context.Context, tenantID string) (*encryption.Service, error) {
    // Tenant-specific key path
    keyPath := fmt.Sprintf("/prod/encryption/tenant/%s/key", tenantID)
    
    provider, err := credentials.NewSecretProvider(ctx,
        "awsparamstore://" + keyPath)
    if err != nil {
        return nil, err
    }
    
    return encryption.NewServiceFromCredentialProvider(ctx, provider)
}

// Use tenant-specific encryption
tenantService, _ := getTenantEncryptionService(ctx, "tenant-123")
encrypted, _ := tenantService.EncryptString("tenant data")
Helper Functions
// Generate and encode key for storage
encoded, _ := encryption.GenerateAndEncodeKey(32)
fmt.Println(encoded) // Store this in AWS Secrets Manager

// Decode key from storage
key, _ := encryption.DecodeKey(encoded)

// Create service with decoded key
service, _ := encryption.NewService(key)

See secure-creds example for complete integration demonstration.

Documentation

Overview

Package encryption provides data encryption at rest for the EventSourcing framework.

This package implements SEC-103 (Data Encryption at Rest) from the security roadmap, providing comprehensive encryption support for events, snapshots, and sensitive data.

Example usage:

// Create encryption service with master key
masterKey := []byte("my-32-byte-master-key-here!!!")
encryptor, err := encryption.NewService(masterKey)

// Encrypt data
ciphertext, err := encryptor.Encrypt([]byte("sensitive data"))

// Decrypt data
plaintext, err := encryptor.Decrypt(ciphertext)

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidCiphertext is returned when ciphertext is invalid or corrupted
	ErrInvalidCiphertext = errors.New("invalid ciphertext")

	// ErrInvalidKey is returned when encryption key is invalid
	ErrInvalidKey = errors.New("invalid encryption key")

	// ErrDecryptionFailed is returned when decryption fails
	ErrDecryptionFailed = errors.New("decryption failed")

	// ErrEncryptionFailed is returned when encryption fails
	ErrEncryptionFailed = errors.New("encryption failed")
)
View Source
var (
	// ErrKeyNotFound is returned when a key is not found
	ErrKeyNotFound = errors.New("encryption key not found")

	// ErrNoActiveKey is returned when no active key is configured
	ErrNoActiveKey = errors.New("no active encryption key")
)

Functions

func DecodeKey

func DecodeKey(encodedKey string) ([]byte, error)

DecodeKey decodes a base64-encoded key

func DeriveKey

func DeriveKey(password string, salt []byte, config *Config) ([]byte, error)

DeriveKey derives an encryption key from a password using the configured KDF

func EncodeKey

func EncodeKey(key []byte) string

EncodeKey encodes a raw key to base64 for storage

func GenerateAndEncodeKey

func GenerateAndEncodeKey(size int) (string, error)

GenerateAndEncodeKey generates a new key and returns it base64-encoded

func GenerateKey

func GenerateKey(size int) ([]byte, error)

GenerateKey generates a random encryption key of the specified size

func GenerateSalt

func GenerateSalt() ([]byte, error)

GenerateSalt generates a random salt for key derivation

Types

type Algorithm

type Algorithm string

Algorithm represents the encryption algorithm

const (
	// AlgorithmAES256GCM uses AES-256 in GCM mode (recommended)
	AlgorithmAES256GCM Algorithm = "AES-256-GCM"

	// AlgorithmAES128GCM uses AES-128 in GCM mode
	AlgorithmAES128GCM Algorithm = "AES-128-GCM"
)

type Cipher

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

Cipher provides encryption and decryption operations

func NewCipher

func NewCipher(key []byte, config *Config) (*Cipher, error)

NewCipher creates a new cipher with the given key The key should be properly derived using DeriveKey if it's a password

func NewCipherWithPassword

func NewCipherWithPassword(password string, salt []byte, config *Config) (*Cipher, error)

NewCipherWithPassword creates a new cipher by deriving a key from a password

func (*Cipher) Decrypt

func (c *Cipher) Decrypt(ciphertext []byte) ([]byte, error)

Decrypt decrypts ciphertext and returns plaintext

func (*Cipher) DecryptString

func (c *Cipher) DecryptString(ciphertext string) (string, error)

DecryptString decrypts a base64-encoded ciphertext string

func (*Cipher) Encrypt

func (c *Cipher) Encrypt(plaintext []byte) ([]byte, error)

Encrypt encrypts plaintext and returns ciphertext Format: nonce || ciphertext || tag

func (*Cipher) EncryptString

func (c *Cipher) EncryptString(plaintext string) (string, error)

EncryptString encrypts a string and returns base64-encoded ciphertext

func (*Cipher) KeyID

func (c *Cipher) KeyID() string

KeyID returns the key identifier

func (*Cipher) SetKeyID

func (c *Cipher) SetKeyID(keyID string)

SetKeyID sets an optional key identifier for key rotation

type Config

type Config struct {
	// Algorithm to use for encryption
	Algorithm Algorithm

	// KeyDerivation function to use
	KeyDerivation KeyDerivation

	// KeySize in bytes (16 for AES-128, 32 for AES-256)
	KeySize int

	// Argon2 parameters (used if KeyDerivation is argon2id)
	Argon2Time    uint32 // Number of iterations
	Argon2Memory  uint32 // Memory in KiB
	Argon2Threads uint8  // Number of threads

	// PBKDF2 parameters (used if KeyDerivation is pbkdf2)
	PBKDF2Iterations int
}

Config represents encryption configuration

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns secure default encryption configuration

func FastConfig

func FastConfig() *Config

FastConfig returns a faster but less secure configuration Suitable for development/testing only

type EventEncryptionConfig

type EventEncryptionConfig struct {
	// EncryptData encrypts the event data payload
	EncryptData bool

	// FieldEncryption enables field-level encryption
	// Only specified fields are encrypted, others remain plaintext
	FieldEncryption bool

	// EncryptedFields lists which fields to encrypt (if FieldEncryption is true)
	// Example: []string{"password", "ssn", "credit_card"}
	EncryptedFields []string
}

EventEncryptionConfig configures event encryption

func DefaultEventEncryptionConfig

func DefaultEventEncryptionConfig() *EventEncryptionConfig

DefaultEventEncryptionConfig returns default event encryption configuration

type EventEncryptor

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

EventEncryptor provides encryption for event data

func NewEventEncryptor

func NewEventEncryptor(service *Service, config *EventEncryptionConfig) *EventEncryptor

NewEventEncryptor creates a new event encryptor

func (*EventEncryptor) DecryptEvent

func (ee *EventEncryptor) DecryptEvent(event *eventsourcing.Event) (*eventsourcing.Event, error)

DecryptEvent decrypts event data Returns a new event with decrypted data

func (*EventEncryptor) DecryptEvents

func (ee *EventEncryptor) DecryptEvents(events []*eventsourcing.Event) ([]*eventsourcing.Event, error)

DecryptEvents decrypts multiple events

func (*EventEncryptor) EncryptEvent

func (ee *EventEncryptor) EncryptEvent(event *eventsourcing.Event) (*eventsourcing.Event, error)

EncryptEvent encrypts event data based on configuration Returns a new event with encrypted data

func (*EventEncryptor) EncryptEvents

func (ee *EventEncryptor) EncryptEvents(events []*eventsourcing.Event) ([]*eventsourcing.Event, error)

EncryptEvents encrypts multiple events

type Key

type Key struct {
	Info   KeyInfo
	Cipher *Cipher
}

Key represents an encryption key with metadata

type KeyDerivation

type KeyDerivation string

KeyDerivation represents the key derivation function

const (
	// KeyDerivationArgon2 uses Argon2id (recommended for new applications)
	KeyDerivationArgon2 KeyDerivation = "argon2id"

	// KeyDerivationPBKDF2 uses PBKDF2-SHA256 (compatible with legacy systems)
	KeyDerivationPBKDF2 KeyDerivation = "pbkdf2-sha256"

	// KeyDerivationNone uses the key directly (only if key is already derived)
	KeyDerivationNone KeyDerivation = "none"
)

type KeyHelper

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

KeyHelper provides utilities for key management with credential providers

func NewKeyHelper

func NewKeyHelper(provider credentials.Provider, config *Config) *KeyHelper

NewKeyHelper creates a new key helper

func (*KeyHelper) LoadService

func (kh *KeyHelper) LoadService(ctx context.Context) (*Service, error)

LoadService loads an encryption service from the credential provider

type KeyInfo

type KeyInfo struct {
	// ID is a unique identifier for the key
	ID string `json:"id"`

	// Version of the key (increments on rotation)
	Version int `json:"version"`

	// CreatedAt is when the key was created
	CreatedAt time.Time `json:"created_at"`

	// RotatedAt is when the key was last rotated
	RotatedAt time.Time `json:"rotated_at,omitempty"`

	// ExpiresAt is when the key expires (optional)
	ExpiresAt time.Time `json:"expires_at,omitempty"`

	// Active indicates if this is the current encryption key
	Active bool `json:"active"`

	// Algorithm used with this key
	Algorithm Algorithm `json:"algorithm"`

	// Purpose describes what this key is used for
	Purpose string `json:"purpose,omitempty"`
}

KeyInfo contains metadata about an encryption key

type KeyManager

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

KeyManager manages encryption keys with support for key rotation

func NewKeyManager

func NewKeyManager(config *Config) *KeyManager

NewKeyManager creates a new key manager

func (*KeyManager) AddKey

func (km *KeyManager) AddKey(id string, key []byte, active bool) error

AddKey adds a new encryption key

func (*KeyManager) AddKeyWithPassword

func (km *KeyManager) AddKeyWithPassword(id, password string, salt []byte, active bool) error

AddKeyWithPassword adds a new encryption key derived from a password

func (*KeyManager) ExportKeys

func (km *KeyManager) ExportKeys() (string, error)

ExportKeys exports key metadata (not the actual keys!) as JSON This is useful for backup and disaster recovery documentation

func (*KeyManager) GetActiveKey

func (km *KeyManager) GetActiveKey() (*Key, error)

GetActiveKey returns the current active encryption key

func (*KeyManager) GetKey

func (km *KeyManager) GetKey(id string) (*Key, error)

GetKey retrieves a key by ID

func (*KeyManager) ListKeys

func (km *KeyManager) ListKeys() []KeyInfo

ListKeys returns all keys

func (*KeyManager) RemoveKey

func (km *KeyManager) RemoveKey(id string) error

RemoveKey removes a key (cannot remove active key)

func (*KeyManager) RotateKey

func (km *KeyManager) RotateKey() (string, error)

RotateKey generates a new key and sets it as active Old keys are kept for decryption of existing data

func (*KeyManager) SetActiveKey

func (km *KeyManager) SetActiveKey(id string) error

SetActiveKey sets the active encryption key

type Service

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

Service provides high-level encryption/decryption operations with key management

func NewService

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

NewService creates a new encryption service with a master key

func NewServiceFromCredentialProvider

func NewServiceFromCredentialProvider(ctx context.Context, provider credentials.Provider) (*Service, error)

NewServiceFromCredentialProvider creates an encryption service using a credential provider The credential's Token field should contain a base64-encoded encryption key

Example:

// AWS Secrets Manager
provider, _ := credentials.NewSecretProvider(ctx,
    "awsparamstore:///prod/encryption/master-key")
service, _ := encryption.NewServiceFromCredentialProvider(ctx, provider)

// Environment variable
provider := credentials.NewEnvProvider("ENCRYPTION_KEY", nil)
service, _ := encryption.NewServiceFromCredentialProvider(ctx, provider)

func NewServiceFromCredentialProviderWithConfig

func NewServiceFromCredentialProviderWithConfig(ctx context.Context, provider credentials.Provider, config *Config) (*Service, error)

NewServiceFromCredentialProviderWithConfig creates an encryption service with custom config

func NewServiceWithConfig

func NewServiceWithConfig(masterKey []byte, config *Config) (*Service, error)

NewServiceWithConfig creates a new encryption service with custom configuration

func NewServiceWithPassword

func NewServiceWithPassword(password string, salt []byte) (*Service, error)

NewServiceWithPassword creates a new encryption service with a password

func NewServiceWithPasswordAndConfig

func NewServiceWithPasswordAndConfig(password string, salt []byte, config *Config) (*Service, error)

NewServiceWithPasswordAndConfig creates a new encryption service with password and config

func (*Service) Decrypt

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

Decrypt decrypts data encrypted by this service Automatically determines which key to use based on the key ID in the ciphertext

func (*Service) DecryptString

func (s *Service) DecryptString(ciphertext string) (string, error)

DecryptString decrypts a string

func (*Service) Encrypt

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

Encrypt encrypts data using the active encryption key Returns: base64(keyID:ciphertext)

func (*Service) EncryptString

func (s *Service) EncryptString(plaintext string) (string, error)

EncryptString encrypts a string

func (*Service) KeyManager

func (s *Service) KeyManager() *KeyManager

KeyManager returns the underlying key manager

func (*Service) ReEncrypt

func (s *Service) ReEncrypt(oldCiphertext string) (string, error)

ReEncrypt re-encrypts data with the current active key Use this after key rotation to update encrypted data

func (*Service) RotateKey

func (s *Service) RotateKey() (string, error)

RotateKey rotates the encryption key Returns the new key ID

Jump to

Keyboard shortcuts

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