Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

encryption confusion

by poprishchin (Sexton)
on Aug 20, 2004 at 04:27 UTC ( [id://384531]=perlquestion: print w/replies, xml ) Need Help??

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

I am having problems with encrypting passwords. When a user registers for my site, their password is encrypted with the function below (which I lifed from Apache::Htpasswd - this module is not available on my server and I do not have permission to install it,) the password is stored in my database, and an entry is entered into the .htpasswd file. Everything is fine so far. If they want to change their password, I prompt them (a different script) for the old password, which I then encrypt with the same function and compare with the one stored in the database. Invariably, the encryption result is different (however is still a vaild encryption of the password.) Is there a reason the result changes depending on what script I call the function from?
#From my first script, test data; result = reu3tDNEHBSyc CryptPasswd("username","password"); #From my second script, test data; result = secGBN1BHq1FA CryptPasswd("username","password"); sub CryptPasswd { my ($self) = shift; my ($passwd, $salt) = @_; if ($salt) { # Make sure only use 2 chars $salt = substr ($salt, 0, 2); } else { ($salt = substr ($0, 0, 2)) =~ tr/:/C/; } return crypt ($passwd, $salt); }
If there is a good reason for this happening, can someone suggest a way for me to confirm the old password in order to change the new one?

Replies are listed 'Best First'.
Re: encryption confusion
by tachyon (Chancellor) on Aug 20, 2004 at 04:32 UTC

    It is a bug in your code. If you don't pass 3 arguments to the function then you generate a salt based on the first 2 chars in $0 -> which is the script name. If the names of the scripts are different the salts will be different and thus the cryptstring will be different.

    Something like this will suffice:

    sub CryptPasswd { my ($username, $passwd, $salt) = @_; $salt ||= 'anystring'; # only first 2 chars will be used return crypt ($passwd, $salt); }

    Note that crypt will ignore all but the first 2 chars of the salt. The two char salt is there to increase the permutations and make it harder to brute force things. Pick a secret two char string and stick with it.

    cheers

    tachyon

      The idea with salt, though, is that it is supposed to be generated randomly. So for better security you salt the password at creation time as some function of, say, time; and then later when you authenticate you read the user's password from the .htpasswd record, extract the salt from there, and use that to salt the current password input. This is rather better than using a single site secret for all the salts.

        I appreciate how it is done on *nix. It seemed appropriate to KISS in this case. Oh, all right I was just too lazy to offer more detail. Here is a half decent implementation that uses pseudorandom salts.....

        sub crypt_pass { my ( $pass ) = @_; my @chars = ( 'A'..'Z','a'..'z',0..9,'.','/' ); my $salt = $chars[rand(64)].$chars[rand(64)]; return crypt( $pass, $salt ); } sub check_pass { my ( $pass, $hashed ) = @_; my $salt = substr $hashed, 0, 2; # salt is first two chars of has +h string return crypt( $pass, $salt ) eq $hashed ? 1 : 0; } for(1..10) { my $crypted = crypt_pass( 'japh' ); printf "%s\t%d\t%d\n", $crypted, check_pass( 'japh', $crypted ), check_pass( '!japh', $crypted +); } __DATA__ MUNh4wMD2XmEM 1 0 3mGrf7lP7OtZc 1 0 oK7ccq5AtY1xI 1 0 .yrauX5ySsKTc 1 0 zW39UkBxi2jPo 1 0 jEzvJ.irRskvo 1 0 fz54UpRw0TZWc 1 0 a0NMpS2IufmzQ 1 0 wLjbdTPPxpwd. 1 0 WeMtUMzGuNWoc 1 0

        cheers

        tachyon

        gaal is right, but there should be an emphasis on some function of time. Since only the first two characters are used for the salt, if you just pass in time, you'll always have "10" as your salt (at least until Nov. 9 of this year, when it hits 11). One quickie way to do it is to use reverse time or even reverse rand time. If you're really paranoiod, take a look at srand or Math::TrulyRandom.

        Update: actually, big "doh" here...passing in a number as your salt only gives you 100 possible salts. tachyon's suggestion below is actually the way to do it (and they way I've done it in the past, which is why I'm kicking myself). You should still read over srand, though.

        -b

Re: encryption confusion
by Gilimanjaro (Hermit) on Aug 20, 2004 at 11:09 UTC
    As your salt question seems to have been answered already, I'd like to point out that you could just use Apache::Htpasswd, without your admin/root needing to install it...

    You can just upload the module-file Htpasswd.pm into a directory '/yourhome/lib/Apache', and add a use lib '/yourhome/lib'; to your code. Then you just use Apache::Htpasswd; as you normally would.

    Less code for you to maintain yourself... :)
Re: encryption confusion
by Random_Walk (Prior) on Aug 20, 2004 at 08:56 UTC
    Salt is to make the pre-calculation of a dictionary of password hashes unfeasable. Without salt any user using the same password would get the same hash, the blackhats run a dictionary through crypt and then it is a simple lookup to find the password coresponding to a hash.

    when you add a variable salt to each users crypt then two users using the same password will get different hashes. (One problem with NTs passwords was related to using a fixed system wide salt allowing a passcraker to check a dictionary against all users on one machine with one pass through the crypt, see l0phtcrack).

    The perl crypt function gives you back the salt as the first two bytes of the hash so you can test a password by passing the current hash as the salt. Here is a password checking example stolen from perldoc.

    if (crypt($password, $hash) ne $hash) { die "Sorry...\n"; } else { print "ok\n"; }
    Cheers,
    Random

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://384531]
Approved by baphomet
Front-paged by pelagic
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (5)
As of 2024-04-19 16:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found