Skip to content

Commit b3d669a

Browse files
committed
[SECURITY] fix salt usage for MD5/SHA1 salted hashes - see #43
1 parent 6df4c4a commit b3d669a

File tree

1 file changed

+40
-23
lines changed

1 file changed

+40
-23
lines changed

src/OSS/Auth/Password.php

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,24 +46,31 @@
4646
*/
4747
class OSS_Auth_Password
4848
{
49-
const HASH_PLAINTEXT = 'plaintext';
50-
const HASH_PLAIN = 'plain';
51-
const HASH_BCRYPT = 'bcrypt';
52-
const HASH_MD5 = 'md5';
53-
const HASH_MD5_SALTED = 'md5.salted';
54-
const HASH_SHA1 = 'sha1';
55-
const HASH_SHA1_SALTED = 'sha1.salted';
56-
const HASH_DOVECOT = 'dovecot:';
57-
const HASH_CRYPT = 'crypt:';
58-
const HASH_UNKNOWN = '*unknown*';
59-
60-
49+
const HASH_PLAINTEXT = 'plaintext';
50+
const HASH_PLAIN = 'plain';
51+
const HASH_BCRYPT = 'bcrypt';
52+
const HASH_MD5 = 'md5';
53+
const HASH_MD5_SALTED = 'md5-salted';
54+
const HASH_SHA1 = 'sha1';
55+
const HASH_SHA1_SALTED = 'sha1-salted';
56+
const HASH_DOVECOT = 'dovecot:';
57+
const HASH_CRYPT = 'crypt:';
58+
const HASH_UNKNOWN = '*unknown*';
59+
60+
// Bad salts - in April 2016 it was pointed out that a typo in the code below meant that
61+
// md5.salted and sha1.salted didn't actually use the requested salt string but a fixed
62+
// salt of "md5.salted" and "sha1.salted" respectivily.
63+
// These constants are for backwards compatibility for anyone that used those:
64+
const HASH_MD5_BADSALT = 'md5.salted';
65+
const HASH_SHA1_BADSALT = 'sha1.salted';
66+
6167
/**
6268
* A generic password hashing method using a given configuration array
6369
*
6470
* The parameters expected in `$config` are:
6571
*
6672
* * `pwhash` - a hashing method from the `HASH_` constants in this class
73+
* * `pwsalt` - a hashing salt for HASH_SHA1_SALTED and HASH_MD5_SALTED
6774
* * `hash_cost` - a *cost* parameter for certain hashing functions - e.g. bcrypt (defaults to 9)
6875
*
6976
* @param string $pw The plaintext password to hash
@@ -74,17 +81,17 @@ class OSS_Auth_Password
7481
public static function hash( $pw, $config )
7582
{
7683
$hash = self::HASH_UNKNOWN;
77-
84+
7885
if( is_array( $config ) )
7986
{
8087
if( !isset( $config['pwhash'] ) )
8188
throw new OSS_Exception( 'Cannot hash password without a hash method' );
82-
89+
8390
$hash = $config['pwhash'];
8491
}
8592
else
8693
$hash = $config;
87-
94+
8895
if( substr( $hash, 0, 8 ) == 'dovecot:' )
8996
{
9097
return ViMbAdmin_Dovecot::password( substr( $hash, 8 ), $pw, $config['username'] );
@@ -114,7 +121,7 @@ public static function hash( $pw, $config )
114121
default:
115122
throw new OSS_Exception( 'Unknown crypt password hashing method' );
116123
}
117-
return crypt( $pw, $salt );
124+
return crypt( $pw, $salt );
118125
}
119126
else
120127
{
@@ -124,11 +131,11 @@ public static function hash( $pw, $config )
124131
case self::HASH_PLAIN:
125132
return $pw;
126133
break;
127-
134+
128135
case self::HASH_BCRYPT:
129136
if( !isset( $config['hash_cost'] ) )
130137
$config['hash_cost'] = 9;
131-
138+
132139
$bcrypt = new OSS_Crypt_Bcrypt( $config['hash_cost'] );
133140
return $bcrypt->hash( $pw );
134141
break;
@@ -138,19 +145,29 @@ public static function hash( $pw, $config )
138145
break;
139146

140147
case self::HASH_MD5_SALTED:
141-
return md5( $pw . $config['pwhash'] );
148+
return md5( $pw . $config['pwsalt'] );
142149
break;
143150

144151
case self::HASH_SHA1:
145152
return sha1( $pw );
146153
break;
147154

148155
case self::HASH_SHA1_SALTED:
156+
return sha1( $pw . $config['pwsalt'] );
157+
break;
158+
159+
160+
161+
case self::HASH_MD5_BADSALT:
162+
return md5( $pw . $config['pwhash'] );
163+
break;
164+
165+
case self::HASH_SHA1_BADSALT:
149166
return sha1( $pw . $config['pwhash'] );
150167
break;
151168

152169
// UPDATE PHPDOC ABOVE WHEN ADDING NEW METHODS!
153-
170+
154171
default:
155172
throw new OSS_Exception( 'Unknown password hashing method' );
156173
}
@@ -176,18 +193,18 @@ public static function verify( $pwplain, $pwhash, $config )
176193
{
177194
if( !isset( $config['pwhash'] ) )
178195
throw new OSS_Exception( 'Cannot verify password without a hash method' );
179-
196+
180197
$hash = $config['pwhash'];
181198
}
182199
else
183200
$hash = $config;
184-
201+
185202
switch( $config['pwhash'] )
186203
{
187204
case self::HASH_BCRYPT:
188205
if( !isset( $config['hash_cost'] ) )
189206
$config['hash_cost'] = 9;
190-
207+
191208
$bcrypt = new OSS_Crypt_Bcrypt( $config['hash_cost'] );
192209
return $bcrypt->verify( $pwplain, $pwhash );
193210
break;

0 commit comments

Comments
 (0)