Complete API documentation for the ENCX library.
- Core Types
- Main Functions
- Crypto Methods
- Validation Functions
- Testing Utilities
- Error Types
- Configuration Options
The main struct that provides all cryptographic operations.
type Crypto struct {
// Internal fields - not directly accessible
}Thread Safety: The Crypto struct is safe for concurrent use.
Interface for all cryptographic operations, useful for dependency injection and testing.
CryptoService provides the low-level primitives that generated Process<Struct>Encx/Decrypt<Struct>Encx
functions call internally (see Generated Functions in the
Code Generation API Reference). Application code normally only needs the generated
functions, not this interface directly.
type CryptoService interface {
// Data operations
GenerateDEK() ([]byte, error)
EncryptData(ctx context.Context, plaintext []byte, dek []byte) ([]byte, error)
DecryptData(ctx context.Context, ciphertext []byte, dek []byte) ([]byte, error)
// DEK operations
EncryptDEK(ctx context.Context, plaintextDEK []byte) ([]byte, error)
DecryptDEKWithVersion(ctx context.Context, ciphertextDEK []byte, kekVersion int) ([]byte, error)
// Hashing operations
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)
// Key management
RotateKEK(ctx context.Context) error
GetCurrentKEKVersion(ctx context.Context, alias string) (int, error)
GetKMSKeyIDForVersion(ctx context.Context, alias string, version int) (string, error)
// Stream operations
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
// Configuration
GetPepper() []byte
GetArgon2Params() *Argon2Params
GetAlias() string
}Interface for cryptographic operations using cloud KMS providers (AWS KMS, HashiCorp Vault Transit Engine).
type KeyManagementService interface {
GetKeyID(ctx context.Context, alias string) (string, error)
CreateKey(ctx context.Context, description string) (string, error)
EncryptDEK(ctx context.Context, keyID string, plaintext []byte) ([]byte, error)
DecryptDEK(ctx context.Context, keyID string, ciphertext []byte) ([]byte, error)
}Implementations:
providers/aws.KMSService- AWS KMS implementationproviders/hashicorp.TransitService- HashiCorp Vault Transit Engine implementation
Interface for secret storage providers (AWS Secrets Manager, HashiCorp Vault KV).
type SecretManagementService interface {
StorePepper(ctx context.Context, alias string, pepper []byte) error
GetPepper(ctx context.Context, alias string) ([]byte, error)
PepperExists(ctx context.Context, alias string) (bool, error)
GetStoragePath(alias string) string
}Implementations:
providers/aws.SecretsManagerStore- AWS Secrets Manager implementationproviders/hashicorp.KVStore- HashiCorp Vault KV v2 implementationInMemorySecretStore- In-memory implementation for testing
Storage Paths:
- AWS:
encx/{PepperAlias}/pepper - Vault:
secret/data/encx/{PepperAlias}/pepper - In-memory:
memory://{PepperAlias}/pepper
Configuration struct for explicit dependency injection.
type Config struct {
KEKAlias string // Required: KMS key identifier
PepperAlias string // Required: Service identifier for pepper storage
DBPath string // Optional: Database directory (default: .encx)
DBFilename string // Optional: Database filename (default: keys.db)
}Validation:
KEKAliasmust not be empty and must be ≤ 256 charactersPepperAliasmust not be emptyDBPathdefaults to.encxif emptyDBFilenamedefaults tokeys.dbif empty
Methods:
func (c *Config) Validate() errorConfiguration for Argon2id hashing.
type Argon2Params struct {
Memory uint32 // Memory in KB
Iterations uint32 // Number of iterations
Parallelism uint8 // Degree of parallelism
SaltLength uint32 // Salt length in bytes
KeyLength uint32 // Generated key length in bytes
}Default Values:
- Memory: 65536 KB (64 MB)
- Iterations: 3
- Parallelism: 4
- SaltLength: 16 bytes
- KeyLength: 32 bytes
Creates a new Crypto instance with explicit dependency injection (low-level API).
func NewCrypto(
ctx context.Context,
kms KeyManagementService,
secrets SecretManagementService,
cfg Config,
options ...Option,
) (*Crypto, error)Parameters:
ctx: Context for initializationkms: Key Management Service for cryptographic operations (required)secrets: Secret Management Service for pepper storage (required)cfg: Configuration struct with KEKAlias, PepperAlias, etc. (required)options: Additional configuration options (optional)
Returns:
*Crypto: Configured crypto instanceerror: Initialization error, if any
Example:
// Initialize providers
kms, _ := aws.NewKMSService(ctx, aws.Config{Region: "us-east-1"})
secrets, _ := aws.NewSecretsManagerStore(ctx, aws.Config{Region: "us-east-1"})
// Create explicit configuration
cfg := encx.Config{
KEKAlias: "alias/my-encryption-key",
PepperAlias: "my-app-service",
}
// Initialize crypto
crypto, err := encx.NewCrypto(ctx, kms, secrets, cfg)
if err != nil {
log.Fatal(err)
}Behavior:
- Validates all required parameters
- Validates Config struct (calls cfg.Validate())
- Checks KMS connectivity by retrieving KEK
- Checks/generates pepper in SecretManagementService
- Initializes key metadata database
- Returns ready-to-use Crypto instance
Creates a new Crypto instance using environment variables (convenience API for 12-factor apps).
func NewCryptoFromEnv(
ctx context.Context,
kms KeyManagementService,
secrets SecretManagementService,
options ...Option,
) (*Crypto, error)Parameters:
ctx: Context for initializationkms: Key Management Service (required)secrets: Secret Management Service (required)options: Additional configuration options (optional)
Returns:
*Crypto: Configured crypto instanceerror: Initialization error, if any
Required Environment Variables:
ENCX_KEK_ALIAS: KMS key identifierENCX_PEPPER_ALIAS: Service identifier for pepper storage
Optional Environment Variables:
ENCX_DB_PATH: Database directory (default:.encx)ENCX_DB_FILENAME: Database filename (default:keys.db)
Example:
// Set environment variables:
// export ENCX_KEK_ALIAS="alias/my-encryption-key"
// export ENCX_PEPPER_ALIAS="my-app-service"
kms, _ := aws.NewKMSService(ctx, aws.Config{Region: "us-east-1"})
secrets, _ := aws.NewSecretsManagerStore(ctx, aws.Config{Region: "us-east-1"})
crypto, err := encx.NewCryptoFromEnv(ctx, kms, secrets)
if err != nil {
log.Fatal(err)
}Loads configuration from environment variables.
func LoadConfigFromEnvironment() (Config, error)Returns:
Config: Loaded configurationerror: Loading/validation error, if any
Environment Variables:
ENCX_KEK_ALIAS: KMS key identifier (required)ENCX_PEPPER_ALIAS: Service identifier (required)ENCX_DB_PATH: Database directory (optional, default:.encx)ENCX_DB_FILENAME: Database filename (optional, default:keys.db)
Example:
cfg, err := encx.LoadConfigFromEnvironment()
if err != nil {
log.Fatalf("Invalid configuration: %v", err)
}
crypto, err := encx.NewCrypto(ctx, kms, secrets, cfg)Creates a crypto instance optimized for testing with in-memory storage.
func NewTestCrypto(t testing.TB) *CryptoParameters:
t: Testing interface (can be nil for non-test usage)
Returns:
*Crypto: Test crypto instance with mock KMS and in-memory secret store
Example:
func TestMyFunction(t *testing.T) {
crypto := encx.NewTestCrypto(t)
// Use crypto in tests
dek, _ := crypto.GenerateDEK()
encrypted, _ := crypto.EncryptData(ctx, plaintext, dek)
}Features:
- Uses
SimpleTestKMS(mock KMS implementation) - Uses
InMemorySecretStore(automatic pepper generation) - Pre-configured with test-friendly Argon2 parameters
- Automatic cleanup on test completion
ENCX uses code generation for struct processing. Generated functions provide better performance and type safety.
For a struct named User, the code generator creates:
// Generated by encx-gen
func ProcessUserEncx(ctx context.Context, crypto encx.CryptoService, source *User) (*UserEncx, error)
func DecryptUserEncx(ctx context.Context, crypto encx.CryptoService, source *UserEncx) (*User, error)Pattern:
- Processing:
Process<StructName>Encx - Decryption:
Decrypt<StructName>Encx
Example:
//go:generate encx-gen generate .
type User struct {
Name string `encx:"encrypt"`
Email string `encx:"hash_basic"`
}
// Use generated functions
user := &User{Name: "John", Email: "john@example.com"}
userEncx, err := ProcessUserEncx(ctx, crypto, user)
if err != nil {
return err
}
// Store userEncx in database...
// Later decrypt
decrypted, err := DecryptUserEncx(ctx, crypto, userEncx)
// decrypted.Name is now availableRecursive Package Discovery:
When using encx-gen generate ., the tool automatically discovers all Go packages in subdirectories recursively, making it ideal for processing entire projects from a single command.
See: Code Generation Guide for complete documentation.
Generates a new 32-byte Data Encryption Key.
func (c *Crypto) GenerateDEK() ([]byte, error)Returns:
[]byte: 32-byte DEKerror: Generation error, if any
Encrypts data using AES-GCM with the provided DEK.
func (c *Crypto) EncryptData(ctx context.Context, plaintext []byte, dek []byte) ([]byte, error)Parameters:
ctx: Context for the operationplaintext: Data to encryptdek: 32-byte Data Encryption Key
Returns:
[]byte: Encrypted data (includes nonce)error: Encryption error, if any
Decrypts data using AES-GCM with the provided DEK.
func (c *Crypto) DecryptData(ctx context.Context, ciphertext []byte, dek []byte) ([]byte, error)Parameters:
ctx: Context for the operationciphertext: Data to decryptdek: 32-byte Data Encryption Key
Returns:
[]byte: Decrypted dataerror: Decryption error, if any
Encrypts a DEK using the current KEK.
func (c *Crypto) EncryptDEK(ctx context.Context, plaintextDEK []byte) ([]byte, error)Parameters:
ctx: Context for the operationplaintextDEK: DEK to encrypt
Returns:
[]byte: Encrypted DEKerror: Encryption error, if any
Decrypts a DEK using a specific KEK version.
func (c *Crypto) DecryptDEKWithVersion(ctx context.Context, ciphertextDEK []byte, kekVersion int) ([]byte, error)Parameters:
ctx: Context for the operationciphertextDEK: Encrypted DEKkekVersion: KEK version to use for decryption
Returns:
[]byte: Decrypted DEKerror: Decryption error, if any
Creates a SHA-256 hash of the input.
func (c *Crypto) HashBasic(ctx context.Context, value []byte) stringParameters:
ctx: Context for the operationvalue: Data to hash
Returns:
string: Hex-encoded hash
Note: This is a fast, deterministic hash suitable for lookups but not cryptographically secure for passwords.
Creates an Argon2id hash of the input with pepper.
func (c *Crypto) HashSecure(ctx context.Context, value []byte) (string, error)Parameters:
ctx: Context for the operationvalue: Data to hash (typically passwords)
Returns:
string: Encoded hash with parameterserror: Hashing error, if any
Note: This is suitable for password storage and other security-critical hashing.
Compares a value against an Argon2id hash.
func (c *Crypto) CompareSecureHashAndValue(ctx context.Context, value any, hashValue string) (bool, error)Parameters:
ctx: Context for the operationvalue: Value to check (will be serialized)hashValue: Encoded hash to compare against
Returns:
bool: True if value matches hasherror: Comparison error, if any
Compares a value against a SHA-256 hash.
func (c *Crypto) CompareBasicHashAndValue(ctx context.Context, value any, hashValue string) (bool, error)Parameters:
ctx: Context for the operationvalue: Value to check (will be serialized)hashValue: Hash to compare against
Returns:
bool: True if value matches hasherror: Comparison error, if any
Rotates the Key Encryption Key, generating a new version.
func (c *Crypto) RotateKEK(ctx context.Context) errorParameters:
ctx: Context for the operation
Returns:
error: Rotation error, if any
Behavior:
- Creates a new KEK version in KMS
- Updates metadata database
- Marks previous version as deprecated
- New encryptions will use the new key version
- Old data can still be decrypted with previous versions
Encrypts data from a reader to a writer using streaming AES-GCM.
func (c *Crypto) EncryptStream(ctx context.Context, reader io.Reader, writer io.Writer, dek []byte) errorParameters:
ctx: Context for the operationreader: Source of plaintext datawriter: Destination for encrypted datadek: 32-byte Data Encryption Key
Returns:
error: Streaming error, if any
Decrypts data from a reader to a writer using streaming AES-GCM.
func (c *Crypto) DecryptStream(ctx context.Context, reader io.Reader, writer io.Writer, dek []byte) errorParameters:
ctx: Context for the operationreader: Source of encrypted datawriter: Destination for decrypted datadek: 32-byte Data Encryption Key
Returns:
error: Streaming error, if any
Struct tag validation is a compile-time CLI step, not a runtime library function. Run it via the
encx-gen validate command before generating code:
# Validate all Go files in the current directory
encx-gen validate -v .
# Validate specific packages
encx-gen validate -v ./models ./apiChecks:
- Tag syntax is valid (e.g. no unsupported tag combinations)
- Tagged field types are compatible with the requested operations
See: Code Generation Guide for full CLI documentation.
For tests that don't need to mock individual CryptoService calls, use
NewTestCrypto (under Main Functions), which returns a fully initialized *Crypto
backed by SimpleTestKMS and InMemorySecretStore in one call:
crypto, err := encx.NewTestCrypto(t)In-memory implementation of SecretManagementService for testing.
func NewInMemorySecretStore() *InMemorySecretStoreReturns:
*InMemorySecretStore: Thread-safe in-memory secret store
Example:
// Create in-memory store
secretStore := encx.NewInMemorySecretStore()
// Use with NewCrypto
kms := encx.NewSimpleTestKMS()
cfg := encx.Config{
KEKAlias: "test-kek",
PepperAlias: "test-service",
}
crypto, err := encx.NewCrypto(ctx, kms, secretStore, cfg)Features:
- Thread-safe for concurrent testing
- Automatic pepper generation
- Isolated storage per PepperAlias
- Data lost on restart (in-memory only)
Warning: Only use for testing. Not suitable for production use.
Mock KMS implementation for testing.
func NewSimpleTestKMS() KeyManagementServiceReturns:
KeyManagementService: Mock KMS that simulates cloud KMS behavior
Example:
kms := encx.NewSimpleTestKMS()
// Use with NewCrypto
secretStore := encx.NewInMemorySecretStore()
cfg := encx.Config{
KEKAlias: "test-kek",
PepperAlias: "test-service",
}
crypto, err := encx.NewCrypto(ctx, kms, secretStore, cfg)var (
ErrUninitializedPepper = errors.New("pepper value appears to be uninitialized (all zeros)")
ErrMissingField = errors.New("missing required field")
ErrMissingTargetField = errors.New("missing required target field")
ErrInvalidFieldType = errors.New("invalid field type")
ErrUnsupportedType = errors.New("unsupported type")
ErrTypeConversion = errors.New("type conversion failed")
ErrNilPointer = errors.New("nil pointer encountered")
ErrOperationFailed = errors.New("operation failed")
ErrInvalidFormat = errors.New("invalid format")
)func NewMissingFieldError(fieldName string, action Action) error
func NewMissingTargetFieldError(fieldName string, targetFieldName string, action Action) error
func NewInvalidFieldTypeError(fieldName string, expectedType, actualType string, action Action) error
func NewUnsupportedTypeError(fieldName string, typeName string, action Action) error
func NewTypeConversionError(fieldName string, typeName string, action Action) error
func NewNilPointerError(fieldName string, action Action) error
func NewOperationFailedError(fieldName string, action Action, details string) error
func NewInvalidFormatError(fieldName string, formatName string, action Action) errorENCX v0.6.0+ provides two configuration approaches:
Use explicit dependency injection with the Config struct:
kms, _ := aws.NewKMSService(ctx, aws.Config{Region: "us-east-1"})
secrets, _ := aws.NewSecretsManagerStore(ctx, aws.Config{Region: "us-east-1"})
cfg := encx.Config{
KEKAlias: "alias/my-encryption-key",
PepperAlias: "my-app-service",
}
crypto, err := encx.NewCrypto(ctx, kms, secrets, cfg)Benefits:
- Full control over dependencies
- No hidden environment variable dependencies
- Better for library code
- Easier to test with dependency injection
Use environment variables with NewCryptoFromEnv:
// Set environment:
// export ENCX_KEK_ALIAS="alias/my-encryption-key"
// export ENCX_PEPPER_ALIAS="my-app-service"
kms, _ := aws.NewKMSService(ctx, aws.Config{Region: "us-east-1"})
secrets, _ := aws.NewSecretsManagerStore(ctx, aws.Config{Region: "us-east-1"})
crypto, err := encx.NewCryptoFromEnv(ctx, kms, secrets)Benefits:
- 12-factor app compliant
- Environment-specific configuration
- Easier deployment across environments
- No hardcoded configuration values
For advanced scenarios, you can pass additional options to NewCrypto or NewCryptoFromEnv:
Sets custom Argon2id parameters for secure hashing.
func WithArgon2Params(params *Argon2Params) OptionExample:
params := &encx.Argon2Params{
Memory: 131072, // 128 MB
Iterations: 4,
Parallelism: 8,
SaltLength: 16,
KeyLength: 32,
}
crypto, err := encx.NewCrypto(ctx, kms, secrets, cfg, encx.WithArgon2Params(params))Use Cases:
- Customizing password hashing strength
- Balancing security vs performance
- Meeting specific compliance requirements
Sets a custom serializer for field values.
func WithSerializer(serializer Serializer) OptionUse Cases:
- Custom encoding formats
- Legacy data format compatibility
- Performance optimization for specific data types
| Variable | Required | Default | Description |
|---|---|---|---|
ENCX_KEK_ALIAS |
Yes | - | KMS key identifier (e.g., alias/my-key) |
ENCX_PEPPER_ALIAS |
Yes | - | Service identifier for pepper storage |
ENCX_DB_PATH |
No | .encx |
Database directory path |
ENCX_DB_FILENAME |
No | keys.db |
Database filename |
The following options are deprecated in v0.6.0+ and replaced by explicit parameters:
→ PassWithKMSService(kms)kmsdirectly toNewCrypto→ Pepper auto-managed viaWithPepper(pepper)SecretManagementService→ UseWithKEKAlias(alias)Config.KEKAliasfield→ Database auto-initialized fromWithKeyMetadataDB(db)Config.DBPath
Migration: See the Migration Guide for upgrading from v0.5.x to v0.6.0+.
const (
StructTag = "encx" // The struct tag name
TagEncrypt = "encrypt" // Tag for encryption
TagHashSecure = "hash_secure" // Tag for Argon2id hashing
TagHashBasic = "hash_basic" // Tag for SHA-256 hashing
)const (
FieldDEK = "DEK" // DEK field name
FieldDEKEncrypted = "DEKEncrypted" // Encrypted DEK field name
FieldKeyVersion = "KeyVersion" // Key version field name
)const (
SuffixEncrypted = "Encrypted" // Suffix for encrypted companion fields
SuffixHashed = "Hash" // Suffix for hash companion fields
)- The
Cryptostruct is safe for concurrent use across multiple goroutines - KMS operations are thread-safe (depends on provider implementation)
- Database operations use proper locking and transactions
- Hash operations are stateless and thread-safe
- DEK Generation: Fast cryptographically secure random generation
- AES-GCM Encryption: Hardware-accelerated on modern CPUs
- Argon2id Hashing: CPU and memory intensive, tune parameters for your needs
- KMS Operations: Network latency dependent, consider connection pooling
- Database Operations: Use connection pooling for better performance
- Serialization: JSON serialization overhead for complex types
- Sensitive data is cleared from memory when possible
- DEKs are not cached by default
- Use
deferto clear sensitive variables when appropriate - The library does not prevent memory dumps or swap to disk