Search code examples
pythonencryptionpycrypto

Using PyCrypto to decrypt Perl encrypted password


I'm trying to decrypt a pass phrase stored in a file. The encryption was done with the Perl::CBC module, but I need to decrypt it for a Python script. Frankly, I don't know much (or anything really) about encryption algorithms.

The pass phrase was encrypted something like this:

use Crypt::CBC;

my $key = '0123456789';
my $iv  = '$KJh#(}q';

my $cipher = Crypt::CBC->new(
    -key    => $key,
    -cipher => 'Blowfish',
    -header => 'none',
    -iv     => $iv,
);

my $passphrase = 'You have decrypted the passphrase.';
my $hex_encrypted = $cipher->encrypt_hex($passphrase);

which gives an encrypted passphrase: 9033c838e4418fbdc50a9fc0813745296d195d59954008f94b2b36a8e65dca959686206960a7828a

Now, I need to use this in a Python script (using Python 2.7). Naively, I was hoping this would work:

from Crypto.Cipher import Blowfish
from binascii import hexlify, unhexlify

perl_pass =  unhexlify('9033c838e4418fbdc50a9fc0813745296d195d59954008f94b2b36a8e65dca959686206960a7828a')
key = '0123456789'
iv  = '$KJh#(}q'
print Blowfish.new(key, Blowfish.MODE_CBC, iv).decrypt(perl_pass)

but that only seems to create a bunch of unprintable junk. I've played around a bit without success. I'm not really sure what I need to do here to get this password decrypted successfully.


Solution

  • The "key" you give to Crypt::CBC is actually a passphrase, from which a 'literal key' is generated; Crypto.Cipher.Blowfish needs that literal key, rather than the passphrase. You can print that generated key in hex from your Perl program, then use it in Python:

    use Crypt::CBC;
    
    my $key = '0123456789';
    my $iv  = '$KJh#(}q';
    
    my $cipher = Crypt::CBC->new(
        -key    => $key,
        -cipher => 'Blowfish',
        -header => 'none',
        -iv     => $iv,
    );
    
    my $passphrase = "You have decrypted the passphrase.";
    my $hex_encrypted = $cipher->encrypt_hex($passphrase);
    
    print unpack('H*', $cipher->key()), "\n";
    

    -

    $ perl perl_crypt_cbc.pl
    781e5e245d69b566979b86e28d23f2c78e938564cd1410f0ec1c1781466a6738bab0a6ed984c75ab34c68bbf7558077714043c5bdb959e46
    

    -

    from Crypto.Cipher import Blowfish
    from binascii import hexlify, unhexlify
    
    perl_pass = unhexlify("9033c838e4418fbdc50a9fc0813745296d195d59954008f94b2b36a8e65dca959686206960a7828a")
    
    key = unhexlify("781e5e245d69b566979b86e28d23f2c78e938564cd1410f0ec1c1781466a6738bab0a6ed984c75ab34c68bbf7558077714043c5bdb959e46")
    iv  = '$KJh#(}q'
    print Blowfish.new(key, Blowfish.MODE_CBC, iv).decrypt(perl_pass)
    

    -

    python python_crypt_cbc.py 
    You have decrypted the passphrase.
    

    Note that there will be a few unprintable characters at the end: Blowfish-encrypted strings must be a multiple of 8 bytes, so Perl silently pads it. The byte it's padded with is the length of the padding: in this case, six bytes of padding, so each of them is 0x06. You can easily remove them:

    from Crypto.Cipher import Blowfish
    from binascii import hexlify, unhexlify
    
    perl_pass = unhexlify("9033c838e4418fbdc50a9fc0813745296d195d59954008f94b2b36a8e65dca959686206960a7828a")
    
    key = unhexlify("781e5e245d69b566979b86e28d23f2c78e938564cd1410f0ec1c1781466a6738bab0a6ed984c75ab34c68bbf7558077714043c5bdb959e46")
    iv  = '$KJh#(}q'
    num_padding = ord(Blowfish.new(key, Blowfish.MODE_CBC, iv).decrypt(perl_pass)[-1])
    
    print Blowfish.new(key, Blowfish.MODE_CBC, iv).decrypt(perl_pass)[:(-1*num_padding)]