Encrypt/Decrypt using mcrypt

匿名 (未验证) 提交于 2019-12-03 09:02:45

问题:

Trying to achieve encrypting and decryption using following strategy, but ending up with random characters mostly.

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; }     } 

Can't get exact values back, sometimes it decrypts but I see some garbage values, but mostly just random characters.

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

Edits after the discussion

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)); } } 

Usage:

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

回答1:

  1. Don't urlencode. Unnecessary.
  2. trim for NULL bytes, not empty strings: rtrim($str, chr(0)); (Instead, you might want to save the source string length in the encrypted result too, so you won't rtrim() too much.)

Why pack('H*', $account) for $key? Also unnecessary.

Rijndael 128 uses 16 byte keys (128 bits), so make sure your key is at least that long:

$key = $account . $account 

will do, but it obviously imperfect. (mcrypt will do something like that if it's too short.) If every account had its own passphrase, that would be good. (Even more so in combination with an app secret, but details.)

rtrim() with chr(0) is fine, very probably, because your source string won't have trailing NUL bytes.

I usually use these en/decrypt functions, or alike, but these have a static secret/key, so yours is better.

To send an encrypted token to the client:

$enc_token = Crypt::encrypt($token, $key); // $enc_token might contain `/` and `+` and `=` $url = 'page.php?token=' . urlencode($enc_token); 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!