Skip to content

Commit

Permalink
Stärkere Passwortverschlüsselung ; update #223
Browse files Browse the repository at this point in the history
  • Loading branch information
Christian Matzat committed Aug 8, 2013
1 parent a09ed40 commit 0c57799
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 20 deletions.
5 changes: 5 additions & 0 deletions bin/dbsv-update.php
Expand Up @@ -341,6 +341,11 @@ function dbv_117() // add user profile flag for OConly notifications
}
}

function dbv_118() // resize field password to fit to the new hashed passwords
{
sql("ALTER TABLE `user` MODIFY COLUMN `password` VARCHAR(128)");
}


// When adding new mutations, take care that they behave well if run multiple
// times. This improves robustness of database versioning.
Expand Down
5 changes: 5 additions & 0 deletions htdocs/config2/settings-dist.inc.php
Expand Up @@ -395,6 +395,11 @@
*/
$opt['logic']['password_hash'] = false;

/* password salt
* is a random generated String that is appended to the password
*/
$opt['logic']['password_salt'] = '';

/* new lows style
*/
$opt['logic']['new_logs_per_country'] = true;
Expand Down
34 changes: 34 additions & 0 deletions htdocs/lib2/logic/crypt.class.php
@@ -0,0 +1,34 @@
<?php
/***************************************************************************
* For license information see doc/license.txt
*
* Cryptographic library for encryption of passwords.
*
* Unicode Reminder メモ
***************************************************************************/

class crypt
{
static function encryptPassword($password)
{
// Calls the password encryption chained
$pwmd5 = crypt::firstStagePasswordEncryption($password);
return crypt::secondStagePasswordEncryption($pwmd5);
}

static function firstStagePasswordEncryption($password)
{
return md5($password);
}

static function secondStagePasswordEncryption($password)
{
global $opt;
if ($opt['logic']['password_hash'])
{
return hash_hmac('sha512', $password, $opt['logic']['password_salt']);
}
return $password;
}
}
?>
16 changes: 6 additions & 10 deletions htdocs/lib2/logic/user.class.php
Expand Up @@ -15,6 +15,7 @@
require_once($opt['rootpath'] . 'lib2/logic/picture.class.php');
require_once($opt['rootpath'] . 'lib2/logic/cache.class.php');
require_once($opt['rootpath'] . 'lib2/logic/cracklib.inc.php');
require_once($opt['rootpath'] . 'lib2/logic/crypt.class.php');
require_once($opt['rootpath'] . 'lib2/translate.class.php');

class user
Expand Down Expand Up @@ -155,21 +156,17 @@ function getPassword()
{
return $this->reUser->getValue('password');
}
function setPassword($value)
function setPassword($password)
{
global $opt;

if (!mb_ereg_match(REGEX_PASSWORD, $value))
if (!mb_ereg_match(REGEX_PASSWORD, $password))
return false;

if (cracklib_checkPW($value, array('open', 'caching', 'cache', $this->getUsername(), $this->getFirstName(), $this->getLastName())) == false)
if (cracklib_checkPW($password, array('open', 'caching', 'cache', $this->getUsername(), $this->getFirstName(), $this->getLastName())) == false)
return false;

$pwmd5 = md5($value);
if ($opt['logic']['password_hash'])
$pwmd5 = hash('sha512', $pwmd5);
$encryptedPassword = crypt::encryptPassword($password);

return $this->reUser->setValue('password', $pwmd5);
return $this->reUser->setValue('password', $encryptedPassword);
}
function getFirstName()
{
Expand Down Expand Up @@ -197,7 +194,6 @@ function setLastName($value)
}
function getCountry()
{
global $opt;
return countriesList::getCountryLocaleName($this->reUser->getValue('country'));
}
function getCountryCode()
Expand Down
15 changes: 5 additions & 10 deletions htdocs/lib2/login.class.php
Expand Up @@ -178,16 +178,12 @@ function verify()

function try_login($user, $password, $permanent)
{
global $opt;

if ($password == '')
return LOGIN_EMPTY_USERPASSWORD;

$pwmd5 = md5($password);
if ($opt['logic']['password_hash'])
$pwmd5 = hash('sha512', $pwmd5);
$encryptedPassword = crypt::encryptPassword($password);

return $this->try_login_md5($user, $pwmd5, $permanent);
return $this->try_login_encrypted($user, $encryptedPassword, $permanent);
}

function checkLoginsCount()
Expand All @@ -207,12 +203,11 @@ function checkLoginsCount()
return true;
}

function try_login_md5($user, $pwmd5, $permanent)
function try_login_encrypted($user, $encryptedPassword, $permanent)
{
global $opt;
$this->pClear();

if ($user == '' || $pwmd5 == '')
if ($user == '' || $encryptedPassword == '')
return LOGIN_EMPTY_USERPASSWORD;

if ($this->checkLoginsCount() == false)
Expand All @@ -224,7 +219,7 @@ function try_login_md5($user, $pwmd5, $permanent)

// compare $user with email and username, if both matches use email
$rsUser = sqlf("SELECT `user_id`, `username`, 2 AS `prio`, `is_active_flag`, `permanent_login_flag`, `admin` FROM `user` WHERE `username`='&1' AND `password`='&2' UNION
SELECT `user_id`, `username`, 1 AS `prio`, `is_active_flag`, `permanent_login_flag`, `admin` FROM `user` WHERE `email`='&1' AND `password`='&2' ORDER BY `prio` ASC LIMIT 1", $user, $pwmd5);
SELECT `user_id`, `username`, 1 AS `prio`, `is_active_flag`, `permanent_login_flag`, `admin` FROM `user` WHERE `email`='&1' AND `password`='&2' ORDER BY `prio` ASC LIMIT 1", $user, $encryptedPassword);
$rUser = sql_fetch_assoc($rsUser);
sql_free_result($rsUser);

Expand Down
48 changes: 48 additions & 0 deletions local/maintenance/update_passwords.php
@@ -0,0 +1,48 @@
<?php
/***************************************************************************
* For license information see doc/license.txt
*
* This script converts all md5-passwords to salted hash passwords.
*
* Unicode Reminder メモ
***************************************************************************/

global $opt;
$opt['rootpath'] = '../htdocs/';
require($opt['rootpath'] . 'lib2/web.inc.php');
require($opt['rootpath'] . 'lib2/logic/crypt.class.php');

if (!isset($opt['logic']['password_salt']) || strlen($opt['logic']['password_salt']) < 32)
{
echo "Warning!\nPassword Salt not set or too short!\n\n";
return;
}
if (!$opt['logic']['password_hash'])
{
echo "Warning!\nHashed Passwords not enabled!\n\n";
return;
}

$rs = sql("SELECT * FROM user where password is not null");
while ($r = sql_fetch_array($rs))
{
$password = $r['password'];
if (strlen($password) == 128)
{
echo "Password seems to be already converted, ommit this password\n";
continue;
}
if (strlen($password) < 32)
{
$password = crypt::firstStagePasswordEncryption($password);
}
$pwhash = crypt::secondStagePasswordEncryption($password);

sql("UPDATE `user` SET `password`='&1' WHERE `user_id`='&2'", $pwhash, $r['user_id']);
}

mysql_free_result($rs);

echo "Update of passwords finished.\n";

?>
31 changes: 31 additions & 0 deletions local/test/lib2/logic/PasswordEncryptionTest.php
@@ -0,0 +1,31 @@
<?php
/****************************************************************************
Unicode Reminder メモ
Password Encryption Test
****************************************************************************/

require '../../../../htdocs/lib2/logic/crypt.class.php';

class PasswordEncryptionTest extends PHPUnit_Framework_TestCase {

function testPasswordEncryption()
{
global $opt;
$opt['logic']['password_hash'] = false;

$plain_text = 'very important data';

$md5HashedPassword = crypt::encryptPassword($plain_text);
$this->assertEquals('c75ac45eabed45d667359462b6a8e93e', $md5HashedPassword);

$opt['logic']['password_hash'] = true;
$opt['logic']['password_salt'] = '?S<,XyB1Y[y_Gz>b';

$encryptedPassword = crypt::encryptPassword($plain_text);
$this->assertEquals('8b1d376a76e6430738d8322a6e3f4ebd5e8632f67052de7b74c8ca745bda6f11c7ea05db7de0c14bb097d3033557eb81d7fae21de988efc5353ed2f77dab504b', $encryptedPassword);
}

}

0 comments on commit 0c57799

Please sign in to comment.