Golang 中的 AES 256 CTR 加密 使用 CryptoJS 在 Node JS 中解密,密钥是字符串(不是 WordArray)
我必须使用 golang 将数据发送到具有 Nodejs 加密的现有(旧)服务,该服务将使用 AES CTR 模式和 Crypto JS 库来解密数据。我编写了一些代码如下(密钥加密是这个问题中的随机密钥)。
Golang 加密:
func main() {
rawKey := "46ca2a49c8074dadb99843f6b86c5975"
data := "the quick brown fox jumps over the lazy dog"
encryptedData := encrypt(rawKey, data);
fmt.Println("encrypted data: ", encryptedData)
}
func encrypt(rawKey string, data string) string {
key := []byte(rawKey)
plainText := []byte(data)
// Create new AES cipher block
block, err := aes.NewCipher(key)
if err != nil {
return err.Error()
}
// The IV (Initialization Vector) need to be unique, but not secure.
// Therefore, it's common to include it at the beginning of the cipher text.
cipherText := make([]byte, aes.BlockSize+len(plainText))
// Creates IV.
iv := cipherText[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return err.Error()
}
// Encrypt.
encryptStream := cipher.NewCTR(block, iv)
encryptStream.XORKeyStream(cipherText[aes.BlockSize:], plainText)
ivHex := hex.EncodeToString(iv)
encryptedDataHex := hex.EncodeToString(cipherText)
return encryptedDataHex[0:len(ivHex)] + ":" + encryptedDataHex[len(ivHex):]
}
GO Playground:https://play.golang.com/p/2I-BTyvUBKJ< /a> 结果如下
加密数据: c7fa927db8d5e95d7a56eaa74ccdbd6c:5c739daa892ca101c0d0f9b122721a1ccda0de473ce1a1d81b12fafa2e63965022c10036fc991d1650e900
并使用带有 CryptoJS 库的 NodeJS 成功解码以下代码
const decrypt = function (rawKey, encryptedData) {
const split = encryptedData.split(':');
if (split.length < 2) return '';
const reb64 = CryptoJS.enc.Hex.parse(split[1]);
const bytes = reb64.toString(CryptoJS.enc.Base64);
const hexKey = rawKey.split("")
.map(c => c.charCodeAt(0).toString(16).padStart(2, "0"))
.join("");
const hash = CryptoJS.AES.decrypt(bytes, CryptoJS.enc.Hex.parse(hexKey), {
iv: CryptoJS.enc.Hex.parse(split[0]),
mode: CryptoJS.mode.CTR,
padding: CryptoJS.pad.NoPadding
});
const plain = hash.toString(CryptoJS.enc.Utf8);
return plain;
}
const rawKey = '46ca2a49c8074dadb99843f6b86c5975';
const encryptedData = 'c7fa927db8d5e95d7a56eaa74ccdbd6c:5c739daa892ca101c0d0f9b122721a1ccda0de473ce1a1d81b12fafa2e63965022c10036fc991d1650e900';
const decyptedData = decrypt(rawKey, encryptedData);
document.write("decrypted data: ", decyptedData)
JS Fiddle: https://jsfiddle.net/cnq7g0vp/ 结果如下
解密数据:敏捷的棕色狐狸跳过了懒狗
但是nodejs中现有的(遗留)服务是解密代码直接使用字符串密钥作为密钥参数(不是WordArray)并且没有NoPadding参数,如下所示:
const decrypt = function (rawKey, encryptedData) {
const split = encryptedData.split(':');
if (split.length < 2) return '';
const reb64 = CryptoJS.enc.Hex.parse(split[1]);
const bytes = reb64.toString(CryptoJS.enc.Base64);
const hash = CryptoJS.AES.decrypt(bytes, rawKey, {
iv: split[0],
mode: CryptoJS.mode.CTR
});
const plain = hash.toString(CryptoJS.enc.Utf8);
return plain;
}
const rawKey = '46ca2a49c8074dadb99843f6b86c5975';
const encryptedData = '3a010df5e7985f2d8b0c00e3a096347f:6036327f61cf3050fddd6ea76325148c81e170a63b514b8818afbbb894c874c87cc4c865300c7b2d0e0fd8';
const decyptedData = decrypt(rawKey, encryptedData);
document.write("decrypted data: ", decyptedData);
JS Fiddle:https://jsfiddle.net/pyntruLj/ 并且失败,没有结果(空字符串)如下:
解密数据:
这是我在 golang 加密代码中编写的内容,以匹配 nodejs 解密代码,通过使用 BytesToKeyAES256CBCMD5 来获取密钥和基于我上一个问题
func main() {
rawKey := "46ca2a49c8074dadb99843f6b86c5975"
data := "the quick brown fox jumps over the lazy dog"
encryptedData := encrypt(rawKey, data);
fmt.Println("encrypted data: ", encryptedData)
}
func encrypt(rawKey string, data string) string {
salt := []byte("ABCDEFGH") // hardcoded at the moment
// Gets key and IV from raw key.
key, iv := evp.BytesToKeyAES256CBCMD5([]byte(salt), []byte(rawKey))
plainText := []byte(data)
// Create new AES cipher block
block, err := aes.NewCipher(key)
if err != nil {
return err.Error()
}
cipherText := make([]byte, len(plainText))
// Encrypt.
encryptStream := cipher.NewCTR(block, iv)
encryptStream.XORKeyStream(cipherText, plainText)
ivHex := hex.EncodeToString(iv)
encryptedDataHex := hex.EncodeToString(cipherText)
return ivHex + ":" + encryptedDataHex
}
GO Playground 的提示的 iv: https://play.golang.com/p/luyTVhvtyOn 和输出如下:
加密数据: 3a010df5e7985f2d8b0c00e3a096347f:6036327f61cf3050fddd6ea76325148c81e170a63b514b8818afbbb894c874c87cc4c865300c7b2d0e0fd8
任何人都可以帮忙吗我的 golang 代码有什么问题吗?能够通过直接在 CryptoJS 解密代码上使用字符串密钥来解密(而且我也无法更改 nodejs 实现,因为它是遗留代码)?
I have to send data by using golang to existing (legacy) service with nodejs encryption that will decrypt data using AES CTR mode with Crypto JS libray. I have made some code as follow (the key encryption is a random key in this question).
Golang Encryption:
func main() {
rawKey := "46ca2a49c8074dadb99843f6b86c5975"
data := "the quick brown fox jumps over the lazy dog"
encryptedData := encrypt(rawKey, data);
fmt.Println("encrypted data: ", encryptedData)
}
func encrypt(rawKey string, data string) string {
key := []byte(rawKey)
plainText := []byte(data)
// Create new AES cipher block
block, err := aes.NewCipher(key)
if err != nil {
return err.Error()
}
// The IV (Initialization Vector) need to be unique, but not secure.
// Therefore, it's common to include it at the beginning of the cipher text.
cipherText := make([]byte, aes.BlockSize+len(plainText))
// Creates IV.
iv := cipherText[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return err.Error()
}
// Encrypt.
encryptStream := cipher.NewCTR(block, iv)
encryptStream.XORKeyStream(cipherText[aes.BlockSize:], plainText)
ivHex := hex.EncodeToString(iv)
encryptedDataHex := hex.EncodeToString(cipherText)
return encryptedDataHex[0:len(ivHex)] + ":" + encryptedDataHex[len(ivHex):]
}
GO Playground: https://play.golang.com/p/2I-BTyvUBKJ
and the result is as follows
encrypted data:
c7fa927db8d5e95d7a56eaa74ccdbd6c:5c739daa892ca101c0d0f9b122721a1ccda0de473ce1a1d81b12fafa2e63965022c10036fc991d1650e900
and successfully decode with nodejs with CryptoJS library with following code
const decrypt = function (rawKey, encryptedData) {
const split = encryptedData.split(':');
if (split.length < 2) return '';
const reb64 = CryptoJS.enc.Hex.parse(split[1]);
const bytes = reb64.toString(CryptoJS.enc.Base64);
const hexKey = rawKey.split("")
.map(c => c.charCodeAt(0).toString(16).padStart(2, "0"))
.join("");
const hash = CryptoJS.AES.decrypt(bytes, CryptoJS.enc.Hex.parse(hexKey), {
iv: CryptoJS.enc.Hex.parse(split[0]),
mode: CryptoJS.mode.CTR,
padding: CryptoJS.pad.NoPadding
});
const plain = hash.toString(CryptoJS.enc.Utf8);
return plain;
}
const rawKey = '46ca2a49c8074dadb99843f6b86c5975';
const encryptedData = 'c7fa927db8d5e95d7a56eaa74ccdbd6c:5c739daa892ca101c0d0f9b122721a1ccda0de473ce1a1d81b12fafa2e63965022c10036fc991d1650e900';
const decyptedData = decrypt(rawKey, encryptedData);
document.write("decrypted data: ", decyptedData)
JS Fiddle: https://jsfiddle.net/cnq7g0vp/ and the result is as follows
decrypted data: the quick brown fox jumps over the lazy dog
But the existing (legacy) service in nodejs is decryption code is using the string key directly as key parameter (not WordArray) and without NoPadding parameter as follows:
const decrypt = function (rawKey, encryptedData) {
const split = encryptedData.split(':');
if (split.length < 2) return '';
const reb64 = CryptoJS.enc.Hex.parse(split[1]);
const bytes = reb64.toString(CryptoJS.enc.Base64);
const hash = CryptoJS.AES.decrypt(bytes, rawKey, {
iv: split[0],
mode: CryptoJS.mode.CTR
});
const plain = hash.toString(CryptoJS.enc.Utf8);
return plain;
}
const rawKey = '46ca2a49c8074dadb99843f6b86c5975';
const encryptedData = '3a010df5e7985f2d8b0c00e3a096347f:6036327f61cf3050fddd6ea76325148c81e170a63b514b8818afbbb894c874c87cc4c865300c7b2d0e0fd8';
const decyptedData = decrypt(rawKey, encryptedData);
document.write("decrypted data: ", decyptedData);
JS Fiddle: https://jsfiddle.net/pyntruLj/ and it failed with no result (empty string) as follows:
decrypted data:
and here is what I write in golang encryption code to match the nodejs decryption code by using BytesToKeyAES256CBCMD5 to get the key and the iv based on the hint on my previous question
func main() {
rawKey := "46ca2a49c8074dadb99843f6b86c5975"
data := "the quick brown fox jumps over the lazy dog"
encryptedData := encrypt(rawKey, data);
fmt.Println("encrypted data: ", encryptedData)
}
func encrypt(rawKey string, data string) string {
salt := []byte("ABCDEFGH") // hardcoded at the moment
// Gets key and IV from raw key.
key, iv := evp.BytesToKeyAES256CBCMD5([]byte(salt), []byte(rawKey))
plainText := []byte(data)
// Create new AES cipher block
block, err := aes.NewCipher(key)
if err != nil {
return err.Error()
}
cipherText := make([]byte, len(plainText))
// Encrypt.
encryptStream := cipher.NewCTR(block, iv)
encryptStream.XORKeyStream(cipherText, plainText)
ivHex := hex.EncodeToString(iv)
encryptedDataHex := hex.EncodeToString(cipherText)
return ivHex + ":" + encryptedDataHex
}
GO Playground: https://play.golang.com/p/luyTVhvtyOn and the output is as follows:
encrypted data:
3a010df5e7985f2d8b0c00e3a096347f:6036327f61cf3050fddd6ea76325148c81e170a63b514b8818afbbb894c874c87cc4c865300c7b2d0e0fd8
Can anyone help me what's wrong with my golang code to be able to be decrypted by using string key directly on CryptoJS decrypt code (also I cant change the nodejs implemention since it's a legacy code)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
代码基本上没问题,只有一些小问题:
以下代码对应于您的代码,并通过 PKCS#7 填充和结果的格式/编码进行扩展(请考虑代码中的注释)。请注意,在您的代码中,为了简单起见,使用了硬编码盐,但实际上出于安全原因必须应用随机生成的盐:
输出为:
该密文可以使用旧代码解密:
The code is mostly OK, there are just a few minor issues:
The following code corresponds to your code, extended by the PKCS#7 padding and the formatting/encoding of the result (consider the comments in the code). Note that, as in your code, a hard-coded salt is used for simplicity, but in practice a randomly generated salt must be applied for security reasons:
The output is:
This ciphertext can be decrypted with the legacy code: