Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mcrypt encrypt adding s bunch of '%00' to end of string

Working with OAuth and encrypting the keys with the following function with a string which we'll call 'foo' (actually an OAuth token)

public function encrypt( $text )
{
    // add end of text delimiter
    $data = mcrypt_encrypt( MCRYPT_RIJNDAEL_128, $this->key, $text, MCRYPT_MODE_ECB, $this->iv );
    return base64_encode( $data );
}

When I decrypt it using the inverse function, I end up with:

Function:

    public function decrypt( $text )
    {
        $text = base64_decode( $text );
        return mcrypt_decrypt( MCRYPT_RIJNDAEL_128, $this->key, $text, MCRYPT_MODE_ECB, $this->iv );
    }

Result:

foo%00%00%00%00%00%00%00%00%00%00%00%00%00%00

Edit:

Looking at it a little more, I realized that it is actually URL encoding to %00, which means that my strings are somehow being padded by null characters? So I am currently using trim() to get rid of them, but I would like to understand why this is happening.

like image 442
Chris Sobolewski Avatar asked Apr 15 '11 03:04

Chris Sobolewski


3 Answers

Rijndael is a block cypher, which means that it operates on chunks of data of a particular length (128 bits in this case). This means that if the length of the input text is not a multiple of the block size, it must be padded out to fit. In this case, the padding is zeros; there are a number of other possible padding schemes that could be used, but if you want them with PHP's mcrypt you'll have to apply them manually.

like image 183
Anomie Avatar answered Nov 11 '22 14:11

Anomie


You can Fix it with this method to get rid of padding characters: In our case we are using Zend.

$filter = new Zend_Filter_Decrypt(array('adapter' => 'mcrypt'));
$filter->setVector($lpt->_seed);
str_replace("\x0", '', trim($filter->filter(base64_decode($textToDecrypt))));
like image 1
Nazanin Daneshvar Avatar answered Nov 11 '22 12:11

Nazanin Daneshvar


MCRYPT_MODE_ECB means that you are using ECB, a block cipher mode of operation. Block ciphers can be handled either for block cipher modes of operation or for stream cipher modes of operation. Common block cipher modes are ECB and CBC, a common stream cipher mode is CTR, better known as counter mode operation.

MCRYPT_RIJNDAEL_128 is an implementation of AES. AES is the Rijndael cipher with a block size of 128 bits, and three possible key sizes, 128, 192 and 256 bits. So if you use a block cipher mode of encryption then you need to divide up the plain text is sizes of 128 bits - 16 bytes - each. Of course this leaves you with the question what to do when the last block is not 16 bytes.

PHP's mcrypt_encrypt more or less leaves this up to the user. It pads with 00 valued characters if the block is not full up to the block size. This is fine if the input is a string; you can simply trim off the 00 characters from the returned string. If the input is however binary data that ends with a 00 character than that character is lost (+ any other character that is taken from the start and end of the string of course). You can also send the length of the string encrypted together with the plaintext of course.

For a better scheme you only have to look at PKCS#7 padding. Multiple code snippets for implementing the padding can be found in the comments section of mcrypt_encrypt.

mcrypt_encrypt currently does not seem to support stream modes for AES, so that option is out if you want to keep with the PHP mcrypt library.

like image 1
Maarten Bodewes Avatar answered Nov 11 '22 13:11

Maarten Bodewes