package cipherx import ( "crypto/cipher" "encoding/hex" "errors" "fmt" "strings" ) // ErrInvalidKeySize 表示密钥长度不被算法接受。 var ErrInvalidKeySize = errors.New("cipherx: invalid key size") // Suite 把一个具体的分组密码算法(分组构造方式 + 允许的密钥长度)与通用模式 // 操作绑定在一起。 // // 引入 Suite 的目的是消除各算法包之间重复的模式实现:aesx / desx / tdesx / // blowfishx 只需声明「如何用密钥构造分组」,ECB/CBC/CFB/OFB/CTR 的加解密、 // 填充、IV 处理与长度校验全部由 Suite 统一提供。 type Suite struct { name string newBlock func(key []byte) (cipher.Block, error) keySizes []int blockSize int } // NewSuite 创建一个算法套件。 // // name 用于错误信息(如 "AES");newBlock 通常是标准库的 aes.NewCipher / // des.NewCipher / des.NewTripleDESCipher 或 x/crypto 的 blowfish.NewCipher; // blockSize 是该算法的分组长度;keySizes 为允许的密钥长度(字节)。 // keySizes 留空表示密钥长度由 newBlock 自行校验(适用于 Blowfish 这类 // 密钥长度可变且非离散取值的算法)。 func NewSuite(name string, newBlock func(key []byte) (cipher.Block, error), blockSize int, keySizes ...int) *Suite { sizes := make([]int, len(keySizes)) copy(sizes, keySizes) return &Suite{ name: name, newBlock: newBlock, keySizes: sizes, blockSize: blockSize, } } // Name 返回算法名称。 func (s *Suite) Name() string { return s.name } // BlockSize 返回分组长度(字节)。 func (s *Suite) BlockSize() int { return s.blockSize } // KeySizes 返回允许的密钥长度(字节)。若为空,表示不限制为离散取值。 func (s *Suite) KeySizes() []int { out := make([]int, len(s.keySizes)) copy(out, s.keySizes) return out } // NewBlock 校验密钥长度后构造分组密码。 // // 所有算法包都应通过本方法构造分组,以便统一错误语义:密钥长度非法时返回的 // 错误可以用 errors.Is(err, ErrInvalidKeySize) 判断。 func (s *Suite) NewBlock(key []byte) (cipher.Block, error) { if len(s.keySizes) > 0 { ok := false for _, size := range s.keySizes { if len(key) == size { ok = true break } } if !ok { return nil, fmt.Errorf("%s: 密钥长度 %d 非法, 允许 %v: %w", s.name, len(key), s.keySizes, ErrInvalidKeySize) } } block, err := s.newBlock(key) if err != nil { // 底层实现(如 blowfish)也会校验密钥长度,统一归类。 return nil, fmt.Errorf("%s: 构造分组密码失败: %w", s.name, errors.Join(ErrInvalidKeySize, err)) } return block, nil } // Encrypt 用随机 IV 加密(IV 前置,格式为 iv||ciphertext;ECB 无 IV)。 func (s *Suite) Encrypt(mode Mode, plaintext, key []byte) ([]byte, error) { block, err := s.NewBlock(key) if err != nil { return nil, err } return Encrypt(block, mode, plaintext) } // Decrypt 解密 Encrypt 产生的数据(IV 前置格式)。 func (s *Suite) Decrypt(mode Mode, ciphertext, key []byte) ([]byte, error) { block, err := s.NewBlock(key) if err != nil { return nil, err } return Decrypt(block, mode, ciphertext) } // EncryptWithIV 使用调用方提供的 IV 加密,返回值不含 IV。 func (s *Suite) EncryptWithIV(mode Mode, plaintext, key, iv []byte) ([]byte, error) { block, err := s.NewBlock(key) if err != nil { return nil, err } return EncryptWithIV(block, mode, plaintext, iv) } // DecryptWithIV 使用调用方提供的 IV 解密。 func (s *Suite) DecryptWithIV(mode Mode, ciphertext, key, iv []byte) ([]byte, error) { block, err := s.NewBlock(key) if err != nil { return nil, err } return DecryptWithIV(block, mode, ciphertext, iv) } // EncryptHex 与 Encrypt 相同,返回大写十六进制字符串。 func (s *Suite) EncryptHex(mode Mode, plaintext, key []byte) (string, error) { ciphertext, err := s.Encrypt(mode, plaintext, key) if err != nil { return "", err } return strings.ToUpper(hex.EncodeToString(ciphertext)), nil } // DecryptHex 解密十六进制密文,大小写均可。 func (s *Suite) DecryptHex(mode Mode, ciphertextHex string, key []byte) ([]byte, error) { ciphertext, err := decodeHex(ciphertextHex) if err != nil { return nil, err } return s.Decrypt(mode, ciphertext, key) } // EncryptWithIVHex 与 EncryptWithIV 相同,返回大写十六进制字符串。 func (s *Suite) EncryptWithIVHex(mode Mode, plaintext, key, iv []byte) (string, error) { ciphertext, err := s.EncryptWithIV(mode, plaintext, key, iv) if err != nil { return "", err } return strings.ToUpper(hex.EncodeToString(ciphertext)), nil } // DecryptWithIVHex 解密十六进制密文,使用调用方提供的 IV。 func (s *Suite) DecryptWithIVHex(mode Mode, ciphertextHex string, key, iv []byte) ([]byte, error) { ciphertext, err := decodeHex(ciphertextHex) if err != nil { return nil, err } return s.DecryptWithIV(mode, ciphertext, key, iv) }