【问题标题】:Triple DES encryption in JavaScript and decryption in PHPJavaScript 中的三重 DES 加密和 PHP 中的解密
【发布时间】:2015-12-03 09:01:31
【问题描述】:

我使用 JavaScript 加密和 php 解密字符串,反之亦然,但问题是在两个平台上生成的输出是不同的,如果我在两个平台上加密字符串“abc”,它们将产生不同结果虽然我确信我的加密是正确的,因为我正在加密的字符串是用相同的语言解密的。

我知道在这种情况下,key 或 iv 中必须有一些不同的东西,但不知道是什么

加密字符串的Javascript代码

var encrypted = CryptoJS.TripleDES.encrypt("Message", "SecretPassphrase");
console.log(encrypted);console.log(String(encrypted));

var text = "<some plain text goes here>";
var key = "00f74597de203655b1ebf5f410f10eb8";
var useHashing = true;

if (useHashing) {
    key = CryptoJS.MD5(key).toString();
    key +=  key.substring(1, 16);
    console.log(key);
}
var textWordArray = CryptoJS.enc.Utf16.parse(text);
var keyHex = CryptoJS.enc.Hex.parse(key);
var iv = String.fromCharCode(0) + String.fromCharCode(0) + String.fromCharCode(0) + String.fromCharCode(0) + String.fromCharCode(0) + String.fromCharCode(0) + String.fromCharCode(0) + String.fromCharCode(0);
var ivHex = CryptoJS.enc.Hex.parse(iv);
console.log('hexadecimal key: ' + keyHex + '\n');
console.log('iv: ' + iv + '\n');
console.log('hexadecimal iv: ' + ivHex + '\n');
var options = {
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7,
    iv: ivHex
};
var encrypted = CryptoJS.TripleDES.encrypt(textWordArray, keyHex, options);
var base64String = encrypted.toString();
console.log('base64: ' + base64String + '\n');
var decrypted = CryptoJS.TripleDES.decrypt({
    ciphertext: CryptoJS.enc.Base64.parse(base64String)
}, keyHex, options);
console.log('decrypted: ' + decrypted.toString(CryptoJS.enc.Utf16));

加密字符串的PHP代码

//Generate a key from a hash
$key = md5(utf8_encode("00f74597de203655b1ebf5f410f10eb8"), true);

//Take first 8 bytes of $key and append them to the end of $key.
$key .= substr($key, 0, 8);
//Padding for 3DES        
$blockSize = mcrypt_get_block_size('tripledes', 'ecb');
$len = strlen($value);
$pad = $blockSize - ($len % $blockSize);
$value .= str_repeat(chr($pad), $pad);

//Generating iv for 3DES
$iv = chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0);

//Encrypt data
$encData = mcrypt_encrypt(MCRYPT_3DES, $key, $value, MCRYPT_MODE_CBC, $iv);

$value = base64_encode($encData);

示例 如果我从javascript加密字符串“admin”,它会给我“U2FsdGVkX1+y/zo1FJEZZ0aqPMQuwilOydbJjzIKpYw="

php 在哪里给我 "AzZFzbnwp2Y="

注意我正在使用 CryptoJSv3 插件进行三重 DES*

【问题讨论】:

  • 你现在为什么使用三重DES?使用 AES:Examples
  • 这是过去项目的一部分,我不应该改变它:)
  • 你不应该改变哪一部分?您能否显示一个示例字符串以便更容易找到匹配的解密?
  • 我不应该改变我们使用的加密方式,即 3DES 到 AES
  • 但是您可以更改其他所有内容(例如,通过使用随机 IV 添加语义安全性或通过运行 HMAC 添加密文身份验证)?

标签: javascript php encryption cryptojs tripledes


【解决方案1】:

MD5 产生 128 位的输出,但三重 DES 密钥应该是 192 位长。这就是为什么您的 PHP 代码将生成的哈希的前 64 位复制到后面的原因。 PHP 和 CryptoJS 都使用 EDE,并且此密钥副本导致 K1 || K2 || K1 的密钥布局。

你可以在 CryptoJS 中做同样的事情。由于 CryptoJS 使用WordArray 将二进制数据内部管理为 32 位字,因此您可以直接将前两个字复制到内部数组的后面。

var pt = "admin";
document.querySelector("#pt").innerHTML = pt;

var key = "00f74597de203655b1ebf5f410f10eb8";
key = CryptoJS.MD5(key);

// copy 3DES subkey 1 to the last 64 bit to make a full 192-bit key
key.words[4] = key.words[0];
key.words[5] = key.words[1];

// create a 64-bit zero filled
var iv = CryptoJS.lib.WordArray.create(64/8);
var encrypted = CryptoJS.TripleDES.encrypt(pt, key, {iv: iv});
var encryptedBase64 = encrypted.toString();

document.querySelector("#enc").innerHTML = encryptedBase64;

var ct = {
    ciphertext: CryptoJS.enc.Base64.parse(encryptedBase64)
};
var decrypted = CryptoJS.TripleDES.decrypt(ct, key, {iv: iv});

document.querySelector("#dec").innerHTML = decrypted.toString(CryptoJS.enc.Utf8);
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/tripledes.js"></script>
<script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/md5.js"></script>
<p>Expected: "AzZFzbnwp2Y="<br/>Got: "<span id="enc"></span>"</p>
<p>Expected: "<span id="pt"></span>"<br/>Got: "<span id="dec"></span>"</p>

由于这些原因,此代码不是很安全:

  • 它使用最多只能提供 112 位安全性的三重 DES。您应该使用 AES。
  • 它使用静态 IV。这在语义上是不安全的,因为攻击者可能仅通过观察密文来查看您是否发送了相同的消息。您需要为每次加密使用随机 IV,并将其与密文一起发送。
  • 它不使用身份验证。该系统可能容易受到填充预言机攻击。这是一种在线攻击,使攻击者能够多次尝试解密任何密文。您要么需要使用像 GCM/EAX 这样的身份验证模式(不建议使用 Triple DES),要么在密文上运行 HMAC-SHA256 以生成身份验证标签并将其与密文一起发送以在接收端进行验证。李>

【讨论】:

  • @MartinBarker CryptoJS 通过使用var iv = CryptoJS.lib.WordArray.random(8); 提供了一个非密码安全的随机字节生成器(3DES 的 IV 长度为 8 个字节)。不过,您应该使用更好的随机性。 Here is a polyfill 如果您的浏览器中提供了更好的随机数。
  • 谢谢,我会调查它,我正在尝试创建一个非常安全的 JSONRPC 方法,所以我将在 SSL 连接中使用 Triple-DES 进行加密,以确保它是安全的:)
  • @MartinBarker 那就不要使用 3DES。 AES 在 CryptoJS 中也可用。 AES 更快、更安全。
猜你喜欢
  • 1970-01-01
  • 2015-03-30
  • 2012-05-06
  • 1970-01-01
  • 2014-02-26
  • 1970-01-01
  • 2012-01-21
  • 2011-10-22
  • 1970-01-01
相关资源
最近更新 更多