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

230 lines
8.5 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 blowfishx 提供 Blowfish 分组密码的加解密封装,支持 ECB/CBC/CFB/OFB/CTR。
//
// Blowfish 本身没有被攻破,但它的分组长度只有 64 位,与 3DES 一样存在 Sweet32
// 风险:同一密钥下加密超过约 32 GB 数据后,生日攻击可能恢复明文分组。因此它
// 适合短消息,不适合大批量数据。作为 AES 的替代品,ChaCha20-Poly1305 或
// AES-GCM 是更好的选择。
//
// 另外,本包所有模式都**不提供完整性保护**,密文可被篡改而不被发现。若需要
// 完整性,请使用 AEAD 或额外配合 HMAC 做「先加密后认证」。
package blowfishx
import (
"crypto/cipher"
"crypto/rand"
"encoding/hex"
"fmt"
"io"
//lint:ignore SA1019 Blowfish 已被上游标记为废弃(建议改用 AES 或 ChaCha20);本包保留它只为与既有系统互操作,包注释已说明其 64 位分组的 Sweet32 风险。
"golang.org/x/crypto/blowfish"
"code.yun.ink/pkg/encryptx/cipherx"
)
const (
// BlockSize 是 Blowfish 的分组长度(字节)。64 位分组存在 Sweet32 风险。
BlockSize = blowfish.BlockSize
// MinKeySize 是本包允许的最小密钥长度(字节)。
//
// 底层实现接受 1 字节起的任意长度,但过短的密钥强度过低,故本包要求至少 4 字节。
MinKeySize = 4
// MaxKeySize 是 Blowfish 允许的最大密钥长度(字节)。
MaxKeySize = 56
// DefaultKeySize 是推荐的默认密钥长度(字节)。
DefaultKeySize = 32
)
// Suite 绑定 Blowfish 的分组构造方式。密钥长度由底层实现校验(1..56 字节),
// Suite 会把失败统一包装为 cipherx.ErrInvalidKeySize。
//
// 导出它是为了让调用方能够以统一方式驱动任意模式,而无需在本包与 cipherx
// 之间写 switch。
var Suite = cipherx.NewSuite("Blowfish", newBlock, BlockSize)
// newBlock 把 blowfish.NewCipher 适配为 cipherx.Suite 需要的签名。
func newBlock(key []byte) (cipher.Block, error) {
return blowfish.NewCipher(key)
}
// GenerateKey 用 crypto/rand 生成指定长度的 Blowfish 密钥。
//
// keySize 必须在 [MinKeySize, MaxKeySize] 范围内;不确定时使用 DefaultKeySize。
func GenerateKey(keySize int) ([]byte, error) {
if keySize < MinKeySize || keySize > MaxKeySize {
return nil, fmt.Errorf("blowfishx: 密钥长度 %d 超出 [%d,%d]: %w",
keySize, MinKeySize, MaxKeySize, cipherx.ErrInvalidKeySize)
}
key := make([]byte, keySize)
if _, err := io.ReadFull(rand.Reader, key); err != nil {
return nil, fmt.Errorf("blowfishx: 生成密钥失败: %w", err)
}
return key, nil
}
// GenerateKeyHex 生成 Blowfish 密钥并以十六进制字符串返回。
//
// 注意:返回值是**编码后的文本**,不能直接当密钥使用。读回后必须先解码
// (encoding/hex 的 DecodeString,或本库的 hexx.Decode),再传给 Encrypt/Decrypt。
func GenerateKeyHex(keySize int) (string, error) {
key, err := GenerateKey(keySize)
if err != nil {
return "", err
}
return hex.EncodeToString(key), nil
}
// ---- ECB ----
//
// 警告:ECB 不具备语义安全性,相同的明文分组会产生相同的密文分组。
// EncryptECB 使用 Blowfish-ECB 加密并做 PKCS#7 填充。
func EncryptECB(plaintext, key []byte) ([]byte, error) {
return Suite.Encrypt(cipherx.ECB, plaintext, key)
}
// DecryptECB 解密 Blowfish-ECB 密文。
func DecryptECB(ciphertext, key []byte) ([]byte, error) {
return Suite.Decrypt(cipherx.ECB, ciphertext, key)
}
// EncryptECBHex 与 EncryptECB 相同,返回大写十六进制字符串。
func EncryptECBHex(plaintext, key []byte) (string, error) {
return Suite.EncryptHex(cipherx.ECB, plaintext, key)
}
// DecryptECBHex 解密十六进制 Blowfish-ECB 密文,大小写均可。
func DecryptECBHex(ciphertextHex string, key []byte) ([]byte, error) {
return Suite.DecryptHex(cipherx.ECB, ciphertextHex, key)
}
// ---- CBC ----
// EncryptCBC 使用 Blowfish-CBC 加密,随机 IV 前置在密文之前。
func EncryptCBC(plaintext, key []byte) ([]byte, error) {
return Suite.Encrypt(cipherx.CBC, plaintext, key)
}
// DecryptCBC 解密 Blowfish-CBC 密文(IV 前置格式)。
func DecryptCBC(ciphertext, key []byte) ([]byte, error) {
return Suite.Decrypt(cipherx.CBC, ciphertext, key)
}
// EncryptCBCHex 与 EncryptCBC 相同,返回大写十六进制字符串。
func EncryptCBCHex(plaintext, key []byte) (string, error) {
return Suite.EncryptHex(cipherx.CBC, plaintext, key)
}
// DecryptCBCHex 解密十六进制 Blowfish-CBC 密文。
func DecryptCBCHex(ciphertextHex string, key []byte) ([]byte, error) {
return Suite.DecryptHex(cipherx.CBC, ciphertextHex, key)
}
// EncryptCBCWithIV 使用调用方指定的 IV 加密,返回值不含 IV。
//
// 仅用于与规定了固定 IV 的既有系统互操作。
func EncryptCBCWithIV(plaintext, key, iv []byte) ([]byte, error) {
return Suite.EncryptWithIV(cipherx.CBC, plaintext, key, iv)
}
// DecryptCBCWithIV 使用调用方指定的 IV 解密。
func DecryptCBCWithIV(ciphertext, key, iv []byte) ([]byte, error) {
return Suite.DecryptWithIV(cipherx.CBC, ciphertext, key, iv)
}
// ---- CFB ----
// EncryptCFB 使用 Blowfish-CFB 加密,随机 IV 前置在密文之前。
func EncryptCFB(plaintext, key []byte) ([]byte, error) {
return Suite.Encrypt(cipherx.CFB, plaintext, key)
}
// DecryptCFB 解密 Blowfish-CFB 密文(IV 前置格式)。
func DecryptCFB(ciphertext, key []byte) ([]byte, error) {
return Suite.Decrypt(cipherx.CFB, ciphertext, key)
}
// EncryptCFBHex 与 EncryptCFB 相同,返回大写十六进制字符串。
func EncryptCFBHex(plaintext, key []byte) (string, error) {
return Suite.EncryptHex(cipherx.CFB, plaintext, key)
}
// DecryptCFBHex 解密十六进制 Blowfish-CFB 密文。
func DecryptCFBHex(ciphertextHex string, key []byte) ([]byte, error) {
return Suite.DecryptHex(cipherx.CFB, ciphertextHex, key)
}
// EncryptCFBWithIV 使用调用方指定的 IV 加密,返回值不含 IV。
func EncryptCFBWithIV(plaintext, key, iv []byte) ([]byte, error) {
return Suite.EncryptWithIV(cipherx.CFB, plaintext, key, iv)
}
// DecryptCFBWithIV 使用调用方指定的 IV 解密。
func DecryptCFBWithIV(ciphertext, key, iv []byte) ([]byte, error) {
return Suite.DecryptWithIV(cipherx.CFB, ciphertext, key, iv)
}
// ---- OFB ----
// EncryptOFB 使用 Blowfish-OFB 加密,随机 IV 前置在密文之前。
func EncryptOFB(plaintext, key []byte) ([]byte, error) {
return Suite.Encrypt(cipherx.OFB, plaintext, key)
}
// DecryptOFB 解密 Blowfish-OFB 密文(IV 前置格式)。
func DecryptOFB(ciphertext, key []byte) ([]byte, error) {
return Suite.Decrypt(cipherx.OFB, ciphertext, key)
}
// EncryptOFBHex 与 EncryptOFB 相同,返回大写十六进制字符串。
func EncryptOFBHex(plaintext, key []byte) (string, error) {
return Suite.EncryptHex(cipherx.OFB, plaintext, key)
}
// DecryptOFBHex 解密十六进制 Blowfish-OFB 密文。
func DecryptOFBHex(ciphertextHex string, key []byte) ([]byte, error) {
return Suite.DecryptHex(cipherx.OFB, ciphertextHex, key)
}
// EncryptOFBWithIV 使用调用方指定的 IV 加密,返回值不含 IV。
func EncryptOFBWithIV(plaintext, key, iv []byte) ([]byte, error) {
return Suite.EncryptWithIV(cipherx.OFB, plaintext, key, iv)
}
// DecryptOFBWithIV 使用调用方指定的 IV 解密。
func DecryptOFBWithIV(ciphertext, key, iv []byte) ([]byte, error) {
return Suite.DecryptWithIV(cipherx.OFB, ciphertext, key, iv)
}
// ---- CTR ----
// EncryptCTR 使用 Blowfish-CTR 加密,随机 IV 前置在密文之前。
func EncryptCTR(plaintext, key []byte) ([]byte, error) {
return Suite.Encrypt(cipherx.CTR, plaintext, key)
}
// DecryptCTR 解密 Blowfish-CTR 密文(IV 前置格式)。
func DecryptCTR(ciphertext, key []byte) ([]byte, error) {
return Suite.Decrypt(cipherx.CTR, ciphertext, key)
}
// EncryptCTRHex 与 EncryptCTR 相同,返回大写十六进制字符串。
func EncryptCTRHex(plaintext, key []byte) (string, error) {
return Suite.EncryptHex(cipherx.CTR, plaintext, key)
}
// DecryptCTRHex 解密十六进制 Blowfish-CTR 密文。
func DecryptCTRHex(ciphertextHex string, key []byte) ([]byte, error) {
return Suite.DecryptHex(cipherx.CTR, ciphertextHex, key)
}
// EncryptCTRWithIV 使用调用方指定的 IV 加密,返回值不含 IV。
func EncryptCTRWithIV(plaintext, key, iv []byte) ([]byte, error) {
return Suite.EncryptWithIV(cipherx.CTR, plaintext, key, iv)
}
// DecryptCTRWithIV 使用调用方指定的 IV 解密。
func DecryptCTRWithIV(ciphertext, key, iv []byte) ([]byte, error) {
return Suite.DecryptWithIV(cipherx.CTR, ciphertext, key, iv)
}