Equvialent for two lines of mcrypt calls?

Get help with using the PHP Secure Communications Library.

Moderator: Nuxius

Forum rules
The purpose of this forum is to provide support for phpseclib, a pure PHP SSH / SFTP / RSA library.

Posts by new users are held in a moderation queue and are not publicly visible until the post is approved.

Equvialent for two lines of mcrypt calls?

Postby DavidAnderson » Thu Sep 19, 2013 12:05 pm

Hi,

Can anyone with my knowledge of encryption tell me how to implement these two lines of mcrypt_encrypt() calls using phpseclib?

# $crypt_source can be either MCRYPT_RAND or MCRYPT_DEV_URANDOM - but it's not hugely important which is used (as long as it's available - needs to be portable)
$iv = mcrypt_create_iv(16, $crypt_source);
# $token is an arbitrary string
$cipherText = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, 'SomeFixedString', $token, MCRYPT_MODE_CBC, $iv);

Doing this will enable me to drop the dependency on mcrypt for using Dropbox in WordPress's most popular (for new installs, according to rankwp.com) backup plugin - http://updraftplus.com. I'd also be sending the patch to the maintainer of the Dropbox library, which would then lead to the mcrypt dependency being dropped for a lot of other projects too. (These are the only two mcrypt calls in the library).

I'm not intending to be lazy (I've contributed patches to phpseclib in the past) - it's rather that since this code is likely to be very widely deployed, and I'm not an encryption expert, I need to make sure I'm getting it right.

Many thanks,
David
DavidAnderson
Traveler
 
Posts: 8
Joined: Tue Jun 11, 2013 11:56 am

Re: Equvialent for two lines of mcrypt calls?

Postby TerraFrost » Thu Sep 19, 2013 2:53 pm

Try this:

Code: Select all
include('Crypt/Random.php');
include('Crypt/AES.php');

$iv = crypt_random(16);

$aes = new Crypt_AES();
$aes->setIV($iv);
$aes->setPassword('SomeFixedString');
$aes->disablePadding();
$aes->encrypt($token);

phpseclib pads by default whereas mcrypt doesn't so I've disabled that.
TerraFrost
Legendary Guard
 
Posts: 12357
Joined: Wed Dec 04, 2002 6:37 am

Re: Equvialent for two lines of mcrypt calls?

Postby DavidAnderson » Thu Sep 19, 2013 7:02 pm

Hi,

Thanks... I've been playing with that, reading the code and documents and trying to get code that outputs the same, whichever of mcrypt or phpseclib is in use... no success yet. Test code:

Code: Select all
$plaintext = "Please encrypt me!";
$key = 'SomeFixedStringX';
$iv = 'randomstringxxxx'; # crypt_random_string(16);

include('Crypt/Rijndael.php');

$rijndael = new Crypt_Rijndael(CRYPT_RIJNDAEL_MODE_CBC);
$rijndael->setIV($iv);
$rijndael->setPassword($key);
$rijndael->disablePadding();

print base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC, $iv))."\n";
print base64_encode(@$rijndael->encrypt($plaintext))."\n";


Output:

Code: Select all
oJZ+VCtLOTivrNAS8CJo4zoAHVTkXwOzZw1nPf59PIY=
VedKF859Z8yZQfMA9QZnDmyrYF7Y5ArlUZANAFHzEqQ=


Leaving out disablePadding() or changing it to enablePadding() makes no difference to the output.

Any idea what I'm doing wrong?
DavidAnderson
Traveler
 
Posts: 8
Joined: Tue Jun 11, 2013 11:56 am

Re: Equvialent for two lines of mcrypt calls?

Postby TerraFrost » Thu Sep 19, 2013 8:35 pm

Do this:

Code: Select all
<?php
$plaintext = "Please encrypt me!";
$key ='SomeFixedStringX';
$iv = 'randomstringxxxx'; # crypt_random_string(16);

include('Crypt/AES.php');

$rijndael = new Crypt_AES();
$rijndael->setIV($iv);
$rijndael->setKey($key);
$rijndael->disablePadding();

print base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC, $iv))."\n";
print base64_encode(@$rijndael->encrypt($plaintext))."\n";

I made a typo in my last post. setPassword() should have been setKey(). setPassword() does PBKDF2 to turn a password into a key, which mcrypt doesn't do. Sorry about the confusion :(
TerraFrost
Legendary Guard
 
Posts: 12357
Joined: Wed Dec 04, 2002 6:37 am

Re: Equvialent for two lines of mcrypt calls?

Postby DavidAnderson » Thu Sep 19, 2013 9:57 pm

Thank you!

They both produce output which matches, as long as the plaintext is a multiple of the blocksize - but they differ after that (i.e. if padding is needed). (BTW, the mcrypt manual says that it does pad, without being asked (and you can't turn it off, as far as I can see): http://php.net/manual/en/function.mcrypt-encrypt.php. For some reason, the net effect of this is that phpseclib doesn't decrypt the output of mcrypt... but mcrypt does decrypt the output of phpseclib. Why is that - i.e., what have I not understood; presumably something different they do regarding the padding?

Code:

Code: Select all
$plaintext = "Please encrypt me!"; # 18 characters
$key ='SomeFixedStringX';
$iv = 'randomstringxxxx'; # crypt_random_string(16);

include('Crypt/AES.php');

$rijndael = new Crypt_AES();
$rijndael->setIV($iv);
$rijndael->setKey($key);
$rijndael->enablePadding();

$crypted_by_mcrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_CBC, $iv);
$crypted_by_phpseclib = $rijndael->encrypt($plaintext);

print mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $crypted_by_mcrypt, MCRYPT_MODE_CBC, $iv)."\n"; # Recovers $plaintext
print mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $crypted_by_phpseclib, MCRYPT_MODE_CBC, $iv)."\n"; # Recovers $plaintext

print $rijndael->decrypt($crypted_by_mcrypt)."\n"; # Fails to recover $plaintext
print $rijndael->decrypt($crypted_by_phpseclib)."\n"; # Recovers $plaintext


Output:

Code: Select all
Please encrypt me!
Please encrypt me!

Please encrypt me!


Also, I couldn't easily spot the answer to this - what does phpseclib do for an IV if one is not supplied? (mcrypt's manual page says that it uses \0 to the required size).
DavidAnderson
Traveler
 
Posts: 8
Joined: Tue Jun 11, 2013 11:56 am

Re: Equvialent for two lines of mcrypt calls?

Postby TerraFrost » Thu Sep 19, 2013 10:16 pm

mcrypt is null-padding stuf. So if you do urlencode(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $crypted_by_mcrypt, MCRYPT_MODE_CBC, $iv)) you'll see there are a bunch of null bytes tacked on at the end.

phpseclib, in contrast, employs PKCS#1 padding. Which is basically where you append the byte x x times. ie. if you need to add seven characters to make the plaintext a multiple of the blocksize you append chr(7) seven times. If the plaintext already is a multiple of the blocksize you append chr(16) (assuming 16 is the block size) 16 times. ie. so you look at the last byte and remove that many bytes from the end.

chr(0) is an illegal character in PKCS#1 padding since, if you add it, you're basically saying "the plaintext is already the correct length" except that it no longer is since you just added one more byte.

So phpseclib sees chr(0) at the end and is like "that's not a valid PKCS#1 padded byte" and so then it stops.

If you wanted to make phpseclib interoperable with mcrypt (phpseclib already uses mcrypt if it's available btw) you'd need to null pad to the block size using str_pad or something.

lso, I couldn't easily spot the answer to this - what does phpseclib do for an IV if one is not supplied? (mcrypt's manual page says that it uses \0 to the required size).

phpseclib does the same thing if no IV is supplied but one is needed.
TerraFrost
Legendary Guard
 
Posts: 12357
Joined: Wed Dec 04, 2002 6:37 am

Re: Equvialent for two lines of mcrypt calls?

Postby DavidAnderson » Thu Sep 19, 2013 10:32 pm

Thanks very much for taking the time!
DavidAnderson
Traveler
 
Posts: 8
Joined: Tue Jun 11, 2013 11:56 am


Return to phpseclib support

Who is online

Users browsing this forum: No registered users and 1 guest

cron