完善不同加密方法的使用

This commit is contained in:
yun
2026-09-30 15:49:12 +08:00
parent 034315ddbd
commit 7db722f8b9
69 changed files with 21362 additions and 2563 deletions
+155
View File
@@ -0,0 +1,155 @@
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)
}