获取 CryptoJS 的 TripleDES 加密字符串的子字符串
Getting substring of a CryptoJS's TripleDES encrypted string
我有一个遗留 php
代码,它使用 TripleDES
方法加密,作为银行流程的一部分来加密购买操作。这是代码:
/****** 3DES Function ******/
function encrypt_3DES($message, $key){
$l = ceil(strlen($message) / 8) * 8;
return substr(openssl_encrypt($message . str_repeat("[=10=]", $l - strlen($message)), 'des-ede3-cbc', $key, OPENSSL_RAW_DATA, "[=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=]"), 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=="
.
问题是 js
和 php
之间的结果略有不同,我的怀疑指向 php 端完成的 substr
操作,因为当我转换 open_ssl
操作的结果(没有子字符串)时,我的 javascript 代码返回相同的 base64
字符串:
<?php
/****** 3DES Function ******/
function encrypt_3DES($message, $key)
{
$l = ceil(strlen($message) / 8) * 8;
return substr(openssl_encrypt($message . str_repeat("[=12=]", $l - strlen($message)), 'des-ede3-cbc', $key, OPENSSL_RAW_DATA, "[=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=]"), 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, "[=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=]"));
/* $res: HLu4p18KtFfTr47KvI/WEw== (My goal is to get this in javascript) */
/* $res2: HLu4p18KtFfy5VjwjFkDHA== (without the substr operation, the results match) */
?>
所以,我的问题是:有没有办法将相同的子字符串应用于 javascript 的 CryptoJS 操作的加密结果?
PHP 代码实现了自定义零填充。但是,默认的 PKCS#7 填充没有被禁用,因此除了显式零填充之外,一个完整的块不必要地附加了隐式 PKCS#7 填充。
使用 substr()
删除最后一个不必要的块。底线是简单地使用零填充。
更有效的 PHP 实现是使用 OPENSSL_ZERO_PADDING
禁用默认填充,而不是截断最后一个块:
return openssl_encrypt($message . str_repeat("[=10=]", $l - strlen($message)), 'des-ede3-cbc', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, "[=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=]").
无论如何,为了使C#代码return与PHP代码相同的密文,需要将C#代码中的填充更改为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>
我有一个遗留 php
代码,它使用 TripleDES
方法加密,作为银行流程的一部分来加密购买操作。这是代码:
/****** 3DES Function ******/
function encrypt_3DES($message, $key){
$l = ceil(strlen($message) / 8) * 8;
return substr(openssl_encrypt($message . str_repeat("[=10=]", $l - strlen($message)), 'des-ede3-cbc', $key, OPENSSL_RAW_DATA, "[=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=]"), 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=="
.
问题是 js
和 php
之间的结果略有不同,我的怀疑指向 php 端完成的 substr
操作,因为当我转换 open_ssl
操作的结果(没有子字符串)时,我的 javascript 代码返回相同的 base64
字符串:
<?php
/****** 3DES Function ******/
function encrypt_3DES($message, $key)
{
$l = ceil(strlen($message) / 8) * 8;
return substr(openssl_encrypt($message . str_repeat("[=12=]", $l - strlen($message)), 'des-ede3-cbc', $key, OPENSSL_RAW_DATA, "[=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=]"), 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, "[=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=]"));
/* $res: HLu4p18KtFfTr47KvI/WEw== (My goal is to get this in javascript) */
/* $res2: HLu4p18KtFfy5VjwjFkDHA== (without the substr operation, the results match) */
?>
所以,我的问题是:有没有办法将相同的子字符串应用于 javascript 的 CryptoJS 操作的加密结果?
PHP 代码实现了自定义零填充。但是,默认的 PKCS#7 填充没有被禁用,因此除了显式零填充之外,一个完整的块不必要地附加了隐式 PKCS#7 填充。
使用 substr()
删除最后一个不必要的块。底线是简单地使用零填充。
更有效的 PHP 实现是使用 OPENSSL_ZERO_PADDING
禁用默认填充,而不是截断最后一个块:
return openssl_encrypt($message . str_repeat("[=10=]", $l - strlen($message)), 'des-ede3-cbc', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, "[=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=]").
无论如何,为了使C#代码return与PHP代码相同的密文,需要将C#代码中的填充更改为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>