package agentcap import ( "crypto/aes" "crypto/cipher" "crypto/rand" "crypto/sha256" "encoding/base64" "encoding/json" "fmt" "io" "strings" "golang.org/x/crypto/hkdf" ) const Prefix = "AJZ1" // Descriptor 智能体解密后才能看到的请求契约(前端不展示明文)。 type Descriptor struct { Version string `json:"v"` BaseURL string `json:"base_url"` AppSlug string `json:"app_slug"` TenantHint string `json:"tenant_hint,omitempty"` Auth AuthSpec `json:"auth"` Resources []ResourceSpec `json:"resources"` Notes string `json:"notes,omitempty"` } type AuthSpec struct { Type string `json:"type"` // bearer_jwt Header string `json:"header"` } type ResourceSpec struct { Name string `json:"name"` Path string `json:"path"` Methods []string `json:"methods"` Filters []string `json:"filters,omitempty"` Sorts []string `json:"sorts,omitempty"` Fields []FieldSpec `json:"fields,omitempty"` PrimaryKey string `json:"primary_key"` } type FieldSpec struct { Name string `json:"name"` Type string `json:"type"` } func DeriveKey(masterSecret string, tenantID int64, userID int64) []byte { h := hkdf.New(sha256.New, []byte(masterSecret), []byte("aijianzhan-agent-v1"), []byte(fmt.Sprintf("%d:%d", tenantID, userID))) key := make([]byte, 32) _, _ = io.ReadFull(h, key) return key } func Encrypt(key []byte, desc *Descriptor) (string, error) { raw, err := json.Marshal(desc) 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 } nonce := make([]byte, gcm.NonceSize()) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return "", err } ciphertext := gcm.Seal(nil, nonce, raw, nil) return fmt.Sprintf("%s.%s.%s", Prefix, base64.RawURLEncoding.EncodeToString(nonce), base64.RawURLEncoding.EncodeToString(ciphertext), ), nil } func Decrypt(key []byte, capsule string) (*Descriptor, error) { parts := strings.Split(capsule, ".") if len(parts) != 3 || parts[0] != Prefix { return nil, fmt.Errorf("invalid capsule format") } nonce, err := base64.RawURLEncoding.DecodeString(parts[1]) if err != nil { return nil, err } ciphertext, err := base64.RawURLEncoding.DecodeString(parts[2]) if err != nil { return nil, err } block, err := aes.NewCipher(key) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } plain, err := gcm.Open(nil, nonce, ciphertext, nil) if err != nil { return nil, fmt.Errorf("decrypt failed") } var desc Descriptor if err := json.Unmarshal(plain, &desc); err != nil { return nil, err } return &desc, nil } func PublicAgentKey(masterSecret string, tenantID, userID int64) string { key := DeriveKey(masterSecret, tenantID, userID) return base64.RawURLEncoding.EncodeToString(key) } func ParseAgentKey(b64 string) ([]byte, error) { return base64.RawURLEncoding.DecodeString(b64) }