Вот пример на JS:
function decryptRandomNumber (pwdHash, encryptedRandomNumber) {
var key = CryptoJS.enc.Utf8.parse(pwdHash);
var encrypted = CryptoJS.enc.Hex.parse(encryptedRandomNumber.toUpperCase());
var result = CryptoJS.AES.decrypt({
ciphertext: encrypted
}, key , {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).toString(CryptoJS.enc.Utf8);
return result;
}
function encryptPwdHash (pwdHash, randomNumber) {
var randomNumberMd5 = CryptoJS.MD5(randomNumber).toString().toUpperCase();
var key = CryptoJS.enc.Utf8.parse(randomNumberMd5);
var result = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(pwdHash), key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).ciphertext;
return result;
}
// пример на js - шифрование
var password = '123456';
var pwdHash = CryptoJS.MD5(password).toString().toUpperCase();
var encriptResult = encryptPwdHash (pwdHash, '3456'); //
Скриншот результата
если привести в строку то f46492dc512a6df5cd7c6b9ee50e7cc44fb2337c1605726518d353ce800d5cc05d4d5540dd7674850079e785ab5f3b77
Нужно переписать на PHP.
Расшифровку смог сделать вот этой функцией
function aes128_cbc_decrypt($key, $data, $iv) {
$data = pack("H*", $data);
$iv = pack("H*", $iv);
$dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv);
return $dec;
}
Входящие параметры --> $key = strtoupper(md5($password));
хеш пароля
$data = '54BAA6158E81E1069EA2AB1C4F9D1F29';- хеш рандомного числа $iv = '00000000000000000000000000000000';
- вектор в виде 16 - ти ричной константы.
Вот теперь нужно зашифровать обратно пароль с помощью случайного числа и отправить.
Написал функцию которая делает подобное:
function aes128_cbc_encript($key, $data, $iv) {
$key = pack("H*", strtoupper(md5($key)));
//var_dump($data);
//$data = pack("H*", $data);
$iv = pack("H*", $iv);
//$enc = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv);
$enc = openssl_encrypt($data, 'AES-128-CBC', $key, true, $iv);
return bin2hex($enc);
}
Пробую запускать
$decript = '34345'; // расшифрованное рандомное число
$pswdHash = strtoupper(md5($password));
$encript = aes128_cbc_encript($decript, $pswdHash, '00000000000000000000000000000000');
На выходе получаю нечто - 72fc1b49db86787b749c3323421496af00933eb79a9b7d845a51f5ea3fefdf750800554f5fdf0c7d3d765fe7f6653da3
Такой шифр и должен быть по длинне и в 16 - ти разрядном виде, но он не правильный
и при отправке на сервер он не расшифровуется.
Вот пример функции на Oracle, которая на сервере делает расшифровку
Fc_Decrypt_Password_Hash(In_Encrypted_Password_Hash In Varchar2,
In_Random_Number_Md5 In Varchar2) Return Varchar2 Is
Raw_Random_Number_Md5 Raw(2000);
Raw_Result Raw(2000);
Result Varchar2(2000);
Begin
Raw_Random_Number_Md5 := Utl_I18n.String_To_Raw(Upper(In_Random_Number_Md5),
'AL32UTF8');
Raw_Result := Dbms_Crypto.Decrypt(Typ => Dbms_Crypto.Aes_Cbc_Pkcs5, Src =>
Upper(In_Encrypted_Password_Hash), Key => Raw_Random_Number_Md5);
Result := Utl_I18n.Raw_To_Char(Raw_Result, 'AL32UTF8');
Return(Result);
End;
Ответы
Ответ 1
Во-первых, если вы действительно хотите защитить обмен сообщениями - пользуйтесь
готовыми решениями.
Функция openssl_encrypt не использует весь $key, а только первые 16 байт, остальные
отбрасываются (для AES-128). Хотя это только практический опыт, возможно это верно
не для всех версий. В качестве $key у вас используется хэш md5 в 16-ричном формате,
а это 32 байта.
CryptoJS, использует весь ключ (или по крайней мере больше 16 байт).
Ожидать, что результаты шифрований совпадут, не приходится.
Функция mcrypt_encrypt не умеет Pkcs7. Она всегда выравнивает блок нулями (и это
небезопасно). Хоть в вашем случае выравнивание и не требуется (длина исходного текста
всегда делится на 16), по вышеуказанному стандарту все равно нужно добавить выравнивание,
это будут 16 байт 0x10.
Пример рабочего кода (практически повторяет ваш пример на js):
function encrypt(){
$data=strtoupper(md5('123456'));
$data.=str_repeat(chr(16), 16);// добавляем выравнивание
$key=strtoupper(md5('3456'));
$iv=hex2bin(str_repeat('00', 16));
$enc = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv);
return bin2hex($enc);
}
var_dump(encrypt()); // -> string(96) "f46492dc512a6df5cd7c6b9ee50e7cc44fb2337c1605726518d353ce800d5cc05d4d5540dd7674850079e785ab5f3b77"
Ответ 2
Так как у вас стоит задача просто реализовать зашифрованный обмен данными между клиентом
и сервером, предлагаю просто готовую реализацию.
PHP библиотека:
/**
* Decrypt data from a CryptoJS json encoding string
*
* @param mixed $passphrase
* @param mixed $jsonString
* @return mixed
*/
function cryptoJsAesDecrypt($passphrase, $jsonString){
$jsondata = json_decode($jsonString, true);
$salt = hex2bin($jsondata["s"]);
$ct = base64_decode($jsondata["ct"]);
$iv = hex2bin($jsondata["iv"]);
$concatedPassphrase = $passphrase.$salt;
$md5 = array();
$md5[0] = md5($concatedPassphrase, true);
$result = $md5[0];
for ($i = 1; $i < 3; $i++) {
$md5[$i] = md5($md5[$i - 1].$concatedPassphrase, true);
$result .= $md5[$i];
}
$key = substr($result, 0, 32);
$data = openssl_decrypt($ct, 'aes-256-cbc', $key, true, $iv);
return json_decode($data, true);
}
/**
* Encrypt value to a cryptojs compatiable json encoding string
*
* @param mixed $passphrase
* @param mixed $value
* @return string
*/
function cryptoJsAesEncrypt($passphrase, $value){
$salt = openssl_random_pseudo_bytes(8);
$salted = '';
$dx = '';
while (strlen($salted) < 48) {
$dx = md5($dx.$passphrase.$salt, true);
$salted .= $dx;
}
$key = substr($salted, 0, 32);
$iv = substr($salted, 32,16);
$encrypted_data = openssl_encrypt(json_encode($value), 'aes-256-cbc', $key, true,
$iv);
$data = array("ct" => base64_encode($encrypted_data), "iv" => bin2hex($iv), "s"
=> bin2hex($salt));
return json_encode($data);
}
Javascript библиотека:
var CryptoJSAesJson = {
stringify: function (cipherParams) {
var j = {ct: cipherParams.ciphertext.toString(CryptoJS.enc.Base64)};
if (cipherParams.iv) j.iv = cipherParams.iv.toString();
if (cipherParams.salt) j.s = cipherParams.salt.toString();
return JSON.stringify(j);
},
parse: function (jsonStr) {
var j = JSON.parse(jsonStr);
var cipherParams = CryptoJS.lib.CipherParams.create({ciphertext: CryptoJS.enc.Base64.parse(j.ct)});
if (j.iv) cipherParams.iv = CryptoJS.enc.Hex.parse(j.iv)
if (j.s) cipherParams.salt = CryptoJS.enc.Hex.parse(j.s)
return cipherParams;
}
}
Пример на Javascript:
var encrypted = CryptoJS.AES.encrypt(JSON.stringify("value to encrypt"), "my passphrase",
{format: CryptoJSAesJson}).toString();
var decrypted = JSON.parse(CryptoJS.AES.decrypt(encrypted, "my passphrase", {format:
CryptoJSAesJson}).toString(CryptoJS.enc.Utf8));
Пример на PHP
$encrypted = cryptoJsAesEncrypt("my passphrase", "value to encrypt");
$decrypted = cryptoJsAesDecrypt("my passphrase", $encrypted);
Взято остюда
Ответ 3
Переписал все полностью, если это оно, то прокомментирую после вашего подтверждения.
';
# вы зашифровали: 1152
# моя функция для шифрования в режиме CBC
function dataEncrypt($plaintext, $key, $iv)
{
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC,
pack('H*', $iv));
$ciphertext = strtoupper(bin2hex($ciphertext));
return $ciphertext;
}
# шифрую то, что вы шифровали ранне (число 1152) своей функцией
echo dataEncrypt('1152', strtoupper(md5('123456')), '00000000000000000000000000000000')
. '
';
# результат: C3364787440D1A610FB3B99C8C6D483C
# расшифровываю результат работы своей функции: C3364787440D1A610FB3B99C8C6D483C
с помощью вашей функцией aes128_cbc_decrypt
echo aes128_cbc_decrypt(strtoupper(md5('123456')), 'C3364787440D1A610FB3B99C8C6D483C',
'00000000000000000000000000000000') . '
';
# я зашифровал: 1152