如何在PHP类上修复mcrypt字符长度

时间:2017-04-22 23:07:37

标签: php encryption mcrypt

我来这里解释我的网站,并显示我的网站上出现的“错误”或“错误”。

前几天我做了一个页面,主题是用AES加密和解密,使用名为“mcrypt”的php类。

以下是截图:

Fist Image

问题是:页面只允许我输入“16,24或32”字符的密钥长度。

所以当我选择另一个字符长度时,它会出现错误。 示例:如果我选择8个关键字符长度,则显示:

Error or Bug that I want to fix

我在互联网上搜索,发现我必须用“\ 0”填充

I found this

但我想知道,这可以做到这一点。

这是php类:

<?php

class AES {

    const M_CBC = 'cbc';
    const M_CFB = 'cfb';
    const M_ECB = 'ecb';
    const M_NOFB = 'nofb';
    const M_OFB = 'ofb';
    const M_STREAM = 'stream';

    protected $key;
    protected $cipher;
    protected $data;
    protected $mode;
     protected $IV;

    /**
     * 
     * @param type $data
     * @param type $key
     * @param type $blockSize
     * @param type $mode
     */
    function __construct($data = null, $key = null, $blockSize = null, $mode = null) {
        $this->setData($data);
        $this->setKey($key);
        $this->setBlockSize($blockSize);
        $this->setMode($mode);
        $this->setIV("");
    }

    /**
     * 
     * @param type $data
     */
    public function setData($data) {
        $this->data = $data;
    }

    /**
     * 
     * @param type $key
     */
    public function setKey($key) {
        $this->key = $key;
    }

    /**
     * 
     * @param type $blockSize
     */
    public function setBlockSize($blockSize) {
        switch ($blockSize) {
            case 128:
                $this->cipher = MCRYPT_RIJNDAEL_128;
                break;

            case 192:
                $this->cipher = MCRYPT_RIJNDAEL_192;
                break;

            case 256:
                $this->cipher = MCRYPT_RIJNDAEL_256;
                break;
        }
    }

    /**
     * 
     * @param type $mode
     */
    public function setMode($mode) {
        switch ($mode) {
            case AES::M_CBC:
                $this->mode = MCRYPT_MODE_CBC;
                break;
            case AES::M_CFB:
                $this->mode = MCRYPT_MODE_CFB;
                break;
            case AES::M_ECB:
                $this->mode = MCRYPT_MODE_ECB;
                break;
            case AES::M_NOFB:
                $this->mode = MCRYPT_MODE_NOFB;
                break;
            case AES::M_OFB:
                $this->mode = MCRYPT_MODE_OFB;
                break;
            case AES::M_STREAM:
                $this->mode = MCRYPT_MODE_STREAM;
                break;
            default:
                $this->mode = MCRYPT_MODE_ECB;
                break;
        }
    }

    /**
     * 
     * @return boolean
     */
    public function validateParams() {
        if ($this->data != null &&
                $this->key != null &&
                $this->cipher != null) {
            return true;
        } else {
            return FALSE;
        }
    }

     public function setIV($IV) {
        $this->IV = $IV;
    }

     protected function getIV() {
    if ($this->IV == "") {
        $this->IV = mcrypt_create_iv(mcrypt_get_iv_size($this->cipher, $this->mode), MCRYPT_RAND);
    }
        return $this->IV;
    }

    /**
     * @return type
     * @throws Exception
     */
    public function encrypt() {

        if ($this->validateParams()) {
            return trim(base64_encode(
                            mcrypt_encrypt(
                                    $this->cipher, $this->key, $this->data, $this->mode, $this->getIV())));
        } else {
            throw new Exception('Invlid params!');
        }
    }

    /**
     * 
     * @return type
     * @throws Exception
     */
    public function decrypt() {
        if ($this->validateParams()) {
            return trim(mcrypt_decrypt(
                            $this->cipher, $this->key, base64_decode($this->data), $this->mode, $this->getIV()));
        } else {
            throw new Exception('Invlid params!');
        }
    }

}

我也发现了这一点,我认为可能是解决方案

function pad_key($key){
    // key is too large
    if(strlen($key) > 32) return false;

    // set sizes
    $sizes = array(16,24,32);

    // loop through sizes and pad key
    foreach($sizes as $s){
        while(strlen($key) < $s) $key = $key."\0";
        if(strlen($k) == $s) break; // finish if the key matches a size
    }

    // return
    return $key;
}

顺便说一句,也许最后一个是修复,我是一个有点业余爱好者。

感谢大家!希望你能帮助我。

2 个答案:

答案 0 :(得分:1)

AES密钥具有特定的密钥大小。如果您想使用不同的大小,那么您可能使用密码而不是密钥。请不要混淆他们。密码可以很容易记住。应该随机选择一个键,看起来应该是随机噪声。您需要使用基于密码的密钥派生函数,如PBKDF2。

请记住,在PHP 7.2中将删除mcrypt。它是放弃软件,不应再使用了。

答案 1 :(得分:1)

您展示的代码存在很多问题,在单个答案中解释的太多了。 TL; DR是:

  1. 不要使用mcrypt,它是放弃软件。
  2. 不要滚动你自己的加密。相反,请使用经过严格审查的库,为您处理所有事情。
  3. 我知道这不是你期待的答案,但我向你保证 - 该领域的每位专家都会回应它。
    密码学非常复杂,很容易搞砸,当然也不是一般的编程问题。这就是它的方式。

    话虽如此,这显然是不正确的:

    AES只是Rijndael的一个子集...

    AES-128是Rijndael-128,带有128位(16字节)密钥
    AES-256是Rijndael-128,带有256位(32字节)密钥 Rijndael-192和Rijndael-256是 NOT AES!

    这也暗示了你问的答案 - 你不能使用任意的密钥大小;只需16或32个字节,具体取决于您想要的AES变化。

    使用零字节填充可能会隐藏错误消息,但那是因为你欺骗 mcrypt认为你正在给它一个正确的密钥,而你实际上并非 - 这不是'帮助你,不要这样做。

    同样,如果你正在构建一些用于实际使用的东西 - 不要自己动手。但是,如果你只是为了学习经验,这里有一个相当好的资源,可以指出你正确的方向:http://timoh6.github.io/2014/06/16/PHP-data-encryption-cheatsheet.html