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

I need to store passwords in a database, and obviously don't want to keep the plaintext passwords. Plaintext passwords should not be retrievable.

The canonical unix-y way to do this a long time ago was to take the plaintext password, run "crypt" on it and store it in the DB. To authenicate, you'd then take crypt and run it on the incoming password, and compare the result to what you had in the DB.

It's been awhile since I've given authentication much thought, and I'm assuming there is some new, better thing for this purpose than "crypt".

Can someone mention what the new encryption algorithm(s) is/are, for this purpose, and the perl libraries that wrap them? One requirement is "better than crypt" (which may be too low a bar to fall over after all these years). Obviously if something is far better than that's wonderful.

  • Comment on Storing encrypted passwords and validating

Replies are listed 'Best First'.
Re: Storing encrypted passwords and validating
by Your Mother (Archbishop) on Mar 28, 2009 at 18:52 UTC

    The Digest family is probably what you want; Digest::SHA1. The algorithms are supported in all the DBs too so it's easy to validate/store.

    perl -MDigest::SHA1 -le 'print Digest::SHA1::sha1_hex(shift)' s3cr3t 25ab86bed149ca6ca9c1c0d5db7c9a91388ddeab perl -MDigest::SHA1 -le 'print Digest::SHA1::sha1_hex(shift)' s3cr3ts 0b8afdce3abe965be751e15143604eb17ee1290e

    Be aware that there are efforts to generate look-up tables for these so you still need to enforce prohibitions against the usual problematic/weak passwords (dictionary words, sequences, etc). The sha for "password" for example, 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8, has 681 hits on Google. And 682 come reindex time. :)

      That's why you salt it.
      sub get_digest { my ($passwd) = @_; my $salt = gen_8_rand_bytes()); my $digest = Digest::SHA1::sha1_hex("$salt$passwd"); return unpack('H16', $salt) . $digest; } sub cmp_digest { my ($passwd, $digest) = @_; my $salt = pack('H16', substr($digest, 0, 16, '')); return $digest eq Digest::SHA1::sha1_hex("$salt$passwd"); }

      There's probably an existing implementation on CPAN that follows established practices.

Re: Storing encrypted passwords and validating
by dsheroh (Monsignor) on Mar 29, 2009 at 00:06 UTC
    MD5 is better than crypt, SHA1 beats MD5, but it's looking like bcrypt is the best current option:

    Enough With The Rainbow Tables: What You Need To Know About Secure Password Schemes

    The short version boils down to that computers are really fast and most digest algorithms (like MD5 and SHA1) are designed to run quickly, meaning that a cracker who gets his hands on your password database can process very large numbers of attempts in a reasonable period of time, which makes brute-force cracking feasible.

    bcrypt, on the other hand, is designed to be slow today and easily tunable to be even slower as computers get faster. If it takes, say, a tenth of a second to bcrypt a password for your system, then users won't notice any difference, but crackers will only be able to process 10 attempts per second instead of the millions of MD5 or SHA1 hashes they could generate. End result: Greatly reduced susceptibility to brute-force cracking.

Re: Storing encrypted passwords and validating
by zwon (Abbot) on Mar 28, 2009 at 19:18 UTC

      SaltedDigest looks like it does exactly the right thing

Re: Storing encrypted passwords and validating
by zentara (Cardinal) on Mar 28, 2009 at 20:06 UTC
    See Blowfish based password hashing

    Most decent encryptions protect you from non-international-espionage level crap. Your REAL security hole is the computer users can get/see the passwords. I would work on USB key security, where each worker gets a key on a usb keyring, and needs to plug it in and give a few answers for the security to open up.


    I'm not really a human, but I play one on earth My Petition to the Great Cosmic Conciousness
Re: Storing encrypted passwords and validating
by locked_user sundialsvc4 (Abbot) on Mar 28, 2009 at 21:28 UTC

    A few thoughts:

    1. Search CPAN first.
    2. If you use a digest, use SHA1, not MD5.
    3. Include some random-text and some “salt” in the string that you hash.
    4. Store only the hashed string (with salt) in the database.