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

This works fine on Encrypting any file but if it is more than a couple lines long it would only decrypt part of the file. I am at a quandary as to why it would do a partial decryption.
Sparky
#!c:/perl/bin/perl -w use Crypt::TripleDES; use strict; my $des = new Crypt::TripleDES; my $passcode; my $inst = $ARGV[0]; my $inputfile = $ARGV[1]; my $outputfile = $ARGV[2]; my $i = @ARGV; &Get_Input; &Cypher_Run; sub Get_Input{ print "Get pass code > "; $passcode = <STDIN>; } sub Cypher_Run{ my @file; open(INPUT, "<$inputfile") || die "Could not open input file:$!\n" +; open(OUTPUT, ">$outputfile") || die "Could not open output file:$! +\n"; while (<INPUT>){chomp($_); push (@file, $_)}; if ($inst eq 'e'){ foreach (@file){ my $cyphertext = $des->encrypt3 ( $_, $passcode ); print OUTPUT "$cyphertext\n"; } } elsif ($inst eq 'd'){ foreach (@file){ my $plaintext = $des->decrypt3 ( $_, $passcode ); print OUTPUT "$plaintext\n"; } } }

Replies are listed 'Best First'.
(ichimunki) Re: Crypt::TripleDES decrypting problem
by ichimunki (Priest) on Jan 10, 2002 at 04:38 UTC
    I have two questions: first, have you tried concatenating the input instead of going through line by line to see if you can get this to work that way? And second, if you are going to continue with the line-by-line approach, why load the whole file into memory at once?
      I dropped the @file and worked directly with the file. I still have the same problem.
      while (<INPUT>){ my $plaintext = $des->decrypt3 ( $_, $passcode ); print OUTPUT "$plaintext"; }
      Sparky
        I think that's odd. It should be able to accept those \n-delimited records as unique bits, and you appeared to be storing them again as \n delimited records. Which means that maybe \n is not a reliable separator for whatever reason. Have you tried concatenating all of the records in the plaintext file before encrypting (i.e. keep the \n in there, just simply slurp the file into a scalar) and then decrypting that ciphertext as a single blob as well?
Re: Crypt::TripleDES decrypting problem
by khkramer (Scribe) on Jan 11, 2002 at 00:33 UTC

    Hi,

    You have a couple of problems, here. One is the "\n". The encrypted data is no longer text, so you can't think about it as line- or record-oriented anymore. You're liable to encounter an "\n" byte where you don't expect it, when reading back in the encrypted file (which is now just bytes, rather than ASCII or whatever it was).

    You note that you've removed the new-line stuff, and that the script still doesn't work, But if you're still using the <> operator to process your files, then you've still got the record-processing problem in a different form.

    DES is a block cipher: it works on data of a fixed length. For DES, the block size is 64 bits. DES expects to be fed 8 bytes of plaintext (64 bits), and will give you back 8 bytes of encrypted data. The Crypt::TripleDES module (like most implementations of a block cipher) will pad short blocks with whitespace.

    What this means is that, unless you're being careful to feed only even multiples of 8 bytes to the encrypt3() method, you're not actually encrypting what you think you are. Here is a naive implementation of chunk-by-chunk encrypting/decrypting that does work, although you are left with up to 7 whitespace characters appended to the end of your encrypted-then-decrypted file:

    #!/usr/bin/perl -w use strict; # demo usage: ./test-des.pl e some-file.txt | ./test-des.pl d use Crypt::TripleDES; my $des = Crypt::TripleDES->new(); my $passphrase = 'hello'; my $operation = shift(); $/ = \8; while ( <> ) { if ( $operation eq 'e' ) { print $des->encrypt3 ( $_, $passphrase ); } else { print $des->decrypt3 ( $_, $passphrase ); } }

    Note that you really don't want to set the input record separator ($/) to a fixed width of 8 characters in real life, that makes things really, really slow. But you do want to set it to some fixed-width multiple of 8.

    If you are bothered by the possible extra whitespace at the end of the plaintext after an encrypt->decrypt round-trip, the usual way to deal with that is to prepend the plaintext size to the message before encrypting it. Then, when you decrypt, you can pull off the size indicator from the front of the data and trim the rest of the message down to that length.

    Hope this helps,
    Kwin