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

I'm fairly new to Perl and have been writing a few test programs to further my knowledge
Your advice on how to clean up this code would be appreciated
The unencrypted contents of a password file are fed into an array and then encrypted via Xor (yes I know about the dangers of this) to another file.
I'm sure there are better ways of doing this. I'd like to avoid using a temporary file if possible but can't figure out how to get this to work in memory instead or via a pipe
my $newenckey = getcryptkey; open(INPF, ">$ENV{HOME}/.tmpass") or die "Can't write $ENV{HOM +E}/.tmpass: $!\n"; for my $rec_ref(@records) { print INPF "$rec_ref->[0] $rec_ref->[1] $rec_r +ef->[2]\n"; } close(INPF); open(INPF, "<$ENV{HOME}/.tmpass") or die "Can't write $ENV{HOM +E}/.tmpass: $!\n"; open(PASSF,">$ENV{HOME}/.perlpasswd") or die "Can't write $ENV +{HOME}/.perlpasswd: $!\n"; my $in; while( sysread(INPF,$in,length($newenckey)) ) { print PASSF $in^substr($newenckey,0,length($in)); } close(PASSF);
This produces the results I want but it's messy !

Replies are listed 'Best First'.
Re: open file or pipe ?
by punch_card_don (Curate) on Nov 10, 2004 at 16:38 UTC
    How about:
    $i = 0; for my $rec_ref(@records) { $new_rec = join('', $rec_ref->[0], $rec_ref->[1], $rec_ref->[2]); push(@new_records, $new_rec); } open(PASSF,">$ENV{HOME}/.perlpasswd") or die "Can't write $ENV{HOME}/. +perlpasswd: $!\n"; for $i (0 .. $#new_rocords) { print PASSF $new_records[$i]^substr($newenckey,0,length($new_recor +ds[$i])); } close(PASSF);
      I have the same problem with this as I did with one of my earlier attempts at avoiding temporary files
      The encryption is only being applied to the first element in the record not to the whole record. So what I end up with is a .perlpasswd file in this format
      encrypted notencrypted notencrypted encrypted notencrypted notencrypted
      Unfortunately the third field is the password, which remains unencrypted. I've tried using map as well but always seem to end up with only the first field encrypted but not the others.
      Any ideas on how I fix this would be welcome
Re: open file or pipe ?
by ikegami (Patriarch) on Nov 10, 2004 at 17:28 UTC

    Your use of sysread is rather buggy. It can make it impossible to decode what you encoded, because sysread can return any number of bytes for any given call. This is rather moot, since we don't need to sysread from the temporary file at all.

    use strict; use warnings; sub getcryptkey { return 'ABCDEFGHIJK'; } { ##### WRITER ##### my @records = ( [ 0, 1, 2 ], [ 3, 4, 5 ], [ 6, 7, 8 ], ); my $newenckey = getcryptkey(); local *PASSF; open(PASSF, ">$ENV{HOME}/.perlpasswd") or die("Can't write $ENV{HOME}/.perlpasswd: $!\n"); binmode(PASSF); my $buf = ''; foreach (@records) { # Might want to use FreezeThaw instead. $buf .= "$_->[0] $_->[1] $_->[2]\n"; print PASSF substr($buf, 0, length($newenckey), '') ^ $newenckey while (length($buf) >= length($newenckey)); } print PASSF $buf ^ substr($newenckey, 0, length($buf)); close(PASSF); } { ##### READER ##### my @records; my $newenckey = getcryptkey(); local *PASSF; open(PASSF, "<$ENV{HOME}/.perlpasswd") or die("Can't read $ENV{HOME}/.perlpasswd: $!\n"); binmode(PASSF); my $buf_e = ''; my $buf_d = ''; my $BLOCK_SIZE = length($newenckey); # Can be anything. while (sysread(PASSF, $buf_e, $BLOCK_SIZE, length($buf_e))) { $buf_d .= substr($buf_e, 0, length($newenckey), '') ^ $newenckey while (length($buf_e) >= length($newenckey)); push(@records, [ $1, $2, $3 ]) while ($buf_d =~ s/^(\S+)\s+(\S+)\s+(\S+)\n//s); } $buf_d .= $buf_e ^ substr($newenckey, 0, length($buf_e)); push(@records, [ $1, $2, $3 ]) while ($buf_d =~ s/^(\S+)\s+(\S+)\s+(\S+)\n//s); close(PASSF); require Data::Dumper; print(Data::Dumper::Dumper(\@records)); } __END__ ##### OUTPUT ##### $VAR1 = [ [ '0', '1', '2' ], [ '3', '4', '5' ], [ '6', '7', '8' ] ];

    sysread and syswrite are properly used (except I don't check for errors), and the key is used from start to end.

Re: open file or pipe ?
by fglock (Vicar) on Nov 10, 2004 at 16:46 UTC
    print PASSF "$rec_ref->[0] $rec_ref->[1] $rec_ref->[2]" ^ getcryptkey();

    update: i forgot the "substr" part.

      Thanks. I had actually tried something similar to this but without pushing the records into a new array first but just doing the join and then applying the encryption to the string.
      needless to say it didn't work as expected