views:

837

answers:

3

Hi,

One of the tasks I have to do needs me to encrypt something from PHP's side, and then decrypt it with Perl.

The PEAR module I've found which appeared to be suitable for my needs was Crypt_CBC. However, there must be something I'm doing wrong or do not understand, as I've been unable to achieve getting the correct results so far.

The code excerpts below are specifically intended for test purposes, as I've wanted to try it all out before applying it to my actual project's code.

First, here's my PHP code, with which I encrypt whatever is passed to a $text parameter (i.e. cryptTest.php?text=hello)

require_once('Crypt/CBC.php');  

$key = "8326554161EB30EFBC6BF34CC3C832E7CF8135C1999603D4022C031FAEE";  
$cipher = new Crypt_CBC($key, 'BLOWFISH');

$encrypted = $cipher->encrypt($text);  

if (PEAR::isError($encrypted)) {  
    echo $encrypted->getMessage();  
} else {  
    echo "ENCRYPTED STRING: " . $encrypted;  
}

From that point, I copy whatever is echoed from this script (on my browser's output) and paste it in the $encrypted variable of my PERL script below:

use Crypt::CBC; 
$encrypted = "RandomIVá´bp3Ó¯làK”Á(Û";  
my $key = "8326554161EB30EFBC6BF34CC3C832E7CF8135C1999603D4022C031FAEE";  
my $vector = "\0\0\0\0\0\0\0\0";  

my $cipher = Crypt::CBC->new(  
                       {'key'             =>$key,  
                        'cipher'          => 'Blowfish',  
                        'iv'              => $vector,  
                        'prepend_iv'      => 0  
                       });  

my $plaintext = $cipher->decrypt($encrypted);

print $plaintext;

I've been trying out many things, like not specifying the IV on Perl side and such, but it kept giving me errors. This form is the only one with which I'm getting any output at all.

The result for the execution of the above, with original $text = "hello" is: Pñšîî7àÐŽZÊ&Rhello

What I find is that my original content is correctly decrypted, but not without adding a bunch of crap-characters before the part I want.

Can anyone point me to whatever I'm doing wrong and how I can resolve it?

Thanks a bunch.

+3  A: 

CBC is not fault tolerant; a problem with the cipher text destroys the entire block. So, the fact that you are able to recover the plain text with some extra garbage suggests that the problem is with padding, not the encryption itself.

A block cipher works on full blocks. If the last block is incomplete, it is padded in a way that allows the recipient to determine what is padding and what is data. Search the API documentation to find out how padding is treated.

If possible, converted the decrypted plaintext to hexadecimal and post it so that the unprintable bytes are visible. That might reveal the padding scheme used on the PHP side.

erickson
+2  A: 

You shouldn't be doing this with the plain output of your encryption routine. You are likely to run into all sorts of encoding problems. I suggest you base64-encode your encrypted string and copy and paste that and then base64-decode it before decryption.

innaM
+3  A: 

I finally found the solution to my problem.

Thanks to both of you guys though, your answers did help out. I did follow your advice to encode/decode in base64 and therefore avoid any plain-text encoding problems.

What I had to do in order to make the decryption work is add 'header' => 'randomiv' to my Perl script's cipher creation, since PEAR's Crypt_CBC class uses a Random IV when encrypting.

I found that particular parameter in Crypt::CBC's documentation.

Also, looking directly into CBC.php's decrypt function, I found what it did in order to determine the IV: Take the header's ('RandomIV') length, and use it as an offset to substr the encrypted string up to the blocksize's value (8 by default). I also specified the keysize (56 by default) for good measure.

For completeness' sake and for reference, here are both of my updated test scripts:

PHP (cryptTest.php):

require_once('Crypt/CBC.php');

$key = "8326554161EB30EFBC6BF34CC3C832E7CF8135C1999603D4022C031FAEE";  
$cipher = new Crypt_CBC($key, 'BLOWFISH');

$encrypted = $cipher->encrypt($text);

if (PEAR::isError($encrypted)) {  
    echo $encrypted->getMessage();  
} else {  
    echo "ENCRYPTED STRING: " . base64_encode($encrypted);  
}

PERL (decryptTest.pl)

use Crypt::CBC;  
use MIME::Base64;

my $encrypted = decode_base64("UmFuZG9tSVbrNE3ony00FlUbiprLn0fu");  
my $key = "8326554161EB30EFBC6BF34CC3C832E7CF8135C1999603D4022C031FAEE";  
my $header_spec = "randomiv";  
my $blocksize = 8;  
my $keysize = 56;  

my $iv_offset = length $header_spec;  
my $iv = substr $encrypted, $iv_offset, $blocksize;

my $cipher = Crypt::CBC->new(  
                {'key'        =>$key,  
                'cipher'     => 'Blowfish',  
                'iv'         => $iv,  
                'header'     => $header_spec,  
                'prepend_iv'    => $iv_offset,  
                'blocksize'  => $blocksize,  
                'keysize'      => $keysize   
                })  

my $plaintext = $cipher->decrypt($encrypted);

print $plaintext;

There you go. Again, thanks a lot!

Mathieu

Mathieu