diff options
author | Wojciech Polak <polak@gnu.org> | 2014-04-23 00:14:58 +0200 |
---|---|---|
committer | Wojciech Polak <polak@gnu.org> | 2014-04-24 00:15:50 +0200 |
commit | a6d9d0ac8558575f3dae6500a939302ec9419be8 (patch) | |
tree | e41d26dd72af60d2806d355c00ae1767bd272392 | |
parent | 4bfca38dd3eaf92a868390ac51ff85b54a6c2c90 (diff) | |
download | cheetah-a6d9d0ac8558575f3dae6500a939302ec9419be8.tar.gz cheetah-a6d9d0ac8558575f3dae6500a939302ec9419be8.tar.bz2 |
Rewrite ancient password handling. Move to PBKDF2.
-rw-r--r-- | frontend/changepassword.php | 4 | ||||
-rw-r--r-- | frontend/lib/register.php | 5 | ||||
-rw-r--r-- | frontend/lib/session.class.php | 117 | ||||
-rw-r--r-- | frontend/signup.php | 2 |
4 files changed, 108 insertions, 20 deletions
diff --git a/frontend/changepassword.php b/frontend/changepassword.php index 69ebfb2..bb726ce 100644 --- a/frontend/changepassword.php +++ b/frontend/changepassword.php @@ -4,7 +4,7 @@ /* Cheetah News changepassword.php - Copyright (C) 2005, 2006, 2010 Wojciech Polak. + Copyright (C) 2005, 2006, 2010, 2014 Wojciech Polak. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -105,7 +105,7 @@ else if (!empty ($hash)) $validPass = false; if ($validPassLen && $validPass) { - $db->query ("UPDATE user SET pass='".md5 ($pass). + $db->query ("UPDATE user SET pass='".make_password ($pass). "', failogCount=0 WHERE email='".$email."'"); $db->query ("DELETE FROM forgotpassword WHERE email='".$email."'"); $message = _('Your password has been successfully changed.'); diff --git a/frontend/lib/register.php b/frontend/lib/register.php index 06b9785..57e58b4 100644 --- a/frontend/lib/register.php +++ b/frontend/lib/register.php @@ -2,7 +2,7 @@ /* Cheetah News lib/register.php - Copyright (C) 2005, 2006, 2010 Wojciech Polak. + Copyright (C) 2005, 2006, 2010, 2014 Wojciech Polak. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -56,7 +56,8 @@ function rpNewSendEmail ($cEmail, $regPassword, $openid_identity = '') if ($newEntry) { $db->query ("INSERT INTO registration SET email='".$db->escape ($cEmail)."', ". "rdate=UTC_TIMESTAMP(), hash='".$hash."', pass='". - md5 ($regPassword)."', openid_identity='".$db->escape ($openid_identity)."'"); + make_password ($regPassword)."', openid_identity='". + $db->escape ($openid_identity)."'"); } return 0; /* OK */ } diff --git a/frontend/lib/session.class.php b/frontend/lib/session.class.php index 7365ed3..76416e7 100644 --- a/frontend/lib/session.class.php +++ b/frontend/lib/session.class.php @@ -2,7 +2,7 @@ /* Cheetah News lib/session.class.php - Copyright (C) 2005, 2006, 2007, 2008, 2010 Wojciech Polak. + Copyright (C) 2005, 2006, 2007, 2008, 2010, 2014 Wojciech Polak. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -87,7 +87,7 @@ class Session $this->status['iflogged'] = ''; } - function login ($email, $pass) + function login ($email, $raw_password) { global $CONF; @@ -95,7 +95,7 @@ class Session $db = new Database (); - if ($CONF['guestAccount'] && $email == 'guest' && $pass == 'guest') + if ($CONF['guestAccount'] && $email == 'guest' && $raw_password == 'guest') { $db->query ("SELECT id FROM user WHERE email='".$CONF['guestAccount']. "' AND active='yes'"); @@ -116,14 +116,17 @@ class Session } else { $db->query ("SELECT id,email,pass,lang FROM user ". - "WHERE email='".$db->escape ($email)."' AND pass='". - md5 ($pass)."' AND active != 'no' AND failogCount < 10"); + "WHERE email='".$db->escape ($email). + "' AND active != 'no' AND failogCount < 10"); if ($db->next_record ()) { $this->id = $db->f ('id'); - $this->email = $db->f ('email'); $this->pass = $db->f ('pass'); + + if ($this->check_password ($raw_password)) + { + $this->email = $db->f ('email'); $this->lang = $db->f ('lang'); $this->status['afterlogged'] = 'yes'; $this->status['iflogged'] = 'yes'; @@ -136,14 +139,14 @@ class Session else redirect ('http://'.$CONF['site'].'/'); } - else /* failog, protection against dictionary attack */ - { + else { /* failog, protection against dictionary attack */ $db->query ("UPDATE user SET failogCount=failogCount+1 WHERE ". "email='".$db->escape ($email). "' AND active != 'no' AND failogCount < 10"); } } } + } function openid1 ($openid_identifier) { @@ -223,7 +226,7 @@ class Session return _("To enable OpenID support, please visit Menu/User Settings/Linked Accounts."); } - $res = rpNewSendEmail ($email, uniqid (rand(), true), $identity); + $res = rpNewSendEmail ($email, '', $identity); switch ($res) { case 0: return _('A registration confirmation e-mail has been sent to you.'); @@ -247,7 +250,7 @@ class Session $db->escape ($identity)."'"); if (!$db->next_record ()) { $hash = sha1 (time().$identity.rand()); - $pass = uniqid (rand(), true); + $pass = ''; $db->query ("INSERT INTO registration SET rdate=UTC_TIMESTAMP(), ". "hash='".$hash."', pass='".$pass."', openid_identity='". $db->escape ($identity)."'"); @@ -301,7 +304,7 @@ class Session return _('To link your Facebook account, please visit Menu/User Settings'); } - $pass = uniqid (rand(), true); + $pass = ''; $db->query ("INSERT INTO user SET email='".$email. "', pass='".$pass."', fbUID=".$fb_uid); $db->query ("SELECT LAST_INSERT_ID() as last_id FROM user"); @@ -379,18 +382,102 @@ class Session } } - function change_password ($old, $new, $repeat) + function check_password ($raw_password) { - if ($new == $repeat && md5 ($old) == $this->pass) + if (!$raw_password || $this->pass === '!') + return false; + + if (strlen ($this->pass) == 32 && $this->pass == md5 ($raw_password)) { + /* good pass, old format */ + $this->set_password ($raw_password); /* regenerate */ + return true; + } + else { + list ($algo, $iterations, $salt, $hash) = explode (':', $this->pass, 4); + $encoded_2 = encode_password ($raw_password, $algo, $salt, + intval ($iterations)); + return $this->pass === $encoded_2; + } + return false; + } + + function set_password ($raw_password) { + $this->pass = make_password ($raw_password); $db = new Database (); - $db->query ("UPDATE user SET pass='".md5 ($new)."' WHERE id=".$this->id); - $this->pass = md5 ($new); + $db->query ("UPDATE user SET pass='".$this->pass."' WHERE id=".$this->id); + } + + function change_password ($raw_password_old, $raw_password_new, $repeat) + { + if ($raw_password_new == $repeat && + $this->check_password ($raw_password_old)) + { + $this->set_password ($raw_password_new); return true; } + return false; + } +} + +function make_password ($raw_password, $salt=null) +{ + if (!$raw_password) + return '!'; + + if (!$salt) + $salt = substr (str_shuffle ('abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '0123456789'), 0, 12); /* 12 random chars */ + + return encode_password ($raw_password, 'pbkdf2_sha256', $salt); +} + +function encode_password ($raw_password, $algo, $salt, $iterations=20000) +{ + if ($algo == 'pbkdf2_sha256') + $hash = cth_pbkdf2 ('sha256', $raw_password, $salt, $iterations, 32, true); else + return '!'; + + $hash = trim (base64_encode ($hash)); + return sprintf ('%s:%d:%s:%s', $algo, $iterations, $salt, $hash); +} + +function cth_pbkdf2 ($algo, $password, $salt, $iterations, $length=0, + $raw_output=false) +{ + if (!in_array (strtolower ($algo), hash_algos ())) { + trigger_error (sprintf ('cth_pbkdf2(): Unknown hashing algorithm: %s', + $algo), E_USER_WARNING); return false; } + + $derived_key = ''; + $loops = 1; + + if ($length > 0) + $loops = (int)ceil ($length / strlen (hash ($algo, '', $raw_output))); + + for ($i = 1; $i <= $loops; $i++) + { + $digest = hash_hmac ($algo, $salt . pack ('N', $i), $password, true); + $block = $digest; + for ($j = 1; $j < $iterations; $j++) + { + $digest = hash_hmac ($algo, $digest, $password, true); + $block ^= $digest; + } + $derived_key .= $block; + } + + if (!$raw_output) + $derived_key = bin2hex ($derived_key); + + if ($length > 0) + return substr ($derived_key, 0, $length); + + return $derived_key; } ?> diff --git a/frontend/signup.php b/frontend/signup.php index 3522bf5..b93fce1 100644 --- a/frontend/signup.php +++ b/frontend/signup.php @@ -53,7 +53,7 @@ if (!empty ($hash)) if (empty ($email)) { if (!empty ($cEmail)) { - $res = rpNewSendEmail ($cEmail, uniqid (rand(), true), $openid_identity); + $res = rpNewSendEmail ($cEmail, '', $openid_identity); switch ($res) { case 0: $db->query ("DELETE FROM registration WHERE hash='".$db->escape ($hash)."'"); |