Files
kanban/backend/modules_crypto.go
T
egutierrez c9e15513c7 chore: auto-commit (23 archivos)
- app.md
- backend/dist/assets/index-CFDWXN9Z.js
- backend/dist/index.html
- backend/handlers.go
- backend/main.go
- backend/users.go
- e2e/smoke_live.sh
- frontend/src/App.tsx
- frontend/src/api.ts
- frontend/src/components/CardChatPanel.tsx
- ...

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 18:22:44 +02:00

69 lines
1.7 KiB
Go

package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"errors"
"fmt"
"io"
"os"
)
const moduleKeyEnv = "KANBAN_MODULE_KEY"
// moduleKey derives a 32-byte AES key from the KANBAN_MODULE_KEY env var.
// Returns (key, true) when present; (zero, false) when missing — callers
// must treat that as "module dispatcher disabled".
func moduleKey() ([32]byte, bool) {
v := os.Getenv(moduleKeyEnv)
if v == "" {
return [32]byte{}, false
}
return sha256.Sum256([]byte(v)), true
}
// encryptConfig encrypts a JSON config blob with AES-GCM. Returns the
// ciphertext and the 12-byte nonce. Caller persists both columns.
func encryptConfig(plain []byte) (cipherOut, nonce []byte, err error) {
key, ok := moduleKey()
if !ok {
return nil, nil, fmt.Errorf("%s not set; cannot encrypt module config", moduleKeyEnv)
}
block, err := aes.NewCipher(key[:])
if err != nil {
return nil, nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, nil, err
}
nonce = make([]byte, gcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return nil, nil, err
}
cipherOut = gcm.Seal(nil, nonce, plain, nil)
return cipherOut, nonce, nil
}
// decryptConfig is the inverse of encryptConfig.
func decryptConfig(cipherIn, nonce []byte) ([]byte, error) {
key, ok := moduleKey()
if !ok {
return nil, fmt.Errorf("%s not set; cannot decrypt module config", moduleKeyEnv)
}
if len(nonce) == 0 {
return nil, errors.New("nonce empty")
}
block, err := aes.NewCipher(key[:])
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
return gcm.Open(nil, nonce, cipherIn, nil)
}