php - 将 PHP mcrypt 与 Rijndael/AES 结合使用

标签 php encryption cryptography aes mcrypt

我正在尝试使用 php 中的 mcrypt 和密码 Rijndael 加密一些文本消息,但我不确定 MCRYPT_MODE_modename(根据 PHP 手册,这些可用“ecb”、“cbc”、“cfb”、“ofb”) ”、“nofb”或“stream”,但我读到实际上还有更多)。我不知道每个人做什么或如何使用它们。

我读到两件事,即不应使用 ECB 模式,也不应使用 MCRYPT_RAND。他们没有解释原因。对于 ECB 模式,我想这是因为它总是为相同的纯文本生成相同的加密输出(也许这可以用于攻击),不知道 MCRYPT_RAND (​​@azz here 提到)。

我的问题是,我应该使用什么 mcrypt 模式,如果能看到使用它的 php 代码示例就太好了,因为我发现的所有示例都使用 ECB。我尝试加密的字符串将仅包含 ascii 文本和可变长度,不超过 500 个字符。

最佳答案

ecb 是最简单的,但也有弱点,因此不推荐 ( http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation )。加拿大央行被认为明显强于欧洲央行。其他一些可能比 cbc 更强,但它们都与流相关,因此 cbc 应该适合您的需求。

来自... http://us.php.net/manual/en/mcrypt.constants.php ...

  • MCRYPT_MODE_ECB(电子密码本)适用于随机数据,例如加密其他 key 。由于数据较短且随机,欧洲央行的缺点会产生有利的负面影响。
  • MCRYPT_MODE_CBC(密码 block 链接)特别适合加密文件,其安全性比 ECB 显着提高。
  • MCRYPT_MODE_CFB(密码反馈)是加密字节流的最佳模式,其中必须加密单个字节。
  • MCRYPT_MODE_OFB(输出反馈,8位)与CFB相当,但可用于不能容忍错误传播的应用中。它不安全(因为它在8位模式下运行),因此不建议使用它。
  • MCRYPT_MODE_NOFB(输出反馈,以 nbit 为单位)与 OFB 相当,但更安全,因为它根据算法的 block 大小进行操作。
  • MCRYPT_MODE_STREAM 是一种额外模式,包含一些流算法,例如“WAKE”或“RC4”。

我不确定为什么建议不要使用 MCRYPT_RAND,但这可能是因为许多系统上的系统随机数生成器不被认为是真正随机的。只有两种选择,并且根据您的系统和 PHP 版本,它们可能不可用。来自... http://php.net/manual/en/function.mcrypt-create-iv.php ...

  • IV 源可以是 MCRYPT_RAND(系统随机数生成器)、MCRYPT_DEV_RANDOM(从/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
    }


}
?>

关于php - 将 PHP mcrypt 与 Rijndael/AES 结合使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6400203/

相关文章:

php - 链接到带有 Vue.js 参数的路由

c# - 如何为加密算法创建加密 key ?

c++ - 使用 FIPS 验证库和 AES 时的 CryptoPP::selfTestFailure

c# - .NET 文件解密 - 错误数据

php - 如何将此 JSON 转换为 php 数组以及如何仅获取特定值

PHP DOMDocument 添加了额外的标签

php - 如何检查操作码缓存是否在服务器上运行?

c++ - 使用不可导出的私钥和 CryptoAPI 进行解密

Java - 为什么我的 AES 程序不加密/解密双引号?

java - Java 中的可重复加密(可能使用 Jasypt)