在客户端(移动设备),我使用CryptoJS加密用户密码:
var lib_crypt = require('aes');
$.loginButton.addEventListener('click', function(e){
var key = lib_crypt.CryptoJS.enc.Hex.parse('bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3');
var iv = lib_crypt.CryptoJS.enc.Hex.parse('101112131415161718191a1b1c1d1e1f');
var encrypted = lib_crypt.CryptoJS.AES.encrypt($.passwordInput.value, key, { iv: iv });
var password_base64 = encrypted.ciphertext.toString(lib_crypt.CryptoJS.enc.Base64);
return password_base64;
});
在服务器端,我想用mcrypt_decrypt解密它:
function decryptPassword($password)
{
$key = pack('H*', "bcb04b7e103a0cd8b54763051cef08bc55abe029fdebae5e1d417e2ffb2a00a3");
$ciphertext_dec = base64_decode($password);
$iv_dec = "101112131415161718191a1b1c1d1e1f";
$ciphertext_dec = substr($ciphertext_dec, 16);
$decryptedPassword = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);
return trim($decryptedPassword);
}
我使用相同的密钥和IV,我做错了什么?
答案 0 :(得分:14)
您好,
为了达到这个目的,应该考虑使用密钥和iv,每个都有32个十六进制数字,我必须正确解决这个问题,这就是它的方式
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js">
</script>
<script type="text/javascript">
//The key and iv should be 32 hex digits each, any hex digits you want, but it needs to be 32 on length each
var key = CryptoJS.enc.Hex.parse("0123456789abcdef0123456789abcdef");
var iv = CryptoJS.enc.Hex.parse("abcdef9876543210abcdef9876543210");
/*
if you wish to have a more friendly key, you can convert letters to Hex this way:
var a = "D";
var hex_D = a.charCodeAt(0).toString(16);
just to mention,
if it were to binary, it would be:
var binary_D = a.charCodeAt(0).toString(2);
*/
var secret = "Hi, this will be seen uncrypted later on";
//crypted
var encrypted = CryptoJS.AES.encrypt(secret, key, {iv:iv});
//and the ciphertext put to base64
encrypted = encrypted.ciphertext.toString(CryptoJS.enc.Base64);
//Assuming you have control on the server side, and know the key and iv hexes(we do),
//the encrypted var is all you need to pass through ajax,
//Let's follow with welcomed pure JS style, to reinforce one and other concept if needed
var xh = new XMLHttpRequest();
xh.open("POST", "decrypt_in_php.php", true);
xh.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xh.send("encrypted="+encodeURIComponent(encrypted));
</script>
现在在PHP中接收和解密
<?php
//Here we have the key and iv which we know, because we have just chosen them on the JS,
//the pack acts just like the parse Hex from JS
$key = pack("H*", "0123456789abcdef0123456789abcdef");
$iv = pack("H*", "abcdef9876543210abcdef9876543210");
//Now we receive the encrypted from the post, we should decode it from base64,
$encrypted = base64_decode($_POST["encrypted"]);
$shown = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted, MCRYPT_MODE_CBC, $iv);
echo $shown;
//Although the decrypted is shown, there may be needed to trim and str_replace some \r \n \x06 \x05, if there is not a better "trim" way to do it though
?>
有了这个,我们将退回&#34;嗨,这将在以后未加密的情况下看到&#34; :)
答案 1 :(得分:1)
以下是基于this comment的解决方案,使用了PHP中的openssl_decrypt
。
JavaScript 部分(使用NodeJS为浏览器开发)—首先,将CryptoJS与npm install crypto-js
一起安装,然后安装JS代码:
import aes from 'crypto-js/aes'
import encHex from 'crypto-js/enc-hex'
import padZeroPadding from 'crypto-js/pad-zeropadding'
// message to encrypt
let msg = "Hello world";
// the key and iv should be 32 hex digits each, any hex digits you want, but it needs to be 32 on length each
let key = encHex.parse("0123456789abcdef0123456789abcdef");
let iv = encHex.parse("abcdef9876543210abcdef9876543210");
// encrypt the message
let encrypted = aes.encrypt(msg, key, {iv:iv, padding:padZeroPadding}).toString();
// and finally, send this "encrypted" string to your server
在 PHP 端,您的代码将如下所示:
// we use the same key and IV
$key = hex2bin("0123456789abcdef0123456789abcdef");
$iv = hex2bin("abcdef9876543210abcdef9876543210");
// we receive the encrypted string from the post
$encrypted = $_POST['decrypt'];
$decrypted = openssl_decrypt($encrypted, 'AES-128-CBC', $key, OPENSSL_ZERO_PADDING, $iv);
// finally we trim to get our original string
$decrypted = trim($decrypted);
答案 2 :(得分:0)
你双方并没有做同样的事情。
你确实在CryptoJS中解析了IV,但忘记用PHP做了:
$iv_dec = pack('H*', "101112131415161718191a1b1c1d1e1f");
要解决你的IV错误,你可能会注意到前16个字节是乱码。当IV出错时就会发生这种情况。请注意,CryptoJS默认使用CBC模式,因此IV在解密期间仅对第一个块有影响。 删除:
$ciphertext_dec = substr($ciphertext_dec, 16);
你可能已经注意到大多数明文都不对。他们最后以一些奇怪的重复字符结尾。这是在CryptoJS中默认应用的PKCS#7填充。你必须自己在PHP中删除填充。好的是,Maarten Bodewes为此here提供了适当的复制粘贴解决方案。
trim()
可能适用于ZeroPadding,但不适用于使用类似PKCS#7中定义的填充方案的情况。您可以完全删除trim()
调用,因为它没有用,可能会导致意外的明文,因为零字节会从开头和结尾修剪空白。