Subject: | Decryption error when splitting data over blocks |
Decrypting doesn't appear to work properly when ->decrypt is called multiple times on small blocks, as opposed to once overall.
Setup using a randomly-generated key:
eval: my $r = Crypt::Rijndael->new( pack('H*', 'af5a82cd7471cf035c50f1aa353d0209'), Crypt::Rijndael::MODE_CFB );
Set an IV and encrypt some plaintext:
eval: $r->set_iv( pack( 'H*', '7a2362b5e9f8aa3b2bc9ba10eaf0fe32' ) );
eval: my $plaintext = "E" x 64;
'EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE'
eval: my $ciphertext = $r->encrypt( $plaintext );
"Z \x1f1;\xca\xee\x95f\xad\xf6\x88K\x8c\t\x053\xb4\n]\xfe\x9b\xf1HD\eb%\xd0\xc97\xf7\x84\xd8\x13\xa9\x81\xd5\xaex\xc5\x9a:e\xc2\x8c\xfc\xdf_\x03i\x85\xcf\xc0\xc2t\x99\x9a\x80\xce\x9c\xaa$\x8a"
Reset the IV and decrypt it in one go:
eval: $r->set_iv( pack( 'H*', '7a2362b5e9f8aa3b2bc9ba10eaf0fe32' ) );
eval: $r->decrypt( $ciphertext )
'EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE'
Reset the IV and decrypt it this time in two individual blocks:
eval: $r->set_iv( pack( 'H*', '7a2362b5e9f8aa3b2bc9ba10eaf0fe32' ) );
eval: $r->decrypt( substr $ciphertext, 0, 16 )
'EEEEEEEEEEEEEEEE'
eval: $r->decrypt( substr $ciphertext, 16, 16 )
",\xd1P)\x80\x14Z\x98g\xf3\xd1\xe8\xde\x00{\xb7"
I believe this comes down to the fact that in _rijndael.c's block_encrypt() and block_decrypt(), you reset the block state to the IV on every call, thus restarting every ->decrypt method from the IV, rather than saving state from the previous call.
I would suggest that to fix it, the object's stored IV should be updated from the latest state of the block, so that multiple small ->decrypt calls can work correctly.
This is vital for me as I am processing a multi-gigabyte file in blocks, as it is downloaded, and I can't buffer the entire thing in RAM first before calling a single ->decrypt operation on the whole thing.
--
Paul Evans