astrocrypt

package
v1.0.19 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 9, 2026 License: MIT Imports: 9 Imported by: 0

README

astrocrypt — AES-256-GCM Encryption Package

A simple, secure encryption package for Go applications with automatic struct field encryption/decryption using tags.

Features

  • AES-256-GCM encryption (industry standard)
  • Automatic encryption/decryption with struct tags (encrypt:"true")
  • Bun ORM integration with hooks
  • Base64 encoding for database storage
  • Thread-safe
  • Easy to use

Installation

go get git.asteroidea.co/go-packages/astroguard/pkg/astrocrypt

Quick Start

1. Setup
package main

import (
    "log"
    "git.asteroidea.co/go-packages/astroguard/pkg/astrocrypt"
)

func main() {
    // Key must be 16, 24, or 32 bytes (AES-128, AES-192, AES-256)
    key := []byte("your-32-character-secret-key!!")

    svc, err := astrocrypt.NewService(key)
    if err != nil {
        log.Fatal(err)
    }

    _ = svc
}
2. Environment Setup

.env or .env.prod

ENCRYPTION_KEY=your-32-character-secret-key!!

Important: Key must be exactly 16, 24, or 32 bytes for AES-128, AES-192, or AES-256.

3. Define Your Model
type User struct {
    bun.BaseModel `bun:"table:users,alias:u"`

    ID        int64     `bun:"id,pk,autoincrement" json:"id"`
    Name      string    `bun:"name" json:"name"`
    Email     string    `bun:"email" json:"email" encrypt:"true"`
    Phone     string    `bun:"phone" json:"phone" encrypt:"true"`
    Address   string    `bun:"address" json:"address" encrypt:"true"`
    CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp"`
}

var encryptionService *astrocrypt.Service

func (u *User) BeforeInsert(ctx context.Context, query *bun.InsertQuery) error {
    return encryptionService.EncryptStruct(u)
}

func (u *User) BeforeUpdate(ctx context.Context, query *bun.UpdateQuery) error {
    return encryptionService.EncryptStruct(u)
}

func (u *User) AfterSelect(ctx context.Context) error {
    return encryptionService.DecryptStruct(u)
}
4. Use in Your Application
// INSERT
user := &User{
    Name:    "John Doe",
    Email:   "john@example.com",   // Auto-encrypted
    Phone:   "+1234567890",        // Auto-encrypted
    Address: "123 Main St",        // Auto-encrypted
}
_, err := db.NewInsert().Model(user).Exec(ctx)

// SELECT
user := new(User)
err := db.NewSelect().Model(user).Where("id = ?", 1).Scan(ctx)
// user.Email, user.Phone, user.Address are auto-decrypted!

// UPDATE
user.Email = "newemail@example.com"
_, err := db.NewUpdate().Model(user).WherePK().Exec(ctx)

// LIST
var users []*User
err := db.NewSelect().Model(&users).Scan(ctx)

API Reference

Service Methods
// Basic encryption/decryption
func (s *Service) Encrypt(plaintext string) (string, error)
func (s *Service) Decrypt(ciphertext string) (string, error)

// Byte slice encryption/decryption
func (s *Service) EncryptBytes(plaintext []byte) ([]byte, error)
func (s *Service) DecryptBytes(ciphertext []byte) ([]byte, error)

// Struct-based encryption/decryption (tag-based)
func (s *Service) EncryptStruct(v interface{}) error
func (s *Service) DecryptStruct(v interface{}) error

// Field-based encryption/decryption (by name)
func (s *Service) EncryptFields(v interface{}, fieldNames ...string) error
func (s *Service) DecryptFields(v interface{}, fieldNames ...string) error

Usage Methods

Add encrypt:"true" tag to fields:

type User struct {
    Email string `encrypt:"true"`
    Phone string `encrypt:"true"`
}

// Bun hooks handle everything automatically
Method 2: Manual Struct Encryption
user := &User{Email: "test@example.com"}

encryptor.EncryptStruct(user)

encryptor.DecryptStruct(user)
Method 3: Field-Specific Encryption
user := &User{Email: "test@example.com", Phone: "+123"}

encryptor.EncryptFields(user, "Email", "Phone")

encryptor.DecryptFields(user, "Email", "Phone")
Method 4: Direct String Encryption
encrypted, err := encryptor.Encrypt("sensitive data")
decrypted, err := encryptor.Decrypt(encrypted)

Security Best Practices

  1. Never hardcode encryption keys — use environment variables or secret managers
  2. Use 32-byte keys for AES-256 (strongest)
  3. Rotate keys periodically (implement key versioning if needed)
  4. Keep keys separate from database — app layer encryption is more secure
  5. Use HTTPS — encryption at rest doesn't protect data in transit
  6. Limit access — not all fields need encryption

Database Storage

Encrypted data is stored as base64-encoded strings, so use TEXT or VARCHAR columns:

CREATE TABLE users (
    id BIGSERIAL PRIMARY KEY,
    name VARCHAR(255),
    email TEXT,        -- Stores encrypted data
    phone TEXT,        -- Stores encrypted data
    address TEXT,      -- Stores encrypted data
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Error Handling

encrypted, err := encryptor.Encrypt("data")
if err != nil {
    switch err {
    case astrocrypt.ErrMissingKey:
    case astrocrypt.ErrInvalidKeyLength:
    case astrocrypt.ErrEncryptionFailed:
    case astrocrypt.ErrDecryptionFailed:
    case astrocrypt.ErrInvalidData:
    }
}

Examples

See the examples/ directory for:

  • basic_example.go — Basic usage without ORM
  • bun_example.go — Full Bun integration
  • repository_example.go — Repository pattern

Documentation

Overview

================ Version : V1.0.0 ===========

================ Version : V1.0.0 ===========

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrMissingKey       = errors.New("encryption key is missing")
	ErrInvalidKeyLength = errors.New("key must be 16, 24, or 32 bytes")
	ErrEncryptionFailed = errors.New("encryption failed")
	ErrDecryptionFailed = errors.New("decryption failed")
	ErrInvalidData      = errors.New("invalid encrypted data")
)

Functions

func Init added in v1.0.10

func Init(key []byte) error

Init must be called once at application startup

func IsInitialized added in v1.0.10

func IsInitialized() bool

IsInitialized lets you check without panicking

Types

type BunModel added in v1.0.10

type BunModel struct{}

func (*BunModel) AfterSelect added in v1.0.10

func (m *BunModel) AfterSelect(ctx context.Context, query *bun.SelectQuery) error

func (*BunModel) BeforeInsert added in v1.0.10

func (m *BunModel) BeforeInsert(ctx context.Context, query *bun.InsertQuery) error

func (*BunModel) BeforeUpdate added in v1.0.10

func (m *BunModel) BeforeUpdate(ctx context.Context, query *bun.UpdateQuery) error

type Service

type Service struct {
	// contains filtered or unexported fields
}

func Default added in v1.0.10

func Default() *Service

Default returns the global service — panics early with a clear message if not initialized

func NewService

func NewService(key []byte) (*Service, error)

NewService creates a new encryption service

func (*Service) Decrypt

func (s *Service) Decrypt(ciphertext string) (string, error)

Decrypt decrypts base64 encoded ciphertext

func (*Service) DecryptBytes

func (s *Service) DecryptBytes(ciphertext []byte) ([]byte, error)

DecryptBytes decrypts byte slice

func (*Service) DecryptFields

func (s *Service) DecryptFields(v interface{}, fieldNames ...string) error

DecryptFields decrypts specific fields by name

func (*Service) DecryptModel added in v1.0.10

func (s *Service) DecryptModel(v interface{}) error

DecryptModel walks a struct / slice / pointer model and decrypts each struct element.

func (*Service) DecryptStruct

func (s *Service) DecryptStruct(v interface{}) error

DecryptStruct decrypts all fields with `encrypt:"true"` tag

func (*Service) Encrypt

func (s *Service) Encrypt(plaintext string) (string, error)

Encrypt encrypts plaintext and returns base64 encoded string

func (*Service) EncryptBytes

func (s *Service) EncryptBytes(plaintext []byte) ([]byte, error)

EncryptBytes encrypts byte slice

func (*Service) EncryptFields

func (s *Service) EncryptFields(v interface{}, fieldNames ...string) error

EncryptFields encrypts specific fields by name

func (*Service) EncryptModel added in v1.0.10

func (s *Service) EncryptModel(v interface{}) error

EncryptModel walks a struct / slice / pointer model and encrypts each struct element.

func (*Service) EncryptStruct

func (s *Service) EncryptStruct(v interface{}) error

EncryptStruct encrypts all fields with `encrypt:"true"` tag

Source Files

  • encrypt_func.go
  • encrypt_tags.go
  • global.go
  • hooks.go

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL