updated to better password hash: use crypt instead of md5
authorArun Persaud <arun@nubati.net>
Sat, 22 Sep 2012 19:38:58 +0000 (12:38 -0700)
committerArun Persaud <arun@nubati.net>
Sat, 22 Sep 2012 19:46:27 +0000 (12:46 -0700)
the upgrade will be done automatically when a user logs in, password recovery is still based
on md5, but that should be OK, since it's a random generated password anyway

INSTALL
create_database.sql
include/db.php
include/functions.php
include/login.php
include/preferences.php
include/register.php
include/user.php
update_db.php

diff --git a/INSTALL b/INSTALL
index 886a94d..372b6b6 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -3,7 +3,7 @@ Installation
 ------------
 
 -1) What you need
-   all you need is PHP and MYSQL. PHP has to include gettext support.
+   all you need is PHP(>=5.3.7) and MYSQL. PHP has to include gettext support.
 
 0) Get files
 
index 3d5a1d4..dc70a0b 100644 (file)
@@ -38,7 +38,7 @@
 
 DROP TABLE IF EXISTS `Version`;
 CREATE TABLE `Version` (
-  `version` int NOT NULL default '0'
+  `version` int NOT NULL default '5'
 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
 --
@@ -360,7 +360,7 @@ CREATE TABLE `User` (
   `id` int(11) NOT NULL auto_increment,
   `fullname` varchar(64) default NULL,
   `email` varchar(64) default NULL,
-  `password` varchar(32) default NULL,
+  `password` varchar(62) default NULL,
   `timezone` varchar(64) default 'Europe/London',
   `last_login` timestamp NOT NULL default '0000-00-00 00:00:00',
   `create_date` timestamp NOT NULL default '0000-00-00 00:00:00',
index 1f02169..6942cd6 100644 (file)
@@ -30,7 +30,7 @@ if(!isset($HOST))
 
 function DB_open()
 {
-  $version_needed = 4;
+  $version_needed = 5;
 
   global $DB,$DB_user,$DB_host,$DB_database,$DB_password;
   $DB = @mysql_connect($DB_host,$DB_user, $DB_password);
@@ -951,6 +951,12 @@ function DB_set_recovery_password($user,$newpw)
   return;
 }
 
+function DB_delete_recovery_passwords($userid)
+{
+  DB_query("DELETE FROM Recovery WHERE user_id=".DB_quote_smart($userid));
+  return;
+}
+
 function DB_get_card_name($card)
 {
   if($card==0)
index 037da48..cb78457 100644 (file)
@@ -1650,4 +1650,53 @@ function get_user_token($userid)
   return $token;
 }
 
+function verify_password($email, $password)
+{
+  /* verify password, if old password has length 32 assume it's an old md5, else use new password scheme */
+  /* return 0 if verified, else return error code
+   *        1 can't find email
+   *        2 can't calculate correct hash
+   *        3 misc error
+   */
+
+  /* check user email by getting his id */
+  $userid = DB_get_userid('email',$email);
+  if(!$userid)
+    return 1;
+
+  /* test for temporary passwords, only valid for one date (tested in the DB) */
+  $tmppasswd = md5($password);
+  if(DB_check_recovery_passwords($tmppasswd,$email))
+    return 0;
+
+  /* get saved password */
+  $existingpassword =  DB_get_passwd_by_userid($userid);
+
+  if(strlen($existingpassword)==32) /* old password type */
+    {
+      if ($existingpassword == md5($password))
+       {
+         /* update password to new crypt version */
+         // create a password hash using the crypt function, need php 5.3 for this
+         // create and random salt
+         $salt = substr(str_replace('+', '.', base64_encode(sha1(microtime(true), true))), 0, 22);
+         // hash incoming password using 12 rounds of blowfish
+         $hash = crypt($password, '$2y$12$' . $salt);
+         if(strlen($hash)>13)
+           DB_query("UPDATE User SET password='$hash' where id='$userid'");
+         else
+           return 2;
+
+         return 0;
+       }
+    }
+  else
+    {
+      if ($existingpassword == crypt($password, $existingpassword))
+       return 0;
+    };
+
+  return 3;
+}
+
 ?>
index ab7b48a..eb7d5b8 100644 (file)
@@ -85,21 +85,27 @@ else if(myisset('email','password'))
     $password  = $_REQUEST['password'];
 
     /* verify password and email */
-    if(strlen($password)!=32)
-      $password = md5($password);
 
     $ok  = 1;
-    $myid = DB_get_userid('email-password',$email,$password);
-    if(!$myid)
-      $ok = 0;
+    $myid = DB_get_userid('email',$email);
 
-    if($ok)
+    $result = verify_password($email, $password);
+    switch($result)
       {
-       /* user information is ok, set session variabel */
-       $myname = DB_get_name('email',$email);
+      case 0:
+       /* user information is ok, set session variable */
+       $myname         = DB_get_name('email',$email);
+       $hashedpassword = DB_get_passwd_by_userid($myid);
        $_SESSION['name'] = $myname;
        $_SESSION['id']   = $myid;
-       $_SESSION['pass'] = $password;
+       $_SESSION['pass'] = $hashedpassword;
+       break;
+      case 1:
+       echo "Can't find you in the database\n";
+       break;
+      case 2:
+       echo "Problem creating password hash, please contact $ADMIN at $ADMIN_EMAIL\n";
+       break;
       }
   }
 else
index 57c025f..a20913a 100644 (file)
@@ -273,9 +273,9 @@ if(myisset("password0","password1","password2") &&  $_REQUEST["password0"]!="" &
     $changed_password = 1;
 
     /* check if old password matches */
-    $oldpasswd = md5($_REQUEST["password0"]);
-    $password  = DB_get_passwd_by_userid($myid);
-    if(!( ($password == $oldpasswd) || DB_check_recovery_passwords($oldpasswd,$email) ))
+    $result = verify_password($email, $_REQUEST["password0"]);
+
+    if( $result!=0 )
       $changed_password = -1;
 
     /* check if new password has been typed in correctly */
@@ -288,8 +288,19 @@ if(myisset("password0","password1","password2") &&  $_REQUEST["password0"]!="" &
 
     if($changed_password==1)
       {
-       DB_query("UPDATE User SET password='".md5($_REQUEST["password1"]).
+       // create a password hash using the crypt function, need php 5.3 for this
+       // create and random salt
+       $salt = substr(str_replace('+', '.', base64_encode(sha1(microtime(true), true))), 0, 22);
+       // hash incoming password using 12 rounds of blowfish
+       $hash = crypt($_REQUEST["password1"], '$2y$12$' . $salt);
+
+       DB_query("UPDATE User SET password='".$hash.
                 "' WHERE id=".DB_quote_smart($myid));
+
+       /* in case this was done using a recovery password delete that password */
+       $tmppasswd = md5($_REQUEST["password0"]);
+       if(DB_check_recovery_passwords($tmppasswd,$email))
+         DB_delete_recovery_passwords($myid);
       }
     /* error output below */
   }
index a1370ea..72e9ad2 100644 (file)
@@ -94,7 +94,7 @@ if(myisset('Rfullname','Remail','Rtimezone') )
       }
     if($robot==0)
       {
-       echo _('You answered the math question wrong.').' <br />\n';
+       echo _('You answered the math question wrong.').' <br />'."\n";
        $ok=0;
       }
     /* everything ok, go ahead and create user */
@@ -102,10 +102,21 @@ if(myisset('Rfullname','Remail','Rtimezone') )
       {
        if(myisset('Rpassword'))
          {
-           $r=DB_query('INSERT INTO User VALUES(NULL,'.DB_quote_smart($_REQUEST['Rfullname']).
-                       ','.DB_quote_smart($_REQUEST['Remail']).
-                       ','.DB_quote_smart(md5($_REQUEST['Rpassword'])).
-                       ','.DB_quote_smart($_REQUEST['Rtimezone']).',NULL,NULL)');
+           // create a password hash using the crypt function, need php 5.3 for this
+           // create a random salt
+           $salt = substr(str_replace('+', '.', base64_encode(sha1(microtime(true), true))), 0, 22);
+           // hash incoming password using 12 rounds of blowfish
+           $hash = crypt($_REQUEST['Rpassword'], '$2y$12$' . $salt);
+
+           if(strlen($hash)>13)
+             {
+               $r=DB_query('INSERT INTO User VALUES(NULL,'.DB_quote_smart($_REQUEST['Rfullname']).
+                           ','.DB_quote_smart($_REQUEST['Remail']).
+                           ','.DB_quote_smart($hash).
+                           ','.DB_quote_smart($_REQUEST['Rtimezone']).',NULL,NULL)');
+             }
+           else /* hash function didn't work */
+             $r=0;
          }
        else if(myisset('Ropenid'))
          {
@@ -113,7 +124,7 @@ if(myisset('Rfullname','Remail','Rtimezone') )
            $r=DB_query('INSERT INTO User VALUES(NULL,'.DB_quote_smart($_REQUEST['Rfullname']).
                        ','.DB_quote_smart($_REQUEST['Remail']).
                        ','.DB_quote_smart(md5($password)).
-                       ','.DB_quote_smart($_REQUEST['Rtimezone').',NULL,NULL)');
+                       ','.DB_quote_smart($_REQUEST['Rtimezone']).',NULL,NULL)');
            if($r)
              {
                include_once('openid.php');
@@ -139,7 +150,7 @@ if(myisset('Rfullname','Remail','Rtimezone') )
       }
     else
       {
-       echo 'Could not register you. Please <a href="index.php">try again</a>! </br />\n';
+       echo '<br />Could not register you. Please <a href="index.php">try again</a>! </br />'."\n";
       }
   }
 else
index 1b3d83e..d486b07 100644 (file)
@@ -25,12 +25,7 @@ if(!isset($HOST))
   exit;
 
 /* test id and password, should really be done in one step */
-if(!isset($_SESSION['name']))
-  {
-    $email     = $_REQUEST['email'];
-    $password  = $_REQUEST['password'];
-  }
-else
+if(isset($_SESSION['name']))
   {
     $name = $_SESSION['name'];
     $email     = DB_get_email('name',$name);
@@ -106,8 +101,6 @@ else
   { /* normal user page */
 
     /* verify password and email */
-    if(strlen($password)!=32)
-      $password = md5($password);
 
     $ok  = 1;
     $myid = DB_get_userid('email-password',$email,$password);
index edb01f9..323d914 100644 (file)
@@ -38,7 +38,7 @@ if(isset($_SERVER['REMOTE_ADDR']))
   exit();
 
 $old_version = DB_get_version();
-$current_version = 4;
+$current_version = 5;
 
 if($old_version < $current_version)
   echo "Will upgrade your database now:\n";
@@ -81,6 +81,10 @@ switch($old_version)
             " ADD COLUMN `type` enum('misc','your_turn') NOT NULL default 'misc' AFTER create_date");
     DB_query("UPDATE Version set version=4");
     echo "Upgraded to version 4.\n";
+  case 4:
+    DB_query("ALTER TABLE User MODIFY password varchar(64)");
+    DB_query("UPDATE Version set version=5");
+    echo "Upgraded to version 5.\n";
 
   }