5759c1862e
M0-M7 已完成:核心网关(身份/RBAC/TOTP/OIDC/SAML/Provider/配额/路由/内容策略/审计/定价)+ 资源市场(MCP/Skills/数字员工)。 含 22 个 PostgreSQL 迁移、管理端/门户端前端源码、OpenAPI 契约、部署 compose。 Co-Authored-By: Claude <noreply@anthropic.com>
78 lines
2.0 KiB
Go
78 lines
2.0 KiB
Go
package cryptox
|
|
|
|
import (
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
var ErrKeyUnavailable = errors.New("encryption key unavailable")
|
|
|
|
type AESGCM struct {
|
|
aead cipher.AEAD
|
|
version int
|
|
purpose string
|
|
}
|
|
|
|
func NewAESGCM(encodedKey string, version int, purpose string) (*AESGCM, error) {
|
|
if encodedKey == "" {
|
|
return nil, nil
|
|
}
|
|
key, err := base64.StdEncoding.DecodeString(encodedKey)
|
|
if err != nil {
|
|
key, err = base64.RawStdEncoding.DecodeString(encodedKey)
|
|
}
|
|
if err != nil || len(key) != 32 {
|
|
return nil, errors.New("encryption key must be base64-encoded 32 bytes")
|
|
}
|
|
if version < 1 || purpose == "" {
|
|
return nil, errors.New("encryption version and purpose are required")
|
|
}
|
|
block, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
aead, err := cipher.NewGCM(block)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &AESGCM{aead: aead, version: version, purpose: purpose}, nil
|
|
}
|
|
|
|
func (c *AESGCM) Encrypt(plaintext []byte) ([]byte, int, error) {
|
|
if c == nil {
|
|
return nil, 0, ErrKeyUnavailable
|
|
}
|
|
nonce := make([]byte, c.aead.NonceSize())
|
|
if _, err := rand.Read(nonce); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
ciphertext := c.aead.Seal(nil, nonce, plaintext, c.additionalData())
|
|
return append(nonce, ciphertext...), c.version, nil
|
|
}
|
|
|
|
func (c *AESGCM) Decrypt(encrypted []byte, version int) ([]byte, error) {
|
|
if c == nil {
|
|
return nil, ErrKeyUnavailable
|
|
}
|
|
if version != c.version {
|
|
return nil, fmt.Errorf("encryption key version %d is not loaded", version)
|
|
}
|
|
nonceSize := c.aead.NonceSize()
|
|
if len(encrypted) <= nonceSize {
|
|
return nil, errors.New("encrypted value is truncated")
|
|
}
|
|
plaintext, err := c.aead.Open(nil, encrypted[:nonceSize], encrypted[nonceSize:], c.additionalData())
|
|
if err != nil {
|
|
return nil, errors.New("encrypted value authentication failed")
|
|
}
|
|
return plaintext, nil
|
|
}
|
|
|
|
func (c *AESGCM) additionalData() []byte {
|
|
return []byte(fmt.Sprintf("ai-gateway/%s/v%d", c.purpose, c.version))
|
|
}
|