使用意外值实现aes 256

nwwlzxa7  于 2021-09-29  发布在  Java
关注(0)|答案(1)|浏览(551)

我试图用javascript cryptojs.aes.encrypt实现aes-256加密,并期望得到与php实现的代码相同的结果。但是,我不仅得到了错误的答案,而且字符串长度不一致。
这是我的javascript代码,带有我使用的参数、键和iv。

let parameter = {
    MerchantID: "3430112",
    RespondType: "JSON",
    TimeStamp: "1485232229",
    Version: "1.4",
    MerchantOrderNo: "S_1485232229",
    Amt: 40,
    ItemDesc: "UnitTest",
}
const Hashkey = "12345678901234567890123456789012";
const HashIV = "1234567890123456";

const CryptoJS = require('crypto-js');
// ------------------INFO----------------------------------------

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.Pkcs7 || CryptoJS.pad.ZeroPadding
};

let result = create_mpg_aes_encrypt(parameter, key, encrypt_mode);
//console.log(result.length);
//console.log(result);

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);
    let encryptedData = CryptoJS.AES.encrypt(str, key, encrypt_mode);
    encryptedData = encryptedData.toString();
    //console.log(encryptedData.length);
    //console.log(encryptedData);

    str = encryptedData;
    str = str.trim();
    return str;
}

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;
}
// The result I really get.
/*
/5HIqgE3nk3mIaROXxH3Lk0lvbGhgkLbbO+e8H2AsBZeR2/R2ayqUxcCcsgtEilh4aBwCnQnz6HPkNt/bWWTu8kxAqTUubZtmXTBPDGnq0u6HU4HkPDLu9etZMbTyAEqYBzqqAi/9w+UqO+lpPmEudQTBP/YeWEhd8Yi919CFPr5gMs1sJrNNskJ560tkazr

* /

下面是我想要实现的php代码。

function create_mpg_aes_encrypt($parameter = "", $key = "", $iv = ""){
    $return_str = '';
    if(!empty($parameter)) {

        // URL ENCODED QUERY STRING
       $return_str = http_build_query($parameter);
       //echo $return_str;
    }

    return trim(bin2hex(openssl_encrypt(addpadding($return_str), 'aes-256-cbc', 
    $key, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv)));
}
function addpadding($string, $blocksize = 32) {
    $len = strlen($string);
    $pad = $blocksize - ($len % $blocksize);
    $string .= str_repeat(chr($pad), $pad);
    return $string;
}

$trade_info_arr = array( 
    'MerchantID' => 3430112, 
    'RespondType' => 'JSON',
    'TimeStamp' => 1485232229, 
    'Version' => 1.4,
    'MerchantOrderNo' => 'S_1485232229', 
    'Amt' => 40, 
    'ItemDesc' => 'UnitTest' 
);  

$mer_key ='12345678901234567890123456789012';
$mer_iv = '1234567890123456'; 

// Result I expected to get
/*ff91c8aa01379e4de621a44e5f11f72e4d25bdb1a18242db6cef9ef07d80b0165e476fd1d9acaa53170272c82d122961e1a0700a7427cfa1cf90db7f6d6593bbc93102a4d4b9b66d9974c13c31a7ab4bba1d4e0790f0cbbbd7ad64c6d3c8012a601ceaa808bff70f94a8efa5a4f984b9d41304ffd879612177c622f75f4214fa*/

在这里输入代码

dgsult0t

dgsult0t1#

cryptojs代码中只有两个小错误:
必须禁用默认填充(aes块大小为16字节的pkcs7),因为在中实现了自定义填充(块大小为32字节的pkcs7) addpadding() :

padding: CryptoJS.pad.ZeroPadding

密文必须返回十六进制编码,而不是base64编码:

encryptedData = encryptedData.ciphertext.toString(CryptoJS.enc.Hex);

通过这两个更改,cryptojs代码可以工作并提供所需的结果:

let parameter = {
    MerchantID: "3430112",
    RespondType: "JSON",
    TimeStamp: "1485232229",
    Version: "1.4",
    MerchantOrderNo: "S_1485232229",
    Amt: 40,
    ItemDesc: "UnitTest",
}
const Hashkey = "12345678901234567890123456789012";
const HashIV = "1234567890123456";

//const CryptoJS = require('crypto-js');
// ------------------INFO----------------------------------------

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.Pkcs7 || CryptoJS.pad.ZeroPadding // Fix 1: Disable padding
    padding: CryptoJS.pad.ZeroPadding
};

let result = create_mpg_aes_encrypt(parameter, key, encrypt_mode);
//console.log(result.length);
console.log(result.replace(/(.{48})/g,'$1\n'));

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);
    let encryptedData = CryptoJS.AES.encrypt(str, key, encrypt_mode);
    //encryptedData = encryptedData.toString(); // Fix 2: Hex encode ciphertext
    encryptedData = encryptedData.ciphertext.toString(CryptoJS.enc.Hex);
    //console.log(encryptedData.length);
    //console.log(encryptedData);

    str = encryptedData;
    str = str.trim();
    return str;
}

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;
}
// The result I really get.
/*
/5HIqgE3nk3mIaROXxH3Lk0lvbGhgkLbbO+e8H2AsBZeR2/R2ayqUxcCcsgtEilh4aBwCnQnz6HPkNt/bWWTu8kxAqTUubZtmXTBPDGnq0u6HU4HkPDLu9etZMbTyAEqYBzqqAi/9w+UqO+lpPmEudQTBP/YeWEhd8Yi919CFPr5gMs1sJrNNskJ560tkazr

* /
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

请注意,php参考代码不必要地应用32字节的块大小进行填充。通常对所用算法的块大小进行填充,aes为16字节。填充到32字节不是一个bug,但它不必要地增加了密文的大小。
此外,静态iv是不安全的(必须为每次加密随机生成iv),并且类似地密码作为密钥(在密码的情况下,使用基于密码的密钥派生函数,例如argon2或pbkdf2),尽管发布的密钥和iv可能仅用于测试目的,这当然是可以的。

相关问题