2013-09-28 33 views
1

我已經編寫了一個使用PHP Mcrypt來加密和解密一些文本數據的小封裝類。 此類生成一個用於散列密鑰的salt,並使用生成的密鑰散列對給定數據進行加密。加密數據與初始化向量和鍵鹽一起存儲到容器類中。當給定密鑰有效時,容器類可以解密。我正在使用PHP Mcrypt的正確方法?

class Mcrypt 
{ 
    /** 
    * @var array 
    */ 
    protected static $validCiphers = [ 
     MCRYPT_BLOWFISH, 
     MCRYPT_TWOFISH, 
     MCRYPT_RIJNDAEL_128, 
     MCRYPT_RIJNDAEL_192, 
     MCRYPT_RIJNDAEL_256, 
     MCRYPT_SERPENT 
    ]; 

    /** 
    * @var string 
    */ 
    protected $cipher = MCRYPT_TWOFISH; 

    /** 
    * @var string 
    */ 
    protected $mode = MCRYPT_MODE_CBC; 

    /** 
    * @var string 
    */ 
    protected $keyHashRounds = '11'; 

    /** 
    * Encrypts the data with the given key. 
    * 
    * @param string $data 
    * @param string $key 
    * @return McryptContainer 
    */ 
    public function encrypt($data, $key) 
    { 
     $data  = trim($data); 
     $container = new McryptContainer; 
     $container->setInitializationVector($this->getInitializationVector()); 
     $container->setPasswordSalt($this->generateSalt()); 
     $container->setCipher($this->cipher); 

     $container->setData(mcrypt_encrypt(
      $this->cipher, 
      $this->getKeyHash($key, $container->getPasswordSalt()), 
      sha1($data) . $data, 
      $this->mode, 
      $container->getInitializationVector() 
     )); 

     return $container; 
    } 

    /** 
    * Decrypts the container data with the given key 
    * or returns false if the key is not valid. 
    * 
    * @param McryptContainer $container 
    * @param string $key 
    * @return bool|string 
    */ 
    public function decrypt(McryptContainer $container, $key) 
    { 
     $data = trim(mcrypt_decrypt(
      $container->getCipher(), 
      $this->getKeyHash($key, $container->getPasswordSalt()), 
      $container->getData(), 
      $this->mode, 
      $container->getInitializationVector() 
     )); 

     $checkSum = substr($data, 0, 40); 
     $data  = substr($data, 40); 

     if (sha1($data) != $checkSum) { 
      return false; 
     } 

     return $data; 
    } 

    /** 
    * Generates a hash for the given key. 
    * 
    * @param string $key 
    * @return string 
    */ 
    protected function getKeyHash($key, $salt) 
    { 
     $length = mcrypt_enc_get_key_size(mcrypt_module_open($this->cipher, '', $this->mode, '')); 
     $hash = crypt($key, sprintf('$2a$%s$%s$', $this->keyHashRounds, $salt)); 

     return substr($hash, $length * -1); 
    } 

    /** 
    * Generates a random salt. 
    * 
    * @return string 
    */ 
    protected function generateSalt() 
    { 
     $length  = mcrypt_enc_get_key_size(mcrypt_module_open($this->cipher, '', $this->mode, '')); 
     $validChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 
     $salt  = ''; 
     $count  = strlen($validChars) - 1; 

     while ($length--) { 
      $salt .= $validChars[mt_rand(0, $count)]; 
     } 

     return $salt; 
    } 

    /** 
    * Generates a new mcrypt initialization vector. 
    * 
    * @return string 
    */ 
    protected function getInitializationVector() 
    { 
     return mcrypt_create_iv(mcrypt_get_iv_size($this->cipher, $this->mode), MCRYPT_DEV_URANDOM); 
    } 

    /** 
    * Sets the cipher. 
    * 
    * @param string $cipher 
    */ 
    public function setCipher($cipher) 
    { 
     if (!in_array($cipher, static::$validCiphers)) { 
      $msg = 'Given cipher is not supported, supported ciphers are: ' . implode(', ', static::$validCiphers); 
      throw new \InvalidArgumentException($msg); 
     } 

     $this->cipher = $cipher; 
    } 

    /** 
    * Sets the rounds used for hashing the key. 
    * 
    * @param string $keyHashRounds 
    */ 
    public function setKeyHashRounds($keyHashRounds) 
    { 
     $this->keyHashRounds = $keyHashRounds; 
    } 
} 

我使用Mcrypt有什麼安全問題嗎?

這裏是包含兩個類的Gist

+2

聽起來更像http://codereview.stackexchange.com的候選人。 – deceze

+0

謝謝,我不知道codereview.stackexchange.com ... –

回答

1

號有一分鐘的你要點的掃描揭示了以下缺陷:

  1. 您使用散列函數(sha1()),而不是一個MAC(例如hash_hmac())。這不增加安全性。
  2. 您將明文而不是密文(加密和MAC)哈希。相反,您應該計算密文的MAC(加密,然後 MAC)。見the cryptographic doom principle
  3. 您正在使用mt_rand()來生成您的鹽。

延伸閱讀: