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

As a get-my-feet-wet/learning exercise I started a CRUD test app from scratch without copying code from anywhere using mod_perl/Postgres, and have gotten stuck comparing strings at login time. I'm following the common idea of taking a password at registration time, hashing it, saving it in the db, and at login time,
The string comparison fails every time.
Here's the representative code snips.. I have my functions in a .pm file in the same directory

In the login page:
# get stored password from pgsql #------------------------------- my $saved_pass = ExternalFunctions::get_word( $dbh, $login_name ); # hash the password given at login time # same function is used at registration time to create the password #------------------------------- my $key = 'KE'; my $eword = ExternalFunctions::create_encrypted( $word, $key ); # Compare the strings #------------------------------- my $passwd_check; $saved_pass eq $eword ? $passwd_check = "good" : $passwd_check = "fail";
At this point, to make sure my scalars hold what I think they do, I write a CGI::Carp warn to the log to compare the strings (the brackets are mine), here is the result:
saved_pass is: [bd0e9f94ce671b3cdd13081fa5a8b32f9ccd9ebf] .. eword is: [bd0e9f94ce671b3cdd13081fa5a8b32f9ccd9ebf] ..

And I've also done this using Data::Dumper (same result). Aren't those SHA1_hex strings inside the brackets identical text? Shouldn't I be able to use eq to compare the scalars that contain these strings? I've even run them through a regex looking for embedded nulls, like  \0. What have I tried? I've tried chomping the values of the password string after form submission at registration and login time, chomping the password given at login time, and also handling them entirely through quotemeta() going in and out of the database. Aside from hmac_sha1_hex, I get the same result with plain old Digest::SHA1 and Digest::MD5. I first tried it with SHA1 and the string returned looked rather binary, some combination of non-printing characters and wing dings, so I thought SHA1 was the problem at first. I'm not understanding something simple or making a mistake... help! (and thank you for taking the time to look at this).

The functions are in the READMORE
#!/usr/bin/perl use strict; use warnings; package ExternalFunctions; sub create_encrypted { use Digest::HMAC_SHA1 qw(hmac_sha1 hmac_sha1_hex); my ( $given, $key ) = @_; my $digest = hmac_sha1_hex( $given, $key ); return quotemeta( $digest ); } sub get_word { my ( $dbh, $login_name ) = @_; my $sql_passcheck = qq{ SELECT word FROM residents WHERE lo +gin_name = ? }; my $sth = $dbh->prepare($sql_passcheck); $sth->execute( $login_name ); my ($saved_pass) = $sth->fetchrow_array; $sth->finish(); return $saved_pass; } 1;
Other parts of my test app:
apache 1333 on freebsd mod_perl built with perl 5.8.5 firefox Postgresql CGI qw('standard') CGI::Carp qw(fatalsToBrowser) CGI::Session CGI::Cookie HTML::Template DBI Digest::HMAC_SHA1 qw(hmac_sha1 hmac_sha1_hex)

Replies are listed 'Best First'.
Re: Problem comparing SHA1 string from db, with hashed login password
by Golo (Friar) on Apr 15, 2005 at 20:55 UTC
    my $saved_pass = 'bd0e9f94ce671b3cdd13081fa5a8b32f9ccd9ebf'; my $eword = 'bd0e9f94ce671b3cdd13081fa5a8b32f9ccd9ebf'; my $passwd_check; $saved_pass eq $eword ? $passwd_check = "good" : $passwd_check = "fail"; print $passwd_check;
    fail
    my $saved_pass = 'bd0e9f94ce671b3cdd13081fa5a8b32f9ccd9ebf'; my $eword = 'bd0e9f94ce671b3cdd13081fa5a8b32f9ccd9ebf'; my $passwd_check = $saved_pass eq $eword ? "good" : "fail"; print $passwd_check;
    good

    I have do admit that I don't really get why. Anyone care to explain?
    update: Got it (from perlop):
    Because this operator produces an assignable result, using assignments without parentheses will get you in trouble. For example, this:
    $a % 2 ? $a += 10 : $a += 2
    Really means this:
    (($a % 2) ? ($a += 10) : $a) += 2
    Rather than this:
    ($a % 2) ? ($a += 10) : ($a += 2)
    so what you wrote really means:
    ($saved_pass eq $eword ? $passwd_check = "good" : $passwd_check ) += "fail";
    perlop also says that you can assign to the ternary operator if both arguments between the ? and : are valid lvalues.
    So the code comes down to:
    if ($saved_pass eq $eword) { $passwd_check = "fail"; }else{ $passwd_check = "fail"; }
    In words: assign "fail" to $passwd_check or $passwd_check :-)
      Golo, thanks for catching and explaining this - now I understand - it's amazing how long I've misunderstood this operator.

      I've never read past the
      If the argument before the ? is true, the argument before the : is ret +urned, otherwise the argument after the : is returned.
      part of the docs.

      Your example
      my $passwd_check = $saved_pass eq $eword ? "good" : "fail";
      makes my login page work perfectly now.. thanks again.

      Harold