【问题标题】:Getting substring of a CryptoJS's TripleDES encrypted string获取 CryptoJS 的 TripleDES 加密字符串的子字符串
【发布时间】:2021-10-23 05:42:54
【问题描述】:

我有一个旧版 php 代码,它使用 TripleDES 方法加密,作为银行流程的一部分,以加密购买操作。这是代码:

/******  3DES Function  ******/
function encrypt_3DES($message, $key){
    $l = ceil(strlen($message) / 8) * 8;
    return substr(openssl_encrypt($message . str_repeat("\0", $l - strlen($message)), 'des-ede3-cbc', $key, OPENSSL_RAW_DATA, "\0\0\0\0\0\0\0\0"), 0, $l);
}

我想使用 CriptoJS 的 TripleDES 在javascript 中重现相同的代码。这是我目前的试验:

<script src=https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/tripledes.js></script>
<script>

    function encrypt_3DES(message, key) {
        // Parse input parameters
        message = CryptoJS.enc.Utf8.parse(message);
        key = CryptoJS.enc.Utf8.parse(key);
        // Build an iv with zero values
        let iv = CryptoJS.lib.WordArray.create(64/8);
        let encrypted = CryptoJS.TripleDES.encrypt(message, key, {iv: iv});
        // Encrypt with TripleDES
        return encrypted.toString();
    }

    let message = "testMessage";
    let key = "testKey";

    let encrypted = encrypt_3DES(message, key);
    // encrypted: "HLu4p18KtFfy5VjwjFkDHA=="
    
</script>

以示例值为例,结果是字符串"HLu4p18KtFfy5VjwjFkDHA=="

问题是jsphp之间的结果略有不同,我的怀疑指向在php端完成的substr操作,因为当我转换@987654330的结果时@ 操作(没有子字符串),我的 javascript 代码返回相同的 base64 字符串:

<?php

/******  3DES Function  ******/
function encrypt_3DES($message, $key)
{
    $l = ceil(strlen($message) / 8) * 8;
    return substr(openssl_encrypt($message . str_repeat("\0", $l - strlen($message)), 'des-ede3-cbc', $key, OPENSSL_RAW_DATA, "\0\0\0\0\0\0\0\0"), 0, $l);
}

$message = "testMessage";
$key = "testKey";

$res = base64_encode(encrypt_3DES($message, $key));
$res2 = base64_encode(openssl_encrypt($message, 'des-ede3-cbc', $key, OPENSSL_RAW_DATA, "\0\0\0\0\0\0\0\0"));

/* $res: HLu4p18KtFfTr47KvI/WEw== (My goal is to get this in javascript) */
/* $res2: HLu4p18KtFfy5VjwjFkDHA== (without the substr operation, the results match) */
?>

所以,我的问题是:有没有办法将相同的子字符串应用于 javascript 的 CryptoJS 操作的加密结果?

【问题讨论】:

    标签: javascript php cryptojs tripledes


    【解决方案1】:

    PHP 代码实现了自定义零填充。但是,默认 PKCS#7 填充未被禁用,因此除了显式零填充外,隐式 PKCS#7 填充不必要地附加了一个完整块。
    使用substr() 删除最后一个不必要的块。底线是仅使用零填充。

    更高效的 PHP 实现是使用 OPENSSL_ZERO_PADDING 禁用默认填充,而不是截断最后一个块:

    return openssl_encrypt($message . str_repeat("\0", $l - strlen($message)), 'des-ede3-cbc', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, "\0\0\0\0\0\0\0\0"). 
    

    无论如何,为了让C#代码返回与PHP代码相同的密文,需要将C#代码中的padding改为CryptoJS.pad.ZeroPadding


    请注意,静态 IV(如此处使用的零 IV)是不安全的,TripleDES 很慢(更好:AES)并且零填充不可靠(更好:PKCS#7)。
    此外,TripleDES 的有效密钥大小为 24 bytes and 16 bytes


    测试:

    PHP 代码如下:

    $key = '012345678901234567890123';
    $message = 'The quick brown fox jumps over the lazy dog';
    print(base64_encode(encrypt_3DES($message, $key)) . PHP_EOL);
    

    产生以下 Base64 编码的密文:

    HNQad59lGkM83byQY2pwhluVkB7YOyIx/kGh/ibcIXQdFoiODkD1kTIIEHhqcoFm
    

    固定的 JavaScript 代码给出相同的密文。

    function encrypt_3DES(message, key) {
        // Parse input parameters
        message = CryptoJS.enc.Utf8.parse(message);
        key = CryptoJS.enc.Utf8.parse(key);
        // Build an iv with zero values
        let iv = CryptoJS.lib.WordArray.create(64/8);
        let encrypted = CryptoJS.TripleDES.encrypt(message, key, {iv: iv, padding: CryptoJS.pad.ZeroPadding});
        // Encrypt with TripleDES
        return encrypted.toString();
    }
    
    let message = "The quick brown fox jumps over the lazy dog";
    let key = "012345678901234567890123";
    
    let encrypted = encrypt_3DES(message, key);
    document.getElementById("ct").innerHTML = encrypted;
    <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="ct"></p>

    【讨论】:

    • 正中目标。在 js 端使用零填充解决了这个问题。谢谢@Topaco
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-07
    • 2012-12-12
    • 2011-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多