Sebastian Hanania
Sebastian Hanania

Reputation: 79

How to fix mcrypt character length on PHP Class

I'm here to explain my website and show the "bug" or "error" that appears to my web.

Some days ago I did a page, the topic is encrypt and decrypt with AES, using the php class called "mcrypt".

Here's a screenshot:

Fist Image

The problem is: the page only allow me to put a key length of "16, 24 or 32" characters.

So when I choose another character length it appears an error. Example: If I choose a 8 key character length it appears:

Error or Bug that I want to fix

I was searching on internet and I found that I have to pad with "\0"

I found this

But I wonder, where exacly do this.

Here's the php class:

<?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!');
        }
    }

}

I also found this, I think could be the solution

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

Maybe this last one is the fix, by the way, I'm a little amateur with php.

Thanks to everyone! Hope u can help me.

Upvotes: 0

Views: 477

Answers (2)

Narf
Narf

Reputation: 14762

There's a lot of issues with the code you've shown, too many to explain in a single answer. The TL;DR is:

  1. Don't use mcrypt, it's abandonware.
  2. Don't roll your own crypto. Instead, use a well-vetted library that will handle everything for you.

I know this isn't the answer you were expecting, but I assure you - every expert in the field would echo it.
Cryptography is very complex, very easy to screw up, and certainly not a generic programming problem. That's just the way it is.

That being said, here's the obviously incorrect:

AES is only a subset of Rijndael ...

AES-128 is Rijndael-128 with a 128-bit (16-byte) key
AES-256 is Rijndael-128 with a 256-bit (32-byte) key
Rijndael-192 and Rijndael-256 are NOT AES!

And that also hints at the answer to what you asked - you can't use arbitrary key sizes; just the 16 or 32 bytes, depending on which AES variation you want.

Padding with zero bytes may hide the error message, but that's because you're tricking mcrypt into thinking that you're giving it a proper key, while you are in fact not - this doesn't help you, don't do it.

Again, if you're building something for real-world usage - don't roll your own. But if you're in it only for the learning experience, here's a fairly good resource to point you in the right direction: http://timoh6.github.io/2014/06/16/PHP-data-encryption-cheatsheet.html

Upvotes: 1

Artjom B.
Artjom B.

Reputation: 61952

An AES key has a specific key size. If you want to use a different size, then you're likely using passwords instead of keys. Please don't confuse them. A password can be easily remembered. A key is supposed to be chosen randomly and should look like random noise. You need to use a password-based key derivation function like PBKDF2.


Keep in mind that mcrypt will be removed in PHP 7.2. It is abandonware and should not be used anymore.

Upvotes: 1

Related Questions