Documentation
¶
Overview ¶
Package encrypt provides helpers for encrypting and decrypting data safely for transport and storage.
It solves the problem of protecting application payloads when data moves between systems such as databases, queues, caches, or external services.
This package uses AES-GCM authenticated encryption with a random nonce prefixed to the ciphertext. It provides both raw byte-level APIs and convenience helpers that serialize arbitrary values with gob or JSON before encryption.
Top features:
- AES-GCM encryption and decryption with standard key sizes (16, 24, or 32 bytes for AES-128, AES-192, and AES-256)
- nonce generation via secure random bytes and nonce-prefix output format for self-contained ciphertext payloads
- additional authenticated data (AAD) support via WithAAD to bind contextual data (such as a record ID) into the authentication tag
- base64 encoded byte and string helpers for transport-safe interchange
- gob and JSON wrappers for encrypting and decrypting structured Go values
- layered error propagation from encoding, base64, and cryptographic operations
Benefits:
- reduce boilerplate for secure payload handling
- avoid accidental use of insecure or unauthenticated encryption modes
- simplify encryption of structured data in distributed systems
Security and caveats ¶
- Random-nonce message limit: each call generates a fresh 96-bit random nonce. With random nonces the number of messages that may safely be encrypted under a single key is bounded by the birthday paradox (see NIST SP 800-38D). Rotate keys well before ~2^32 messages per key to keep the nonce-collision probability negligible. A nonce collision under the same key breaks both confidentiality and authentication.
- Nonce uniqueness depends entirely on the randomness source. Encrypt uses crypto/rand.Reader. Override it (via EncryptWith and WithRandReader) only in tests; a non-cryptographic or repeating reader causes nonce reuse.
- The gob helpers (ByteEncryptAny/ByteDecryptAny and their string wrappers) decode with encoding/gob, which is not designed for adversarial input. Because the payload is authenticated before decoding, only data produced by a holder of the key ever reaches the decoder; even so, prefer the JSON family (the *SerializeAny helpers) for cross-language or lower-trust payloads.
- The Base64 output uses standard encoding (RFC 4648 with '+' and '/'), which is not URL- or filename-safe. Re-encode at the call site if you need to embed the payload in a URL or path.
- All exported functions are stateless and safe for concurrent use.
Index ¶
- Variables
- func ByteDecryptAny(key, msg []byte, data any) error
- func ByteDecryptSerializeAny(key, msg []byte, data any) error
- func ByteEncryptAny(key []byte, data any) ([]byte, error)
- func ByteEncryptSerializeAny(key []byte, data any) ([]byte, error)
- func Decrypt(key, msg []byte) ([]byte, error)
- func DecryptAny(key []byte, msg string, data any) error
- func DecryptSerializeAny(key []byte, msg string, data any) error
- func DecryptWith(key, msg []byte, opts ...Option) ([]byte, error)
- func Encrypt(key, msg []byte) ([]byte, error)
- func EncryptAny(key []byte, data any) (string, error)
- func EncryptSerializeAny(key []byte, data any) (string, error)
- func EncryptWith(key, msg []byte, opts ...Option) ([]byte, error)
- type Option
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrInvalidInputSize = errors.New("encrypt: input shorter than nonce size")
ErrInvalidInputSize is returned by Decrypt and DecryptWith when the payload is shorter than the AES-GCM nonce, so it cannot contain a nonce plus ciphertext.
Functions ¶
func ByteDecryptAny ¶
ByteDecryptAny decrypts Base64 bytes produced by ByteEncryptAny into data.
data must be a pointer to the destination type.
func ByteDecryptSerializeAny ¶
ByteDecryptSerializeAny decrypts Base64 bytes into JSON-decoded data.
data must be a pointer to the destination type.
func ByteEncryptAny ¶
ByteEncryptAny gob-encodes data, encrypts it, and returns Base64 bytes.
This helper is useful for encrypting arbitrary Go values for transport.
func ByteEncryptSerializeAny ¶
ByteEncryptSerializeAny JSON-encodes data, encrypts it, and returns Base64 bytes.
Use this helper for cross-language payloads where JSON interoperability is required.
func Decrypt ¶
Decrypt opens a nonce-prefixed AES-GCM payload produced by Encrypt.
key must match the key used during encryption.
func DecryptAny ¶
DecryptAny wraps ByteDecryptAny for string input payloads.
func DecryptSerializeAny ¶
DecryptSerializeAny wraps ByteDecryptSerializeAny for string input payloads.
func DecryptWith ¶
DecryptWith behaves like Decrypt but accepts options. Only WithAAD is honored: the AAD must match the value passed to EncryptWith or decryption fails. WithRandReader has no effect on decryption.
func Encrypt ¶
Encrypt seals msg with AES-GCM and prepends the random nonce.
key must be 16, 24, or 32 bytes for AES-128/192/256. The output is self-contained: nonce || ciphertext. The nonce is generated from crypto/rand.Reader.
Example ¶
The nonce is random, so the ciphertext differs on every run; these examples print the decrypted round-trip result, which is deterministic and verifiable.
package main
import (
"fmt"
"log"
"github.com/tecnickcom/nurago/pkg/encrypt"
)
func main() {
key := []byte("abcdefghijklmnopqrstuvwxyz012345") // 32 bytes: AES-256
enc, err := encrypt.Encrypt(key, []byte("secret message"))
if err != nil {
log.Fatal(err)
}
dec, err := encrypt.Decrypt(key, enc)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(dec))
}
Output: secret message
func EncryptAny ¶
EncryptAny wraps ByteEncryptAny and returns a string payload.
func EncryptSerializeAny ¶
EncryptSerializeAny wraps ByteEncryptSerializeAny and returns a string payload.
Example ¶
package main
import (
"fmt"
"log"
"github.com/tecnickcom/nurago/pkg/encrypt"
)
func main() {
type Payload struct {
Name string
Count int
}
key := []byte("abcdefghijklmnopqrstuvwxyz012345")
enc, err := encrypt.EncryptSerializeAny(key, Payload{Name: "widget", Count: 7})
if err != nil {
log.Fatal(err)
}
var out Payload
err = encrypt.DecryptSerializeAny(key, enc, &out)
if err != nil {
log.Fatal(err)
}
fmt.Println(out.Name, out.Count)
}
Output: widget 7
func EncryptWith ¶
EncryptWith behaves like Encrypt but accepts options that customize the random source used for nonce generation (see WithRandReader) and bind additional authenticated data (see WithAAD).
Without options it is identical to Encrypt and uses crypto/rand.Reader.
Example ¶
ExampleEncryptWith binds additional authenticated data (AAD) to the payload. The same AAD must be supplied when decrypting.
package main
import (
"fmt"
"log"
"github.com/tecnickcom/nurago/pkg/encrypt"
)
func main() {
key := []byte("abcdefghijklmnopqrstuvwxyz012345")
aad := []byte("record-id-42")
enc, err := encrypt.EncryptWith(key, []byte("secret message"), encrypt.WithAAD(aad))
if err != nil {
log.Fatal(err)
}
dec, err := encrypt.DecryptWith(key, enc, encrypt.WithAAD(aad))
if err != nil {
log.Fatal(err)
}
fmt.Println(string(dec))
}
Output: secret message
Types ¶
type Option ¶
type Option func(*config)
Option customizes the behavior of EncryptWith and DecryptWith.
Options are additive: existing Encrypt/Decrypt signatures are unchanged and always use the secure default reader (crypto/rand.Reader) with no AAD.
func WithAAD ¶
WithAAD binds additional authenticated data (AAD) to the ciphertext.
The AAD is authenticated but not encrypted: the exact same value must be supplied to DecryptWith or decryption fails. Use it to bind contextual data (such as a record ID or schema version) to a payload. The high-level Any/Serialize helpers do not expose AAD; use EncryptWith/DecryptWith for it.
func WithRandReader ¶
WithRandReader overrides the random source used to generate the AES-GCM nonce.
SECURITY: the reader MUST be a cryptographically secure source of unique bytes. Reusing a nonce under the same key breaks AES-GCM confidentiality and authentication, so this option is intended for tests only. Production code must use Encrypt (or EncryptWith without this option), which reads from crypto/rand.Reader. It has no effect on DecryptWith.