HTTP Digest authentication with encrypted passwords

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
marxJ
Forum Newbie
Posts: 2
Joined: Wed Apr 15, 2009 6:25 am

HTTP Digest authentication with encrypted passwords

Post by marxJ »

Hi everyone, I'm currently trying to implement HTTP Digest authentication to a script. I've had a thorough read of the documentation as well as a few examples, but all of then have the same problem in that they rely on the passwords being stored as plain text, a practice I've never been keen on.

The way I've tried to get around it is instead of storing a hash of the password, storing the a1 hash in the database (i.e. md5($username.":".$realm.":".$password); ). I've got this working OK for authentication through a form, but not through HTTP. Here's the class I've written:

Code: Select all

class auth_digest {
    
    public $username;
    public $nonce;
    public $uri;
    public $response;
    public $qop;
    public $nc;
    public $cnonce;
    
    public function __construct($digest) {
        if(preg_match('/username="([^"]+)"/', $digest, $username)
        && preg_match('/nonce="([^"]+)"/', $digest, $nonce)
        && preg_match('/uri="([^"]+)"/', $digest, $uri)
        && preg_match('/response="([^"]+)"/', $digest, $response)
        && preg_match('/qop="?([^,\s"]+)/', $digest, $qop)
        && preg_match('/nc=([^,\s"]+)/', $digest, $nc)
        && preg_match('/cnonce="([^"]+)"/', $digest, $cnonce)) {
            $this->username = $username[1];
            $this->nonce = $nonce[1];
            $this->uri = $uri[1];
            $this->response = $response[1];
            $this->qop = $qop[1];
            $this->nc = $nc[1];
            $this->cnonce = $nonce[1];
            return true;
        } else {
            return false;
        }
    }
    
    public function authenticate($hash) {
        $A1 = $hash;
        $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$this->uri);
        $valid_response = md5($A1.':'.$this->nonce.':'.$this->nc.':'.$this->cnonce.':'.$this->qop.':'.$A2);
        if ($valid_response ==  $this->response) {
            return true;
        } else {
            return false;
        }
    }
};
The idea is that you pass $_SERVER['PHP_AUTH_DIGEST'] to the constructor which pulls out all the relevant data and stores it in the properties. This seems to work fine. You then get the user's hash from the database (using the username property in the query) and pass it into the authenticate() method, which hashes it and compares it to the digest sent with the request. However, for some reason, the digest generated by the script isn't matching that sent with the request. Can anyone see something I'm doing wrong?
Post Reply