package cipherx_test import ( "bytes" "crypto/aes" "errors" "testing" "code.yun.ink/pkg/encryptx/cipherx" ) // testSuite 返回一个以 AES 为实现、覆盖两种密钥长度的套件。 func testSuite() *cipherx.Suite { return cipherx.NewSuite("TEST", aes.NewCipher, 16, 16, 32) } func TestSuiteMetadata(t *testing.T) { suite := testSuite() if got := suite.Name(); got != "TEST" { t.Errorf("Name() = %q, 期望 TEST", got) } if got := suite.BlockSize(); got != 16 { t.Errorf("BlockSize() = %d, 期望 16", got) } sizes := suite.KeySizes() if len(sizes) != 2 || sizes[0] != 16 || sizes[1] != 32 { t.Errorf("KeySizes() = %v, 期望 [16 32]", sizes) } // KeySizes 必须返回副本,改动它不应影响套件本身 sizes[0] = 999 if again := suite.KeySizes(); again[0] != 16 { t.Error("KeySizes 返回了内部切片,调用方可意外篡改套件配置") } } func TestSuiteNewBlockValidatesKeyLength(t *testing.T) { suite := testSuite() for _, size := range []int{16, 32} { key := bytes.Repeat([]byte{0x11}, size) if _, err := suite.NewBlock(key); err != nil { t.Errorf("NewBlock(密钥长度 %d) 失败: %v", size, err) } } for _, size := range []int{0, 8, 15, 17, 24, 31, 64} { key := bytes.Repeat([]byte{0x11}, size) if _, err := suite.NewBlock(key); !errors.Is(err, cipherx.ErrInvalidKeySize) { t.Errorf("NewBlock(密钥长度 %d): 期望 ErrInvalidKeySize, 得到 %v", size, err) } } } // TestSuiteWithoutKeySizes 验证未声明密钥长度时由底层实现校验, // 且失败仍被统一归类为 ErrInvalidKeySize(Blowfish 走的就是这条路径)。 func TestSuiteWithoutKeySizes(t *testing.T) { suite := cipherx.NewSuite("NOCHECK", aes.NewCipher, 16) if _, err := suite.NewBlock(bytes.Repeat([]byte{0x11}, 16)); err != nil { t.Fatalf("合法的 16 字节密钥被拒绝: %v", err) } if _, err := suite.NewBlock(bytes.Repeat([]byte{0x11}, 17)); !errors.Is(err, cipherx.ErrInvalidKeySize) { t.Errorf("非法密钥长度: 期望 ErrInvalidKeySize, 得到 %v", err) } } func TestSuiteEncryptDecryptAllModes(t *testing.T) { suite := testSuite() key := bytes.Repeat([]byte{0x42}, 32) plaintext := []byte("suite 往返测试 payload") modes := []cipherx.Mode{cipherx.ECB, cipherx.CBC, cipherx.CFB, cipherx.OFB, cipherx.CTR} for _, mode := range modes { ciphertext, err := suite.Encrypt(mode, plaintext, key) if err != nil { t.Fatalf("%s: Encrypt 失败: %v", mode, err) } decrypted, err := suite.Decrypt(mode, ciphertext, key) if err != nil { t.Fatalf("%s: Decrypt 失败: %v", mode, err) } if !bytes.Equal(decrypted, plaintext) { t.Errorf("%s: 往返不一致", mode) } } // 密钥长度非法时必须在构造阶段就失败 if _, err := suite.Encrypt(cipherx.CBC, plaintext, []byte("short")); !errors.Is(err, cipherx.ErrInvalidKeySize) { t.Errorf("Encrypt 非法密钥: 期望 ErrInvalidKeySize, 得到 %v", err) } if _, err := suite.Decrypt(cipherx.CBC, []byte("x"), []byte("short")); !errors.Is(err, cipherx.ErrInvalidKeySize) { t.Errorf("Decrypt 非法密钥: 期望 ErrInvalidKeySize, 得到 %v", err) } } func TestSuiteWithIV(t *testing.T) { suite := testSuite() key := bytes.Repeat([]byte{0x42}, 16) iv := bytes.Repeat([]byte{0x7E}, 16) plaintext := []byte("explicit iv via suite") for _, mode := range []cipherx.Mode{cipherx.CBC, cipherx.CFB, cipherx.OFB, cipherx.CTR} { ciphertext, err := suite.EncryptWithIV(mode, plaintext, key, iv) if err != nil { t.Fatalf("%s: EncryptWithIV 失败: %v", mode, err) } decrypted, err := suite.DecryptWithIV(mode, ciphertext, key, iv) if err != nil { t.Fatalf("%s: DecryptWithIV 失败: %v", mode, err) } if !bytes.Equal(decrypted, plaintext) { t.Errorf("%s: WithIV 往返不一致", mode) } } if _, err := suite.EncryptWithIV(cipherx.CBC, plaintext, key, []byte("bad")); !errors.Is(err, cipherx.ErrInvalidIVSize) { t.Errorf("非法 IV 长度: 期望 ErrInvalidIVSize, 得到 %v", err) } if _, err := suite.EncryptWithIV(cipherx.ECB, plaintext, key, iv); !errors.Is(err, cipherx.ErrInvalidMode) { t.Errorf("ECB 传 IV: 期望 ErrInvalidMode, 得到 %v", err) } } func TestSuiteHexHelpers(t *testing.T) { suite := testSuite() key := bytes.Repeat([]byte{0x42}, 16) iv := bytes.Repeat([]byte{0x7E}, 16) plaintext := []byte("hex 辅助函数") for _, mode := range []cipherx.Mode{cipherx.ECB, cipherx.CBC, cipherx.CFB, cipherx.OFB, cipherx.CTR} { hexStr, err := suite.EncryptHex(mode, plaintext, key) if err != nil { t.Fatalf("%s: EncryptHex 失败: %v", mode, err) } decrypted, err := suite.DecryptHex(mode, hexStr, key) if err != nil { t.Fatalf("%s: DecryptHex 失败: %v", mode, err) } if !bytes.Equal(decrypted, plaintext) { t.Errorf("%s: Hex 往返不一致", mode) } } // 带显式 IV 的十六进制辅助函数 for _, mode := range []cipherx.Mode{cipherx.CBC, cipherx.CFB, cipherx.OFB, cipherx.CTR} { hexStr, err := suite.EncryptWithIVHex(mode, plaintext, key, iv) if err != nil { t.Fatalf("%s: EncryptWithIVHex 失败: %v", mode, err) } decrypted, err := suite.DecryptWithIVHex(mode, hexStr, key, iv) if err != nil { t.Fatalf("%s: DecryptWithIVHex 失败: %v", mode, err) } if !bytes.Equal(decrypted, plaintext) { t.Errorf("%s: WithIVHex 往返不一致", mode) } } // 非法十六进制 if _, err := suite.DecryptHex(cipherx.CBC, "zz", key); err == nil { t.Error("非法十六进制期望错误") } if _, err := suite.EncryptWithIVHex(cipherx.CBC, plaintext, []byte("short"), iv); !errors.Is(err, cipherx.ErrInvalidKeySize) { t.Errorf("非法密钥: 期望 ErrInvalidKeySize, 得到 %v", err) } if _, err := suite.DecryptWithIVHex(cipherx.CBC, "zz", key, iv); err == nil { t.Error("非法十六进制期望错误") } } // TestSuiteMemberVariants 覆盖 Suite 各方法的失败分支,确保错误在 // 构造阶段就被发现,而不是留到更难排查的位置。 func TestSuiteMemberVariants(t *testing.T) { suite := testSuite() key := bytes.Repeat([]byte{0x42}, 16) iv := bytes.Repeat([]byte{0x7E}, 16) if _, err := suite.Encrypt(cipherx.Mode(99), []byte("x"), key); !errors.Is(err, cipherx.ErrInvalidMode) { t.Errorf("Encrypt 非法模式: 期望 ErrInvalidMode, 得到 %v", err) } if _, err := suite.Decrypt(cipherx.Mode(99), []byte("x"), key); !errors.Is(err, cipherx.ErrInvalidMode) { t.Errorf("Decrypt 非法模式: 期望 ErrInvalidMode, 得到 %v", err) } if _, err := suite.EncryptWithIV(cipherx.Mode(99), []byte("x"), key, iv); !errors.Is(err, cipherx.ErrInvalidMode) { t.Errorf("EncryptWithIV 非法模式: 期望 ErrInvalidMode, 得到 %v", err) } if _, err := suite.DecryptWithIV(cipherx.Mode(99), []byte("x"), key, iv); !errors.Is(err, cipherx.ErrInvalidMode) { t.Errorf("DecryptWithIV 非法模式: 期望 ErrInvalidMode, 得到 %v", err) } if _, err := suite.EncryptHex(cipherx.CBC, []byte("x"), []byte("short")); !errors.Is(err, cipherx.ErrInvalidKeySize) { t.Errorf("EncryptHex 非法密钥: 期望 ErrInvalidKeySize, 得到 %v", err) } if _, err := suite.DecryptWithIV(cipherx.CBC, []byte("x"), key, []byte("bad")); !errors.Is(err, cipherx.ErrInvalidIVSize) { t.Errorf("DecryptWithIV 非法 IV: 期望 ErrInvalidIVSize, 得到 %v", err) } }