不该自己封装crypto底层接口,因密钥管理混乱、模式错配、填充不一致易致panic和解密失败;应抽象encrypter/decrypter接口,内置安全参数,密钥获取解耦,新算法通过接口实现无缝接入。

为什么不该自己封装 crypto 包的底层接口
直接调 crypto/aes、crypto/rsa 这些包写加解密,短期能跑通,但很快会掉进密钥管理混乱、模式参数错配、填充方式不一致的坑里。比如 aes.NewCipher 只接受 16/24/32 字节密钥,但业务传进来的是字符串或 base64,没人统一处理就容易 panic;又比如 rsa.EncryptPKCS1v15 和 rsa.EncryptOAEP 完全不兼容,混用会导致解密失败且错误信息模糊(crypto/rsa: decryption error)。
- 密钥长度、IV 生成、padding 方式必须和算法强绑定,不能靠文档约定
- 不同算法的输入输出类型不统一([]byte / string / []byte / *big.Int),调用方要反复转换
- 没有默认安全参数(如 AES-GCM 默认用 12 字节 nonce,少于这个长度就可能被重放)
定义统一接口:Encrypter / Decrypter 是核心
真正能收敛差异的不是“把所有算法塞进一个 struct”,而是抽象出行为契约。Golang 的 interface 天然适合这事:
type Encrypter interface {
Encrypt(plaintext []byte) ([]byte, error)
}
type Decrypter interface {
Decrypt(ciphertext []byte) ([]byte, error)
}
这样上层代码只关心“我能加密”“我能解密”,不用管背后是 AES 还是 SM4。实际实现时,每个算法封装体都该自带默认安全参数:
-
AESGCMEncrypter初始化时强制生成 12 字节 nonce,并把 nonce 拼在密文前(避免调用方漏传) -
SM4CBCEncrypter内部自动补 PKCS7 填充,不暴露block.Mode细节 - RSA 加密器只接受
*rsa.PrivateKey和*rsa.PublicKey,拒绝 raw []byte 密钥——防止 PEM 解析逻辑散落各处
密钥管理必须脱离算法实例
很多人把密钥硬编码在 NewAESGCM(...) 调用里,或者用全局变量存,结果测试环境用开发密钥、生产环境忘记替换。正确做法是让加密器只接收 func() ([]byte, error) 类型的密钥获取函数:
func NewAESGCM(keyGetter func() ([]byte, error)) (*AESGCM, error) { ... }
这样密钥来源可以是环境变量(os.Getenv("AES_KEY"))、KMS(kmsClient.Decrypt(...))、甚至 HSM 设备,而算法模块完全无感。特别注意:RSA 私钥必须用 *rsa.PrivateKey 类型传入,不能传 PEM 字符串——否则每个地方都要重复写 pem.Decode + x509.ParsePKCS1PrivateKey,极易出错。
- 对称密钥建议用
crypto/rand.Read生成,别用math/rand - 私钥文件读取必须校验
err != nil,PEM block type 错误(比如传了证书当私钥)会返回nil私钥,后续Encrypt直接 panic - 不要在 Encrypter 实例里缓存密钥字节——密钥轮换时实例无法感知
怎么让新算法快速接入而不改老代码
新增国密 SM2 时,只要实现 Encrypter 和 Decrypter 接口,再注册到工厂函数即可:
var Encrypters = map[string]func(func() ([]byte, error)) (Encrypter, error){
"aes-gcm": NewAESGCM,
"sm2": NewSM2Encrypter, // 新增这一行
}
调用方代码完全不变:
enc, _ := Encrypters["sm2"](keyGetter)
ciphertext, _ := enc.Encrypt([]byte("hello"))
真正的复杂点在于:SM2 的签名和加密是两套流程,不能简单套用 RSA 接口。所以 NewSM2Encrypter 必须明确区分是用于加密(sm2.Encrypt)还是签名(sm2.Sign)——它们密钥格式、参数、错误码都不一样,强行合并会导致接口语义污染。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











