golang AES-CBC 加密解密

要弄懂 CBC 加密解密,需要先弄清楚其原理,这样在写代码的时候思路也会清晰很多。
原理可以搜索 AES-CBC 和 PKCS7Padding,我也是 google、bing 出来的。
这里就不说了,直接贴代码,采用 PKCS7Padding 的方式填充明文。

python 的在这里:博客:python AES-CBC 加密解密 ,可以跟 golang 无缝对接。

// CBCEncrypt AES-CBC 加密
// key 必须是 16(AES-128)、24(AES-192) 或 32(AES-256) 字节的 AES 密钥;
// 初始化向量 iv 为随机的 16 位字符串 (必须是16位),
// 解密需要用到这个相同的 iv,因此将它包含在密文的开头。
func CBCEncrypt(plaintext string, key string) string {
    defer func() {
        if err := recover(); err != nil {
            fmt.Println("cbc decrypt err:", err)
        }
    }()

    block, err := aes.NewCipher([]byte(key))
    if err != nil {
        return ""
    }

    blockSize := len(key)
    padding := blockSize - len(plaintext)%blockSize // 填充字节
    if padding == 0 {
        padding = blockSize
    }

    // 填充 padding 个 byte(padding) 到 plaintext
    plaintext += string(bytes.Repeat([]byte{byte(padding)}, padding))
    ciphertext := make([]byte, aes.BlockSize+len(plaintext))
    iv := ciphertext[:aes.BlockSize]
    if _, err = rand.Read(iv); err != nil { // 将同时写到 ciphertext 的开头
        return ""
    }

    mode := cipher.NewCBCEncrypter(block, iv)
    mode.CryptBlocks(ciphertext[aes.BlockSize:], []byte(plaintext))

    return base64.StdEncoding.EncodeToString(ciphertext)
}
// CBCDecrypt AES-CBC 解密
func CBCDecrypt(ciphertext string, key string) string {
    defer func() {
        if err := recover(); err != nil {
            fmt.Println("cbc decrypt err:", err)
        }
    }()

    block, err := aes.NewCipher([]byte(key))
    if err != nil {
        return ""
    }

    ciphercode, err := base64.StdEncoding.DecodeString(ciphertext)
    if err != nil {
        return ""
    }

    iv := ciphercode[:aes.BlockSize]        // 密文的前 16 个字节为 iv
    ciphercode = ciphercode[aes.BlockSize:] // 正式密文

    mode := cipher.NewCBCDecrypter(block, iv)
    mode.CryptBlocks(ciphercode, ciphercode)

    plaintext := string(ciphercode) // ↓ 减去 padding
    return plaintext[:len(plaintext)-int(plaintext[len(plaintext)-1])]
}
func main() {
    key := "hwWe\mS2`kvu8,z/|hvop7^~)ZUgQhHT" // 32位 AES-256

    ciphertext, err := CBCEncrypt(`{"code":200,"data":{"apts":[]},"message":"","success":true}`, key)
    if err != nil {
        fmt.Println("cbc encrypt err:", err)
        return
    }

    plaintext, err := CBCDecrypt(ciphertext, key)
    if err != nil {
        fmt.Println("cbc decrypt err:", err)
        return
    }

    fmt.Println("ciphertext:", ciphertext)
    fmt.Println("plaintext:", plaintext)
本作品采用《CC 协议》,转载必须注明作者和本文链接
一代咩神
讨论数量: 2

路过看到,推一下我的开源库 github.com/Hanson/aes

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!