Skip to content

Encryption & Hashing

λ Cosmos provides encryption and hashing implementations through the contract.Encrypter and contract.Hasher interfaces.

type Encrypter interface {
Encrypt(value []byte) ([]byte, error)
Decrypt(value []byte) ([]byte, error)
}
type Hasher interface {
Hash(value []byte) ([]byte, error)
Check(value []byte, hash []byte) (bool, error)
}

Both implementations use authenticated encryption (AEAD), which provides both confidentiality and integrity. The nonce is automatically generated and prepended to the ciphertext.

import "github.com/studiolambda/cosmos/framework/crypto"
// Key must be 16, 24, or 32 bytes for AES-128, AES-192, or AES-256
key := []byte("your-32-byte-secret-key-here!!!!") // 32 bytes = AES-256
enc, err := crypto.NewAES(key)
if err != nil {
log.Fatal(err)
}
// Encrypt
ciphertext, err := enc.Encrypt([]byte("sensitive data"))
// Decrypt
plaintext, err := enc.Decrypt(ciphertext)

AES-GCM is the standard choice for most applications. Use AES-256 (32-byte key) for maximum security.

import "github.com/studiolambda/cosmos/framework/crypto"
// Key must be exactly 32 bytes
key := []byte("your-32-byte-secret-key-here!!!!")
enc, err := crypto.NewChaCha20(key)
if err != nil {
log.Fatal(err)
}
ciphertext, err := enc.Encrypt([]byte("sensitive data"))
plaintext, err := enc.Decrypt(ciphertext)

ChaCha20-Poly1305 is an alternative to AES-GCM that performs better on hardware without AES instruction set support (e.g., older ARM devices). On modern x86 hardware with AES-NI, performance is comparable.

AES-GCMChaCha20-Poly1305
Key size16, 24, or 32 bytes32 bytes only
Hardware accelerationAES-NI on x86Software-optimized
Best forServers with AES-NIMobile, embedded, or mixed hardware
StandardNISTIETF RFC 8439

Both are secure and widely used. AES-256-GCM is the most common choice for server applications.

The recommended choice for password hashing:

import "github.com/studiolambda/cosmos/framework/hash"
hasher := hash.NewArgon2()
// Hash a password
hashed, err := hasher.Hash([]byte("user-password"))
// Verify a password
ok, err := hasher.Check([]byte("user-password"), hashed)
if ok {
// password matches
}

Customize the Argon2 parameters:

hasher := hash.NewArgon2With(hash.Argon2Config{
// Configure memory, iterations, parallelism, etc.
})

The default configuration uses argon2.DefaultConfig() which provides secure defaults suitable for most applications.

A well-established alternative:

import "github.com/studiolambda/cosmos/framework/hash"
hasher := hash.NewBcrypt()
hashed, err := hasher.Hash([]byte("user-password"))
ok, err := hasher.Check([]byte("user-password"), hashed)

Customize the cost factor:

hasher := hash.NewBcryptWith(hash.BcryptOptions{
cost: 12, // default is 10
})

Higher cost means slower hashing, which is more resistant to brute force attacks but increases CPU usage during authentication.

Argon2Bcrypt
Memory-hardYesNo
GPU resistanceHighModerate
ConfigurableMemory, time, parallelismCost factor only
RecommendedYes (modern standard)Yes (proven, widely supported)

Argon2 is the winner of the Password Hashing Competition and is recommended for new applications. Bcrypt remains a solid choice and is well-supported across ecosystems if you need interoperability.

Inject encryption or hashing instances into the request context:

app.Use(middleware.Provide(encKey, encrypter))
app.Use(middleware.Provide(hashKey, hasher))
func register(w http.ResponseWriter, r *http.Request) error {
h := r.Context().Value(hashKey).(contract.Hasher)
body, err := request.JSON[RegisterRequest](r)
if err != nil {
return err
}
hashed, err := h.Hash([]byte(body.Password))
if err != nil {
return err
}
// Store hashed password...
}