About Chris Morrell

I am a Philadelphia web designer and developer who focuses on PHP development and usable design. I am also the Director of IT for the International Association of Certified Home Inspectors.

Please Note: My site fell victim to a Wordpress security flaw a few weeks ago, and I'm just getting everything back to normal. Please bear with me.

I am currently not accepting any new clients.

Other Sites/Clients

Contact Me

If you need to get in touch with me, my name is Chris and my domain name is cmorrell.com. Think about it.

Crazy idea…

Posted by Chris Morrell on November 23rd, 2009 in Web Development

I’ve been toying with the idea of using my cache as a data store for a project where the data doesn’t need to be updated very often.  Basically, I’d write out plain XHTML documents and then parse the data using XPath when needed.  But that’s a different story.  Once I decided to give my idea a try, I started thinking about how to store authentication information.  The application doesn’t store any private information, so authentication is only needed to prove that you are authorized to edit the information.  So why not store the authentication information publicly as well (as an HTML comment at the top of the file)?  Here’s what I was thinking, in pseudo code:

identity = base64(encrypt_rijndael256([
	sha512_hmac(username, appUsernameSecret),
	sha512_hmac(password, appPasswordSecret)
], appSecret))

This would produce an base64 representation of an encrypted array of hashes.  Basically, the system would produce two hashes using HMAC and two separate secret keys (one for the username hash and one for the password hash).  It would store that data in a way that it could later retrieve it (in my case a serialized array) and then encrypt the whole thing with a third key (the base64 is just so it could easily be represented by an ASCII string).  That way there are multiple points of failure.  An attacker would have to know all three keys just to get at the hashes, but then that’s all they’d have.  They’d still need to brute force both the username and password separately.  It seems to me that this would be pretty darn secure.  Clearly not good enough for a bank, but certainly fine for a web app that would have very few negative consequences if it were broken into.

I would love feedback from someone who know’s what they’re talking about :)   Below is some working PHP code to illustrate my point:

class PublicAuth
{
    private $_secret;
    private $_usernameSecret;
    private $_passwordSecret;

    private $_td = null;
    private $_iv = null;

    public function __construct($secret, $usernameSecret, $passwordSecret)
    {
        $this->_secret = $secret;
        $this->_usernameSecret = $usernameSecret;
        $this->_passwordSecret = $passwordSecret;
    }

    public function generateIdentifier($username, $password, $algorithm = 'sha512')
    {
        return $this->_encrypt(serialize(array(
            hash_hmac($algorithm, $username, $this->_usernameSecret, true),
            hash_hmac($algorithm, $password, $this->_passwordSecret, true),
        )));
    }

    public function verifyIdentity($identifier, $username, $password, $algorithm = 'sha512')
    {
        $identifier = unserialize($this->_decrypt($identifier));
        return (hash_hmac($algorithm, $username, $this->_usernameSecret, true) == $identifier[0]
            && hash_hmac($algorithm, $password, $this->_passwordSecret, true) == $identifier[1]);
    }

    private function _encrypt($string)
    {
        $this->_initMcrypt();
        return base64_encode(mcrypt_generic($this->_td, $string));
    }

    private function _decrypt($string)
    {
        $this->_initMcrypt();
        return mdecrypt_generic($this->_td, base64_decode($string));
    }

    private function _initMcrypt($algorithm = 'rijndael-256')
    {
        if (null == $this->_td || null == $this->_iv) {
            $this->_td = mcrypt_module_open($algorithm, '', 'ecb', '');
            $this->_iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($this->_td), MCRYPT_RAND);
        }

        mcrypt_generic_init($this->_td, $this->_secret, $this->_iv);
    }
}

And here’s some sample usage:

$pa = new PublicAuth('a', 'b', 'c');
echo $pa->generateIdentifier('user', 'pass');

Which would print out:

NLgAYjlGbmJA2Wdcgwntm4ixhHHCiZBA6TvgrVMgEOBEjZQJ0tHgAlw7931p2S6KRtfCkLjrsA2DBilcgBX/pPPXFgyAx3g0/CKMcjdU8DKn3/9M2aIZHOrdi/G68C0oxVe6pDlWvVwvofpJnu9RxMbFN49x1uVgBuHTjKagpD6y83fm+hX4G+CoPRcHM5PUq/nJ1iwtZipRtno8TllO6A==

Then to verify the identity:

$pa = new PublicAuth('a', 'b', 'c'); // Needs to be the same as when generated
var_export($pa->verifyIdentity($id, 'user', 'pass')); // $id contains the string above; returns TRUE

Thoughts?

No Comments (Respond Now) »

Leave a Reply

Additional comments powered by BackType

Comments & Trackbacks

You can leave a response, or trackback from your own site. Follow any responses to this entry through the RSS 2.0 feed.

More...

@inxilpro

  • Anyone want a free TiVo Series 2 w/ upgrade eligibility and month-to-month service? Its yours if I know you. 1 day ago
  • Just canceled the cable. 1 day ago
  • You know it's spring when the daily Tony Danza sightings start again. 1 day ago
  • More updates...
Copyright © Chris Morrell, Powered by WordPress, Entry RSS Feed / Comment RSS Feed