golang AES-CBC 加密解密

一代咩神發表於2021-12-26

要弄懂 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 協議》,轉載必須註明作者和本文連結

相關文章