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