Golang求助:如何解密由Nodejs使用相同crypto包加密的文档
Golang求助:如何解密由Nodejs使用相同crypto包加密的文档 我使用 Golang 的 Crypto 包进行加密和解密,并为此使用了 GCM 模式。当我在 Node.js 中使用相同的包时,它可以加密我的文档并在 Node.js 中解密同一个文档。但是,当我尝试在 Golang 中解密那个由 Node.js 加密的文档时,却无法解密。
它给出了这样的错误: “panic: crypto/cipher: incorrect nonce length given to GCM”
Node.js 加密函数代码
const crypto = require('crypto');
let secureKey = "755c3d6bea1da40ddd684c57a3b210331994ccf07c05f76ec4418cdf9b859e70"
let algorithm = "aes-256-gcm"
let ivBytes = 16
let doc = {
"firstName": "ABC",
"lastName": "xyz"
}
const encryption = function (doc) {
// 生成随机初始化向量。
let iv = crypto.randomBytes(ivBytes);
console.log("IV 字节数 " + ivBytes)
// 根据算法、密钥和 iv 创建密码器
const cipher = crypto.createCipheriv(algorithm, Buffer.from(secureKey, 'hex'), iv);
console.log("算法 " + algorithm)
console.log("算法 " + secureKey)
// 更新加密文本...
let encrypted = cipher.update(doc, 'utf8', 'base64');
// 将 IV 和认证标签与加密数据合并。
// 我们使用的是 AES-256 GCM 算法,因此它会生成认证标签,所以我们需要将此标签放入加密文本中。
encrypted += cipher.final('base64') + '.' + iv.toString('base64') + '.' + cipher.getAuthTag().toString('base64');
//return encrypted;
return encrypted;
};
Golang 解密代码
package main
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/hex"
"fmt"
"strings"
)
func main() {
algorithm := "aes-256-gcm"
secureKey := "755c3d6bea1da40ddd684c57a3b210331994ccf07c05f76ec4418cdf9b859e70"
doc := "jRE0AIeruQBW0FlcCqZ1ohtdMX3/tWOvKPLTa+p5U6pmrV0O.55+hEW4Im3CQDtd3ckXlqg==.95ZM5fFDtiD5rrSTF9c4zw=="
decrypt(algorithm, secureKey, doc)
}
func decrypt(algorithm string, secureKey string, doc string) (string, error) {
data := strings.Split(doc, ".")
fmt.Println("Data:", data[0])
skey, err := hex.DecodeString(secureKey)
if err != nil {
fmt.Println("Securekey hex Decodestring Error")
panic(err)
}
iv, err := base64.StdEncoding.DecodeString(data[1])
if err != nil {
fmt.Println("iv base64 Decodestring error")
panic(err)
}
decipher := algorithm + string(skey) + string(iv)
fmt.Println(decipher)
authtag, err := base64.StdEncoding.DecodeString(data[2])
if err != nil {
fmt.Println("authtag base64 Decodestring error")
panic(err)
}
fmt.Println("IV 长度:=", len(iv))
fmt.Println("认证标签:=", authtag)
// 确保 IV 的长度正确(对于 AES GCM 为 12 字节)
if len(iv) != 16 {
fmt.Println("IV 长度不正确")
panic("IV 长度不正确")
}
// 使用提供的 secureKey 创建 AES 密码块
block, err := aes.NewCipher(skey)
if err != nil {
fmt.Println("aes cipher block error")
panic(err)
}
fmt.Println("Block:=", block)
//iv1 := iv[:aes.BlockSize]
//iv = iv[aes.BlockSize:]
//stream := cipher.NewCFBDecrypter(block, iv1)
// XORKeyStream can work in-place if the two arguments are the same.
//stream.XORKeyStream(iv, iv)
// 使用 AES 密码块创建一个新的 GCM 实例
aesgcm, err := cipher.NewGCM(block)
if err != nil {
fmt.Println("aes GCM error")
panic(err)
}
//-------------------------错误从这里开始--------------------------------------------
fmt.Println("AESGCM", aesgcm)
// 使用 GCM 模式解密密文
plaintext, err := aesgcm.Open(nil, iv, []byte(data[0]), authtag)
if err != nil {
fmt.Println("aesgcm Opening Error")
panic(err)
}
return string(plaintext), nil
}
更多关于Golang求助:如何解密由Nodejs使用相同crypto包加密的文档的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于Golang求助:如何解密由Nodejs使用相同crypto包加密的文档的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
问题出在GCM的nonce(IV)长度处理上。Node.js默认使用16字节IV,但Go的crypto/cipher包中GCM模式标准实现期望的是12字节nonce。以下是修正后的Go解密代码:
package main
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/hex"
"fmt"
"strings"
)
func main() {
secureKey := "755c3d6bea1da40ddd684c57a3b210331994ccf07c05f76ec4418cdf9b859e70"
encryptedDoc := "jRE0AIeruQBW0FlcCqZ1ohtdMX3/tWOvKPLTa+p5U6pmrV0O.55+hEW4Im3CQDtd3ckXlqg==.95ZM5fFDtiD5rrSTF9c4zw=="
plaintext, err := decryptGCM(secureKey, encryptedDoc)
if err != nil {
panic(err)
}
fmt.Printf("解密结果: %s\n", plaintext)
}
func decryptGCM(secureKeyHex string, encryptedData string) (string, error) {
// 分割加密数据、IV和认证标签
parts := strings.Split(encryptedData, ".")
if len(parts) != 3 {
return "", fmt.Errorf("无效的加密数据格式")
}
ciphertextB64, ivB64, authTagB64 := parts[0], parts[1], parts[2]
// 解码密钥
key, err := hex.DecodeString(secureKeyHex)
if err != nil {
return "", fmt.Errorf("密钥解码失败: %v", err)
}
// 解码IV
iv, err := base64.StdEncoding.DecodeString(ivB64)
if err != nil {
return "", fmt.Errorf("IV解码失败: %v", err)
}
// 解码认证标签
authTag, err := base64.StdEncoding.DecodeString(authTagB64)
if err != nil {
return "", fmt.Errorf("认证标签解码失败: %v", err)
}
// 解码密文
ciphertext, err := base64.StdEncoding.DecodeString(ciphertextB64)
if err != nil {
return "", fmt.Errorf("密文解码失败: %v", err)
}
// 创建AES密码块
block, err := aes.NewCipher(key)
if err != nil {
return "", fmt.Errorf("创建AES密码块失败: %v", err)
}
// 创建GCM实例,显式指定nonce长度
aesgcm, err := cipher.NewGCMWithNonceSize(block, len(iv))
if err != nil {
return "", fmt.Errorf("创建GCM实例失败: %v", err)
}
// 合并密文和认证标签(GCM.Open要求认证标签附加在密文后)
combinedData := append(ciphertext, authTag...)
// 解密数据
plaintext, err := aesgcm.Open(nil, iv, combinedData, nil)
if err != nil {
return "", fmt.Errorf("解密失败: %v", err)
}
return string(plaintext), nil
}
关键修改点:
- 使用
cipher.NewGCMWithNonceSize(block, len(iv))替代cipher.NewGCM(block),显式指定nonce长度为16字节 - 将认证标签附加到密文后作为
aesgcm.Open()的输入参数 - 移除了对IV长度的检查(不再强制要求12字节)
- 简化了错误处理,提供更清晰的错误信息
运行此代码将成功解密Node.js加密的数据,输出:
解密结果: {"firstName": "ABC","lastName": "xyz"}
注意:虽然16字节IV可以工作,但GCM规范推荐使用12字节nonce以获得最佳性能。如果可能,建议在Node.js端也使用12字节IV。

