Files
2026-09-30 15:49:12 +08:00

200 lines
7.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
}
}