astrocrypt

package
v1.1.6 Latest Latest
Warning

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

Go to latest
Published: Apr 7, 2026 License: MIT Imports: 7 Imported by: 0

README

🔐 Encryption Package

A simple, secure, and reusable 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
✅ Bun ORM integration with hooks
✅ Base64 encoding for database storage
✅ Thread-safe
✅ Easy to use

Installation

go get github.com/yourusername/encryption

Quick Start

1. Setup
package main

import (
    "log"
    "github.com/yourusername/encryption"
)

func main() {
    // Option 1: From environment variable
    config, err := encryption.NewConfigFromEnv("ENCRYPTION_KEY")
    if err != nil {
        log.Fatal(err)
    }

    // Option 2: From your config struct
    config, err := encryption.NewConfig(yourConfig.EncryptionKey)
    if err != nil {
        log.Fatal(err)
    }

    // Create encryption service
    encryptor, err := encryption.NewService(config)
    if err != nil {
        log.Fatal(err)
    }
}
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"`
}

// Global encryption service
var encryptionService *encryption.Service

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

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

// AfterSelect - decrypts after SELECT
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)
// All users are auto-decrypted!

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"}

// Encrypt all tagged fields
encryptor.EncryptStruct(user)

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

// Encrypt specific fields
encryptor.EncryptFields(user, "Email", "Phone")

// Decrypt specific fields
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 encryption.ErrMissingKey:
        // Handle missing key
    case encryption.ErrInvalidKeyLength:
        // Handle invalid key length
    case encryption.ErrEncryptionFailed:
        // Handle encryption failure
    }
}

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.1.0 ===========

================ Version : V1.1.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

This section is empty.

Types

type Service

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

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) 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) EncryptStruct

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

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

Jump to

Keyboard shortcuts

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