Context7 Users: See Quick Integration Guide for structured examples and patterns
A production-ready Go library for field-level encryption, hashing, and key management. ENCX provides struct-based cryptographic operations with support for key rotation, multiple KMS backends, and comprehensive testing utilities.
// Install: go get github.com/hengadev/encx
// Define struct with encryption tags (no companion fields needed)
type User struct {
Email string `encx:"encrypt,hash_basic"` // Encrypt + searchable
Password string `encx:"hash_secure"` // Secure password hash
}
// Generate code using one of 3 options:
// 1. go run ./cmd/encx-gen generate .
// 2. Build first: go build -o bin/encx-gen ./cmd/encx-gen && ./bin/encx-gen generate .
// 3. Add: //go:generate go run ../../cmd/encx-gen generate . (path must be relative)
// Use generated functions for type-safe encryption
crypto, _ := encx.NewTestCrypto(nil)
user := &User{Email: "user@example.com", Password: "secret123"}
// Process returns separate struct with encrypted/hashed fields
// Note: Function name follows pattern Process<YourStructName>Encx
// For a User struct, it generates ProcessUserEncx
userEncx, err := ProcessUserEncx(ctx, crypto, user)
// userEncx.EmailEncrypted contains encrypted email
// userEncx.EmailHash contains searchable hash
// userEncx.PasswordHashSecure contains secure hash
// Decrypt when needed
// Note: Function name follows pattern Decrypt<YourStructName>Encx
decryptedUser, err := DecryptUserEncx(ctx, crypto, userEncx)β See all patterns and use cases
- Field-level encryption with AES-GCM
- Secure hashing with Argon2id and basic SHA-256
- Combined operations - encrypt AND hash the same field
- Automatic key management with DEK/KEK architecture
- Key rotation support with version tracking
- Multiple KMS backends (AWS KMS, HashiCorp Vault, etc.)
- Comprehensive testing utilities and mocks
- Compile-time validation for struct tags
go get github.com/hengadev/encxpackage main
import (
"context"
"fmt"
"log"
"github.com/hengadev/encx"
)
// Define your struct with encx tags (no companion fields needed)
type User struct {
Name string `encx:"encrypt"`
Email string `encx:"hash_basic"`
Password string `encx:"hash_secure"`
}
// Run code generation using one of 3 options:
// 1. go run ./cmd/encx-gen generate .
// 2. Build first: go build -o bin/encx-gen ./cmd/encx-gen && ./bin/encx-gen generate .
// 3. Add: //go:generate go run ../../cmd/encx-gen generate . (path must be relative)
func main() {
ctx := context.Background()
crypto, _ := encx.NewTestCrypto(nil)
// Create user with sensitive data
user := &User{
Name: "John Doe",
Email: "john@example.com",
Password: "secret123",
}
// Process returns encrypted struct (generated function)
// Note: For your struct, replace "User" with your actual struct name
// Example: ProcessCustomerEncx, ProcessOrderEncx, etc.
userEncx, err := ProcessUserEncx(ctx, crypto, user)
if err != nil {
log.Fatal(err)
}
// Store encrypted data in database
fmt.Printf("NameEncrypted: %d bytes\n", len(userEncx.NameEncrypted))
fmt.Printf("EmailHash: %s\n", userEncx.EmailHash[:16]+"...")
fmt.Printf("PasswordHashSecure: %s...\n", userEncx.PasswordHashSecure[:20]+"...")
// Decrypt when needed (generated function)
decryptedUser, err := DecryptUserEncx(ctx, crypto, userEncx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Decrypted Name: %s\n", decryptedUser.Name)
}encx:"encrypt"- Encrypts field valueencx:"hash_basic"- Creates SHA-256 hash for searchable indexingencx:"hash_secure"- Creates Argon2id hash with pepper (for passwords)
encx:"encrypt,hash_basic"- Both encrypts AND hashes the field (searchable encryption)encx:"hash_secure,encrypt"- Secure hash for auth + encryption for recovery
encx-gen discovers structs automatically by parsing Go source files. No special directives required.
Code Generation Methods:
# Build the tool once
go build -o bin/encx-gen ./cmd/encx-gen
# Generate code for current directory and all subdirectories recursively
./bin/encx-gen generate .
# Generate code for specific packages
./bin/encx-gen generate ./path/to/package# No building needed - runs directly from source
go run ./cmd/encx-gen generate ./path/to/package
# Generate code for current directory and all subdirectories recursively
go run ./cmd/encx-gen generate .
# Works from any directory with correct relative path
go run ../../cmd/encx-gen generate .Add this to your Go source file (path must be relative to your file):
//go:generate go run ../../cmd/encx-gen generate .Then run: go generate ./...
Note: When using encx-gen generate ., the tool automatically discovers all Go packages in subdirectories recursively, making it ideal for processing entire projects from the root directory.
cmd/encx-gen. Options 1 & 2 work consistently in all environments.
When you define a struct with encx tags:
// Your source struct - clean and simple
type User struct {
Email string `encx:"encrypt,hash_basic"`
}
// encx-gen automatically generates a UserEncx struct
type UserEncx struct {
EmailEncrypted []byte // Encrypted email data
EmailHash string // Searchable hash
DEKEncrypted []byte // Encrypted data encryption key
KeyVersion int // Key version for rotation
Metadata string // Serialization metadata
}
// And generates these functions:
// - ProcessUserEncx(ctx, crypto, user) (*UserEncx, error)
// - DecryptUserEncx(ctx, crypto, userEncx) (*User, error)
//
// Note: Function names follow the pattern Process<StructName>Encx
// Replace "User" with your actual struct namePerfect for user lookup + privacy using code generation:
// Source struct - clean definition
type User struct {
Email string `encx:"encrypt,hash_basic"`
}
// Run: go run ./cmd/encx-gen generate .
// Usage
user := &User{Email: "user@example.com"}
userEncx, err := ProcessUserEncx(ctx, crypto, user)
// Generated UserEncx has:
// - EmailEncrypted []byte // For secure storage
// - EmailHash string // For fast user lookups
// Database search example
db.Where("email_hash = ?", userEncx.EmailHash).First(&foundUser)
// Decrypt when needed
decrypted, _ := DecryptUserEncx(ctx, crypto, foundUser)
fmt.Println(decrypted.Email) // "user@example.com"Secure authentication + recovery capability:
type User struct {
Password string `encx:"hash_secure,encrypt"`
}
// Run: go run ./cmd/encx-gen generate .
// Example: Registration
// (Replace "User" with your actual struct name)
user := &User{Password: "secret123"}
userEncx, _ := ProcessUserEncx(ctx, crypto, user)
// Generated UserEncx has:
// - PasswordHashSecure string // For authentication (Argon2id)
// - PasswordEncrypted []byte // For recovery scenarios
// Login verification
isValid := crypto.CompareSecureHashAndValue(ctx, inputPassword, userEncx.PasswordHashSecure)
// Password recovery (admin function)
recovered, _ := DecryptUserEncx(ctx, crypto, userEncx)
fmt.Println(recovered.Password) // Original password temporarily availableCode generation handles embedded structs automatically:
//go:generate go run ../../cmd/encx-gen generate .
type Address struct {
Street string `encx:"encrypt"`
City string `encx:"hash_basic"`
}
type User struct {
Name string `encx:"encrypt"`
Address Address // Embedded struct, automatically processed
}
// Example: Usage
// (Replace "User" with your actual struct name)
user := &User{
Name: "John Doe",
Address: Address{
Street: "123 Main St",
City: "Springfield",
},
}
userEncx, _ := ProcessUserEncx(ctx, crypto, user)
// Generated UserEncx includes all encrypted/hashed fields from embedded structENCX supports two configuration approaches:
- Explicit Configuration - Full control over all dependencies (recommended for libraries)
- Environment-based Configuration - 12-factor app pattern (recommended for applications)
import (
"github.com/hengadev/encx"
awskms "github.com/hengadev/encx/providers/keys/aws"
awssecrets "github.com/hengadev/encx/providers/secrets/aws"
)
// Initialize KMS for cryptographic operations
kms, err := awskms.NewKMSService(ctx, awskms.Config{
Region: "us-east-1",
})
// Initialize Secrets Manager for pepper storage
secrets, err := awssecrets.NewSecretsManagerStore(ctx, awssecrets.Config{
Region: "us-east-1",
})
// Create explicit configuration
cfg := encx.Config{
KEKAlias: "my-app-kek", // KMS key identifier
PepperAlias: "my-app-service", // Service identifier for pepper
}
// Initialize crypto with explicit dependencies
crypto, err := encx.NewCrypto(ctx, kms, secrets, cfg)import (
"github.com/hengadev/encx"
awskms "github.com/hengadev/encx/providers/keys/aws"
awssecrets "github.com/hengadev/encx/providers/secrets/aws"
)
// Set environment variables:
// export ENCX_KEK_ALIAS="my-app-kek"
// export ENCX_PEPPER_ALIAS="my-app-service"
// Initialize providers
kms, _ := awskms.NewKMSService(ctx, awskms.Config{Region: "us-east-1"})
secrets, _ := awssecrets.NewSecretsManagerStore(ctx, awssecrets.Config{Region: "us-east-1"})
// Load configuration from environment
crypto, err := encx.NewCryptoFromEnv(ctx, kms, secrets)import (
"github.com/hengadev/encx"
vaulttransit "github.com/hengadev/encx/providers/keys/hashicorp"
vaultkv "github.com/hengadev/encx/providers/secrets/hashicorp"
)
// Initialize Transit Engine for cryptographic operations
transit, err := vaulttransit.NewTransitService()
// Initialize KV Store for pepper storage
kvStore, err := vaultkv.NewKVStore()
// Explicit configuration
cfg := encx.Config{
KEKAlias: "my-app-kek",
PepperAlias: "my-app-service",
}
crypto, err := encx.NewCrypto(ctx, transit, kvStore, cfg)When using NewCryptoFromEnv(), these environment variables are required:
ENCX_KEK_ALIAS- Key encryption key identifier (required)ENCX_PEPPER_ALIAS- Service identifier for pepper storage (required)ENCX_DB_PATH- Database directory (optional, default:.encx)ENCX_DB_FILENAME- Database filename (optional, default:keys.db)
For AWS configuration:
AWS_REGION- AWS regionAWS_ACCESS_KEY_ID- AWS credentialsAWS_SECRET_ACCESS_KEY- AWS credentials
For Vault configuration:
VAULT_ADDR- Vault server address (required)VAULT_TOKEN- Vault token (or use AppRole)VAULT_NAMESPACE- Vault namespace (HCP Vault)
// For unit tests with code generation
func TestUserEncryption(t *testing.T) {
crypto, _ := encx.NewTestCrypto(t)
user := &User{Name: "Test User"}
userEncx, err := ProcessUserEncx(ctx, crypto, user)
assert.NoError(t, err)
assert.NotEmpty(t, userEncx.NameEncrypted)
}
// For integration tests
func TestUserEncryptionIntegration(t *testing.T) {
crypto, _ := encx.NewTestCrypto(t, &encx.TestCryptoOptions{
Pepper: []byte("test-pepper-exactly-32-bytes!!"),
})
// Test full encrypt/decrypt cycle
user := &User{Name: "Integration Test"}
userEncx, err := ProcessUserEncx(ctx, crypto, user)
assert.NoError(t, err)
decrypted, err := DecryptUserEncx(ctx, crypto, userEncx)
assert.NoError(t, err)
assert.Equal(t, "Integration Test", decrypted.Name)
}ENCX uses a custom compact binary serializer that provides deterministic encryption with minimal overhead. The serialization is handled automatically by the generated code - you don't need to configure anything.
Validate your struct tags before generating code:
# Validate all Go files in current directory
encx-gen validate -v .
# Validate specific packages
encx-gen validate -v ./models ./api
# Validation is automatically run before generation
go run ./cmd/encx-gen generate -v .// Rotate the Key Encryption Key (KEK)
if err := crypto.RotateKEK(ctx); err != nil {
log.Fatalf("Key rotation failed: %v", err)
}
// Data encrypted with old keys can still be decrypted
// New encryptions will use the new key versionENCX automatically handles multiple key versions:
// User encrypted with key version 1
oldUser := &User{Name: "Alice"}
oldUserEncx, _ := ProcessUserEncx(ctx, crypto, oldUser) // Uses current key (v1)
// Rotate key
crypto.RotateKEK(ctx)
// New user encrypted with key version 2
newUser := &User{Name: "Bob"}
newUserEncx, _ := ProcessUserEncx(ctx, crypto, newUser) // Uses current key (v2)
// Both can be decrypted regardless of key version
DecryptUserEncx(ctx, crypto, oldUserEncx) // Automatically uses key v1
DecryptUserEncx(ctx, crypto, newUserEncx) // Automatically uses key v2ENCX separates key management (cryptographic operations) from secret management (pepper storage). Each provider implements both interfaces.
AWS provider offers two services:
- KMSService - Handles encryption/decryption using AWS KMS
- SecretsManagerStore - Stores pepper in AWS Secrets Manager
import (
"github.com/hengadev/encx"
awskms "github.com/hengadev/encx/providers/keys/aws"
awssecrets "github.com/hengadev/encx/providers/secrets/aws"
)
// Initialize both services
kms, err := awskms.NewKMSService(ctx, awskms.Config{
Region: "us-east-1",
})
if err != nil {
log.Fatal(err)
}
secrets, err := awssecrets.NewSecretsManagerStore(ctx, awssecrets.Config{
Region: "us-east-1",
})
if err != nil {
log.Fatal(err)
}
// Create crypto instance
cfg := encx.Config{
KEKAlias: "alias/my-encryption-key",
PepperAlias: "my-app-service",
}
crypto, err := encx.NewCrypto(ctx, kms, secrets, cfg)
if err != nil {
log.Fatal(err)
}Key Benefits:
- Pepper automatically stored in AWS Secrets Manager
- No filesystem dependencies
- Follows AWS security best practices
- Supports key rotation
Required IAM Permissions:
- KMS:
kms:Encrypt,kms:Decrypt,kms:DescribeKey - Secrets Manager:
secretsmanager:GetSecretValue,secretsmanager:CreateSecret,secretsmanager:PutSecretValue
β Full AWS KMS Documentation
β Full AWS Secrets Manager Documentation
HashiCorp provider offers two services:
- TransitService - Handles encryption/decryption using Vault Transit Engine
- KVStore - Stores pepper in Vault KV v2 storage
import (
"github.com/hengadev/encx"
vaulttransit "github.com/hengadev/encx/providers/keys/hashicorp"
vaultkv "github.com/hengadev/encx/providers/secrets/hashicorp"
)
// Initialize both services (uses same Vault connection)
transit, err := vaulttransit.NewTransitService()
if err != nil {
log.Fatal(err)
}
kvStore, err := vaultkv.NewKVStore()
if err != nil {
log.Fatal(err)
}
// Create crypto instance
cfg := encx.Config{
KEKAlias: "my-encryption-key",
PepperAlias: "my-app-service",
}
crypto, err := encx.NewCrypto(ctx, transit, kvStore, cfg)
if err != nil {
log.Fatal(err)
}Key Benefits:
- Pepper automatically stored in Vault KV v2
- Leverages Vault's secret versioning
- Supports multi-region Vault deployments
- AppRole authentication support
Required Vault Policies:
- Transit:
transit/encrypt/<key-name>,transit/decrypt/<key-name> - KV:
secret/data/encx/<pepper-alias>/pepper(read/write)
β Full Vault Transit Documentation
β Full Vault KV Documentation
Example showing how to encrypt files on-the-fly and stream them directly to AWS S3:
import (
"github.com/hengadev/encx"
awskms "github.com/hengadev/encx/providers/keys/aws"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
// Encrypt file and stream to S3
err := crypto.EncryptStream(ctx, fileReader, s3Writer, dek)Features:
- Zero-copy streaming encryption
- Minimal memory usage (4KB buffer)
- Production-ready with error handling
- Includes HTTP upload server example
// Good: Email needs both lookup and privacy
Email string `encx:"encrypt,hash_basic"`
// Good: Password needs auth and recovery
Password string `encx:"hash_secure,encrypt"`
// Avoid: Unnecessary combinations
InternalID string `encx:"encrypt,hash_basic,hash_secure"` // Too muchuserEncx, err := ProcessUserEncx(ctx, crypto, user)
if err != nil {
// Log the error for debugging
log.Printf("Encryption failed: %v", err)
// Return user-friendly error
return nil, fmt.Errorf("failed to process user data: %w", err)
}//go:generate encx-gen validate -v .
//go:generate go run ./cmd/encx-gen generate -v .
// Run validation and generation during development
// Run: go generate ./...// Schedule regular key rotation
go func() {
ticker := time.NewTicker(30 * 24 * time.Hour) // 30 days
defer ticker.Stop()
for range ticker.C {
if err := crypto.RotateKEK(ctx); err != nil {
log.Printf("Key rotation failed: %v", err)
}
}
}()- Batch Operations: Process multiple structs in batches when possible
- Connection Pooling: Use connection pooling for KMS and database
- Caching: Consider caching decrypted DEKs for frequently accessed data
- Monitoring: Monitor KMS API calls and database performance
- Pepper Management: Peppers are automatically stored in KMS/Vault, never on filesystem
- Service Isolation: Use unique
PepperAliasfor each service/environment - KMS Permissions: Use least-privilege IAM policies for KMS and Secrets Manager
- Vault Policies: Restrict access to Transit Engine and KV paths
- Database Security: Encrypt database at rest and in transit
- Memory Management: Clear sensitive data from memory when possible
- Audit Logging: Log all cryptographic operations for compliance
- Key Rotation: Implement regular KEK rotation schedules (e.g., every 90 days)
The library includes comprehensive testing utilities:
// Unit testing with generated code
func TestUserEncryption(t *testing.T) {
crypto, _ := encx.NewTestCrypto(t)
user := &User{
Email: "test@example.com",
Password: "secret123",
}
userEncx, err := ProcessUserEncx(ctx, crypto, user)
assert.NoError(t, err)
assert.NotEmpty(t, userEncx.EmailEncrypted)
assert.NotEmpty(t, userEncx.EmailHash)
}
// Integration testing with full cycle
func TestUserEncryptDecryptCycle(t *testing.T) {
crypto, _ := encx.NewTestCrypto(t)
original := &User{Email: "integration@test.com"}
userEncx, err := ProcessUserEncx(ctx, crypto, original)
assert.NoError(t, err)
decrypted, err := DecryptUserEncx(ctx, crypto, userEncx)
assert.NoError(t, err)
assert.Equal(t, original.Email, decrypted.Email)
}The .encx/ directory contains the local key metadata database (SQLite). This should be excluded from version control:
.encx/Note: Peppers are stored in your configured SecretManagementService (AWS Secrets Manager, Vault KV, or in-memory for testing), not in the .encx/ directory. The directory only contains key version metadata for encryption key rotation.
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Run the validation utility:
go run ./cmd/validate-tags -v - Ensure all tests pass:
go test ./... - Submit a pull request
- implement example for different key management services:
- HashiCorp Vault
- AWS KMS
- Azure Key Vault
- Google Cloud KMS
- Thales CipherTrust (formerly Vormetric)
- AWS CloudHSM
- explore concurrency for performance improvements
- comprehensive tests
- combined tags support
- compile-time validation
- enhanced error handling
- improved documentation
[Add your license here]
[Add support information here]
- Integration Guide - Step-by-step integration into your codebase
- Context7 Integration Guide - Quick reference for Context7 users
- Code Generation Guide - High-performance code generation
- Examples Documentation - Real-world use cases
- API Reference - Complete API documentation
- Migration Guide - Upgrade instructions
- Use Cases: Data encryption, PII protection, searchable encryption, password management
- Performance: Code generation provides 10x speed improvement over reflection
- Security: AES-GCM encryption, Argon2id hashing, automatic key management
- Integration: Works with PostgreSQL, SQLite, MySQL, AWS KMS, HashiCorp Vault
For Context7 users, here are optimized query patterns:
| Query Pattern | Documentation Section |
|---|---|
| "encrypt user email golang" | Quick Start + Context7 Guide |
| "password hashing with encryption" | Advanced Examples + Context7 Guide |
| "database schema for encrypted fields" | Context7 Guide |
| "performance optimization encryption" | Code Generation Guide |
| "struct tag validation" | Validation + API Reference |
| Pattern | Use Case | Documentation |
|---|---|---|
encx:"encrypt" |
Simple data protection | Struct Tags Reference |
encx:"hash_basic" |
Fast search/lookup | Quick Start |
encx:"hash_secure" |
Password security | Advanced Examples |
encx:"encrypt,hash_basic" |
Searchable encryption | Combined Tags |
| Technology | Integration Guide |
|---|---|
| PostgreSQL | Context7 Guide - Database |
| AWS KMS | Configuration |
| HashiCorp Vault | KMS Providers |
| Docker | Complete Web App Example |
| Per-Struct Serializers | Serializer Example |