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

I'm quite new in perl. Trying a password changing form through perl with encrypt / decrypt. Below is my code -
#!/usr/bin/perl local ($buffer, @pairs, $pair, $name, $value, %FORM); # Read in text $ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/; if ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); }else { $buffer = $ENV{'QUERY_STRING'}; } # Split information into name/value pairs @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%(..)/pack("C", hex($1))/eg; $FORM{$name} = $value; } my $old_pass = $FORM{oldpass}; my $new_pass = $FORM{newpass1}; my $new_pass2 = $FORM{newpass2}; print "Content-type:text/html\r\n\r\n"; use CGI; use warnings; use strict; use Crypt::CBC; my $KEY = 'secrect_foo'; my $readfile ="pass.txt"; open (my $passfile, '<', $readfile) or die "could not open fil +e"; my $readpass = do{ local $/; <$passfile> }; # print "Reading pass from file: $readpass\n"; close ($passfile); my $dec = decryptString($readpass); if($dec eq $old_pass) { print "<h2>Password Matched<h2>\n"; if($new_pass eq $new_pass2) { my $enc = encrypString($new_pass); print "encrypted binary: $enc\n"; my $storedpassfile = 'pass.txt'; open(my $fh, '>', $storedpassfile) or die "Cou +ld not open the pass file"; print $fh "$enc"; close $fh; print "New Password Updated\n"; } else { print "New pass & Confirm Pass is not same"; } } else{ print "Old Pass & Stored Pass mismatch\n"; } sub encrypString { my $string = shift; my $cipher = Crypt::CBC->new( -key => $KEY, -cipher => 'Blowfish', -padding => 'space', -add_header => 1 ); my $enc = $cipher->encrypt($string); return $enc; } sub decryptString { my $string = shift; my $cipher = Crypt::CBC->new( -key => $KEY, -cipher => 'Blowfish', -padding => 'space', -add_header => 1 ); my $dec = $cipher->decrypt($string); return $dec; }
Problem is while everything alright - oldpass and both newpass matched then program endup at " print "encrypted binary: $enc\n"; " and not updating the pass.txt file. Where possible I've made mistake ? Any advise is highly appreciable.

Replies are listed 'Best First'.
Re: Getting issue with encrypt / decrypt
by afoken (Chancellor) on Jul 23, 2015 at 18:03 UTC

    There are some other problems with your code:

    #!/usr/bin/perl local ($buffer, @pairs, $pair, $name, $value, %FORM); # Read in text $ENV{'REQUEST_METHOD'} =~ tr/a-z/A-Z/; if ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); }else { $buffer = $ENV{'QUERY_STRING'}; } # Split information into name/value pairs @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%(..)/pack("C", hex($1))/eg; $FORM{$name} = $value; } my $old_pass = $FORM{oldpass}; my $new_pass = $FORM{newpass1}; my $new_pass2 = $FORM{newpass2}; print "Content-type:text/html\r\n\r\n"; use CGI;

    (1) Get rid of all that manual CGI handling. It looks like copied from some Perl 4 script, it can't handle multipart forms, and it is completely redundant. You already loaded CGI, so use it:

    use CGI qw( param header ); my $old_pass=param('oldpass'); my $new_pass=param('newpass1'); my $new_pass=param('newpass2'); print header({-type=>'text/html'});

    (2) Choose one indent style, and use it consistently. It costs far too much time to follow the code with this messy indent.

    (3) Unless you need to pass the password to some other system, encrypting it is dangerously wrong. Especially if your code contains the encryption key in plain text. The safe approach to handling passwords is to salt (add some random value) and hash them using a strong hash algorithm. Forget MD4 and MD5, they are nearly broken. Use bcrypt and be prepared to change the hashing algorithm in the future. To verify a password, salt it with the stored salt value and hash it, then compare the stored hash value with the freshly calculated hash value.

    (4) You allow to change the password using GET requests. This will make both the old and the new password appear in clear text in the web server logs, and in the browser history. Use only POST requests for checking and changing passwords. They can be logged, too, but they aren't by default.

    (5) RFC 2616 states that "the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval", i.e. you should actively prevent changing the password using something else than a POST request.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re: Getting issue with encrypt / decrypt
by 1nickt (Canon) on Jul 23, 2015 at 15:46 UTC

    Does the program really end where you say it does? Or does it print the final debug statement in that block?

    Did you test the return value of your print() statement?

    The way forward always starts with a minimal test.
      While I call this file on browser, its showing till the "encrypted binary : xxx" I've tested the file separately - encryption, decryption or reading - perform ok. The code that I used to call this one is
      #!/usr/bin/perl print "Content-type: text/html\n\n"; print "<html><head>\n"; print "<title>Change Pass</title>\n"; print '<body>'; print '<form action="pass_change.cgi" method="POST">'; print "Old Pass : ".'<input type="password" name="oldpass">'."<br>" +; print "New Pass : ".'<input type="password" name="newpass1">'."<br> +"; print "Confirm Pass: ".'<input type="password" name="newpass2">'."<br> +"; print '<input type="submit" name="sub" value="Change Pass">'; print '</body>'; print '</head>'; print '</html>';
        Add this line temporarily to your pass_change.cgi script.
        use CGI::Carp 'fatalsToBrowser';

        and change this line
        open (my $passfile,'<',$readfile) or die "could not open file";
        to
        open (my $passfile,'<',$readfile) or die "could not open file $readfile ; $!";

        poj