Reputation: 47
I'm encountering a problem on building a decryption function by CryptoJS.
I've create an encryption string through the function create_mpg_aes_encrypt(), and trying to built another function create_mpg_aes_decrypt() to decrypt the string I generated.
However, I can't get the result I want.
On the other hands, I built a function create_aes_encrypt_try(), to test how CryptoJS work on decryption. I successfully got the result I want. However, according to my observation, the parameter I pass into CryptoJS.AES.decrypt() isn't a string, but an array.
The function I want to build is for decrypting the string. Is there any way to parse the string or how could I build this function?
//------------------Info--------------------------------------------------------------
let parameter = {
MerchantID: "3430112",
RespondType: "JSON",
TimeStamp: "1485232229",
Version: "1.4",
MerchantOrderNo: "S_1485232229",
Amt: 40,
ItemDesc: "UnitTest",
}
//-------------------Encryption-------------------------------------------------------
const Hashkey = "12345678901234567890123456789012";
const HashIV = "1234567890123456";
const CryptoJS = require('crypto-js');
const key = CryptoJS.enc.Utf8.parse(Hashkey);
const iv = CryptoJS.enc.Utf8.parse(HashIV);
const encrypt_mode = {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
};
//-----------------------------Main---------------------------------------------------
let str = create_mpg_aes_encrypt(parameter, key, encrypt_mode);
//console.log(str);
let try_decryption = create_mpg_aes_encrypt_try(parameter, key, encrypt_mode);
let result = create_aes_decrypt(str, key, encrypt_mode);
console.log(result);
//-----------------------------Function-----------------------------------------------
function create_mpg_aes_encrypt(parameter, key, encrypt_mode){
//URL ENCODED QUERY STRING
let params = new URLSearchParams(parameter);
let str = params.toString();
str = addpadding(str);
console.log(str, "\n");
let encrypted_data = CryptoJS.AES.encrypt(str, key, encrypt_mode);
encrypted_data = encrypted_data.ciphertext.toString(CryptoJS.enc.Hex);
str = encrypted_data;
str = str.trim();
return str;
}
function hex2bin (s) {
const ret = []
let i = 0
let l
s += ''
for (l = s.length; i < l; i += 2) {
const c = parseInt(s.substr(i, 1), 16)
const k = parseInt(s.substr(i + 1, 1), 16)
if (isNaN(c) || isNaN(k)) return false
ret.push((c << 4) | k)
}
return String.fromCharCode.apply(String, ret)
}
function addpadding(str){
const blocksize = 32;
let len = str.length;
let pad = blocksize - (len % blocksize);
let string = str;
for(let i = 0; i < pad; i++) {
string += String.fromCharCode(pad);
}
return string;
}
function create_aes_decrypt(tradeinfo, key, encrypt_mode) {
let return_str = "";
let decrypted_data = CryptoJS.AES.decrypt(tradeinfo, key, encrypt_mode);
decrypted_data = decrypted_data.toString();
//console.log(decrypted_data, "\n");
return_str = decrypted_data;
return return_str;
}
function create_mpg_aes_encrypt_try(parameter, key, encrypt_mode){
// URL ENCODED QUERY STRING
let params = new URLSearchParams(parameter);
let str = params.toString();
str = addpadding(str);
let encrypted_data = CryptoJS.AES.encrypt(str, key, encrypt_mode);
let decrypted_data = CryptoJS.AES.decrypt(encrypted_data, key, encrypt_mode);
encrypted_data = encrypted_data.ciphertext.toString(CryptoJS.enc.Hex);
decrypted_data = decrypted_data.toString();
decrypted_data = hex2bin(decrypted_data);
console.log(encrypted_data, "\n");
console.log(decrypted_data, "\n");
str = encrypted_data;
str = str.trim();
return str;
}
// The result I want
/*the string going to be encrypted
MerchantID=3430112&RespondType=JSON&TimeStamp=1485232229&Version=1.4&MerchantOrderNo=S_1485232229&Amt=40&ItemDesc=UnitTest*/
/*the string after encryption
ff91c8aa01379e4de621a44e5f11f72e4d25bdb1a18242db6cef9ef07d80b0165e476fd1d9acaa53170272c82d122961e1a0700a7427cfa1cf90db7f6d6593bbc93102a4d4b9b66d9974c13c31a7ab4bba1d4e0790f0cbbbd7ad64c6d3c8012a601ceaa808bff70f94a8efa5a4f984b9d41304ffd879612177c622f75f4214fa*/
/* After Decryption
MerchantID=3430112&RespondType=JSON&TimeStamp=1485232229&Version=1.4&MerchantOrderNo=S_1485232229&Amt=40&ItemDesc=UnitTest*/
The following is the php reference code I wanted to realized
function create_aes_decrypt($parameter = "", $key = "", $iv = "") {
return openssl_decrypt(hex2bin($parameter),'AES-256-CBC',
$key, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);
}
Upvotes: 1
Views: 716
Reputation: 49351
Decryption fails because CryptoJS.AES.decrypt()
requires a CipherParams
object:
{ciphertext: CryptoJS.enc.Hex.parse(ciphertextHex)}
where ciphertextHex
is the hex encoded ciphertext. If you fix this, decryption works. This is shown in the JavaScript below.
//------------------Info--------------------------------------------------------------
let parameter = {
MerchantID: "3430112",
RespondType: "JSON",
TimeStamp: "1485232229",
Version: "1.4",
MerchantOrderNo: "S_1485232229",
Amt: 40,
ItemDesc: "UnitTest",
}
//-------------------Encryption-------------------------------------------------------
const Hashkey = "12345678901234567890123456789012";
const HashIV = "1234567890123456";
const key = CryptoJS.enc.Utf8.parse(Hashkey);
const iv = CryptoJS.enc.Utf8.parse(HashIV);
const encrypt_mode = {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
};
//-----------------------------Main---------------------------------------------------
let str = create_mpg_aes_encrypt(parameter, key, encrypt_mode);
let try_decryption = create_mpg_aes_encrypt_try(parameter, key, encrypt_mode);
let result = create_aes_decrypt(str, key, encrypt_mode);
document.getElementById("pt_3").innerHTML = result;
//-----------------------------Function-----------------------------------------------
function create_mpg_aes_encrypt(parameter, key, encrypt_mode){
//URL ENCODED QUERY STRING
let params = new URLSearchParams(parameter);
let str = params.toString();
str = addpadding(str);
document.getElementById("pt_1").innerHTML = str;
let encrypted_data = CryptoJS.AES.encrypt(str, key, encrypt_mode);
encrypted_data = encrypted_data.ciphertext.toString(CryptoJS.enc.Hex);
str = encrypted_data;
str = str.trim();
return str;
}
function hex2bin (s) {
const ret = []
let i = 0
let l
s += ''
for (l = s.length; i < l; i += 2) {
const c = parseInt(s.substr(i, 1), 16)
const k = parseInt(s.substr(i + 1, 1), 16)
if (isNaN(c) || isNaN(k)) return false
ret.push((c << 4) | k)
}
return String.fromCharCode.apply(String, ret)
}
function addpadding(str){
const blocksize = 32;
let len = str.length;
let pad = blocksize - (len % blocksize);
let string = str;
for(let i = 0; i < pad; i++) {
string += String.fromCharCode(pad);
}
return string;
}
function create_aes_decrypt(tradeinfo, key, encrypt_mode) {
let return_str = "";
/*
let decrypted_data = CryptoJS.AES.decrypt(tradeinfo, key, encrypt_mode);
decrypted_data = decrypted_data.toString();
*/
// Fix
let decrypted_data = CryptoJS.AES.decrypt({ciphertext: CryptoJS.enc.Hex.parse(tradeinfo)}, key, encrypt_mode);
decrypted_data = decrypted_data.toString(CryptoJS.enc.Utf8);
return_str = decrypted_data;
return return_str;
}
function create_mpg_aes_encrypt_try(parameter, key, encrypt_mode){
// URL ENCODED QUERY STRING
let params = new URLSearchParams(parameter);
let str = params.toString();
str = addpadding(str);
let encrypted_data = CryptoJS.AES.encrypt(str, key, encrypt_mode);
let decrypted_data = CryptoJS.AES.decrypt(encrypted_data, key, encrypt_mode);
encrypted_data = encrypted_data.ciphertext.toString(CryptoJS.enc.Hex);
decrypted_data = decrypted_data.toString();
decrypted_data = hex2bin(decrypted_data);
document.getElementById("ct_2").innerHTML = encrypted_data;
document.getElementById("pt_2").innerHTML = decrypted_data;
str = encrypted_data;
str = str.trim();
return str;
}
// The result I want
/*the string going to be encrypted
MerchantID=3430112&RespondType=JSON&TimeStamp=1485232229&Version=1.4&MerchantOrderNo=S_1485232229&Amt=40&ItemDesc=UnitTest*/
/*the string after encryption
ff91c8aa01379e4de621a44e5f11f72e4d25bdb1a18242db6cef9ef07d80b0165e476fd1d9acaa53170272c82d122961e1a0700a7427cfa1cf90db7f6d6593bbc93102a4d4b9b66d9974c13c31a7ab4bba1d4e0790f0cbbbd7ad64c6d3c8012a601ceaa808bff70f94a8efa5a4f984b9d41304ffd879612177c622f75f4214fa*/
/* After Decryption
MerchantID=3430112&RespondType=JSON&TimeStamp=1485232229&Version=1.4&MerchantOrderNo=S_1485232229&Amt=40&ItemDesc=UnitTest*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
<p style="font-family:'Courier New', monospace;" id="pt_1"></p>
<p style="font-family:'Courier New', monospace;" id="ct_2"></p>
<p style="font-family:'Courier New', monospace;" id="pt_2"></p>
<p style="font-family:'Courier New', monospace;" id="pt_3"></p>
Currently, when encrypting with the CryptoJS code, you use PKCS7 padding over a block size of 32 bytes, which is inefficient for AES with a block size of 16 bytes.
When decrypting with the PHP code (and therefore also with the CryptoJS code), the padding is disabled, i.e. not removed, which is rather unusual for PKCS7.
So it's unclear whether the correct padding is used for encryption in the CryptoJS code. Therefore, you should check for encryption if the padding used in the CryptoJS code really matches that of the PHP code.
Upvotes: 1