Search code examples
c#.netperlencryptionrijndael

Encrypt file in Perl and decrypt in c#


I'm trying to encrypt a text file using Perl and then decrypt it using a different application written in C#. Here's my Perl code:

use strict;
use Crypt::CBC;

my $ifh;
my $ofh;
my $line;

my $cipher = Crypt::CBC->new(
    {
        'key'         => 'length16length16',
        'cipher'      => 'Rijndael',
        'iv'          => 'length16length16',
        'literal_key' => 1,
        'header'      => 'none',
    'padding'     => 'null',
        'keysize'     => 128 / 8
    }
);

open($ifh,'<', $infile)
            or die "Can't open $infile for encryption input: $!\n";
open($ofh, '>', $outfile)
        or die "Can't open $outfile for encryption output: $!\n";

$cipher->start('encrypting');

for $line (<$ifh>) {
    print $ofh $cipher->crypt($line);
  }

print $ofh $cipher->finish;

close($ifh)
    or die "Error closing input file: $!\n";

close($ofh)
    or die "Error closing output file: $!\n";

And my C# code for decryption:

    RijndaelManaged myRijndael = new System.Security.Cryptography.RijndaelManaged();
    myRijndael.Key = System.Text.Encoding.UTF8.GetBytes("length16length16");
    myRijndael.IV = System.Text.Encoding.UTF8->GetBytes("length16length16");
    myRijndael.Mode = CipherMode.CBC;
    myRijndael.Padding = PaddingMode.None;

    // Create a decryptor to perform the stream transform.
    ICryptoTransform decryptor = myRijndael.CreateDecryptor(myRijndael.Key, myRijndael.IV);

    //Create the streams used for decryption.
    FileStream file = File.OpenRead(strInFile);
    CryptoStream csDecrypt = new CryptoStream(file, decryptor, CryptoStreamMode.Read);
    StreamReader srDecrypt = new StreamReader(csDecrypt);

    // Read the decrypted bytes from the decrypting stream
    string decryptedText = srDecrypt.ReadToEnd();

I keep getting

System.Security.Cryptography.CryptographicException: Length of the data to decrypt is invalid

When I try to read the data a few bytes at a time, I notice that the first 100 or so bytes are decrypted properly, but the rest is just garbage.

BTW, I can decrypt the encrypted file using Perl with:

$cipher->start('decrypting');

So what am I doing wrong with C# and Perl?

EDIT: I tried following @munissor advice and change the C# code to use

PaddingMode.Zeros

but I still get the same exception. Help please...


Solution

  • Found the solution!!!

    In Perl, I had to add after the opening of the output file:

    binmode $ofh;

    The padding suggestion was helpful, but in the end I omitted the padding directive and used the default which is PKCS7 in Perl and in C#.

    My final Perl code looks like this:

    use strict;
    use Crypt::CBC;
    
    my $ifh;
    my $ofh;
    
    my $cipher = Crypt::CBC->new(
        {
          'key'         => 'length16length16',
          'cipher'      => 'Rijndael',
          'iv'          => 'length16length16',
          'literal_key' => 1,
          'header'      => 'none',
          'keysize'     => 128 / 8
        }
    );
    
    #open input and output file
    open($ifh,'<', $infile)
            or die "Can't open $infile for encryption input: $!\n";
    open($ofh, '>', $outfile)
        or die "Can't open $outfile for encryption output: $!\n";
    binmode &ofh;
    
    $cipher->start('encrypting');
    
    #write encrypted data to output file
    while (read($ifh,my $buffer,1024)) 
    {
        print $ofh $cipher->crypt($buffer);
    } 
    
    print $ofh $cipher->finish;
    
    #close file handles
    close($ifh)
        or die "Error closing input file: $!\n";
    close($ofh)
        or die "Error closing output file: $!\n";
    

    and the C# part:

    RijndaelManaged myRijndael = new System.Security.Cryptography.RijndaelManaged();
    myRijndael.Key = System.Text.Encoding.UTF8.GetBytes("length16length16");
    myRijndael.IV = System.Text.Encoding.UTF8->GetBytes("length16length16");
    myRijndael.Mode = CipherMode.CBC;
    
    // Create a decryptor to perform the stream transform.
    ICryptoTransform decryptor = myRijndael.CreateDecryptor(myRijndael.Key, myRijndael.IV);
    
    //Create the streams used for decryption.
    FileStream file = File.OpenRead(strInFile);
    CryptoStream csDecrypt = new CryptoStream(file, decryptor, CryptoStreamMode.Read);
    StreamReader srDecrypt = new StreamReader(csDecrypt);
    
    // Read the decrypted bytes from the decrypting stream
    string decryptedText = srDecrypt.ReadToEnd();