robert
robert

Reputation: 841

Checking typed password against file containing APR1-MD5 hashes of passwords

I'm working on a website that is trying to switch from Apache authentication to PHP authentication for username/password on login. The passwords are currently stored in a file and they are encrypted in Apache's own md5 format (for example, $apr1$z6hoasr5$0Kk7p/8Hfhy9nBxu/hFUj1).

The passwords are not stored in the database.

Now, I'm writing a PHP login script. My question is, how do I check if the typed password is the same as the encrypted password in the file? I've found code for generating APR1-MD5 based on a plain text password, but that is NOT what I need since it generates codes different than the ones in the file.

Long story short, is there a way to identically check whether the typed password is indeed the one saved in the file?

I know Apache has open source code for generating these, but the code is in C which I know next to nothing about.

Surely there's a way to migrate from Apache authentication to PHP without changing every user's password?

Upvotes: 2

Views: 5575

Answers (2)

whitehat101
whitehat101

Reputation: 2549

I ran into this myself, and I thought I'd publish a good solution. I started with people's prior work, and polished it into a tested and packaged solution.

composer.json:

"require": {
  "whitehat101/apr1-md5": "~1.0"
}

Use:

// Check plaintext password against an APR1-MD5 hash
APR1_MD5::check('plaintext', '$apr1$z6hoasr5$0Kk7p/8Hfhy9nBxu/hFUj1'); // bool

// Hash a password with a known salt
echo APR1_MD5::hash('PASSWORD', 'z6hoasr5');

// Hash a password with a secure random salt
echo APR1_MD5::hash('PASSWORD');

Shy of doing I/O on .htpasswd files, I think this library pretty much covers everything one would want to do with Apache's APR1-MD5 hashes.

Upvotes: 0

uguraslan
uguraslan

Reputation: 91

As far as I understand, a password is coming from your login function. And you have to check this password against APR1-md5 hash. If your login page doesn't include any username, this would be very difficult to search. But if you have usernames for corresponding passwords it can be achieved :

Let's assume that login function sends two parameters : $username and $password. Call APRI-md5 password file as 'password.txt'. The method I'll explain only works when you have user names in password.txt file and user names from login script are the same with ones in password.txt file.

$apr1$z6hoasr5$0Kk7p/8Hfhy9nBxu/hFUj1 password hash has three parts :

apr1 = format identifier [static, same for every password line]

z6hoasr5 = salt text [different for every password]

0Kk7p/8Hfhy9nBxu/hFUj1 = real md5 hash string

You cannot generate same password by this method even if the input text is the same, unless you use the same salt text. So, to produce same hash string and compare with input you have to know what the salt text is for a given user.

For example, when you get $username and $password from login script, you should find username in password.txt file. Then you should extract salt text part from password.txt ("z6hoasr5" in your example). Then using this salt text and $password [coming from login] you should generate APR1-md5 hash. (you can modify http://www.php.net/manual/en/function.crypt.php#73619 in order to put $salt as input parameter. So you can send salt and text and get password hash). If password is correct, the newly created hash string by using the salt text in password.txt will be the same with password.txt. Then you can do string comparision to check if the password is valid.

Upvotes: 4

Related Questions