Шифроване/декриптиране с помощта на mcrypt

Опитвате се да постигнете криптиране и декриптиране, като използвате следната стратегия, но завършвате предимно с произволни знаци.

class Crypt {

public static function encrypt($string, $account) {
    // create a random initialization vector to use with CBC encoding
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

    $key = pack('H*', $account . $account);

    $output = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $string, MCRYPT_MODE_CBC, $iv);
    $output = $iv . $output;
    $output = base64_encode($output);
    $output = urlencode($output);

    return $output;
}

public static function decrypt($token, $account) {
    $ciphertext_dec = base64_decode($token);

    // retrieves the IV, iv_size should be created using mcrypt_get_iv_size()
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
    $iv_dec = substr($ciphertext_dec, 0, $iv_size);

    // retrieves the cipher text (everything except the $iv_size in the front)
    $ciphertext_dec = substr($ciphertext_dec, $iv_size);

    $key = pack('H*', $account . $account);

    $token = urldecode($token);

    $output = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);
    $output = rtrim($output, "");
    return $output;
}

   }

Не мога да върна точните стойности, понякога дешифрира, но виждам някои ненужни стойности, но най-вече само произволни знаци.

$a = \Crypt::encrypt("MyPassword", "1974246e");
echo \Crypt::decrypt($a, "1974246e");

Редакции след дискусията

class Crypt {

public static function encrypt($data, $passphrase) {
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC); //create a random initialization vector to use with CBC encoding
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $key = pack('H*', $passphrase . $passphrase);
    return base64_encode($iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_CBC, $iv));
}

public static function decrypt($data, $passphrase) {
    $data = base64_decode($data);
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC); //retrieves the IV, iv_size should be created using mcrypt_get_iv_size()
    $iv = substr($data, 0, $iv_size);
    $data = substr($data, $iv_size); //retrieves the cipher text (everything except the $iv_size in the front)
    $key = pack('H*', $passphrase . $passphrase);
    return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_CBC, $iv), chr(0));
}
}

Употреба:

$pass = "MyPassword*&^*&^(*&^(";
$token = \Crypt::encrypt($pass, "1974246e8e8a479bb0233495e8a3ed12");
$answer = \Crypt::decrypt($token, "1974246e8e8a479bb0233495e8a3ed12");
echo $answer == $pass ? "yes" : "no";

person user2727195    schedule 10.12.2013    source източник


Отговори (1)


  1. Не урленкодирайте. Ненужно.
  2. изрязване за NULL байтове, а не празни низове: rtrim($str, chr(0)); (Вместо това може да искате да запазите дължината на изходния низ и в шифрования резултат, така че да не rtrim() твърде много.)

Защо pack('H*', $account) за $key? Също ненужно.

Rijndael 128 използва 16-байтови ключове (128 бита), така че се уверете, че вашият ключ е поне толкова дълъг:

$key = $account . $account

ще свърши работа, но очевидно е несъвършено. (mcrypt ще направи нещо подобно, ако е твърде кратко.) Ако всеки акаунт имаше собствена парола, това би било добре. (Още повече в комбинация с тайна на приложението, но подробности.)

rtrim() с chr(0) е добре, много вероятно, защото вашият изходен низ няма да има крайни NUL байтове.

Обикновено използвам тези функции за шифриране/дешифриране или други подобни , но тези имат статичен секрет/ключ, така че вашият е по-добър.

За да изпратите криптиран токен до клиента:

$enc_token = Crypt::encrypt($token, $key);
// $enc_token might contain `/` and `+` and `=`
$url = 'page.php?token=' . urlencode($enc_token);
person Rudie    schedule 10.12.2013
comment
Благодаря, Руди, премахнах urlencode и добавих подрязване за нежелани знаци и работи, но не разбрах как мога да избегна използването на $key (pack и т.н.) и rtrim твърде много, не написах кода, но можеш ли моля, редактирайте горните две функции, за да предоставите ефективно решение, което не използва ненужни елементи. - person user2727195; 11.12.2013
comment
Мога да избегна предаването на $account като цяло, при условие че си върна оригиналния низ, също така генерираният токен трябва да бъде случаен/различен всеки път. - person user2727195; 11.12.2013
comment
Разширих отговора си, но няма да пренапиша методите за криптиране. В повечето случаи са добре. Само бележките rtrim() и urlencode() са важни. - person Rudie; 11.12.2013
comment
Трябва да подадете $account (или нещо подобно), защото имате нужда от en/decryption ключ. Може да е тайна на приложението (вместо нещо специфично за акаунта), но колкото по-уникално, толкова по-добре. - person Rudie; 11.12.2013
comment
да, всяка парола за акаунт е 32 знака и всяка парола за акаунт е различна, моля, продължете с пренаписването на функциите за шифроване и декриптиране - person user2727195; 11.12.2013
comment
$account всъщност е низ - person user2727195; 11.12.2013
comment
Да разбирам. Хешираната парола/парола е добра като ключ, стига криптираните данни да не надживеят ключа (промените на паролата › промените на ключ › не могат да дешифрират данни). - person Rudie; 11.12.2013
comment
Въпрос... 1. Не кодирайте urlencode. Ненужно. (трябва да изпратим токена по кабела до браузъра, така че мисля, че url кодирането беше необходимо, въпреки че работи добре и без него, но някакви мисли? - person user2727195; 11.12.2013
comment
Наистина не трябва да изпращате ключа за криптиране на клиента... Само приложението трябва да знае ключа. Шифрованите данни трябва да се споделят с клиента или където и да е, но не и ключът. - person Rudie; 11.12.2013
comment
ние изпращаме шифрованото означение (резултат от функцията за шифроване) по кабела, искам да кажа, че така работи системата (приложението на трета страна, което се намира на клиентска машина, всъщност не браузър) и трябва да се съобразим с това. така че в този случай смятате ли, че url кодирането е необходимо? - person user2727195; 11.12.2013
comment
Шифровате ли токена? Да, това е добре. Вие (или вашата рамка) трябва да кодирате urlencode на криптирания, base64 кодиран резултат, тогава, да. base64 резултатите имат / и + и =, така че те трябва да бъдат urlencoded. Зависи как е създаден URL адресът. Вашето приложение/библиотека/рамка може да се погрижи за това. В противен случай: вижте отговора. - person Rudie; 11.12.2013
comment
готино, промених въпроса въз основа на нашата дискусия, любезно благословете. - person user2727195; 11.12.2013
comment
Здравей Руди: Сблъсках се с малък проблем, тъй като кодът, който създадох, е базиран на тази тема. Моля те, погледни. stackoverflow.com/ въпроси/21049220/ - person user2727195; 10.01.2014