2011-06-19 58 views
8

我想加密一些文本消息使用來自php和密碼Rijndael的mcrypt,但我不確定MCRYPT_MODE_modename(根據PHP的手冊這些都可用「ecb」,「cbc」 ,「cfb」,「ofb」,「nofb」或「stream」,但我讀過的其實還有更多)。我不知道每個人做什麼或如何使用它們。使用PHP mcrypt與Rijndael/AES

我讀了兩件事,ECB模式不應該被使用,MCRYPT_RAND也不會。他們沒有解釋爲什麼。對於ECB模式,我想這是因爲它總是爲相同的純文本生成相同的加密輸出(也許這可以用於攻擊),不知道MCRYPT_RAND(由@azz here提及)。

我的問題是,我應該使用什麼樣的mcrypt模式,並且很高興看到使用的php代碼示例,因爲我發現的所有示例都使用ECB。我試圖加密的字符串將只包含ascii文本,並且可變長度不超過500個字符。

+0

相關:[哪個PHP mcrypt密碼是最安全的?](http://stackoverflow.com/questions/2809855/which-php-mcrypt-cipher-is-safest) – hakre

+0

維基百科對不同的[cipher塊模式](http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation),它們如何運行以及它們的優點和缺點。 – Tails

+0

查看[加密爲平均開發人員](http://www.slideshare.net/ircmaxell/cryptography-for-the-average-developer-1)爲一個偉大的工作實現 –

回答

16

ecb是最簡單的,有弱點,所以不建議(http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation)。 cbc被認爲比ecb強得多。其他一些可能比cbc更強大,但它們都與流相關,因此cbc應該適合您的需求。

從... http://us.php.net/manual/en/mcrypt.constants.php ...

  • MCRYPT_MODE_ECB(電子碼本)適用於隨機數據,例如加密其它密鑰。由於數據短缺且隨機,歐洲央行的不利因素具有良好的負面影響。
  • MCRYPT_MODE_CBC(密碼塊鏈接)特別適用於對ECB的安全性顯着提高的文件進行加密。
  • MCRYPT_MODE_CFB(密碼反饋)是加密單字節必須加密的字節流的最佳模式。
  • MCRYPT_MODE_OFB(輸出反饋,8位)與CFB相當,但可用於無法容忍錯誤傳播的應用。這是不安全的(因爲它在8位模式下運行),所以不建議使用它。
  • MCRYPT_MODE_NOFB(輸出反饋,nbit)與OFB相當,但更安全,因爲它在算法的塊大小上運行。
  • MCRYPT_MODE_STREAM是一個額外的模式,包括一些像「WAKE」或「RC4」這樣的流算法。

我不確定爲什麼建議使用MCRYPT_RAND,但這可能是因爲許多系統上的系統隨機數生成器不被認爲是真正的隨機數。只有兩種選擇,它們可能不可用,具體取決於您的系統和PHP版本。從... http://php.net/manual/en/function.mcrypt-create-iv.php ...

  • 的IV源可以是MCRYPT_RAND(系統隨機數發生器),MCRYPT_DEV_RANDOM(讀取/數據開發/隨機的)並且MCRYPT_DEV_URANDOM(讀取從/ dev/urandom的數據)。在5.3.0之前,MCRYPT_RAND是Windows上唯一支持的。

下面的代碼只是一個快速示例。它有效,但我無法證實它的實力。

 

<?php 

// Test code 

    $objEncManager = new DataEncryptor(); 

    $sensitiveData = "7890"; 
    echo "Raw Data: _" . $sensitiveData . "_<br><br>"; 

    $encryptedData = $objEncManager->mcryptEncryptString($sensitiveData); 
    echo "Enc Data: _" . $encryptedData . "_<br><br>"; 
    echo "Enc Data length: " . strlen($encryptedData) . "<br><br>"; 

    $decryptedData = $objEncManager->mcryptDecryptString($encryptedData, $objEncManager->lastIv); 
    echo "D-enc Data: _" . $decryptedData . "_<br><br>"; 

    echo "IV: _" . $objEncManager->lastIv . "_<br><br>"; 


/* 
* Note: These functions do not accurately handle cases where the data 
* being encrypted have trailing whitespace so the data 
*  encrypted by them must not have any. Leading whitespace is okay. 
* 
* Note: If your data needs to be passed through a non-binary safe medium you should 
* base64_encode it but this makes the data about 33% larger. 
* 
* Note: The decryption IV must be the same as the encryption IV so the encryption 
* IV must be stored or transmitted with the encrypted data. 
* From (http://php.net/manual/en/function.mcrypt-create-iv.php)... 
* "The IV is only meant to give an alternative seed to the encryption routines. 
* This IV does not need to be secret at all, though it can be desirable. 
* You even can send it along with your ciphertext without losing security." 
* 
* Note: These methods don't do any error checking on the success of the various mcrypt functions 
*/ 
class DataEncryptor 
{ 
    const MY_MCRYPT_CIPHER  = MCRYPT_RIJNDAEL_256; 
    const MY_MCRYPT_MODE   = MCRYPT_MODE_CBC; 
    const MY_MCRYPT_KEY_STRING = "1234567890-abcDEFGHUzyxwvutsrqpo"; // This should be a random string, recommended 32 bytes 

    public $lastIv    = ''; 


    public function __construct() 
    { 
     // do nothing 
    } 


    /** 
    * Accepts a plaintext string and returns the encrypted version 
    */ 
    public function mcryptEncryptString($stringToEncrypt, $base64encoded = true) 
    { 
     // Set the initialization vector 
      $iv_size  = mcrypt_get_iv_size(self::MY_MCRYPT_CIPHER, self::MY_MCRYPT_MODE); 
      $iv   = mcrypt_create_iv($iv_size, MCRYPT_RAND); 
      $this->lastIv = $iv; 

     // Encrypt the data 
      $encryptedData = mcrypt_encrypt(self::MY_MCRYPT_CIPHER, self::MY_MCRYPT_KEY_STRING, $stringToEncrypt , self::MY_MCRYPT_MODE , $iv); 

     // Data may need to be passed through a non-binary safe medium so base64_encode it if necessary. (makes data about 33% larger) 
      if ($base64encoded) { 
       $encryptedData = base64_encode($encryptedData); 
       $this->lastIv = base64_encode($iv); 
      } else { 
       $this->lastIv = $iv; 
      } 

     // Return the encrypted data 
      return $encryptedData; 
    } 


    /** 
    * Accepts a plaintext string and returns the encrypted version 
    */ 
    public function mcryptDecryptString($stringToDecrypt, $iv, $base64encoded = true) 
    { 
     // Note: the decryption IV must be the same as the encryption IV so the encryption IV must be stored during encryption 

     // The data may have been base64_encoded so decode it if necessary (must come before the decrypt) 
      if ($base64encoded) { 
       $stringToDecrypt = base64_decode($stringToDecrypt); 
       $iv    = base64_decode($iv); 
      } 

     // Decrypt the data 
      $decryptedData = mcrypt_decrypt(self::MY_MCRYPT_CIPHER, self::MY_MCRYPT_KEY_STRING, $stringToDecrypt, self::MY_MCRYPT_MODE, $iv); 

     // Return the decrypted data 
      return rtrim($decryptedData); // the rtrim is needed to remove padding added during encryption 
    } 


} 
?> 
+0

警告:MCRYPT_RIJNDAEL_256是Rijndael密碼與塊大小爲256位,換句話說,它與AES不一樣。另外請注意,PHP不使用PKCS#7填充的事實標準,並且它不能非常好地處理鍵(在需要時擴展和剪切)。然後,隨機生成器再次改進。 –

2

ECB模式不安全,因爲它不會在加密數據中引入隨機性。這基本上意味着您將在輸出中看到相同的輸入模式(即看到報告的圖像here,它是Tux的「加密」版本,Linux的標誌)。

MT_RAND不被認爲是安全的,因爲它使用操作系統的隨機數生成器(PHP的rand()函數)。

爲了加密的目的,最好使用MCRYPT_DEV_RANDOM(從/ dev/random讀取數據)或MCRYPT_DEV_URANDOM(從/ dev/urandom讀取數據)。

Mcrypt提供的最常用和最安全的加密模式是CBC和CTR模式,適用於一般用途。使用加密+認證總是更好(即使用HMAC進行加密然後認證)。例如,沒有身份驗證的CBC模式受Padding Oracle attack影響。