Golang实现AES256-CBC加密后,OpenSSL解密报块长度错误求助
AES256-CBC加密后OpenSSL解密报「最终块长度错误」问题解决
问题描述
我用Golang编写了一个函数,将载荷加密为AES256-CBC字符串后写入磁盘。编译后的程序功能正常,但使用OpenSSL命令解密时出现「最终块长度错误」。
密钥生成命令
export AES_KEY=$(python -c 'import uuid;print(uuid.uuid4().hex)') export AES_IV=$(python -c 'import uuid;print(uuid.uuid4().hex[:16])')
Golang加密解密代码
import ( "crypto/aes" "crypto/cipher" "encoding/base64" "errors" "bytes" "os" ) func GetEnv(key, fallback string) string { if value, ok := os.LookupEnv(key); ok { return value } return fallback } func AesEncrypt(plaintext string) (string, error) { key := GetEnv("AES_KEY", "") iv := GetEnv("AES_IV", "") if key == "" || iv == "" { return "", errors.New("AES_KEY and AES_IV must be set") } bKey := []byte(key) bIV := []byte(iv) bPlaintext := PKCS5Padding([]byte(plaintext), aes.BlockSize) block, err := aes.NewCipher(bKey) if err != nil { return "", err } ciphertext := make([]byte, len(bPlaintext)) mode := cipher.NewCBCEncrypter(block, bIV) mode.CryptBlocks(ciphertext, bPlaintext) return base64.StdEncoding.EncodeToString(ciphertext), nil // return hex.EncodeToString(ciphertext), nil } func PKCS5Padding(ciphertext []byte, blockSize int) []byte { padding := (blockSize - len(ciphertext)%blockSize) padtext := bytes.Repeat([]byte{byte(padding)}, padding) return append(ciphertext, padtext...) } func AesDecrypt(ciphertext string) (string, error) { key := GetEnv("AES_KEY", "") iv := GetEnv("AES_IV", "") if key == "" || iv == "" { return "", errors.New("AES_KEY and AES_IV must be set") } bKey := []byte(key) bIV := []byte(iv) // base64 decode cipherTextDecoded, err := base64.StdEncoding.DecodeString(ciphertext) if err != nil { return "", err } // cipherTextDecoded, err := hex.DecodeString(cipherText) block, err := aes.NewCipher(bKey) if err != nil { return "", err } mode := cipher.NewCBCDecrypter(block, bIV) mode.CryptBlocks([]byte(cipherTextDecoded), []byte(cipherTextDecoded)) return string(cipherTextDecoded), nil }
OpenSSL解密命令
openssl aes-256-cbc -d -a -v -nosalt \ -K $AES_KEY \ -iv $AES_IV \ -in variables.enc -out variables.dec
报错信息
bad decrypt 8503165248:error:06FFF06D:digital envelope routines:CRYPTO_internal:wrong final block length:/AppleInternal/Library/BuildRoots/9e200cfa-7d96-11ed-886f-a23c4f261b56/Library/Caches/com.apple.xbs/Sources/libressl/libressl-3.3/crypto/evp/evp_enc.c:540:
问题根源与解决方案
1. 密钥/IV长度与解析不匹配
- 问题:AES256需要32字节密钥,CBC模式需要16字节IV。当前生成的
AES_KEY是32位十六进制字符(对应16字节),AES_IV是16位十六进制字符(对应8字节),长度不符合要求。同时Golang直接将十六进制字符串转为字节数组(每个字符占1字节),而OpenSSL的-K/-iv参数是将十六进制字符串解码为字节(每两个字符对应1字节),导致两边密钥/IV完全不一致。 - 解决:
- 修正密钥/IV生成命令,生成符合长度要求的十六进制字符串:
# 生成32字节密钥(对应64位十六进制字符) export AES_KEY=$(python -c 'import os;print(os.urandom(32).hex())') # 生成16字节IV(对应32位十六进制字符) export AES_IV=$(python -c 'import os;print(os.urandom(16).hex())') - 修正Golang代码中密钥/IV的解析逻辑,使用
hex.DecodeString将十六进制字符串解码为字节数组:import "encoding/hex" func AesEncrypt(plaintext string) (string, error) { key := GetEnv("AES_KEY", "") iv := GetEnv("AES_IV", "") if key == "" || iv == "" { return "", errors.New("AES_KEY and AES_IV must be set") } // 解析十六进制密钥为字节数组 bKey, err := hex.DecodeString(key) if err != nil { return "", err } // 解析十六进制IV为字节数组 bIV, err := hex.DecodeString(iv) if err != nil { return "", err } bPlaintext := PKCS5Padding([]byte(plaintext), aes.BlockSize) block, err := aes.NewCipher(bKey) if err != nil { return "", err } ciphertext := make([]byte, len(bPlaintext)) mode := cipher.NewCBCEncrypter(block, bIV) mode.CryptBlocks(ciphertext, bPlaintext) // 将base64分割为每64字符一行,匹配OpenSSL默认格式 encoded := base64.StdEncoding.EncodeToString(ciphertext) wrapped := "" for i := 0; i < len(encoded); i += 64 { end := i + 64 if end > len(encoded) { end = len(encoded) } wrapped += encoded[i:end] + "\n" } return wrapped, nil }
- 修正密钥/IV生成命令,生成符合长度要求的十六进制字符串:
2. 解密函数未去除PKCS5填充
- 问题:Golang解密函数未去除加密时添加的PKCS5填充,导致解密结果末尾存在多余字节,也可能引发OpenSSL的块长度错误。
- 解决:添加PKCS5去填充函数,并在解密后调用:
func PKCS5Unpadding(plaintext []byte) []byte { length := len(plaintext) if length == 0 { return plaintext } padding := int(plaintext[length-1]) return plaintext[:length-padding] } func AesDecrypt(ciphertext string) (string, error) { key := GetEnv("AES_KEY", "") iv := GetEnv("AES_IV", "") if key == "" || iv == "" { return "", errors.New("AES_KEY and AES_IV must be set") } bKey, err := hex.DecodeString(key) if err != nil { return "", err } bIV, err := hex.DecodeString(iv) if err != nil { return "", err } cipherTextDecoded, err := base64.StdEncoding.DecodeString(ciphertext) if err != nil { return "", err } block, err := aes.NewCipher(bKey) if err != nil { return "", err } mode := cipher.NewCBCDecrypter(block, bIV) mode.CryptBlocks(cipherTextDecoded, cipherTextDecoded) // 去除PKCS5填充 plaintext := PKCS5Unpadding(cipherTextDecoded) return string(plaintext), nil }
3. 验证修正后流程
- 重新生成密钥和IV
- 用修正后的Golang代码加密载荷并写入文件
- 使用原OpenSSL命令解密,即可正常得到明文
内容的提问来源于stack exchange,提问作者user1314147
相关产品推荐
相关产品推荐

