2
votes

I have some ciphertext that has been encrypted using Perl's Crypt::CBC module that I wish to decrypt elsewhere.

The ciphertext was generated using the 'simple' version of the Crypt::CBC constructor, that is:

use Crypt::CBC;
$cipher = Crypt::CBC->new( -key    => 'my secret key',
                           -cipher => 'Blowfish'
                          );

From reading the MAN page, this method of construction will take the simple string key and random salt to generate an IV & literal key to use for encryption, as well as embed a header with the salt.

"salt" -- Combine the passphrase with an 8-byte random value to generate both the block cipher key and the IV from the provided passphrase. The salt will be appended to the beginning of the data stream allowing decryption to regenerate both the key and IV given the correct passphrase. This method is compatible with current versions of OpenSSL.

I now need to decrypt the ciphertext on another platform that only supports CBC decryption given the ciphertext, a literal key & IV. To attempt to generate the literal key, IV & salt, I used Crypt::CBC to generate the values like so:

my $crypt = new Crypt::CBC(-key => 'my secret key', -cipher => 'Blowfish');
my $out = $crypt->decrypt($ciphertext);
my $literal_key = $crypt->key();
my $iv = $crypt->iv();
my $salt = $crypt->salt();

The decryption here is correct, but I've been unable to use the generated literal key & IV to decrypt the cipher; this produces rubbish:

my $crypt2 = new Crypt::CBC(
    -literal_key => 1,
    -key => $literal_key,
    -cipher => 'Blowfish',
    -iv => $iv,
    -header => 'none');
my $rubbish - $crypt2->decrypt($ciphertext);

I can't provide a literal key and use a salted header so I'm lost as to the next move.

How can I decrypt this text?

EDIT: The target system is not running Perl, but I have been able to generate the identical value as in $rubbish above, so I'm sure it's using the same algorithm (CBC, Blowfish) to decipher.

3

3 Answers

1
votes

To decrypt the stream, you first need to remove the header added by Crypt::CBC's "salt" mode. The header consists of the 8 characters Salted__ followed by 8 bytes of salt data.

In perl, something like this should do it:

my $crypt2 = new Crypt::CBC(
    -literal_key => 1,
    -key => $literal_key,
    -cipher => 'Blowfish',
    -iv => $iv,
    -header => 'none');
my $cleartext = $crypt2->decrypt(substr($ciphertext, 16));
1
votes

This may work. Your key will have to be exactly 56 bytes in length and the iv will have to be exactly eight bytes long:

#!/usr/bin/perl

use strict;
use warnings;

use Crypt::CBC;

my $key = "x" x 56;
my $iv  = "x" x 8;

my $plaintext  = "this is just some normal text\n";
my $ciphertext = Crypt::CBC->new(
    -cipher      => 'Blowfish',
    -header      => 'none',
    -literal_key => 1,
    -key         => $key,
    -iv          => $iv,
)->encrypt($plaintext);

print Crypt::CBC->new(
    -cipher      => 'Blowfish',
    -header      => 'none',
    -literal_key => 1,
    -key         => $key,
    -iv          => $iv,
)->decrypt($ciphertext);
1
votes

If anybody needs the _salted_key_and_iv function in PHP - here it is:

function _salted_key_and_iv ($pass, $salt) {
        if(strlen($salt) != 8) {
            die("Salt must be 8 bytes long");
        }

        $key_len = 56;
        $iv_len  = 8;

        $desired_len = $key_len+$iv_len;

        $data  = '';
        $d = '';

        while (strlen($data) < $desired_len) {
            $d = pack("H*", md5($d . $pass . $salt));
            $data .= "$d";
        }

        return $data;
}