Documentation
¶
Overview ¶
Package encx provides production-ready field-level encryption, hashing, and key management for Go applications.
Context7 Metadata: - Library Type: Encryption & Security - Use Cases: Data protection, PII encryption, password hashing, searchable encryption - Complexity: Intermediate to Advanced - Performance: High (10x improvement with code generation) - Compliance: HIPAA, GDPR, SOX ready - Integration: PostgreSQL, MySQL, SQLite, AWS KMS, HashiCorp Vault
ENCX enables you to encrypt and hash struct fields using simple struct tags, with automatic key management through a DEK/KEK architecture. It supports multiple KMS backends, key rotation, combined operations, and comprehensive testing utilities.
Key Features ¶
- 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
Quick Start ¶
Define your struct with encx tags:
type User struct {
Name string `encx:"encrypt"`
Email string `encx:"hash_basic"`
Password string `encx:"hash_secure"`
// No companion fields needed! Code generation creates separate output struct
}
Generate type-safe functions (recommended approach):
//go:generate encx-gen generate .
Create crypto instance and process with generated functions:
crypto, _ := encx.NewTestCrypto(nil)
user := &User{
Name: "John Doe",
Email: "john@example.com",
Password: "secret123",
}
// Use generated type-safe functions
userEncx, err := ProcessUserEncx(ctx, crypto, user)
orderEncx, err := ProcessOrderEncx(ctx, crypto, order)
// Pattern: Process{YourStructName}Encx
Struct Tags ¶
Single operation tags:
- encx:"encrypt" - Encrypts field value
- encx:"hash_basic" - Creates SHA-256 hash for searchable indexing
- encx:"hash_secure" - Creates Argon2id hash with pepper (for passwords)
Combined operation tags:
- encx:"encrypt,hash_basic" - Both encrypts AND hashes the field (searchable encryption)
- encx:"hash_secure,encrypt" - Secure hash for auth + encryption for recovery
Code Generation ¶
Code generation creates a separate {StructName}Encx struct with all encrypted/hashed fields:
// Your source struct
type User struct {
Email string `encx:"encrypt,hash_basic"`
}
// Generated UserEncx struct (automatic)
type UserEncx struct {
EmailEncrypted []byte
EmailHash string
DEKEncrypted []byte
KeyVersion int
Metadata string
}
Advanced Example: Combined Tags ¶
Perfect for user lookup with privacy protection:
type User struct {
Email string `encx:"encrypt,hash_basic"`
// No companion fields needed! Code generation creates:
// - UserEncx.EmailEncrypted []byte (for secure storage)
// - UserEncx.EmailHash string (for fast lookups)
}
// Usage
user := &User{Email: "user@example.com"}
userEncx, err := ProcessUserEncx(ctx, crypto, user)
// Now you can:
// 1. Store userEncx.EmailEncrypted securely in database
// 2. Use userEncx.EmailHash for fast user lookups
// 3. Decrypt with DecryptUserEncx when needed for display
Production Configuration ¶
// With AWS KMS
crypto, err := encx.NewCrypto(ctx,
encx.WithKMSService(awsKMS),
encx.WithDatabase(db),
encx.WithPepper(pepper),
encx.WithKEKAlias("myapp-kek"),
)
// With HashiCorp Vault
crypto, err := encx.NewCrypto(ctx,
encx.WithKMSService(vaultKMS),
encx.WithDatabase(db),
encx.WithPepper(pepper),
encx.WithKEKAlias("myapp-kek"),
)
Validation ¶
Validate struct tags before generating code:
encx-gen validate -v . encx-gen validate -v ./models ./api
Validation runs automatically before generation:
encx-gen generate -v .
Error Handling ¶
ENCX provides structured error handling with sentinel errors for precise error classification:
user := &User{Name: "John", Email: "john@example.com"}
userEncx, err := ProcessUserEncx(ctx, crypto, user)
if err != nil {
switch {
case encx.IsRetryableError(err):
// KMS or database temporarily unavailable - retry with backoff
log.Warn("Retryable error: %v", err)
return handleRetry(err)
case encx.IsConfigurationError(err):
// Invalid configuration - fix setup
log.Error("Configuration error: %v", err)
return handleConfigError(err)
case encx.IsAuthError(err):
// Authentication failed - check credentials
log.Error("Authentication failed: %v", err)
return handleAuthError(err)
case encx.IsOperationError(err):
// Encryption/decryption failed - check data/keys
log.Error("Operation failed: %v", err)
return handleOperationError(err)
case encx.IsValidationError(err):
// Data validation failed - check input
log.Error("Validation error: %v", err)
return handleValidationError(err)
default:
log.Error("Unknown error: %v", err)
return err
}
}
Checking specific errors:
if errors.Is(err, encx.ErrKMSUnavailable) {
// Implement retry logic
return retryWithBackoff(operation)
}
if errors.Is(err, encx.ErrAuthenticationFailed) {
// Refresh credentials and retry
return refreshAuthAndRetry(operation)
}
Testing ¶
Unit testing with generated functions:
func TestUserEncryption(t *testing.T) {
crypto, _ := encx.NewTestCrypto(t)
user := &User{Email: "test@example.com"}
userEncx, err := ProcessUserEncx(ctx, crypto, user)
assert.NoError(t, err)
assert.NotEmpty(t, userEncx.EmailEncrypted)
}
Integration testing with full cycle:
func TestUserEncryptDecryptCycle(t *testing.T) {
crypto, _ := encx.NewTestCrypto(t)
original := &User{Email: "test@example.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)
}
Documentation ¶
For comprehensive documentation, examples, and advanced usage:
- README.md - Complete getting started guide
- docs/EXAMPLES.md - Detailed examples for all use cases
- docs/API.md - Complete API reference
- docs/MIGRATION.md - Version upgrade guide
- docs/TROUBLESHOOTING.md - Common issues and solutions
Important: Version Control ¶
Add to your .gitignore:
.encx/
Index ¶
- Constants
- Variables
- func DeserializeValue(data []byte, target any) error
- func IsAuthError(err error) bool
- func IsConfigurationError(err error) bool
- func IsOperationError(err error) bool
- func IsRetryableError(err error) bool
- func IsValidationError(err error) bool
- func NewInvalidFieldTypeError(fieldName string, expectedType, actualType string, action types.Action) error
- func NewInvalidFormatError(fieldName string, formatName string, action types.Action) error
- func NewMissingFieldError(fieldName string, action types.Action) error
- func NewMissingTargetFieldError(fieldName string, targetFieldName string, action types.Action) error
- func NewNilPointerError(fieldName string, action types.Action) error
- func NewOperationFailedError(fieldName string, action types.Action, details string) error
- func NewSimpleTestKMS() config.KeyManagementService
- func NewTypeConversionError(fieldName string, typeName string, action types.Action) error
- func NewUninitalizedPepperError() error
- func NewUnsupportedTypeError(fieldName string, typeName string, action types.Action) error
- func SerializeValue(value any) ([]byte, error)
- func VersionInfo() string
- type Action
- type Argon2Params
- type Config
- type Crypto
- func (c *Crypto) CompareBasicHashAndValue(ctx context.Context, value any, hashValue string) (bool, error)
- func (c *Crypto) CompareSecureHashAndValue(ctx context.Context, value any, hashValue string) (bool, error)
- func (c *Crypto) DecryptDEKWithVersion(ctx context.Context, ciphertextDEK []byte, kekVersion int) ([]byte, error)
- func (c *Crypto) DecryptData(ctx context.Context, ciphertext []byte, dek []byte) ([]byte, error)
- func (c *Crypto) DecryptStream(ctx context.Context, reader io.Reader, writer io.Writer, dek []byte) error
- func (c *Crypto) EncryptDEK(ctx context.Context, plaintextDEK []byte) ([]byte, error)
- func (c *Crypto) EncryptData(ctx context.Context, plaintext []byte, dek []byte) ([]byte, error)
- func (c *Crypto) EncryptStream(ctx context.Context, reader io.Reader, writer io.Writer, dek []byte) error
- func (c *Crypto) GenerateDEK() ([]byte, error)
- func (c *Crypto) GetAlias() string
- func (c *Crypto) GetArgon2Params() *Argon2Params
- func (c *Crypto) GetCurrentKEKVersion(ctx context.Context, alias string) (int, error)
- func (c *Crypto) GetKMSKeyIDForVersion(ctx context.Context, alias string, version int) (string, error)
- func (c *Crypto) GetPepper() []byte
- func (c *Crypto) HashBasic(ctx context.Context, value []byte) string
- func (c *Crypto) HashSecure(ctx context.Context, value []byte) (string, error)
- func (c *Crypto) RotateKEK(ctx context.Context) error
- type CryptoService
- type EncryptionMetadata
- type KeyManagementService
- type MetricsCollector
- type ObservabilityHook
- type Option
- type SimpleTestKMS
- func (s *SimpleTestKMS) CreateKey(ctx context.Context, description string) (string, error)
- func (s *SimpleTestKMS) DecryptDEK(ctx context.Context, keyID string, ciphertext []byte) ([]byte, error)
- func (s *SimpleTestKMS) EncryptDEK(ctx context.Context, keyID string, plaintext []byte) ([]byte, error)
- func (s *SimpleTestKMS) GetKeyID(ctx context.Context, alias string) (string, error)
- type VersionDetails
Constants ¶
const ( FieldKeyVersion = "KeyVersion" FieldDEK = "DEK" FieldDEKEncrypted = FieldDEK + SuffixEncrypted )
Field name constants - exported for public use
const ( SuffixEncrypted = "Encrypted" SuffixHashed = "Hash" )
Suffix constants for generated fields
const ( StructTag = "encx" TagEncrypt = "encrypt" TagHashSecure = "hash_secure" TagHashBasic = "hash_basic" )
Tag constants for struct field annotations
const ( Unknown = types.Unknown BasicHash = types.BasicHash SecureHash = types.SecureHash Encrypt = types.Encrypt Decrypt = types.Decrypt )
Action constants
const Version = "1.0.0"
Version of the encx library
Variables ¶
var ( // High-level service errors ErrKeyRotationRequired = errors.New("key rotation required") ErrInvalidConfiguration = errors.New("invalid configuration") ErrAuthenticationFailed = errors.New("authentication failed") ErrEncryptionFailed = errors.New("encryption failed") ErrDecryptionFailed = errors.New("decryption failed") // Crypto errors ErrUninitializedPepper = errors.New("pepper value appears to be uninitialized (all zeros)") // Field errors ErrMissingField = errors.New("missing required field") ErrMissingTargetField = errors.New("missing required target field") ErrInvalidFieldType = errors.New("invalid field type") ErrUnsupportedType = errors.New("unsupported type") // Conversion errors ErrTypeConversion = errors.New("type conversion failed") ErrNilPointer = errors.New("nil pointer encountered") // Operation errors ErrOperationFailed = errors.New("operation failed") ErrInvalidFormat = errors.New("invalid format") // Metadata validation errors ErrMissingKEKAlias = errors.New("KEK alias is required") ErrMissingGeneratorVersion = errors.New("generator version is required") )
var ( NewInMemoryMetricsCollector = monitoring.NewInMemoryMetricsCollector NewLoggingObservabilityHook = monitoring.NewLoggingObservabilityHook NewMetricsObservabilityHook = monitoring.NewMetricsObservabilityHook NewCompositeObservabilityHook = monitoring.NewCompositeObservabilityHook )
Constructor functions
var ( NoOpMetricsCollector = &monitoring.NoOpMetricsCollector{} NoOpObservabilityHook = &monitoring.NoOpObservabilityHook{} )
Default implementations
var ( WithKMSService = config.WithKMSService WithKEKAlias = config.WithKEKAlias WithPepper = config.WithPepper WithPepperSecretPath = config.WithPepperSecretPath WithArgon2Params = config.WithArgon2Params WithKeyMetadataDB = config.WithKeyMetadataDB WithDBPath = config.WithDBPath WithDBFilename = config.WithDBFilename WithKeyMetadataDBPath = config.WithKeyMetadataDBPath WithKeyMetadataDBFilename = config.WithKeyMetadataDBFilename WithMetricsCollector = config.WithMetricsCollector WithObservabilityHook = config.WithObservabilityHook )
Configuration option functions
var ( DefaultConfig = config.DefaultConfig ApplyOptions = config.ApplyOptions )
Helper functions
var ( GitCommit string BuildDate string BuildUser string )
Build information (set by ldflags during build)
var DefaultArgon2Params = &Argon2Params{
Memory: 64 * 1024,
Iterations: 3,
Parallelism: 2,
SaltLength: 16,
KeyLength: 32,
}
DefaultArgon2Params provides secure default parameters
Functions ¶
func DeserializeValue ¶
DeserializeValue converts bytes back to a value using ENCX's compact binary format. The target parameter must be a pointer to the type you want to deserialize into.
Example:
var result string
err := encx.DeserializeValue(data, &result)
if err != nil {
// handle error
}
func IsAuthError ¶
IsAuthError returns true if the error represents an authentication problem.
func IsConfigurationError ¶
IsConfigurationError returns true if the error represents a configuration problem.
func IsOperationError ¶
IsOperationError returns true if the error represents a failure during encryption/decryption operations.
func IsRetryableError ¶
IsRetryableError returns true if the error represents a transient failure that might succeed on retry.
func IsValidationError ¶
IsValidationError returns true if the error represents a data validation problem.
func NewInvalidFormatError ¶
func NewOperationFailedError ¶
func NewSimpleTestKMS ¶
func NewSimpleTestKMS() config.KeyManagementService
NewSimpleTestKMS creates a new simple test KMS with a default key
func NewTypeConversionError ¶
func NewUninitalizedPepperError ¶
func NewUninitalizedPepperError() error
func NewUnsupportedTypeError ¶
func SerializeValue ¶
SerializeValue converts a value to bytes using ENCX's compact binary format. This is the same serialization used internally by ENCX for field encryption. Applications can use this function to create consistent hash values for database queries.
Supported types: string, int, int32, int64, uint, uint32, uint64, bool, time.Time, []byte, float32, float64
Example:
data, err := encx.SerializeValue("hello world")
if err != nil {
// handle error
}
Types ¶
type Argon2Params ¶
type Argon2Params = config.Argon2Params
Argon2Params defines the parameters for Argon2id (re-exported from internal)
func NewArgon2Params ¶
func NewArgon2Params( memory uint32, iterations uint32, parallelism uint8, saltLength uint32, keyLength uint32, ) (*Argon2Params, error)
NewArgon2Params creates a new Argon2Params instance with validation
type Crypto ¶
type Crypto struct {
// contains filtered or unexported fields
}
func NewTestCrypto ¶
NewTestCrypto creates a simple Crypto instance for testing and examples If t is nil, creates a basic test crypto for examples/demos
func (*Crypto) CompareBasicHashAndValue ¶
func (*Crypto) CompareSecureHashAndValue ¶
func (*Crypto) DecryptDEKWithVersion ¶
func (*Crypto) DecryptData ¶
func (*Crypto) DecryptStream ¶
func (*Crypto) EncryptDEK ¶
func (*Crypto) EncryptData ¶
func (*Crypto) EncryptStream ¶
func (*Crypto) GenerateDEK ¶
func (*Crypto) GetArgon2Params ¶
func (c *Crypto) GetArgon2Params() *Argon2Params
func (*Crypto) GetCurrentKEKVersion ¶
Internal interface implementations
func (*Crypto) GetKMSKeyIDForVersion ¶
func (*Crypto) HashSecure ¶
type CryptoService ¶
type CryptoService interface {
GetPepper() []byte
GetArgon2Params() *Argon2Params
GetAlias() string
GenerateDEK() ([]byte, error)
EncryptData(ctx context.Context, plaintext []byte, dek []byte) ([]byte, error)
DecryptData(ctx context.Context, ciphertext []byte, dek []byte) ([]byte, error)
EncryptDEK(ctx context.Context, plaintextDEK []byte) ([]byte, error)
DecryptDEKWithVersion(ctx context.Context, ciphertextDEK []byte, kekVersion int) ([]byte, error)
RotateKEK(ctx context.Context) error
HashBasic(ctx context.Context, value []byte) string
HashSecure(ctx context.Context, value []byte) (string, error)
CompareSecureHashAndValue(ctx context.Context, value any, hashValue string) (bool, error)
CompareBasicHashAndValue(ctx context.Context, value any, hashValue string) (bool, error)
EncryptStream(ctx context.Context, reader io.Reader, writer io.Writer, dek []byte) error
DecryptStream(ctx context.Context, reader io.Reader, writer io.Writer, dek []byte) error
GetCurrentKEKVersion(ctx context.Context, alias string) (int, error)
GetKMSKeyIDForVersion(ctx context.Context, alias string, version int) (string, error)
}
type EncryptionMetadata ¶
type EncryptionMetadata struct {
PepperVersion int `json:"pepper_version"`
KEKAlias string `json:"kek_alias"`
EncryptionTime int64 `json:"encryption_time"`
GeneratorVersion string `json:"generator_version"`
}
EncryptionMetadata contains metadata about how a struct was encrypted
func NewEncryptionMetadata ¶
func NewEncryptionMetadata(kekAlias, generatorVersion string, pepperVersion int) *EncryptionMetadata
NewEncryptionMetadata creates a new EncryptionMetadata instance
func (*EncryptionMetadata) FromJSON ¶
func (em *EncryptionMetadata) FromJSON(data []byte) error
FromJSON deserializes metadata from JSON bytes
func (*EncryptionMetadata) ToJSON ¶
func (em *EncryptionMetadata) ToJSON() ([]byte, error)
ToJSON serializes the metadata to JSON bytes
func (*EncryptionMetadata) Validate ¶
func (em *EncryptionMetadata) Validate() error
Validate checks if the metadata is valid
type KeyManagementService ¶
type KeyManagementService = config.KeyManagementService
Interface aliases
type SimpleTestKMS ¶
type SimpleTestKMS struct {
// contains filtered or unexported fields
}
SimpleTestKMS implements a basic in-memory KMS for testing and examples
func (*SimpleTestKMS) DecryptDEK ¶
func (s *SimpleTestKMS) DecryptDEK(ctx context.Context, keyID string, ciphertext []byte) ([]byte, error)
DecryptDEK decrypts the DEK using AES-GCM
func (*SimpleTestKMS) EncryptDEK ¶
func (s *SimpleTestKMS) EncryptDEK(ctx context.Context, keyID string, plaintext []byte) ([]byte, error)
EncryptDEK encrypts the DEK using AES-GCM
type VersionDetails ¶
type VersionDetails struct {
Version string `json:"version"`
GitCommit string `json:"git_commit,omitempty"`
BuildDate string `json:"build_date,omitempty"`
BuildUser string `json:"build_user,omitempty"`
}
VersionDetails contains detailed version information
func FullVersionInfo ¶
func FullVersionInfo() VersionDetails
FullVersionInfo returns complete version information including build user
func (VersionDetails) String ¶
func (v VersionDetails) String() string
String returns a formatted version string
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
encx-gen
command
|
|
|
Package examples demonstrates various use cases for the encx library.
|
Package examples demonstrates various use cases for the encx library. |
|
basic_demo
command
|
|
|
combined_tags_demo
command
|
|
|
combined_tags_simple
command
|
|
|
context7/01-basic/basic_hashing
command
|
|
|
context7/02-intermediate
command
|
|
|
context7/03-advanced
command
|
|
|
context7/04-industry
command
|
|
|
enhanced_validation
command
|
|
|
error_handling
command
|
|
|
go_generate_demo
Package go_generate_demo demonstrates encx-gen integration
|
Package go_generate_demo demonstrates encx-gen integration |
|
per_struct_serializers
command
|
|
|
internal
|
|
|
providers
|
|
|
awskms
Package awskms provides AWS Key Management Service (KMS) integration for encx.
|
Package awskms provides AWS Key Management Service (KMS) integration for encx. |
|
test
|
|