AES-CBC加密实现完整笔记
文件路径:
1. 主流程完整实现
func main() {
// 生成32字节密钥(AES-256)
key, _ := generateKey(32) // 实际使用时需要处理错误
// 生成16字节随机IV
iv, _ := generateIV() // 实际使用时需要处理错误
// 创建AES加密块
block, _ := aes.NewCipher(key)
// 原始数据(支持任意长度)
src := []byte("我是原始数据哦!")
// CBC模式加密
dst := encrypt(src, iv, block)
fmt.Printf("加密结果: %x\n", dst)
// CBC模式解密
decrypted := decrypt(dst, iv, block)
fmt.Printf("解密结果: %s\n", decrypted)
}
2. 密钥与IV生成器
// 生成密码学安全随机密钥
func generateKey(i int) ([]byte, error) {
key := make([]byte, i)
if _, err := rand.Read(key); err != nil {
return nil, err
}
return key, nil
}
// 生成符合块大小的随机IV
<mcsymbol name="generateIV" filename="main.go" path="/Users/niu/Documents/jwt/main.go" startline="47" type="function"></mcsymbol>
func generateIV() ([]byte, error) {
iv := make([]byte, aes.BlockSize)
if _, err := rand.Read(iv); err != nil {
return nil, err
}
return iv, nil
}
3. 完整加密流程
func encrypt(src []byte, iv []byte, block cipher.Block) []byte {
// 初始化CBC加密器
mode := cipher.NewCBCEncrypter(block, iv)
// 添加PKCS7填充
paddedSrc := PKCS7Pad(src, aes.BlockSize)
// 准备加密缓冲区
dst := make([]byte, len(paddedSrc))
// 执行加密(原地加密,输入输出缓冲区可相同)
mode.CryptBlocks(dst, paddedSrc)
return dst
}
4. 完整解密流程
func decrypt(dst []byte, iv []byte, block cipher.Block) []byte {
// 初始化CBC解密器
decryptMode := cipher.NewCBCDecrypter(block, iv)
// 准备解密缓冲区
decrypted := make([]byte, len(dst))
// 执行解密(原地解密,输入输出缓冲区可相同)
decryptMode.CryptBlocks(decrypted, dst)
// 去除填充并验证
unpadded, err := PKCS7Unpad(decrypted, aes.BlockSize)
if err != nil {
panic(err) // 实际使用应返回错误
}
return unpadded
}
5. 完整填充实现
// PKCS7填充实现
func PKCS7Pad(data []byte, blockSize int) []byte {
padding := blockSize - len(data)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(data, padText...)
}
// PKCS7去填充实现(含完整校验)
<mcsymbol name="PKCS7Unpad" filename="main.go" path="/Users/niu/Documents/jwt/main.go" startline="94" type="function"></mcsymbol>
func PKCS7Unpad(data []byte, blockSize int) ([]byte, error) {
// 校验1:数据长度必须是块大小的整数倍
if len(data)%blockSize != 0 || len(data) == 0 {
return nil, fmt.Errorf("无效的填充长度")
}
// 校验2:填充值必须在1-blockSize范围内
padding := int(data[len(data)-1])
if padding < 1 || padding > blockSize {
return nil, fmt.Errorf("无效的填充值")
}
// 校验3:所有填充字节必须相同
for i := 0; i < padding; i++ {
if data[len(data)-1-i] != byte(padding) {
return nil, fmt.Errorf("填充验证失败")
}
}
return data[:len(data)-padding], nil
}
6. 完整注释说明
/* 密钥长度说明:
- AES-128:16字节
- AES-192:24字节
- AES-256:32字节
⚠️ 密钥长度错误会导致aes.NewCipher panic
IV使用规范:
- 长度必须等于块大小(16字节)
- CBC模式下必须使用密码学安全随机数
- 禁止重复使用相同IV */
完整代码
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
)
func main() {
key, _ := generateKey(32) // 实际使用时需要处理错误
iv, _ := generateIV() // 实际使用时需要处理错误
// 创建加密块
block, _ := aes.NewCipher(key)
// 原始数据(任意长度)
src := []byte("我是原始数据哦!")
// 加密
dst := encrypt(src, iv, block)
fmt.Printf("加密结果: %x\n", dst)
// 解密
decrypted := decrypt(dst, iv, block)
fmt.Printf("解密结果: %s\n", decrypted)
}
// 生成随机key和IV
/* - 密钥长度 :
- AES-128:16字节(当前代码使用的)
- AES-192:24字节
- AES-256:32字节
- 🔥 如果密钥长度不符合, aes.NewCipher 会直接panic
- IV长度 :
- 必须严格等于块大小(16字节)
- 在CBC模式下需要是随机的不可预测值(当前示例中的固定IV仅用于测试) */
func generateKey(i int) ([]byte, error) {
key := make([]byte, i) // 256位(32字节)的密钥
_, err := rand.Read(key)
if err != nil {
return nil, err
}
return key, nil
}
// 推荐生成随机IV(需要添加crypto/rand导入)
func generateIV() ([]byte, error) {
iv := make([]byte, aes.BlockSize)
if _, err := rand.Read(iv); err != nil {
return nil, err
}
return iv, nil
}
// 加密函数
func encrypt(src []byte, iv []byte, block cipher.Block) []byte {
// 使用CBC模式
mode := cipher.NewCBCEncrypter(block, iv)
// 原始数据(任意长度)
// 添加PKCS7填充
paddedSrc := PKCS7Pad(src, aes.BlockSize)
// 创建目标缓冲区
dst := make([]byte, len(paddedSrc))
// 执行加密
mode.CryptBlocks(dst, paddedSrc)
return dst
}
// 解密函数
func decrypt(dst []byte, iv []byte, block cipher.Block) []byte {
// 新增解密部分
decryptMode := cipher.NewCBCDecrypter(block, iv)
decrypted := make([]byte, len(dst))
decryptMode.CryptBlocks(decrypted, dst)
unpadded, err := PKCS7Unpad(decrypted, aes.BlockSize)
if err != nil {
panic(err)
}
// 返回去除填充后的原始数据
return unpadded
}
// PKCS7填充函数
func PKCS7Pad(data []byte, blockSize int) []byte {
padding := blockSize - len(data)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(data, padText...)
}
// 新增去除填充函数(带错误检查)
func PKCS7Unpad(data []byte, blockSize int) ([]byte, error) {
if len(data)%blockSize != 0 || len(data) == 0 {
return nil, fmt.Errorf("无效的填充长度")
}
padding := int(data[len(data)-1])
if padding < 1 || padding > blockSize {
return nil, fmt.Errorf("无效的填充值")
}
for i := 0; i < padding; i++ {
if data[len(data)-1-i] != byte(padding) {
return nil, fmt.Errorf("填充验证失败")
}
}
return data[:len(data)-padding], nil
}