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
}

每日更新-免费小火箭账号
不要错过任何机会,探索最新的应用和游戏,就在我们的平台。
立即访问
最后修改:2025 年 04 月 12 日
如果觉得我的文章对你有用,请随意赞赏