// internal/shared/crypto/encryption.go package crypto import ( "crypto/aes" "crypto/cipher" "crypto/rand" "encoding/base64" "errors" "io" "os" "crypto/sha256" ) func Encrypt(plain string) (string, error) { key := []byte(os.Getenv("SESSION_SECRET")) if len(key) != 32 { return "", errors.New("SESSION_SECRET must be 32 bytes") } block, err := aes.NewCipher(key) if err != nil { return "", err } gcm, err := cipher.NewGCM(block) if err != nil { return "", err } nonce := make([]byte, gcm.NonceSize()) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return "", err } ciphertext := gcm.Seal(nonce, nonce, []byte(plain), nil) return base64.StdEncoding.EncodeToString(ciphertext), nil } func Decrypt(enc string) (string, error) { key := []byte(os.Getenv("SESSION_SECRET")) data, err := base64.StdEncoding.DecodeString(enc) if err != nil { return "", err } block, err := aes.NewCipher(key) if err != nil { return "", err } gcm, err := cipher.NewGCM(block) if err != nil { return "", err } nonceSize := gcm.NonceSize() if len(data) < nonceSize { return "", errors.New("invalid ciphertext") } nonce, ciphertext := data[:nonceSize], data[nonceSize:] plain, err := gcm.Open(nil, nonce, ciphertext, nil) if err != nil { return "", err } return string(plain), nil } func SHA256Base64URL(input string) string { hash := sha256.Sum256([]byte(input)) return base64.RawURLEncoding.EncodeToString(hash[:]) }