Frederic Lemoine has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I wrote a script using Crypt::CBC to encrypt a file with Rijndael. The script is "almost" working. I can encrypt and decrypt, however, in the decrypted text, I always get two or three words "corrupted". You will find the script here under, and an example of a decrypted text, so that you can see what I mean by "corrupted" (the original plaintext contains lines of 0123456789).

Thanks for your help.

#!/usr/bin/perl use strict; use warnings; use Crypt::Rijndael; use Crypt::CBC; my $my_key = $ARGV[0]; my $plainfile="test2.txt"; my $cipher; my $buffer; my $decrypted="$plainfile.cry.txt"; # this sub makes all keysize of 32 bytes, in case the key you give is # smaller. However, remember to use a strong key !!! sub get32 { my $data = shift; return "\0" x ( 32 - length($data)%32 ) . $data; } #-------------------------------------------------------------------- # Parameters #-------------------------------------------------------------------- $cipher = Crypt::CBC->new( {'key' => get32($my_key), 'cipher' => 'Rijndael', 'iv' => '§%(Ml7!B', 'regenerate_key' => 1, 'padding' => 'standard', 'prepend_iv' => 0 }); #-------------------------------------------------------------------- # Encryption #-------------------------------------------------------------------- open(FH_plain,"./$plainfile"); open(FH_crypted, ">$plainfile.cry"); while (read(FH_plain,$buffer,1024)) { print FH_crypted $cipher->encrypt($buffer); } close FH_plain; close FH_crypted; #-------------------------------------------------------------------- # Decryption #-------------------------------------------------------------------- open(FH_crypted, "<$plainfile.cry"); open(FH_decrypted, ">$decrypted"); while (read(FH_crypted,$buffer,1024)) { print FH_decrypted $cipher->decrypt($buffer); } close FH_crypted; close FH_decrypted;

Example of decrypted text

0123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789
0123456789012HüÐ3ùÇI5SËLó±Ÿïr g²Ï®Æ›5678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789

0123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789
0123456789012345678901234567890123456789012345678901234567890123456789
01234567890123456789012345¹š°ê6t€Á€&hOÁ*ŠF%Œö8O>¶f
Ë3456789012345678901234567890123456789012345678901234567890123456789

Replies are listed 'Best First'.
Re: Crypt::CBC, Crypt::Rijndael - "almost" working
by Thelonius (Priest) on May 26, 2003 at 14:05 UTC
    The way you are using Crypt::CBC, you are encoding each 1024-byte block of input independently. This produces--for Rijndael at least--a 1040 byte output for each block. So, a work-around (not recommended) would be to read 1040 bytes at a time from the encrypted file. This seems like a fragile solution since the size of the output block might change if you change ciphers or even upgrade the module.

    The better solution is to not encrypt each block independently, but use the chaining feature of Crypt::CBC--which enhances security, too.

    Here's the correct code. Note that I also use binmode. Yes, I'm on Windows, but it's still a good idea to use it on Unix to avoid any unwanted Unicode semantics. Also, I have commented out the 'iv' => '§%(Ml7!B'. Unless you have some specific reason not to, it's better to use a random iv.

    use strict; use warnings; use Crypt::Rijndael; use Crypt::CBC; my $my_key = $ARGV[0]; my $plainfile="test2.txt"; my $cipher; my $buffer; my $decrypted="$plainfile.cry.txt"; # this sub makes all keysize of 32 bytes, in case the key you give is # smaller. However, remember to use a strong key !!! sub get32 { my $data = shift; return "\0" x ( 32 - length($data)%32 ) . $data; } #-------------------------------------------------------------------- # Parameters #-------------------------------------------------------------------- $cipher = Crypt::CBC->new( {'key' => get32($my_key), 'cipher' => 'Rijndael', # 'iv' => '§%(Ml7!B', 'regenerate_key' => 1, 'padding' => 'standard', # 'prepend_iv' => 0 }); #-------------------------------------------------------------------- # Encryption #-------------------------------------------------------------------- open(FH_plain,"./$plainfile"); binmode FH_plain; open(FH_crypted, ">$plainfile.cry"); binmode FH_crypted; $cipher->start('encrypting'); while (read(FH_plain,$buffer,1024)) { print FH_crypted $cipher->crypt($buffer); } print FH_crypted $cipher->finish; close FH_plain; close FH_crypted; #-------------------------------------------------------------------- # Decryption #-------------------------------------------------------------------- open(FH_crypted, "<$plainfile.cry"); binmode FH_crypted; open(FH_decrypted, ">$decrypted"); binmode FH_decrypted; $cipher->start('decrypting'); while (read(FH_crypted,$buffer,1024)) { print FH_decrypted $cipher->crypt($buffer); } print FH_decrypted $cipher->finish; close FH_crypted; close FH_decrypted;
    Your "get32" function is not necessary. It doesn't add to security in any significant way, except slightly by obscurity.

      Thank you so much for your help and your very good explanation.