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)?