1. ホーム
  2. php

[解決済み] php が MCRYPT_RIJNDAEL_256 で文字列を復号します。

2022-02-15 06:29:32

質問

<?php
function encrypt ($key,$iv,$str)
{     
  $block=mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
  $padding=$block-(strlen($str) % $block);
  $str.=str_repeat(chr($padding), $padding);  
  $encryptxt=mcrypt_encrypt(MCRYPT_RIJNDAEL_256,$key,$str,MCRYPT_MODE_CBC,$iv);  
  $encryptxt64=base64_encode($encryptxt);
  return $encryptxt64;
}
function decrypt ($key,$iv,$str)
{     
  $block=mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
  $padding=$block-(strlen($str) % $block);
  $str.=str_repeat(chr($padding), $padding);  
  $decryptxt=mcrypt_decrypt(MCRYPT_RIJNDAEL_256,$key,$str,MCRYPT_MODE_CBC,$iv);  
  $decryptxt64=base64_decode($decryptxt);
  return $decryptxt64;
}
echo encrypt("1234567890123456","12345678901234561234567890123456","test")."\n<br/>";
echo decrypt("1234567890123456","12345678901234561234567890123456","xHqKvRQ6FXehOGGMrKoek04146M2l9bv1ScP6C1qCyg=")."\n<br/>";
?>

この方法で文字列を暗号化することができ、問題なく動作しますが、文字列を復号化しようとすると、上記のコードが動作しません。 復号化出力は以下のようなものです。

� S�'=�l_25A�?

どなたか復号化部分を修正する方法をご存知ですか?

解決方法は?

コメントで述べたように、これはあなたが持っているものです。

  //encrypt
 $encryptxt=mcrypt_encrypt(MCRYPT_RIJNDAEL_256,$key,$str,MCRYPT_MODE_CBC,$iv);  
  $encryptxt64=base64_encode($encryptxt);

 //decrypt 
   $decryptxt=mcrypt_decrypt(MCRYPT_RIJNDAEL_256,$key,$str,MCRYPT_MODE_CBC,$iv);  
  $decryptxt64=base64_decode($decryptxt);

  1. 暗号化
  2. base64エンコード
  3. 復号化
  4. base64デコード

FILO ( First in Last Out ) であるべきです。

  1. 暗号化
  2. base64エンコード
  3. ベース64デコード
  4. 復号化

そうすると、encryptの出力を復号化することになり ではなく base64でエンコードされた出力です。

Like So:

$encryptxt=mcrypt_encrypt(MCRYPT_RIJNDAEL_256,$key,$str,MCRYPT_MODE_CBC,$iv);  
  $encryptxt64=base64_encode($encryptxt);

//decrypt 
 $decryptxt64=base64_decode($str);
$decryptxt=mcrypt_decrypt(MCRYPT_RIJNDAEL_256,$key,$decryptxt64,MCRYPT_MODE_CBC,$iv);  

MCRYPT_RIJNDAEL_256 は AES 256 ではないので、MCRYPT_RIJNDAEL_128 と 32 バイトの鍵が必要です。

もうひとつ、入力文字列のmd5ハッシュをとって、それを暗号化の前に入力文字列にプリペンドすることをお勧めします。 これは、暗号化を解除するときに、最初の32文字をsubstrして、それを使って入力をチェックすることができるようにするためです。 基本的に、復号化されたかどうかを確認するためには、入力文字列を知る必要があります。 しかし、ハッシュ化し、このように比較することで、入力文字列を知る必要がなくなり、動作確認ができるようになります。

というわけで、まとめてみました(テストはしていませんが、近いものがあるはずです)。

function encrypt ($key,$iv,$str)
{     
  $block=mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
  $padding=$block-(strlen($str) % $block);
  $str.=str_repeat(chr($padding), $padding);  

  ///prepend a md5 hash of the plain text input before encrypting it ( so we can check it later )
  $str = md5( $str ) . $str;

    $encryptxt=mcrypt_encrypt(MCRYPT_RIJNDAEL_256,$key,$str,MCRYPT_MODE_CBC,$iv);  
  $encryptxt64=base64_encode($encryptxt);
  return $encryptxt64;
}
function decrypt ($key,$iv,$str)
{     
  $block=mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
  $padding=$block-(strlen($str) % $block);
  $str.=str_repeat(chr($padding), $padding);  

  $decryptxt64=base64_decode($str);
  $decryptxt=mcrypt_decrypt(MCRYPT_RIJNDAEL_256,$key,$decryptxt64,MCRYPT_MODE_CBC,$iv);  

   ///Separate the md5 hash from the other text, and then hash the other text and compare to the hash we included when encrypting  if they are = it all worked.
  /// it is perfectly safe to use md5 here because it will be part of what we encrypt, and not accessible until it is decrypted. 
 ///it's sole purpose is to give us 2 things we can compare to check that the decryption worked
  $hash = substr( $decryptxt, 0, 32); //find first 32 characters (md5 output is always 32 characters long )
  $decryptxt = substr($decryptxt, 33); //find everything after the fist 32
  if( $hash != md5($decryptxt) ){
        die( 'fail' ); /// or some other error
  }


  return $decryptxt64;
}