http://www.perlmonks.org?node_id=509238


in reply to AES Interoperability between Perl and C#

It appears that Crypt::Rijndael's set_iv (16 byte IV) should be used instead of Crypt::CBC's set_initialization_vector (8 byte IV).

Update: That's apparently easier said than done, when using Crypt::CBC. I'm looking into it.

Update: Sorry, I don't see how Crypt::Rijndael (from Crypt-Rijndael-0.05) can possibly be compatible with Crypt::CBC (from Crypt-CBC-2.15) as it claims. Not necessarily by choice, mind you. Crypt::CBC is fixated on 8 byte blocks.

Crypt::Rijndael without Crypt::CBC seems to do CBC just fine, but it doesn't provide a mechanism to pad the data to encrypt to a multiple of 16 bytes, and it doesn't provide a mechanism to remove padding from decrypted data. And if you have to send/extract the IV... not handled either.

Replies are listed 'Best First'.
Re^2: AES Interoperability between Perl and C#
by ikegami (Patriarch) on Nov 17, 2005 at 00:33 UTC

    There! Figured it out!

    There is an IV in Crypt::Rijndael and there is a different one in Crypt::CBC. Previously, I thought there was a conflict between the two. However, I finally realized the one in Crypt::Rijndael is not used when Crypt::Rijndael is used through Crypt::CBC. Crypt::CBC uses Crypt::Rijndael in ECB mode. In ECB mode, Crypt::Rijndael doesn't use its IV, leaving Crypt::CBC free to use its IV.

    So why must the Crypt::CBC IV be 8 bytes long? It turns out that Crypt::CBC works with 16 byte blocks with Crypt::Rijndael, so the IV must be 16 bytes long for Crypt::CBC too! It turns out the IV length check is bogus.

    So all you need to do is to bypass the IV length check. It's actually quite simple: Use the method iv instead of the method get_initialization_vector and set_initialization_vector, or use the iv argument to the Crypt::CBC constructor. These don't check the length of the supplied IV. For example:

    use Crypt::CBC; $cipher = Crypt::CBC->new( -cipher => 'Rijndael', ... ); $cipher->iv($iv); $ciphertext = $cipher->encrypt("This data is hush hush"); $plaintext = $cipher->decrypt($ciphertext);
    or
    use Crypt::CBC; $cipher = Crypt::CBC->new( -cipher => 'Rijndael', -iv => $iv, ... ); $ciphertext = $cipher->encrypt("This data is hush hush"); $plaintext = $cipher->decrypt($ciphertext);

    (Untested. I don't have these modules.)

      Looks like that got me past the IV problem, but I still can't get a clean decryption of the AES output from C#. I'm starting to wonder if Crypt::CBC is just plain broken for Crypt::Rijndael. I ran the C# code that Thelonius provided and then passed the generated string back through Crypt::CBC with the correct IV set and it still didn't decrypt properly.

      While I'd have to implement padding and IV extraction by hand if I don't use the module (which is not ideal) I don't know what else to do if the module won't do it properly.

      Found the error; Thelonius was using the key literally to encrypt his data, while I was using a hash of the key to decrypt it. When I told Crypt::CBC to use the key literally, it worked!