不一定。aes加密前是否需十六进制解码取决于输入类型:十六进制字符串(如"48656c6c6f")必须用hex.decodestring()转为[]byte;明文字符串(如"hello")可直接转换,但需注意块对齐填充;密钥同理,hex字符串须解码,否则报invalid key size或乱码。

Go里AES加密前必须做十六进制解码吗?
不一定。是否需要先解码,取决于你传给aes.Encrypt的输入类型:如果原始数据是十六进制字符串(比如"48656c6c6f"),就必须用hex.DecodeString()转成[]byte;如果已经是明文字符串(比如"Hello"),直接[]byte(str)即可。
常见错误现象:crypto/aes: invalid key size 或加密后乱码,往往是因为把 hex 字符串当字节流直接用了,没解码——AES 操作对象永远是[]byte,不是字符串。
- 十六进制字符串 → 加密前必须
hex.DecodeString() - 普通 UTF-8 字符串 → 直接
[]byte(str),但要注意长度是否满足块对齐(需填充) - 密钥也同理:若密钥是 hex 字符串(如
"a1b2c3..."),同样要先解码;若已知是 16/24/32 字节切片,跳过
为什么AES加密后输出常转成十六进制或Base64?
因为aes.Encrypt()返回的是原始二进制[]byte,含不可见控制字符和\0,无法安全打印、传输或存入JSON/DB字段。转换成hex或base64是为了可读性与兼容性。
性能影响很小,但选择有差异:
-
hex.EncodeToString():结果长度翻倍(每字节变2字符),纯ASCII,适合调试和日志 -
base64.StdEncoding.EncodeToString():结果约增1/3长度,更紧凑,标准网络协议常用 - 不要用
fmt.Sprintf("%x", data)处理大数组,它比hex.EncodeToString()慢且内存开销高
Go中AES填充(PKCS#7)怎么写才不出错?
Go标准库crypto/cipher不自带填充逻辑,必须手动实现。最常见坑是:填充字节数算错、解密后去填充越界、或误用PKCS#5(只适用于8字节块)。
AES块大小固定为16字节,PKCS#7填充规则是:补足到16的倍数,填充字节值等于填充长度。
- 填充函数示例:
pad := make([]byte, 16-len(data)%16); for i := range pad { pad[i] = byte(len(pad)) } - 解密后必须检查最后一个字节是否在
1–16范围内,再截取;否则可能被篡改攻击利用 - 如果明文长度恰为16的倍数(如16、32字节),仍要填充16个
0x10,不能跳过
DES和AES在Go里初始化密钥长度要求不同
DES(包括3DES)和AES对密钥长度的要求是硬性约束,不满足会直接panic或返回invalid key size错误。
- AES-128:密钥必须是
16字节(不是16字符!注意UTF-8编码下中文字符占3字节) - AES-192:
24字节;AES-256:32字节 - DES:
8字节;3DES(三重DES):16或24字节(取决于模式) - 别用
md5.Sum([]byte(key)).Sum(nil)直接当AES密钥——虽然长度固定16字节,但MD5输出缺乏密钥随机性,应优先用crypto/rand生成
真正容易被忽略的点:填充和解填充必须严格配对,且解密前永远要校验密文长度是否为16的倍数;十六进制字符串和字节切片的边界混淆,是Go加密代码里最常导致“加密能跑、解密失败”的原因。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











