Страницы

Поиск по вопросам

четверг, 25 октября 2018 г.

Как реализовать шифрование данных на PHP

Вот пример на 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;


Ответ

Во-первых, если вы действительно хотите защитить обмен сообщениями - пользуйтесь готовыми решениями.
Функция 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"

Комментариев нет:

Отправить комментарий