in reply to Re^2: line by line Encryption fun with Crypt::CBC and Rijndael? File Ownership issues?
in thread line by line Encryption fun with Crypt::CBC and Rijndael? File Ownership issues?

I wrote the code you need.

Some utility functions

sub read_bytes { my ($fh, $to_read) = @_; my $buf = ''; while ($to_read) { my $bytes_read = read($fh, $buf, $to_read, length($buf)); die("$!\n") if !defined($bytes_read); die("Unexpected end of file\n") if !$bytes_read; $to_read -= $bytes_read; } return $buf; } sub read_uint32 { my ($fh) = @_; return (unpack('N', read_bytes($fh, 4))); } sub read_str { my ($fh) = @_; my $length = read_uint32($fh); return read_bytes($fh, $length); } sub write_uint32 { my ($fh, $n) = @_; print $fh (pack('N', $n)); } sub write_str { my ($fh, $str) = @_; print $fh (pack('N', length($str)), $str); }

The line-by-line encrypter:

sub writeSubmissions { my ($cipher, $log_file, $str) = @_; open(my $FH_encrypted, '>>', $log_file) or die; binmode $FH_encrypted; flock $FH_encrypted, LOCK_EX; write_str($FH_encrypted, $cipher->encrypt($str)); } my $key_file = 'key_file.txt'; my $act_log_file = "pem.enc"; my $pem_log_file = "act_encrypted.enc"; my $my_key = `openssl enc -bf-cbc -d -in \Q$key_file\E -k encrypt`; my $cipher = Crypt::CBC->new({ key => $my_key, cipher => 'Rijndael' }) +; writeSubmissions($cipher, ..., ...);

The line-by-line decrypter:

my $key_file = 'key_file.txt'; my $encrypted = '...'; my $decrypted = '...'; my $my_key = `openssl enc -bf-cbc -d -in \Q$key_file\E -k encrypt`; my $cipher = Crypt::CBC->new({ key => $my_key, cipher => 'Rijndael' }) +; open(my $FH_decrypted, '>', $decrypted) or die("Unable to create decrypted file \"$decrypted\": $!\n"); binmode $FH_decrypted; flock $FH_decrypted, LOCK_EX; open(my $FH_encrypted, '<', $encrypted) or die("Unable to open encrypted file \"$encrypted\": $!\n"); binmode $FH_encrypted; flock $FH_encrypted, LOCK_SH; while (!eof($FH_encrypted)) { print $FH_decrypted $cipher->decrypt(read_str($FH_encrypted)); }

Update: Fixed bugs mentioned in replies.
Update: Tested (minus the openssl bit). Fixed other bugs.

  • Comment on Re^3: line by line Encryption fun with Crypt::CBC and Rijndael? File Ownership issues? (code)
  • Select or Download Code

Replies are listed 'Best First'.
Re^4: line by line Encryption fun with Crypt::CBC and Rijndael? File Ownership issues? (code)
by hmbscully (Scribe) on Dec 05, 2007 at 19:16 UTC
    Many thanks.
    I'm off to test away...

    I learn more and more about less and less until eventually I know everything about nothing.

      Oops!
      while (!eof($FH_decrypted)) {
      should be
      while (!eof($FH_encrypted)) {
      (Fixed in original)

Re^4: line by line Encryption fun with Crypt::CBC and Rijndael? File Ownership issues? (code)
by hmbscully (Scribe) on Dec 05, 2007 at 20:18 UTC
    I'm a little lost in
    open(my $FH_encrypted, '<', $encrypted") or die("Unable to open encrypted file \"$encrypted\": $!\n"); binmode $FH_crypted; flock $FH_crypted, LOCK_SH; while (!eof($FH_encrypted)) { print $FH_decrypted $cipher->decrypt(read_str($FH_crypted)); }
    the $FH_crypted is confusing me. Is that a third filehandle or should it be either _decrypted or _encrypted?

    I learn more and more about less and less until eventually I know everything about nothing.
      Sorry, copy and paste error due to the lack of consistency between the file handle names in your two programs.
Re^4: line by line Encryption fun with Crypt::CBC and Rijndael? File Ownership issues? (code)
by hmbscully (Scribe) on Dec 06, 2007 at 15:42 UTC
    Trying to understand what is going on here:
    sub read_bytes { my ($fh, $to_read) = @_; $buf = ''; while ($to_read) { <b>my $bytes_read = read($FH_decrypted, $buf, length($buf));</b> die("$!\n") if !defined($bytes_read); die("Unexpected end of file\n") if !$bytes_read; $to_read -= $bytes_read; } return $buf; }

    Should $FH_decrypted be $fh instead? Otherwise the value in $fh being passed to the function is seemingly never used.
    Why is the value of $buf set to an empty string? Won't length($buf) be zero and therefore nothing would ever be read?


    I learn more and more about less and less until eventually I know everything about nothing.
      my $bytes_read = read($fh, $buf, $to_read, length($buf));

      Sorry, so many mistakes. I went and tested the code, made a couple more fixes. See the original post with the code.

Re^4: line by line Encryption fun with Crypt::CBC and Rijndael? File Ownership issues? (code)
by Anonymous Monk on Jul 23, 2008 at 17:27 UTC
    Hi, I am trying to use your code and I get the "Unexpected end of file" error while decrypting.

    The call to SUB read_uint32 works fine the first time and the value of $to_read = 4 in SUB read_bytes. Inside SUB read_bytes in the while ($to_read) loop, the value of $buf = 'Rand' (the first 4 characters in my encrypted file).

    Once SUB read_unit32 returns control to SUB read_str, the value of $length is set at some large number. I get an error during the call: read_bytes($fh, $length).

    It attempts to read $length the first time around, so say length = 825373492 was passed to read_bytes. Then, to_read = 825373492 The first iteration through the while loop decrements $to_read as below: WHILE to_read = 825370130

    However, in the next iteration I get the error.

    13:05:54 ERROR ***** 13:05:54 Unexpected end of file

    Could you please help or guide me in the right direction? I apologize if my elaborating the problem in this way causes problems. I wasn't sure on how else to do it. Thanks, Sam
      Are you sure the file was created using my write_str? The point of this thread was to create an appendable encrypted file format. I proposed such a file format, my encrypter produces it, and my decrypter decrypts it (and only it).
      >perl 700015.pl Hello World foo bar >debug data.enc -rcx CX 0040 : -d100 l40 0100 00 00 00 20 53 61 6C 74-65 64 5F 5F 90 66 5E D2 ... Salted__.f^. ^^^^^^^^^^^ 0110 88 43 CE 87 E6 FE 44 DA-2C E8 84 FF 2B 2B A1 84 .C....D.,...++.. 0120 FD BB 96 89 00 00 00 18-53 61 6C 74 65 64 5F 5F ........Salted__ ^^^^^^^^^^^ 0130 1F 12 77 C8 38 9A 4B 69-A2 33 51 9D 03 60 50 27 ..w.8.Ki.3Q..`P' -q

      You seem to be missing the higlighted parts.

      700015.pl:

      use strict; use warnings; use Crypt::CBC qw( ); my $qfn = 'data.enc'; sub read_bytes { my ($fh, $to_read) = @_; my $buf = ''; while ($to_read) { my $bytes_read = read($fh, $buf, $to_read, length($buf)); die("$!\n") if !defined($bytes_read); die("Unexpected end of file\n") if !$bytes_read; $to_read -= $bytes_read; } return $buf; } sub read_uint32 { my ($fh) = @_; return (unpack('N', read_bytes($fh, 4))); } sub read_str { my ($fh) = @_; my $length = read_uint32($fh); return read_bytes($fh, $length); } sub write_uint32 { my ($fh, $n) = @_; print $fh (pack('N', $n)); } sub write_str { my ($fh, $str) = @_; print $fh (pack('N', length($str)), $str); } { my $key = Crypt::CBC->random_bytes(8); my $cipher = Crypt::CBC->new({ key => $key, cipher => 'Blowfish' }) +; { open(my $fh, '>', $qfn) or die; binmode($fh); write_str($fh, $cipher->encrypt("Hello World")); write_str($fh, $cipher->encrypt("foo bar")); } { open(my $fh, '<', $qfn) or die; binmode($fh); while (!eof($fh)) { print($cipher->decrypt(read_str($fh)), "\n"); } } }

      (Blowfish was used since I'm having a linking problem with Rjindael. You should get similar results with both)

        Thank you very much for your help. I changed the pack/unpack to little-endian order and that worked. If I have to encrypt something on an outside machine and decrypt it at my end (using the encrypter and decrypter above), do they both have to be the same endian?

        Could I use your recommendation above to encrypt and decrypt large files (about 3 million records) or would you have any suggestions or reference points you could guide me to?

        As a useless side-note: I use Tera Term Pro version 2.3 and sometimes when I 'more' the encrypted and decrypted files, my entire charset on the terminal gets funky.

        Thanks again.