2011-06-19 59 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影响。