【问题标题】:Building a decryption function by CryptoJSCryptoJS 构建解密函数
【发布时间】:2021-10-11 04:55:29
【问题描述】:

我在使用 CryptoJS 构建解密函数时遇到问题。

我已经通过函数 create_mpg_aes_encrypt() 创建了一个加密字符串,并尝试构建另一个函数 create_mpg_aes_decrypt() 来解密我生成的字符串。

但是,我无法得到我想要的结果。

另一方面,我构建了一个函数 create_aes_encrypt_try(),以测试 CryptoJS 如何进行解密。我成功地得到了我想要的结果。 但是,根据我的观察,我传递给 CryptoJS.AES.decrypt() 的参数不是字符串,而是数组。

我要构建的函数是用于解密字符串。有什么方法可以解析字符串或者我如何构建这个函数?

  //------------------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*/

以下是我想实现的php参考代码

function create_aes_decrypt($parameter = "", $key = "", $iv = "") {
return openssl_decrypt(hex2bin($parameter),'AES-256-CBC', 
$key, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv); 

}

【问题讨论】:

  • 只是一般说明:加密适用于二进制数据,而不适用于字符串。如果您的输入是一个字符串(或例如 json-object/string),您需要在加密之前将其转换为二进制形式(例如使用 CryptoJS.enc.Utf8.parse)。加密函数的 输出 不适合常规字符串(想想十六进制 x00),因为很多数据是不可打印的。要获得用于传输或存储的字符串编码,最好在输出上使用 Base64 编码,并在解密之前运行 Base64 解码。有时输出是“十六进制编码字符串” - 然后运行十六进制到二进制转换。
  • @MichaelFehr - 您在哪里确切地看到问题? JavaScript 对象 序列化,密文 十六进制编码,并且将字符串作为纯文本 允许 用于CryptoJS.AES.encrypt()。但是,它的输出不能简单地用 Base64 或十六进制编码,因为它是一个 JavaScript 对象。
  • @Topaco:我在代码中看不到问题(这就是我写“一般”的原因)。对我来说,看起来 OP 对他自己的函数的不同输入类型有点困惑。
  • @MichaelFehr - 嗯,好的,但有点令人困惑,期待在代码中找到列出的问题之一(不确定我错过了什么),谢谢。
  • 究竟什么是不清楚的(编码是一个广泛的领域)?如果您提到编码器,请尝试例如this。否则,最好在 SO 上发布问题并详细描述问题。但是,请确保对编程的引用是可识别的,否则问题可能会被关闭(请注意,关于教程、书籍等的问题与 SO 无关)。 IE。发布例如MVCE 和测试数据,以便理解问题。

标签: javascript php encryption aes cryptojs


【解决方案1】:

解密失败,因为CryptoJS.AES.decrypt() 需要CipherParams 对象:

{ciphertext: CryptoJS.enc.Hex.parse(ciphertextHex)}

其中ciphertextHex 是十六进制编码的密文。如果你解决了这个问题,解密就可以了。这在下面的 JavaScript 中显示。

  //------------------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>

目前,在使用 CryptoJS 代码进行加密时,您在 32 字节的块大小上使用 PKCS7 填充,这对于 16 字节的块大小的 AES 来说效率很低。
当使用 PHP 代码(因此也使用 CryptoJS 代码)解密时,填充被禁用,即不被删除,这对于 PKCS7 来说是相当不寻常的。
所以不清楚 CryptoJS 代码中的加密是否使用了正确的填充。因此,如果 CryptoJS 代码中使用的填充确实与 PHP 代码中的填充匹配,则应检查加密。

【讨论】:

    猜你喜欢
    • 2020-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多