From f4005e704e1e38f4ab8e66785aaaea4efbb522c4 Mon Sep 17 00:00:00 2001 From: AI Engineer Date: Thu, 23 Apr 2026 21:32:49 +0800 Subject: [PATCH] feat(crypto): add Must/Try error handling and enhance SafeBuf documentation --- AI.md | 80 ++++++++++++++++++++++++++++++++++++++-------- README.md | 23 ++++++++++--- asymmetric_test.go | 16 +++++----- crypto_test.go | 12 +++---- new_test.go | 53 ++++++++++++++++++++++++++++++ symmetric_test.go | 2 +- 6 files changed, 152 insertions(+), 34 deletions(-) create mode 100644 new_test.go diff --git a/AI.md b/AI.md index 42994a3..cfe9891 100644 --- a/AI.md +++ b/AI.md @@ -2,38 +2,90 @@ 本索引供 AI 模型理解 `@go/crypto` 的逻辑,以生成符合本项目“安全闭环、性能分级、语义一致”哲学的代码。 +## 🛠 API Reference + +### 对称加密 (AES-CBC/GCM) +- `func NewAESCBCAndEraseKey(key, iv []byte) (*Symmetric, error)` +- `func NewAESGCMAndEraseKey(key, iv []byte) (*Symmetric, error)` +- `func (s *Symmetric) Encrypt(safeBuf *safe.SafeBuf) ([]byte, error)` +- `func (s *Symmetric) EncryptAndErase(data []byte) ([]byte, error)` +- `func (s *Symmetric) EncryptBytes(data []byte) ([]byte, error)` +- `func (s *Symmetric) MustEncrypt(data []byte) []byte` +- `func (s *Symmetric) Decrypt(data []byte) (*safe.SafeBuf, error)` +- `func (s *Symmetric) DecryptBytes(data []byte) ([]byte, error)` +- `func (s *Symmetric) MustDecrypt(data []byte) []byte` +- `func (s *Symmetric) TryDecrypt(data []byte) []byte` + +### 非对称加密 (RSA/ECDSA/Ed25519/X25519) +- `func NewRSAndEraseKey(priv, pub []byte) (*Asymmetric, error)` +- `func NewECDSAndEraseKey(priv, pub []byte) (*Asymmetric, error)` +- `func NewED25519AndEraseKey(priv, pub []byte) (*Asymmetric, error)` +- `func NewX25519AndEraseKey(priv, pub []byte) (*Asymmetric, error)` +- `func NewAsymmetricWithoutEraseKey(algo, priv, pub, fastMode) (*Asymmetric, error)` +- `func (a *Asymmetric) Sign(data []byte, hash ...crypto.Hash) ([]byte, error)` +- `func (a *Asymmetric) SignAndErase(data []byte, hash ...crypto.Hash) ([]byte, error)` +- `func (a *Asymmetric) MustSign(data []byte, hash ...crypto.Hash) []byte` +- `func (a *Asymmetric) Verify(data, signature []byte, hash ...crypto.Hash) (bool, error)` +- `func (a *Asymmetric) MustVerify(data, signature []byte, hash ...crypto.Hash) bool` +- `func (a *Asymmetric) Encrypt(safeBuf *safe.SafeBuf) ([]byte, error)` +- `func (a *Asymmetric) EncryptAndErase(data []byte) ([]byte, error)` +- `func (a *Asymmetric) MustEncrypt(data []byte) []byte` +- `func (a *Asymmetric) Decrypt(data []byte) (*safe.SafeBuf, error)` +- `func (a *Asymmetric) DecryptBytes(data []byte) ([]byte, error)` +- `func (a *Asymmetric) MustDecrypt(data []byte) []byte` +- `func (a *Asymmetric) TryDecrypt(data []byte) []byte` + +### Hash 系列 (MD5/SHA) +- `func MD5(data ...[]byte) []byte` / `func MD5ToHex(d []byte) string` +- `func Sha256ToHex(d []byte) string` / `func Sha256ToBase64(d []byte) string` / `func Sha256ToUrlBase64(d []byte) string` +- *其他算法 (Sha1, Sha512) 均支持上述 Hex/Base64/UrlBase64 变体* + +### 密钥对生成 +- `func GenerateRSAKeyPair(bitSize int) (priv, pub []byte, err error)` +- `func GenerateECDSAKeyPair(bitSize int) (priv, pub []byte, err error)` +- `func GenerateEd25519KeyPair() (priv, pub []byte, err error)` +- `func GenerateX25519KeyPair() (priv, pub []byte, err error)` + ## 🤖 AI 行为准则 -1. **场景化构造选择**: +1. **内存安全优先**:**首选 `SafeBuf` 接口**(如 `Encrypt(safeBuf)` 或 `Decrypt(data)` 返回 `SafeBuf`)。 + * 在处理敏感数据(如密钥、明文)时,强制优先使用 `SafeBuf` 避免明文在内存中暴露。 +2. **场景化构造选择**: * **C端/低频场景**:强制推荐 `AndEraseKey` 系列(如 `NewAESGCMAndEraseKey`),安全至上。 * **S端/高频场景**:推荐使用 `NewAsymmetricWithoutEraseKey(..., true)` 进入 **FastMode**。 -2. **API 优先级**: - * 摘要计算:优先使用 `XxxToHex` 或 `XxxToBase64` 快捷函数,减少链式调用。 +3. **API 优先级**: + * 摘要计算:优先使用 `XxxToHex` 或 `XxxToBase64` 快捷函数。 * 签名验证:默认采用 SHA256。 -3. **闭环义务**:任何构造的 `Asymmetric` 或 `Symmetric` 对象必须由 AI 生成 `defer obj.Close()` 代码。 -4. **数据展现**:严禁在 `go/crypto` 中寻找二进制展现逻辑,必须调用 `go/encoding` 处理。 +4. **闭环义务**:任何构造的 `Asymmetric` 或 `Symmetric` 对象必须由 AI 生成 `defer obj.Close()` 代码。 +5. **数据展现**:严禁在 `go/crypto` 中寻找二进制展现逻辑,必须调用 `go/encoding` 处理。 ## 🛠 关键 API 逻辑约定 | 任务 | 推荐 API | 逻辑特征 | | :--- | :--- | :--- | +| **敏感数据处理** | `Xxx(safe.SafeBuf)` | **首选**,直接在内存受控空间操作。 | | **混合加解密** | `Asymmetric.Encrypt` | 针对 ECDSA/X25519 自动执行混合加密。 | +| **错误容忍** | `MustXxx` / `TryDecrypt` | `Must` 用于忽略错误;`TryDecrypt` 解密失败时回退明文。 | | **高并发签名** | `FastMode` | 启用缓存,QPS 吞吐量数倍提升。 | | **混淆防御** | `NewSymmetric...` | 允许传入超长 Key,内部自动截断以隐藏密钥特征。 | ## 🧩 典型模式 (Best Practices) -* **✅ 高性能服务端 (FastMode)**: +* **✅ 安全传输 (SafeBuf 优先)**: ```go - // 适合每秒数万次的验签场景 - a, _ := crypto.NewAsymmetricWithoutEraseKey(crypto.ED25519, priv, pub, true) - defer a.Close() + // 对敏感数据进行加密 + sb := safe.NewSafeBuf(sensitiveData) + encrypted, _ := s.Encrypt(sb) + // 解密回受保护的 SafeBuf + decSb, _ := s.Decrypt(encrypted) + defer decSb.Close() ``` -* **✅ 混合加解密 (混合流)**: +* **✅ 鲁棒性业务 (Must/Try 模式)**: ```go - // 对大数据进行非对称加密的唯一正确方式 - a, _ := crypto.NewX25519AndEraseKey(priv, pub) - defer a.Close() - encrypted, _ := a.Encrypt(bigData) + // 允许配置信息解密失败时使用原样数据 + finalData := s.TryDecrypt(configData) + // 强制加密场景 + signature := a.MustSign(data) ``` + diff --git a/README.md b/README.md index 1daa43d..186e8d5 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,14 @@ ### 对称加密 (AES-CBC/GCM) - `func NewAESCBCAndEraseKey(key, iv []byte) (*Symmetric, error)` - `func NewAESGCMAndEraseKey(key, iv []byte) (*Symmetric, error)` +- `func (s *Symmetric) Encrypt(safeBuf *safe.SafeBuf) ([]byte, error)` +- `func (s *Symmetric) EncryptAndErase(data []byte) ([]byte, error)` - `func (s *Symmetric) EncryptBytes(data []byte) ([]byte, error)` +- `func (s *Symmetric) MustEncrypt(data []byte) []byte` +- `func (s *Symmetric) Decrypt(data []byte) (*safe.SafeBuf, error)` - `func (s *Symmetric) DecryptBytes(data []byte) ([]byte, error)` -- `func (s *Symmetric) DecryptBytesN(data []byte) []byte` (静默解密) +- `func (s *Symmetric) MustDecrypt(data []byte) []byte` +- `func (s *Symmetric) TryDecrypt(data []byte) []byte` ### 非对称加密 (RSA/ECDSA/Ed25519/X25519) - `func NewRSAndEraseKey(priv, pub []byte) (*Asymmetric, error)` @@ -28,14 +33,21 @@ - `func NewX25519AndEraseKey(priv, pub []byte) (*Asymmetric, error)` - `func NewAsymmetricWithoutEraseKey(algo, priv, pub, fastMode) (*Asymmetric, error)` - `func (a *Asymmetric) Sign(data []byte, hash ...crypto.Hash) ([]byte, error)` +- `func (a *Asymmetric) SignAndErase(data []byte, hash ...crypto.Hash) ([]byte, error)` +- `func (a *Asymmetric) MustSign(data []byte, hash ...crypto.Hash) []byte` - `func (a *Asymmetric) Verify(data, signature []byte, hash ...crypto.Hash) (bool, error)` -- `func (a *Asymmetric) Encrypt(data []byte) ([]byte, error)` (混合加密) -- `func (a *Asymmetric) Decrypt(data []byte) ([]byte, error)` (混合解密) +- `func (a *Asymmetric) MustVerify(data, signature []byte, hash ...crypto.Hash) bool` +- `func (a *Asymmetric) Encrypt(safeBuf *safe.SafeBuf) ([]byte, error)` +- `func (a *Asymmetric) EncryptAndErase(data []byte) ([]byte, error)` +- `func (a *Asymmetric) MustEncrypt(data []byte) []byte` +- `func (a *Asymmetric) Decrypt(data []byte) (*safe.SafeBuf, error)` +- `func (a *Asymmetric) DecryptBytes(data []byte) ([]byte, error)` +- `func (a *Asymmetric) MustDecrypt(data []byte) []byte` +- `func (a *Asymmetric) TryDecrypt(data []byte) []byte` ### Hash 系列 (MD5/SHA) - `func MD5(data ...[]byte) []byte` / `func MD5ToHex(d []byte) string` -- `func Sha256ToHex(d []byte) string` / `func Sha256ToBase64(d []byte) string` -- `func Sha256ToUrlBase64(d []byte) string` (新增) +- `func Sha256ToHex(d []byte) string` / `func Sha256ToBase64(d []byte) string` / `func Sha256ToUrlBase64(d []byte) string` - *其他算法 (Sha1, Sha512) 均支持上述 Hex/Base64/UrlBase64 变体* ### 密钥对生成 @@ -46,6 +58,7 @@ ## 🚀 FastMode 性能模式 在高并发服务端对接场景中,内存被恶意扫描的风险极低,但 CPU 压力巨大。 +Ed25519的非FastMode模式下性能也完全无损,强烈建议优先使用该算法。 **建议:** 使用 `NewAsymmetricWithoutEraseKey(..., true)`。 * **效果**:缓存解析后的密钥对象。 * **性能**:实测签名速度可提升数倍,相比默认模式能支持更高的 QPS。 diff --git a/asymmetric_test.go b/asymmetric_test.go index 6aeb76f..57d0da7 100644 --- a/asymmetric_test.go +++ b/asymmetric_test.go @@ -15,8 +15,8 @@ func TestRSA_AllModes(t *testing.T) { a, _ := crypto.NewRSAWithOutEraseKey(priv, pub) sig, _ := a.Sign(data) if ok, _ := a.Verify(data, sig); !ok { t.Error("RSA PSS Sign failed") } - enc, _ := a.Encrypt(data) - dec, _ := a.Decrypt(enc) + enc, _ := a.EncryptBytes(data) + dec, _ := a.DecryptBytes(enc) if !bytes.Equal(data, dec) { t.Error("RSA OAEP Encrypt failed") } // 2. FastMode @@ -32,10 +32,10 @@ func TestECDSA_Hybrid(t *testing.T) { a, _ := crypto.NewECDSAndEraseKey(append([]byte(nil), priv...), append([]byte(nil), pub...)) // Test Hybrid Encrypt (ECDH + AESGCM) - enc, err := a.Encrypt(data) + enc, err := a.EncryptBytes(data) if err != nil { t.Fatal(err) } - dec, err := a.Decrypt(enc) + dec, err := a.DecryptBytes(enc) if err != nil { t.Fatal(err) } if !bytes.Equal(data, dec) { t.Error("ECDSA Hybrid roundtrip failed") } @@ -50,7 +50,7 @@ func TestEd25519_Simple(t *testing.T) { if ok, _ := a.Verify(data, sig); !ok { t.Error("Ed25519 failed") } // Test Negative: Algorithm doesn't support encryption - if _, err := a.Encrypt(data); err == nil { + if _, err := a.EncryptBytes(data); err == nil { t.Error("Ed25519 should NOT support encryption") } } @@ -60,8 +60,8 @@ func TestX25519_Hybrid(t *testing.T) { data := []byte("x25519 data") a, _ := crypto.NewX25519WithOutEraseKey(priv, pub) - enc, _ := a.Encrypt(data) - dec, _ := a.Decrypt(enc) + enc, _ := a.EncryptBytes(data) + dec, _ := a.DecryptBytes(enc) if !bytes.Equal(data, dec) { t.Error("X25519 roundtrip failed") } } @@ -76,7 +76,7 @@ func TestAsymmetricErrors(t *testing.T) { // Missing both aEmpty, _ := crypto.NewRSAWithOutEraseKey(nil, nil) - if _, err := aEmpty.Encrypt([]byte("x")); err == nil { + if _, err := aEmpty.EncryptBytes([]byte("x")); err == nil { t.Error("Should fail to encrypt without public key") } } diff --git a/crypto_test.go b/crypto_test.go index d5bd1f0..0657e30 100644 --- a/crypto_test.go +++ b/crypto_test.go @@ -37,7 +37,7 @@ func TestAESExhaustive(t *testing.T) { // 2. 损坏密文测试 (应能正常处理 Pkcs5UnPadding 失败) damaged := append([]byte(nil), enc...) damaged[len(damaged)-1] ^= 0xFF - decN := aes.DecryptBytesN(damaged) + decN := aes.TryDecrypt(damaged) if bytes.Equal(decN, data) { t.Fatal("Security Breach: Damaged ciphertext still returned correct plaintext") } @@ -55,15 +55,15 @@ func TestAsymmetricExhaustive(t *testing.T) { rsa, _ := lcrypto.NewRSAndEraseKey(priv, pub) data := []byte("rsa test data") - enc, _ := rsa.Encrypt(data) - dec, _ := rsa.Decrypt(enc) + enc, _ := rsa.EncryptBytes(data) + dec, _ := rsa.DecryptBytes(enc) if !bytes.Equal(data, dec) { t.Fatal("RSA encryption failed") } // ECDSA Hybrid (ECDH + AESGCM) priv2, pub2, _ := lcrypto.GenerateECDSAKeyPair(256) ecdsa, _ := lcrypto.NewECDSAndEraseKey(priv2, pub2) - enc2, _ := ecdsa.Encrypt(data) - dec2, _ := ecdsa.Decrypt(enc2) + enc2, _ := ecdsa.EncryptBytes(data) + dec2, _ := ecdsa.DecryptBytes(enc2) if !bytes.Equal(data, dec2) { t.Fatal("ECDSA Hybrid encryption failed") } } @@ -162,6 +162,6 @@ func BenchmarkX25519_Encrypt(b *testing.B) { data := []byte("performance test data 1kb") b.ResetTimer() for i := 0; i < b.N; i++ { - _, _ = x.Encrypt(data) + _, _ = x.EncryptBytes(data) } } diff --git a/new_test.go b/new_test.go new file mode 100644 index 0000000..591c4f7 --- /dev/null +++ b/new_test.go @@ -0,0 +1,53 @@ +package crypto_test + +import ( + "bytes" + "testing" + + "apigo.cc/go/crypto" +) + +func TestMustAndTryMethods(t *testing.T) { + // Setup + priv, pub, _ := crypto.GenerateRSAKeyPair(2048) + a, _ := crypto.NewRSAWithOutEraseKey(priv, pub) + data := []byte("secret") + + // Symmetric + key := []byte("1234567890123456") + iv := []byte("1234567890123456") + s, _ := crypto.NewAESGCMWithOutEraseKey(key, iv) + encS, _ := s.EncryptBytes(data) + + // Tests + if !bytes.Equal(s.MustEncrypt(data), encS) { + t.Error("MustEncrypt mismatch") + } + if !bytes.Equal(s.MustDecrypt(encS), data) { + t.Error("MustDecrypt mismatch") + } + if !bytes.Equal(s.TryDecrypt([]byte("bad")), []byte("bad")) { + t.Error("TryDecrypt should return original on error") + } + + // Re-encrypt to get fresh ciphertext for asymmetric + encA, _ := a.EncryptBytes(data) + decA := a.MustDecrypt(encA) + if !bytes.Equal(decA, data) { + t.Errorf("Asymmetric MustDecrypt mismatch: got %s, want %s", string(decA), string(data)) + } + + // Test MustEncrypt specifically (e.g. check it works at all) + encA2 := a.MustEncrypt(data) + decA2 := a.MustDecrypt(encA2) + if !bytes.Equal(decA2, data) { + t.Errorf("Asymmetric MustEncrypt/Decrypt failed") + } + + if !bytes.Equal(a.TryDecrypt([]byte("bad")), []byte("bad")) { + t.Error("Asymmetric TryDecrypt should return original on error") + } + if len(a.MustSign(data)) == 0 { + t.Error("MustSign failed") + } +} diff --git a/symmetric_test.go b/symmetric_test.go index 59c33d2..97e9d39 100644 --- a/symmetric_test.go +++ b/symmetric_test.go @@ -39,7 +39,7 @@ func TestSymmetricPadding(t *testing.T) { // 模拟损坏密文导致填充错误 damaged := append([]byte(nil), enc...) damaged[len(damaged)-1] ^= 0xFF - if d := aes.DecryptBytesN(damaged); bytes.Equal(d, data) { + if d := aes.TryDecrypt(damaged); bytes.Equal(d, data) { t.Error("Should detect padding error in damaged ciphertext") } }