Golang中使用AES解密时遇到的问题:消息验证失败
Golang中使用AES解密时遇到的问题:消息验证失败 我正在编写一个自定义的AES-256加密和解密函数,并将这些函数保存在一个名为zeus的包中。
/*
索引:
101 --> 哈希函数
102 --> 加密函数
*/
package zeus
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
"fmt"
"golang.org/x/crypto/bcrypt"
"io"
"log"
)
// 101 --> 哈希函数
// 接收一个字符串,使用sha256进行哈希,并返回哈希后的字符串
func SHA_256(plainText string) (hashedString string) {
bytes := []byte(plainText)
hash := sha256.Sum256(bytes)
hashedString = fmt.Sprintf("%X\n", hash)
return hashedString
}
// 接收一个字符串,使用sha512进行哈希,并返回哈希后的字符串
func SHA_512(plainText string) (hashedString string) {
bytes := []byte(plainText)
hash := sha512.Sum512(bytes)
hashedString = fmt.Sprintf("%X\n", hash)
return hashedString
}
// 接收明文和成本值,使用bcrypt进行哈希,并返回哈希后的字符串
func Bcrypt(plainText string, cost int) (hashedString string) {
bytes := []byte(plainText)
// 生成哈希字符串
hash, err := bcrypt.GenerateFromPassword(bytes, cost)
if err != nil {
log.Fatal(err)
}
hashedString = fmt.Sprintf("%s\n", hash)
return hashedString
}
// 检查哈希是否与明文匹配
func Bcrypt_Check(hashedString string, plainText string) {
hashedString_bytes := []byte(hashedString)
plainText_bytes := []byte(plainText)
result := bcrypt.CompareHashAndPassword(hashedString_bytes, plainText_bytes)
if result != nil {
log.Fatal(result)
}
fmt.Println("匹配成功!")
}
// 对你输入的密钥字符串进行哈希,将其修剪为32字节并转换为字节
func GenerateKey(key string) (final_key []byte) {
hashed_key := SHA_256(key)
// 将密钥修剪为32字节(AES-256)
trimmed_key := hashed_key[0:32]
// 将修剪后的密钥转换为字节
final_key = []byte(trimmed_key)
return final_key
}
// 102 --> 加密函数
// AES_256加密,接收明文和密钥,返回密文字符串
func Encrypt_AES_256(plainText string, key string) (cipherText_String string) {
// 将消息(文本)转换为字节
plainText_bytes := []byte(plainText)
// 生成密钥
final_key := GenerateKey(key)
// 创建一个新的密码块
cipher1, err := aes.NewCipher(final_key)
// 检查是否有错误,如果有则退出脚本
if err != nil {
log.Fatal(err)
}
// 将密码块传递给伽罗瓦/计数器模式(GCM)
gcm, err := cipher.NewGCM(cipher1)
if err != nil {
log.Fatal(err)
}
// 创建一个大小为Nonce的新字节数组
nonce := make([]byte, gcm.NonceSize())
// 用加密安全的随机序列填充字节数组
_, err = io.ReadFull(rand.Reader, nonce)
if err != nil {
log.Fatal(err)
}
// Seal对明文进行加密和认证,并对附加数据进行认证
cipherText := gcm.Seal(nonce, nonce, plainText_bytes, nil)
cipherText_String = fmt.Sprintf("%X\n", cipherText)
return cipherText_String
}
这是我的主文件:
package main
import (
"crypto/aes"
"crypto/cipher"
// "crypto/rand"
// "crypto/sha256"
// "crypto/sha512"
// "encoding/hex"
"fmt"
"github.com/kkaskdf/zeus"
// "golang.org/x/crypto/bcrypt"
// "io"
// "io/ioutil"
"log"
)
func Decrypt_AES_256(cipherText_String string, key string) (plainText string) {
final_key := zeus.GenerateKey(key)
cipher1, err := aes.NewCipher(final_key)
if err != nil {
log.Fatal(err)
}
gcmDecrypt, err := cipher.NewGCM(cipher1)
if err != nil {
log.Fatal(err)
}
nonceSize := gcmDecrypt.NonceSize()
cipherText_byte := []byte(cipherText_String)
if len(cipherText_byte) < nonceSize {
log.Fatal(err)
}
nonce, encryptedMessage := cipherText_byte[:nonceSize],
cipherText_byte[nonceSize:]
nonce_byte := []byte(nonce)
encryptedMessage_byte := []byte(encryptedMessage)
plaintext, err := gcmDecrypt.Open(nil, nonce_byte, encryptedMessage_byte, nil)
fmt.Println("err0")
if err != nil {
log.Fatal(err)
}
return fmt.Sprintf("%s", plaintext)
}
func main() {
// str1 := "Hi man Can"
// str2 := "Hi man Can"
// fmt.Printf("%v", zeus.SHA_256(str1))
// fmt.Printf("%v", zeus.SHA_512(str1))
// fmt.Printf("%v", zeus.Bcrypt(str1, 5))
// zeus.Bcrypt_Check(zeus.Bcrypt(str1, 5), str2)
password := "This is the password"
plainText := "Hi man Can 32 Hi man Can 23 Hi man Can"
cipherText := zeus.Encrypt_AES_256(plainText, password)
fmt.Printf("%v", cipherText)
fmt.Printf("%v", Decrypt_AES_256(cipherText, password))
}
现在,当我尝试解密密文时,我得到以下输出:
4E4E31C4D70AC4F6F6696CB2921C208BE3124F3CBB5E73AFEE7FBB81F503034AA64EFAB3CC35784D25ED125943E835B9371BA4D3AAC9A292C00A4F256CECEF9A815B
err0
2020/12/11 00:51:49 cipher: message authentication failed
输出中的第一行是加密文本,它是Encrypt_AES_256()函数的输出。
第二行是我打印的一个字符串,用于定位Decrypt_AES_256()函数内部的错误位置。
第三行是此处错误的输出:
plaintext, err := gcmDecrypt.Open(nil, nonce_byte, encryptedMessage_byte, nil)
fmt.Println("err0")
if err != nil {
log.Fatal(err)
}
错误出现在Decrypt_AES_256()函数的这一行:
plaintext, err := gcmDecrypt.Open(nil, nonce_byte, encryptedMessage_byte, nil)
有人知道如何解决这个问题吗?
我遵循了这篇文章的说明:

Golang Encryption Decryption Example | AES Encryption In Go
Golang加密解密示例。我们将看到使用AES算法进行非对称和对称加密解密。我们在Go中实现AES-GCM代码。
预计阅读时间:7分钟
更多关于Golang中使用AES解密时遇到的问题:消息验证失败的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于Golang中使用AES解密时遇到的问题:消息验证失败的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
问题出在Encrypt_AES_256函数返回的是十六进制字符串,而Decrypt_AES_256函数直接将其作为字节处理。fmt.Sprintf("%X\n", cipherText)生成的字符串包含十六进制字符和换行符,需要先解码为原始字节。
以下是修正后的解密函数:
package main
import (
"crypto/aes"
"crypto/cipher"
"encoding/hex"
"fmt"
"github.com/kkaskdf/zeus"
"log"
)
func Decrypt_AES_256(cipherText_String string, key string) (plainText string) {
// 解码十六进制字符串
cipherText_byte, err := hex.DecodeString(cipherText_String)
if err != nil {
log.Fatal(err)
}
final_key := zeus.GenerateKey(key)
cipher1, err := aes.NewCipher(final_key)
if err != nil {
log.Fatal(err)
}
gcmDecrypt, err := cipher.NewGCM(cipher1)
if err != nil {
log.Fatal(err)
}
nonceSize := gcmDecrypt.NonceSize()
if len(cipherText_byte) < nonceSize {
log.Fatal("ciphertext too short")
}
nonce, encryptedMessage := cipherText_byte[:nonceSize], cipherText_byte[nonceSize:]
plaintext, err := gcmDecrypt.Open(nil, nonce, encryptedMessage, nil)
if err != nil {
log.Fatal(err)
}
return string(plaintext)
}
func main() {
password := "This is the password"
plainText := "Hi man Can 32 Hi man Can 23 Hi man Can"
cipherText := zeus.Encrypt_AES_256(plainText, password)
// 移除换行符
cipherText = cipherText[:len(cipherText)-1]
fmt.Printf("密文: %v\n", cipherText)
fmt.Printf("明文: %v\n", Decrypt_AES_256(cipherText, password))
}
同时建议修改Encrypt_AES_256函数,移除末尾的换行符:
func Encrypt_AES_256(plainText string, key string) (cipherText_String string) {
// ... 原有代码 ...
cipherText := gcm.Seal(nonce, nonce, plainText_bytes, nil)
cipherText_String = fmt.Sprintf("%X", cipherText) // 移除\n
return cipherText_String
}
主要问题:
- 加密返回的十六进制字符串包含换行符
\n - 解密时未将十六进制字符串解码为字节
- 解密函数中对nonce和encryptedMessage进行了不必要的类型转换
修正后应该能正常解密。

