将 PHP mcrypt 与 Rijndael/AES 结合使用

发布于 2024-11-16 14:39:41 字数 507 浏览 2 评论 0原文

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

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

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

I am trying to encrypt some text messages using mcrypt from php and the cipher Rijndael, but I am not sure about the MCRYPT_MODE_modename (according to PHP's manual these are available "ecb", "cbc", "cfb", "ofb", "nofb" or "stream" but I read there are actually a few more). I have no idea what each one do or how to use them.

I read two things, that ECB mode should not be used and MCRYPT_RAND neither. They didn't explain why. For the ECB mode I guess it's because it always generate the same encrypted output for the same plain text (maybe this could be used for an attack), no idea about MCRYPT_RAND (mentioned by @azz here).

My question is, what mcrypt mode should I use, and it would be great to see an example of php code using it because all the examples I found use ECB. The strings I am trying to encrypt will contain only ascii text, and variable length, not bigger than 500 chars.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

咋地 2024-11-23 14:39:41

ecb 是最简单的,并且有弱点,因此不推荐(http://en.wikipedia.org/wiki/块_cipher_modes_of_operation)。加拿大央行被认为明显强于欧洲央行。其他一些可能比 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(从 /dev/random 读取数据)和 MCRYPT_DEV_URANDOM(从 /dev/random 读取数据) /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
    }


}
?>

ecb is the simplest and has weaknesses so it is not recommended (http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation). cbc is considered significantly stronger than ecb. Some of the others may be even stronger than cbc but they are all stream related so cbc should suit your needs.

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

  • MCRYPT_MODE_ECB (electronic codebook) is suitable for random data, such as encrypting other keys. Since data there is short and random, the disadvantages of ECB have a favorable negative effect.
  • MCRYPT_MODE_CBC (cipher block chaining) is especially suitable for encrypting files where the security is increased over ECB significantly.
  • MCRYPT_MODE_CFB (cipher feedback) is the best mode for encrypting byte streams where single bytes must be encrypted.
  • MCRYPT_MODE_OFB (output feedback, in 8bit) is comparable to CFB, but can be used in applications where error propagation cannot be tolerated. It's insecure (because it operates in 8bit mode) so it is not recommended to use it.
  • MCRYPT_MODE_NOFB (output feedback, in nbit) is comparable to OFB, but more secure because it operates on the block size of the algorithm.
  • MCRYPT_MODE_STREAM is an extra mode to include some stream algorithms like "WAKE" or "RC4".

I'm not sure why MCRYPT_RAND is recommended against but it may be because the system random number generator on many systems is not considered to be truely random. There are only two alternatives and they may not be available depending on your system and PHP version. From... http://php.net/manual/en/function.mcrypt-create-iv.php...

  • The IV source can be MCRYPT_RAND (system random number generator), MCRYPT_DEV_RANDOM (read data from /dev/random) and MCRYPT_DEV_URANDOM (read data from /dev/urandom). Prior to 5.3.0, MCRYPT_RAND was the only one supported on Windows.

The code below is just a quick sample. It works but I can't attest to it's strength.

<?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
    }


}
?>
甜宝宝 2024-11-23 14:39:41

ECB 模式并不安全,因为它不会在加密数据中引入随机性。这基本上意味着您将在输出中看到相同的输入模式(即查看报告的图像 这里是Tux的“加密”版本,Linux的标志)。

MT_RAND 不被认为是安全的,因为它使用操作系统的随机数生成器(PHP 的 rand() 函数)。

出于加密目的,最好使用 MCRYPT_DEV_RANDOM (从 /dev/random 读取数据)或 MCRYPT_DEV_URANDOM (从 /dev/urandom 读取数据)。

Mcrypt 提供的最常用且安全的加密模式是 CBC 和 CTR 模式,适用于一般用例。使用加密+身份验证(即使用 HMAC 进行加密然后身份验证)总是更好。例如,无需认证的CBC模式就受到Padding Oracle攻击的影响。

The ECB mode is not secure because it doesn't introduce randomness in the encrypted data. That basically means you will see the same patterns of the input in the output (i.e. see the image reported here, it's an "encrypted" version of Tux, the logo of Linux).

The MT_RAND is not considered secure because it uses the random number generator of the operating system (the rand() function of PHP).

For cryptography purposes it's better to use MCRYPT_DEV_RANDOM (read data from /dev/random) or MCRYPT_DEV_URANDOM (read data from /dev/urandom).

The most used and secure encryption modes, available with Mcrypt, are CBC and CTR mode and are fine for general use cases. It's always better to use encryption + authentication (i.e. encrypt-then-authenticate using HMAC). For instance, the CBC mode without authentication is affected by the Padding Oracle attack.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文