当前位置:首页 > Go > 正文

Go语言实现AES-CBC加密(详解crypto/aes包的CBC模式使用)

在现代软件开发中,数据安全至关重要。Go语言通过标准库中的 crypto/aes 包提供了强大的对称加密支持。本文将详细讲解如何使用 Go语言 的 crypto/aes 包配合 CBC 模式进行加密和解密操作,即使是编程新手也能轻松上手。

什么是AES和CBC模式?

AES(Advanced Encryption Standard)是一种广泛使用的对称加密算法,具有高安全性与高性能。而 CBC(Cipher Block Chaining,密码分组链接)是 AES 的一种工作模式,它通过引入初始化向量(IV)使得相同的明文每次加密结果都不同,从而增强安全性。

Go语言实现AES-CBC加密(详解crypto/aes包的CBC模式使用) Go语言 AES加密 CBC模式 crypto/aes包 第1张

准备工作:导入必要的包

在 Go 中实现 AES-CBC 加密,我们需要以下标准库:

import (    "crypto/aes"    "crypto/cipher"    "crypto/rand"    "fmt"    "io")

AES-CBC 加密实现步骤

AES-CBC 加密的关键在于:

  • 密钥(Key)必须为 16、24 或 32 字节(对应 AES-128、AES-192、AES-256)
  • 初始化向量(IV)长度必须等于 AES 的块大小(16 字节)
  • 明文需填充至块大小的整数倍(常用 PKCS7 填充)

1. 实现 PKCS7 填充

func pkcs7Padding(data []byte, blockSize int) []byte {    padding := blockSize - len(data)%blockSize    padtext := make([]byte, padding)    for i := range padtext {        padtext[i] = byte(padding)    }    return append(data, padtext...)}

2. AES-CBC 加密函数

func encryptAES_CBC(plaintext []byte, key []byte) ([]byte, error) {    // 创建 AES 密码块    block, err := aes.NewCipher(key)    if err != nil {        return nil, err    }    // PKCS7 填充    plaintext = pkcs7Padding(plaintext, block.BlockSize())    // 生成随机 IV    ciphertext := make([]byte, aes.BlockSize+len(plaintext))    iv := ciphertext[:aes.BlockSize]    if _, err := io.ReadFull(rand.Reader, iv); err != nil {        return nil, err    }    // 使用 CBC 模式加密    mode := cipher.NewCBCEncrypter(block, iv)    mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)    return ciphertext, nil}

AES-CBC 解密实现

1. PKCS7 去填充

func pkcs7Unpadding(data []byte) ([]byte, error) {    length := len(data)    if length == 0 {        return nil, fmt.Errorf("invalid padding")    }    unpadding := int(data[length-1])    if unpadding > length {        return nil, fmt.Errorf("invalid padding size")    }    return data[:(length - unpadding)], nil}

2. 解密函数

func decryptAES_CBC(ciphertext []byte, key []byte) ([]byte, error) {    block, err := aes.NewCipher(key)    if err != nil {        return nil, err    }    if len(ciphertext) < aes.BlockSize {        return nil, fmt.Errorf("ciphertext too short")    }    iv := ciphertext[:aes.BlockSize]    ciphertext = ciphertext[aes.BlockSize:]    // CBC 解密    mode := cipher.NewCBCDecrypter(block, iv)    mode.CryptBlocks(ciphertext, ciphertext)    // 去除填充    return pkcs7Unpadding(ciphertext)}

完整示例代码

package mainimport (    "crypto/aes"    "crypto/cipher"    "crypto/rand"    "fmt"    "io")func pkcs7Padding(data []byte, blockSize int) []byte {    padding := blockSize - len(data)%blockSize    padtext := make([]byte, padding)    for i := range padtext {        padtext[i] = byte(padding)    }    return append(data, padtext...)}func pkcs7Unpadding(data []byte) ([]byte, error) {    length := len(data)    if length == 0 {        return nil, fmt.Errorf("invalid padding")    }    unpadding := int(data[length-1])    if unpadding > length {        return nil, fmt.Errorf("invalid padding size")    }    return data[:(length - unpadding)], nil}func encryptAES_CBC(plaintext []byte, key []byte) ([]byte, error) {    block, err := aes.NewCipher(key)    if err != nil {        return nil, err    }    plaintext = pkcs7Padding(plaintext, block.BlockSize())    ciphertext := make([]byte, aes.BlockSize+len(plaintext))    iv := ciphertext[:aes.BlockSize]    if _, err := io.ReadFull(rand.Reader, iv); err != nil {        return nil, err    }    mode := cipher.NewCBCEncrypter(block, iv)    mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)    return ciphertext, nil}func decryptAES_CBC(ciphertext []byte, key []byte) ([]byte, error) {    block, err := aes.NewCipher(key)    if err != nil {        return nil, err    }    if len(ciphertext) < aes.BlockSize {        return nil, fmt.Errorf("ciphertext too short")    }    iv := ciphertext[:aes.BlockSize]    ciphertext = ciphertext[aes.BlockSize:]    mode := cipher.NewCBCDecrypter(block, iv)    mode.CryptBlocks(ciphertext, ciphertext)    return pkcs7Unpadding(ciphertext)}func main() {    key := []byte("my-secret-key-16") // 16字节,AES-128    plaintext := []byte("Hello, this is a secret message!")    // 加密    encrypted, err := encryptAES_CBC(plaintext, key)    if err != nil {        panic(err)    }    fmt.Printf("Encrypted: %x\n", encrypted)    // 解密    decrypted, err := decryptAES_CBC(encrypted, key)    if err != nil {        panic(err)    }    fmt.Printf("Decrypted: %s\n", decrypted)}

安全提示

虽然 AES-CBC 是一种经典加密模式,但在实际生产环境中,建议优先考虑使用更安全的模式如 GCM(Galois/Counter Mode),因为它同时提供加密和认证。此外,请确保密钥安全存储,不要硬编码在源码中。

总结

通过本教程,你已经掌握了如何在 Go语言 中使用 crypto/aes 包结合 CBC 模式进行数据加密与解密。我们详细讲解了密钥、IV、填充等关键概念,并提供了完整的可运行代码。希望这篇关于 Go语言 AES加密 CBC模式 的指南能帮助你构建更安全的应用程序!

关键词:Go语言、AES加密、CBC模式、crypto/aes包