Documentation
¶
Overview ¶
Package crypto provides secure cryptographic utilities for Go applications.
This package offers a comprehensive set of cryptographic primitives including:
- AES-256-GCM authenticated encryption and decryption
- Argon2id key derivation for secure password-based key generation
- PBKDF2-SHA256 legacy support for backward compatibility
- Cryptographically secure random number generation
- Key management utilities (import/export, validation, fingerprinting)
- Secure memory zeroization for sensitive data
The package is designed for clarity, reliability, and high code quality, following Go best practices and security standards.
Quick Start ¶
Basic encryption and decryption:
// Generate a new encryption key
key, err := crypto.GenerateKey()
if err != nil {
log.Fatal(err)
}
// Encrypt some data
ciphertext, err := crypto.Encrypt("sensitive data", key)
if err != nil {
log.Fatal(err)
}
// Decrypt the data
plaintext, err := crypto.Decrypt(ciphertext, key)
if err != nil {
log.Fatal(err)
}
fmt.Println(plaintext) // Output: sensitive data
Key Derivation ¶
For deriving keys from passwords:
password := []byte("my-secure-password")
salt := []byte("random-salt-123")
// Derive a key using Argon2id with secure defaults
derivedKey, err := crypto.DeriveKeyDefault(password, salt, 32)
if err != nil {
log.Fatal(err)
}
// Use custom parameters for higher security
params := &crypto.KDFParams{
Time: 4, // 4 iterations
Memory: 128, // 128 MB memory
Threads: 2, // 2 threads
}
key, err := crypto.DeriveKey(password, salt, 32, params)
Key Management ¶
Key utilities for import/export and validation:
// Generate and export a key
key, _ := crypto.GenerateKey()
base64Key := crypto.KeyToBase64(key)
hexKey := crypto.KeyToHex(key)
// Import and validate a key
importedKey, err := crypto.KeyFromBase64(base64Key)
if err != nil {
log.Fatal(err)
}
err = crypto.ValidateKey(importedKey)
if err != nil {
log.Fatal("Invalid key:", err)
}
// Generate a fingerprint for identification
fingerprint := crypto.GetKeyFingerprint(key)
fmt.Println("Key fingerprint:", fingerprint)
// Securely wipe sensitive data
crypto.Zeroize(key)
Error Handling ¶
All functions return standard Go errors for maximum compatibility. For advanced error handling with rich error details, the library integrates with github.com/agilira/go-errors.
Example error handling:
ciphertext, err := crypto.Encrypt("data", key)
if err != nil {
if errors.Is(err, crypto.ErrInvalidKeySize) {
// Handle invalid key size
} else if errors.Is(err, crypto.ErrEmptyPlaintext) {
// Handle empty plaintext
}
// Handle other errors
}
Security Considerations ¶
This library uses industry-standard cryptographic algorithms:
- AES-256-GCM for authenticated encryption
- Argon2id for key derivation (resistant to ASIC/FPGA attacks)
- Cryptographically secure random number generation
- Secure memory zeroization
For detailed security information, see the Security documentation.
Performance ¶
The library is optimized for typical use cases with:
- Minimal memory allocations
- Efficient base64 encoding/decoding
- Fast key fingerprinting algorithm
- Configurable Argon2id parameters for security/performance balance
Copyright (c) 2025 AGILira Series: an AGLIra library SPDX-License-Identifier: MPL-2.0
Index ¶
- Constants
- Variables
- func Decrypt(encryptedText string, key []byte) (string, error)
- func DecryptBytes(encryptedText string, key []byte) ([]byte, error)
- func DeriveKey(password, salt []byte, keyLen int, params *KDFParams) ([]byte, error)
- func DeriveKeyDefault(password, salt []byte, keyLen int) ([]byte, error)
- func DeriveKeyPBKDF2(password, salt []byte, iterations, keyLen int) ([]byte, error)deprecated
- func DeriveKeyWithParams(password, salt []byte, time, memoryMB, threads, keyLen int) ([]byte, error)
- func Encrypt(plaintext string, key []byte) (string, error)
- func EncryptBytes(plaintext []byte, key []byte) (string, error)
- func GenerateKey() ([]byte, error)
- func GenerateNonce(size int) ([]byte, error)
- func GetKeyFingerprint(key []byte) string
- func KeyFromBase64(s string) ([]byte, error)
- func KeyFromHex(s string) ([]byte, error)
- func KeyToBase64(key []byte) string
- func KeyToHex(key []byte) string
- func ValidateKey(key []byte) error
- func Zeroize(b []byte)
- type KDFParams
Constants ¶
const ( ErrCodeInvalidKey = "CRYPTO_INVALID_KEY" ErrCodeEmptyPlain = "CRYPTO_EMPTY_PLAINTEXT" ErrCodeCipherInit = "CRYPTO_CIPHER_INIT" ErrCodeGCMInit = "CRYPTO_GCM_INIT" ErrCodeNonceGen = "CRYPTO_NONCE_GEN" ErrCodeBase64Decode = "CRYPTO_BASE64_DECODE" ErrCodeCipherShort = "CRYPTO_CIPHERTEXT_SHORT" ErrCodeDecrypt = "CRYPTO_DECRYPT" )
Error codes for rich error handling
const ( // DefaultTime is the default number of iterations for Argon2id. // Higher values increase security but also computation time. DefaultTime = 3 // DefaultMemory is the default memory usage in MB for Argon2id. // Higher values increase security against memory-based attacks. DefaultMemory = 64 // DefaultThreads is the default number of threads for Argon2id. // Should not exceed the number of CPU cores. DefaultThreads = 4 )
Default Argon2 parameters for key derivation. These values provide a good balance between security and performance.
const KeySize = 32
KeySize is the required key size for AES-256 encryption in bytes. AES-256 requires exactly 32 bytes (256 bits) for the encryption key.
Variables ¶
var ( // ErrInvalidKeySize is returned when the provided key is not exactly 32 bytes. ErrInvalidKeySize = errors.New("crypto: invalid key size") // ErrEmptyPlaintext is returned when trying to decrypt an empty string. // Note: Empty plaintext is supported for encryption. ErrEmptyPlaintext = errors.New("crypto: plaintext cannot be empty") // ErrCipherInit is returned when AES cipher initialization fails. ErrCipherInit = errors.New("crypto: cipher initialization error") // ErrGCMInit is returned when GCM mode initialization fails. ErrGCMInit = errors.New("crypto: GCM initialization error") // ErrNonceGen is returned when nonce generation fails. ErrNonceGen = errors.New("crypto: nonce generation error") // ErrBase64Decode is returned when base64 decoding fails. ErrBase64Decode = errors.New("crypto: base64 decode error") // ErrCiphertextShort is returned when the ciphertext is too short to contain a valid nonce. ErrCiphertextShort = errors.New("crypto: ciphertext too short") // ErrDecrypt is returned when decryption fails due to authentication failure or corruption. ErrDecrypt = errors.New("crypto: decryption error") )
Public standard errors for drop-in compatibility. These errors can be used with errors.Is() for error checking.
Functions ¶
func Decrypt ¶
Decrypt decrypts a base64-encoded ciphertext string using AES-256-GCM authenticated decryption.
This is a convenience wrapper around DecryptBytes that works with strings. The function verifies the authenticity of the ciphertext using the embedded authentication tag. If the ciphertext has been tampered with, the function will return an error.
Parameters:
- encryptedText: The base64-encoded encrypted string (cannot be empty)
- key: The 32-byte decryption key (must be exactly KeySize bytes)
Returns:
- The decrypted plaintext string
- An error if decryption fails (authentication failure, corruption, or invalid input)
Example:
key, _ := crypto.GenerateKey()
ciphertext, _ := crypto.Encrypt("sensitive data", key)
plaintext, err := crypto.Decrypt(ciphertext, key)
if err != nil {
log.Fatal(err)
}
fmt.Println("Decrypted:", plaintext) // Output: sensitive data
The function will return an error if:
- The key size is incorrect
- The encrypted text is empty
- The base64 decoding fails
- The ciphertext is too short
- Authentication fails (tampering detected)
func DecryptBytes ¶
DecryptBytes decrypts a base64-encoded ciphertext string using AES-256-GCM authenticated decryption.
The function verifies the authenticity of the ciphertext using the embedded authentication tag. If the ciphertext has been tampered with, the function will return an error. This is the core decryption function that returns binary data.
Parameters:
- encryptedText: The base64-encoded encrypted string (cannot be empty)
- key: The 32-byte decryption key (must be exactly KeySize bytes)
Returns:
- The decrypted plaintext as a byte slice
- An error if decryption fails (authentication failure, corruption, or invalid input)
Example:
key, _ := crypto.GenerateKey()
data := []byte("sensitive binary data")
ciphertext, _ := crypto.EncryptBytes(data, key)
plaintext, err := crypto.DecryptBytes(ciphertext, key)
if err != nil {
log.Fatal(err)
}
fmt.Println("Decrypted:", string(plaintext)) // Output: sensitive binary data
The function will return an error if:
- The key size is incorrect
- The encrypted text is empty
- The base64 decoding fails
- The ciphertext is too short
- Authentication fails (tampering detected)
func DeriveKey ¶
DeriveKey derives a key from a password and salt using Argon2id (the recommended variant).
Argon2id is the recommended variant of Argon2, providing resistance against both side-channel attacks and time-memory trade-off attacks. It uses secure default parameters that provide strong protection against both CPU and memory-based attacks.
Parameters:
- password: The password to derive the key from (cannot be empty)
- salt: The salt to use for key derivation (cannot be empty, should be random)
- keyLen: The desired length of the derived key in bytes (must be positive)
- params: Custom Argon2id parameters (nil to use secure defaults)
Returns:
- The derived key as a byte slice
- An error if key derivation fails
Example:
password := []byte("my-secure-password")
salt := []byte("random-salt-123")
// Use secure defaults
key, err := crypto.DeriveKey(password, salt, 32, nil)
if err != nil {
log.Fatal(err)
}
// Use custom parameters
params := &crypto.KDFParams{
Time: 4,
Memory: 128,
Threads: 2,
}
key, err := crypto.DeriveKey(password, salt, 32, params)
If params is nil, secure defaults are used (Time: 3, Memory: 64MB, Threads: 4).
func DeriveKeyDefault ¶
DeriveKeyDefault derives a key using Argon2id with secure default parameters.
This is a convenience function for when you don't need custom parameters. It's equivalent to calling DeriveKey with params set to nil.
Parameters:
- password: The password to derive the key from (cannot be empty)
- salt: The salt to use for key derivation (cannot be empty, should be random)
- keyLen: The desired length of the derived key in bytes (must be positive)
Returns:
- The derived key as a byte slice
- An error if key derivation fails
Example:
password := []byte("my-secure-password")
salt := []byte("random-salt-123")
key, err := crypto.DeriveKeyDefault(password, salt, 32)
if err != nil {
log.Fatal(err)
}
func DeriveKeyPBKDF2
deprecated
DeriveKeyPBKDF2 derives a key using PBKDF2-SHA256 (deprecated).
This function is deprecated and kept only for backward compatibility. Use DeriveKey with Argon2id instead for better security against modern attacks. This function will be removed in a future version.
Parameters:
- password: The password to derive the key from (cannot be empty)
- salt: The salt to use for key derivation (cannot be empty, should be random)
- iterations: The number of iterations (must be positive, recommend at least 100,000)
- keyLen: The desired length of the derived key in bytes (must be positive)
Returns:
- The derived key as a byte slice
- An error if key derivation fails
Example:
password := []byte("my-secure-password")
salt := []byte("random-salt-123")
key, err := crypto.DeriveKeyPBKDF2(password, salt, 100000, 32)
if err != nil {
log.Fatal(err)
}
Deprecated: Use DeriveKey instead for better security.
func DeriveKeyWithParams ¶
func DeriveKeyWithParams(password, salt []byte, time, memoryMB, threads, keyLen int) ([]byte, error)
DeriveKeyWithParams derives a key from a password and salt using Argon2id with custom parameters.
This is a legacy function that provides direct parameter control. For new code, consider using DeriveKey with a KDFParams struct for better readability and maintainability.
Parameters:
- password: The password to derive the key from (cannot be empty)
- salt: The salt to use for key derivation (cannot be empty, should be random)
- time: The number of iterations (must be positive)
- memoryMB: The memory usage in MB (must be positive)
- threads: The number of threads (must be positive)
- keyLen: The desired length of the derived key in bytes (must be positive)
Returns:
- The derived key as a byte slice
- An error if key derivation fails
Example:
password := []byte("my-secure-password")
salt := []byte("random-salt-123")
key, err := crypto.DeriveKeyWithParams(password, salt, 4, 128, 2, 32)
if err != nil {
log.Fatal(err)
}
Use this function only if you need to customize the parameters for specific requirements.
func Encrypt ¶
Encrypt encrypts a plaintext string using AES-256-GCM authenticated encryption.
This is a convenience wrapper around EncryptBytes that works with strings. The function uses AES-256 in GCM mode, which provides both confidentiality and authenticity. The returned string is base64-encoded and contains the nonce, ciphertext, and authentication tag.
Parameters:
- plaintext: The string to encrypt (can be empty)
- key: The 32-byte encryption key (must be exactly KeySize bytes)
Returns:
- A base64-encoded string containing the encrypted data
- An error if encryption fails
Example:
key, _ := crypto.GenerateKey()
ciphertext, err := crypto.Encrypt("sensitive data", key)
if err != nil {
log.Fatal(err)
}
fmt.Println("Encrypted:", ciphertext)
Empty plaintext is supported and will result in a valid ciphertext containing only the nonce and authentication tag.
func EncryptBytes ¶
EncryptBytes encrypts a plaintext byte slice using AES-256-GCM authenticated encryption.
The function uses AES-256 in GCM mode, which provides both confidentiality and authenticity. The returned string is base64-encoded and contains the nonce, ciphertext, and authentication tag. This is the core encryption function that works with binary data.
Parameters:
- plaintext: The byte slice to encrypt (can be empty)
- key: The 32-byte encryption key (must be exactly KeySize bytes)
Returns:
- A base64-encoded string containing the encrypted data
- An error if encryption fails
Example:
key, _ := crypto.GenerateKey()
data := []byte("sensitive binary data")
ciphertext, err := crypto.EncryptBytes(data, key)
if err != nil {
log.Fatal(err)
}
fmt.Println("Encrypted:", ciphertext)
Empty plaintext is supported and will result in a valid ciphertext containing only the nonce and authentication tag.
func GenerateKey ¶
GenerateKey generates a cryptographically secure random key of KeySize bytes.
This function creates a new 32-byte (256-bit) key suitable for AES-256 encryption. The key is generated using the cryptographically secure random number generator provided by the operating system.
Returns:
- A 32-byte key as a byte slice
- An error if key generation fails
Example:
key, err := crypto.GenerateKey()
if err != nil {
log.Fatal(err)
}
fmt.Println("Generated key length:", len(key)) // Output: 32
The generated key is suitable for use with Encrypt and Decrypt functions.
func GenerateNonce ¶
GenerateNonce generates a cryptographically secure random nonce of the given size.
A nonce (number used once) is a random value that should be used only once for each encryption operation. This function generates a cryptographically secure random nonce suitable for use with AES-GCM encryption.
Parameters:
- size: The desired size of the nonce in bytes (must be positive)
Returns:
- A byte slice containing the random nonce
- An error if nonce generation fails
Example:
nonce, err := crypto.GenerateNonce(12) // 12 bytes is standard for AES-GCM
if err != nil {
log.Fatal(err)
}
fmt.Println("Generated nonce length:", len(nonce)) // Output: 12
For AES-GCM, a 12-byte nonce is recommended for optimal security and performance.
func GetKeyFingerprint ¶
GetKeyFingerprint generates a fingerprint for a key (non-cryptographic).
This function creates a short, human-readable identifier for a key by computing the SHA-256 hash and taking the first 8 bytes. This provides better collision resistance than using just the first few bytes of the key while maintaining speed.
The fingerprint is useful for logging, debugging, and identifying keys without exposing the actual key material.
Parameters:
- key: The key to generate a fingerprint for
Returns:
- A 16-character hexadecimal string representing the fingerprint
- An empty string if the key is empty
Example:
key, _ := crypto.GenerateKey()
fingerprint := crypto.GetKeyFingerprint(key)
fmt.Println("Key fingerprint:", fingerprint) // e.g., "a1b2c3d4e5f67890"
Uses the first 8 bytes of SHA-256 for better collision resistance while maintaining speed.
func KeyFromBase64 ¶
KeyFromBase64 decodes a base64 string to a key.
This function is the inverse of KeyToBase64 and is useful for loading keys from text-based storage formats like JSON or configuration files.
Parameters:
- s: The base64-encoded string to decode
Returns:
- The decoded key as a byte slice
- An error if the base64 decoding fails
Example:
base64Key := "dGVzdC1rZXktZGF0YS0xMjM0NTY3ODkwYWJjZGVm"
key, err := crypto.KeyFromBase64(base64Key)
if err != nil {
log.Fatal(err)
}
fmt.Println("Decoded key length:", len(key))
func KeyFromHex ¶
KeyFromHex decodes a hexadecimal string to a key.
This function is the inverse of KeyToHex and is useful for loading keys from hexadecimal representations. The input string can contain both uppercase and lowercase hexadecimal characters.
Parameters:
- s: The hexadecimal string to decode
Returns:
- The decoded key as a byte slice
- An error if the hexadecimal decoding fails
Example:
hexKey := "746573742d6b65792d646174612d31323334353637383930616263646566"
key, err := crypto.KeyFromHex(hexKey)
if err != nil {
log.Fatal(err)
}
fmt.Println("Decoded key length:", len(key))
func KeyToBase64 ¶
KeyToBase64 encodes a key as a base64 string.
This function is useful for storing keys in text-based formats like JSON or configuration files. The returned string is safe to use in URLs and other text contexts.
Parameters:
- key: The key to encode (can be any byte slice)
Returns:
- A base64-encoded string representation of the key
Example:
key, _ := crypto.GenerateKey()
base64Key := crypto.KeyToBase64(key)
fmt.Println("Base64 key:", base64Key)
func KeyToHex ¶
KeyToHex encodes a key as a hexadecimal string.
This function is useful for displaying keys in a human-readable format or storing them in text-based formats. The returned string contains only lowercase hexadecimal characters (0-9, a-f).
Parameters:
- key: The key to encode (can be any byte slice)
Returns:
- A hexadecimal string representation of the key
Example:
key, _ := crypto.GenerateKey()
hexKey := crypto.KeyToHex(key)
fmt.Println("Hex key:", hexKey)
func ValidateKey ¶
ValidateKey checks that a key has the correct size for AES-256.
This function verifies that the provided key is exactly 32 bytes (256 bits), which is required for AES-256 encryption. It's useful for validating keys before using them with the Encrypt and Decrypt functions.
Parameters:
- key: The key to validate
Returns:
- An error if the key size is incorrect, nil if valid
Example:
key, _ := crypto.GenerateKey()
err := crypto.ValidateKey(key)
if err != nil {
log.Fatal("Invalid key:", err)
}
fmt.Println("Key is valid for AES-256")
The function will return an error if the key is not exactly 32 bytes.
func Zeroize ¶
func Zeroize(b []byte)
Zeroize securely wipes a byte slice from memory.
This function overwrites all bytes in the slice with zeros to prevent sensitive data from remaining in memory after use. This is important for security when dealing with cryptographic keys and other sensitive data.
Note: This function modifies the original slice in place.
Parameters:
- b: The byte slice to zeroize
Example:
key, _ := crypto.GenerateKey()
// Use the key for encryption/decryption
ciphertext, _ := crypto.Encrypt("data", key)
// Securely wipe the key from memory
crypto.Zeroize(key)
Types ¶
type KDFParams ¶
type KDFParams struct {
// Time is the number of iterations for Argon2id.
// Higher values increase security but also computation time.
// If zero, DefaultTime is used.
Time uint32 `json:"time,omitempty"`
// Memory is the memory usage in MB for Argon2id.
// Higher values increase security against memory-based attacks.
// If zero, DefaultMemory is used.
Memory uint32 `json:"memory,omitempty"`
// Threads is the number of threads for Argon2id.
// Should not exceed the number of CPU cores.
// If zero, DefaultThreads is used.
Threads uint8 `json:"threads,omitempty"`
}
KDFParams defines custom parameters for Argon2id key derivation.
If a field is zero, the library's secure default will be used. This allows for flexible configuration while maintaining security.
Example:
// Use custom parameters
params := &crypto.KDFParams{
Time: 4, // 4 iterations
Memory: 128, // 128 MB memory
Threads: 2, // 2 threads
}
key, err := crypto.DeriveKey(password, salt, 32, params)
// Use secure defaults (pass nil)
key, err := crypto.DeriveKey(password, salt, 32, nil)