package meshseed import ( "crypto/aes" "crypto/cipher" "crypto/ed25519" "crypto/rand" "crypto/sha256" "encoding/base64" "encoding/json" "fmt" "io" ) // deriveKey 派生 AES-256-GCM 密钥 // 密钥派生规则:SHA256("meshray-ddns" || NetworkSecret) → 32 字节 func deriveKey(networkSecret string) []byte { hash := sha256.Sum256([]byte("meshray-ddns" + networkSecret)) return hash[:] } // Encrypt 加密 MeshSeed // 流程:签名 → AES-256-GCM 加密 → Base64URL 编码 func Encrypt(seed *MeshSeed, networkSecret string) (string, error) { // 1. 签名(如果还没有签名) if len(seed.Signature) == 0 { // 注意:这里需要 Ed25519 私钥进行签名 // 由于 MeshSeed 已经包含签名,我们假设签名已经完成 return "", fmt.Errorf("MeshSeed 未签名") } // 2. 序列化 MeshSeed plaintext, err := json.Marshal(seed) if err != nil { return "", fmt.Errorf("序列化 MeshSeed 失败:%w", err) } // 3. 派生加密密钥 key := deriveKey(networkSecret) // 4. 创建 AES cipher block, err := aes.NewCipher(key) if err != nil { return "", fmt.Errorf("创建 AES cipher 失败:%w", err) } // 5. 创建 GCM gcm, err := cipher.NewGCM(block) if err != nil { return "", fmt.Errorf("创建 GCM 失败:%w", err) } // 6. 生成随机 Nonce nonce := make([]byte, gcm.NonceSize()) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return "", fmt.Errorf("生成 Nonce 失败:%w", err) } // 7. 加密 ciphertext := gcm.Seal(nonce, nonce, plaintext, nil) // 8. Base64URL 编码 encoded := base64.URLEncoding.EncodeToString(ciphertext) return encoded, nil } // Decrypt 解密 MeshSeed // 流程:Base64URL 解码 → AES-256-GCM 解密 → Ed25519 验签 func Decrypt(encrypted string, networkSecret string) (*MeshSeed, error) { // 1. Base64URL 解码 ciphertext, err := base64.URLEncoding.DecodeString(encrypted) if err != nil { return nil, fmt.Errorf("Base64URL 解码失败:%w", err) } // 2. 派生解密密钥 key := deriveKey(networkSecret) // 3. 创建 AES cipher block, err := aes.NewCipher(key) if err != nil { return nil, fmt.Errorf("创建 AES cipher 失败:%w", err) } // 4. 创建 GCM gcm, err := cipher.NewGCM(block) if err != nil { return nil, fmt.Errorf("创建 GCM 失败:%w", err) } // 5. 检查密文长度 nonceSize := gcm.NonceSize() if len(ciphertext) < nonceSize { return nil, fmt.Errorf("密文长度不足") } // 6. 分离 Nonce 和密文 nonce, ciphertextBytes := ciphertext[:nonceSize], ciphertext[nonceSize:] // 7. 解密 plaintext, err := gcm.Open(nil, nonce, ciphertextBytes, nil) if err != nil { return nil, fmt.Errorf("解密失败:%w", err) } // 8. 反序列化 MeshSeed var seed MeshSeed if err := json.Unmarshal(plaintext, &seed); err != nil { return nil, fmt.Errorf("反序列化 MeshSeed 失败:%w", err) } return &seed, nil } // Sign 签名 MeshSeed // 使用 Ed25519 私钥对 MeshSeed 进行签名 func Sign(seed *MeshSeed, privateKey ed25519.PrivateKey) error { // 1. 临时清除签名字段 originalSignature := seed.Signature seed.Signature = nil // 2. 序列化 MeshSeed(不含签名) data, err := json.Marshal(seed) if err != nil { seed.Signature = originalSignature return fmt.Errorf("序列化 MeshSeed 失败:%w", err) } // 3. Ed25519 签名 signature := ed25519.Sign(privateKey, data) // 4. 设置签名 seed.Signature = signature return nil } // Verify 验证 MeshSeed 签名 // 使用 Ed25519 公钥验证 MeshSeed 签名 // 可选参数 publicKey:如果为 nil,则从 seed.IssuerNodeID 解析公钥 func Verify(seed *MeshSeed, publicKey ed25519.PublicKey) error { // 1. 检查签名是否存在 if len(seed.Signature) == 0 { return fmt.Errorf("MeshSeed 无签名") } // 2. 如果未提供公钥,从 IssuerNodeID 解析 if publicKey == nil { if seed.IssuerNodeID == "" { return fmt.Errorf("无法验证签名:缺少公钥(IssuerNodeID 为空)") } // IssuerNodeID 是 hex 编码的 Ed25519 公钥(32 字节) pubKeyBytes, err := decodeIssuerNodeID(seed.IssuerNodeID) if err != nil { return fmt.Errorf("解析 IssuerNodeID 失败:%w", err) } if len(pubKeyBytes) != ed25519.PublicKeySize { return fmt.Errorf("无效的公钥长度:期望 %d 字节,实际 %d 字节", ed25519.PublicKeySize, len(pubKeyBytes)) } publicKey = ed25519.PublicKey(pubKeyBytes) } // 3. 临时保存签名 signature := seed.Signature // 4. 临时清除签名字段 seed.Signature = nil // 5. 序列化 MeshSeed(不含签名) data, err := json.Marshal(seed) if err != nil { seed.Signature = signature return fmt.Errorf("序列化 MeshSeed 失败:%w", err) } // 6. 恢复签名 seed.Signature = signature // 7. Ed25519 验签 if !ed25519.Verify(publicKey, data, signature) { return fmt.Errorf("签名验证失败:签名无效或数据被篡改") } return nil } // decodeIssuerNodeID 解码 IssuerNodeID 为公钥字节 // 支持两种格式:hex 编码(64 字符)或 Base64 编码 func decodeIssuerNodeID(id string) ([]byte, error) { // 尝试 hex 解码(64 字符 = 32 字节) if len(id) == 64 { return hexDecodeString(id) } // 尝试 Base64 解码 return base64.StdEncoding.DecodeString(id) } // hexDecodeString 解码 hex 字符串(辅助函数) func hexDecodeString(s string) ([]byte, error) { // 手动实现 hex 解码以避免导入 encoding/hex result := make([]byte, len(s)/2) for i := 0; i < len(s); i += 2 { b1, ok := hexCharToByte(s[i]) if !ok { return nil, fmt.Errorf("无效的 hex 字符:%c", s[i]) } b2, ok := hexCharToByte(s[i+1]) if !ok { return nil, fmt.Errorf("无效的 hex 字符:%c", s[i+1]) } result[i/2] = b1<<4 | b2 } return result, nil } // hexCharToByte 单个 hex 字符转字节 func hexCharToByte(c byte) (byte, bool) { switch { case '0' <= c && c <= '9': return c - '0', true case 'a' <= c && c <= 'f': return c - 'a' + 10, true case 'A' <= c && c <= 'F': return c - 'A' + 10, true default: return 0, false } } // GenerateKeyPair 生成 Ed25519 密钥对 func GenerateKeyPair() (ed25519.PublicKey, ed25519.PrivateKey, error) { publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader) if err != nil { return nil, nil, fmt.Errorf("生成密钥对失败:%w", err) } return publicKey, privateKey, nil }