Kohana: Understanding and reproducing Salt & Hashed passwords using the Auth Module - php

I'm using the Auth Module in Kohana v 2.3.4.
In terms of authenticating users, there's a two step process. The entry point is the function login. It's first task is to retrieve the password stored in the database and retrieve the password and determine the salt value. The salt is supposedly determined by an array of values, each corresponding to a point in the $salt.$password hashed value to introduce yet another part of the salt. In my case, I'm using md5.
Problems:
I can't find a configuration for this SALT value. It seems to be relying on one already present within the password stored in the database. Is there one or do I need to configure AUTH to do so since this login needs to be portable and reproducible? If it can't detect the salt, in the hash_password routine, it defaults to using uniqid(), which I don't believe is portable at all.
In terms of adding users, does it make sense to modify the Auth library to add this feature? ie, introduce my own customized SALT that I can say, do an MD5 hash on that and then use that md5 generated by the salt to seed the password at given points in the md5sum?
I'm no security expert, but is this overkill? Granted, it prevents someone who were to get access to the md5 password list from using a md5 lookup of predetermined hashes.
If you have used the Kohana PHP framework, if you have any lessons learned or experiences after using it that might give insight as to the right approach for this problem, let me know. I'm reading numerous forums and wiki's about it, and there isn't a real concrete opinion yet that I've seen. I'm essentially trying to get a reproducible approach for authenticating someone in this site, both using PHP and eventually from a mobile device, like an iPhone. I'm also thinking of eventually adding support for google friend connect for openID support and integration.
Below are snippets from the Auth module in Kohana concerning the functions of interest. They have some debugging in them as I'm trying to better understand what's going on.
public function login($username, $password, $remember = FALSE)
{
if (empty($password))
return FALSE;
if (is_string($password))
{
// Get the salt from the stored password
$salt = $this->find_salt($this->driver->password($username));
Kohana::log('debug', "--- Auth_Core login salt = $salt ");
Kohana::log('debug', "--- Auth_Core login pass = $password ");
// Create a hashed password using the salt from the stored password
$password = $this->hash_password($password, $salt);
}
Kohana::log('debug', "--- Auth_Core login pass_hash = $password ");
return $this->driver->login($username, $password, $remember);
}
public function find_salt($password)
{
$salt = '';
foreach ($this->config['salt_pattern'] as $i => $offset)
{
// Find salt characters, take a good long look...
//$salt .= $password[$offset + $i];
$salt .= substr($password, $offset + $i, 0);
}
return $salt;
}
public function hash_password($password, $salt = FALSE)
{
Kohana::log('debug', "--- Auth_Core Original Pass = $password ");
if ($salt === FALSE)
{
// Create a salt seed, same length as the number of offsets in the pattern
$salt = substr($this->hash(uniqid(NULL, TRUE)), 0, count($this->config['salt_pattern']));
Kohana::log('debug', "--- Auth_Core salt created = $salt ");
}
// Password hash that the salt will be inserted into
$hash = $this->hash($salt.$password);
// Change salt to an array
$salt = str_split($salt, 1);
// Returned password
$password = '';
// Used to calculate the length of splits
$last_offset = 0;
foreach ($this->config['salt_pattern'] as $offset)
{
// Split a new part of the hash off
$part = substr($hash, 0, $offset - $last_offset);
// Cut the current part out of the hash
$hash = substr($hash, $offset - $last_offset);
// Add the part to the password, appending the salt character
$password .= $part.array_shift($salt);
// Set the last offset to the current offset
$last_offset = $offset;
}
Kohana::log('debug', "--- Auth_Core hashpw = $password + $hash ");
// Return the password, with the remaining hash appended
return $password.$hash;
}

Problem 1. The salt configuration is stored in config/auth.php. Find that file in modules/auth/config, then in your app/config folder (as you might have already known, Kohana uses cascading file system mechanism). The default file, which you are encouraged to customize into app/config/ folder, looks like below:
<?php defined('SYSPATH') OR die('No direct access allowed.');
return array
(
'driver' => 'ORM',
'hash_method' => 'sha1',
'salt_pattern' => '1, 3, 5, 9, 14, 15, 20, 21, 28, 30',
'lifetime' => 1209600,
'session_key' => 'auth_user',
'users' => array
(
// 'admin' => 'b3154acf3a344170077d11bdb5fff31532f679a1919e716a02',
),
);
Problem 2. In my opinion, the password hashing mechanism used by Auth, which is SHA1 with salt insertion, is quite secure provided you keep your salts, i.e. your auth.php file, secure.
Problem 3. Auth built-in hashing mechanism uses SHA1, which is relatively more crack-proof than MD5, so I would say don't do the MD5 way, no matter how complicated your scheme might look. A security expert Thomas Ptacek in his blog wrote:
No, really. Use someone else’s
password system. Don’t build your own.
Most of the industry’s worst security
problems (like the famously bad LANMAN
hash) happened because smart
developers approached security code
the same way they did the rest of
their code.
Problem 4. Yup I'm using Kohana to build my small company website and some of our clients' website and so far I don't find any problem with the Auth module, although I can't say much since I haven't really used it for real security-concerned website. But in general, I'd say Kohana is an excellent framework especially with the cascading filesystem mechanism.

Regarding point 1, the hash_password() function is used both to generate the password hash (against the salt and including the salt) that is stored in the database (e.g. at signup-time), as well as to recreate that hash when the password needs to be verified (e.g. at login-time). The hash_password() function will encode any salt that is given (or uniqid() if none is given) in the password-hash itself; that's a form of encryption where the salt_pattern is the key; if the salt_pattern can be kept secret, then that provides additional security since an adversary will not be able to do offline brute-forcing of the hash since the method of hashing is not reproducible (if the salt_pattern can be kept secret):
// Signup time; forget about uniqid(); you can use any salt that
// you please; once the password hash is stored in the database there
// is no need to know where your salt came from since it will be
// included in the password hash.
$password_hash = hash_password($password, FALSE);
// Login time; note that the salt is taken from the password hash itself.
$reproduced = hash_password($password, find_salt($password_hash));
$verifies = $password_hash == $reproduced;
The hash_password() function will first hash the password against the salt, and then insert each char of the salt into the password hash at the corresponding salt_pattern offset. find_salt() will extract these salt chars so that the hash can be reproduced. You can see it as hash_password() encrypting the salt and find_salt() decrypting it. Although you can also see it has hash_password() hiding the salt and find_salt() finding it, this method of encryption can't be called steganography, I think, because it is clear from the code that there is a salt stored with the password hash (the existence of the salt is not secret).
Regarding point 2, using your own salt is straightforward and fully compatible with the Auth module and an already existing database.
Regarding point 3, using a per user salt (uniqid() by default) is not overkill. Especially with MD5 which is broken for security purposes and where finding collisions is already practical with today's technology. Even better would be to use bcrypt() which uses a purposefully slower hashing algorithm to thwart brute-forcing attempts.
Regarding point 4, I haven't used the Kohana framework before, but reproducing or porting the Auth module is straightforward. Care must be taken that the salt_pattern is not forgotten or lost since it is an essential part of the hashing algorithm. The salt_pattern should also be kept secret since it is the only thing that keeps a determined adversary from brute-forcing the password hashes. uniqid() is just a reasonable default and can be replaced with whatever you want (as long as it is per-user and not a constant site-wide value.)
Also, there is a very good answer here on stackoverflow regarding portable bcrypt() and PHP. Naturally that will not be compatible with the Auth module, but I'd like to mention it anyway since it's just best practice to use a slow hash and not to rely on secrets that are difficult to keep, like the salt_patten.

Related

decrypt the password if I know the encryption function

I am developing a system using Codeigniter!
All I wanted to know is if it would be possible for someone to find out what the password is if he/she knows the function and steps I have used to generate the encrypted hash?
For now all I have to generate my hash strings is:
$pass = str_split($password, 2);
$hashPass = '';
foreach($pass as $p){
$hashPass .= md5($p);
}
Your hash method is not hash and its very bad idea.. You must hash your password strings!
Here is 2 pretty simple functions for that..
function hash_my_pass($password){
return generate_hash($password);
}
function generate_hash($password){
return hash('sha256', $password . substr($password, 1, 3));
# In this case I put to hash $password + some substr of the password..
# Its good when you hash pass to add something secret..
}
function check_password($password, $hashed_pass){
return generate_hash($password) == $hashed_pass;
}
$password = '123456789';
$hash = hash_my_pass($password);
echo $hash;#this hash you must keep at your DB.
#when user login just compare his pass with the hash from your DB
var_dump(check_password($password, $hash));
Honestly if you are not using Bcrypt in the year 2013 then passwords will be vulnerable. What you have going at the moment is quite low grade if any grade at that matter in terms of "encryption".
I use CodeIgniter with Bcrypt with this class
Then all you have to do is call this file bcrypt.php and then the class name is :
class Bcrypt extends CI_Controller {............}
Keep in mind though with php 5.5 > the new password hashing functions will be supported which will automatically use Bcrypt until a stronger method comes out. Info here
Good luck and at the end of the day stop trying to roll your own "encryption/hashing" algorithms / methods / disasters. Doing so might leave your clients vulnerable.
If they know the actual method of encryption, they have an easiert time hacking it.
For all hashes there exist rainbow tables for instance, which allow for fast reverting of passwords. That's why hashed password usually get salted.
str_split on the other hand is not a hash function, as far as i know.
look at Ion_auth http://benedmunds.com/ion_auth/ and use the bcrypt option - password hashing isn't something to try to create yourself.

Update old stored md5 passwords in PHP to increase security

At the moment I have a database with md5 passwords stored, a few years back this was considered a little more secure than it is now and it's got to the point where the passwords need to be more secure.
I've read a lot of posts on here about crypt, md5, hash, bcrypt, etc and have come to consider using something along the lines of the following to 'secure' the passwords better than they are now.
I will use a combination of hash("sha512" and two salts, the first salt will be a site wide salt stored in a file such as .htaccess and the second salt will be created for each user.
Here's an example along the lines of what I'm testing at the moment:
.htaccess
SetEnv SITEWIDE_SALT NeZa5Edabex?26Y#j5pr7VASpu$8UheVaREj$yA*59t*A$EdRUqer_prazepreTr
example.php
$currentpassword = //get password
$pepper = getenv('SITEWIDE_SALT');
$salt = microtime().ip2long($_SERVER['REMOTE_ADDR']);
$saltpepper = $salt.$pepper;
$password = hash("sha512", md5($currentpassword).$saltpepper);
The salt would obviously need to be stored in a separate table to allow checking of future inserted login passwords but it would never be possible for a user to see. Do you think this is a sufficient way to go about this?
Ok, let's go over a few points here
What you have in $salt is not a salt. It's deterministic (meaning that there is no randomness in there at all). If you want a salt, use either mcrypt_create_iv($size, MCRYPT_DEV_URANDOM) or some other source of actual random entropy. The point is that it should be both unique and random. Note that it doesn't need to be cryptographically secure random... At absolute worst, I'd do something like this:
function getRandomBytes($length) {
$bytes = '';
for ($i = 0; $i < $length; $i++) {
$bytes .= chr(mt_rand(0, 255));
}
return $bytes;
}
As #Anony-Mousse indicated, never feed the output of one hash function into another without re-appending the original data back to it. Instead, use a proper iterative algorithm such as PBKDF2, PHPASS or CRYPT_BLOWFISH ($2a$).
My suggestion would be to use crypt with blowfish, as it's the best available for PHP at this time:
function createBlowfishHash($password) {
$salt = to64(getRandomBytes(16));
$salt = '$2a$10$' . $salt;
$result = crypt($password, $salt);
}
And then verify using a method like this:
function verifyBlowfishHash($password, $hash) {
return $hash == crypt($password, $hash);
}
(note that to64 is a good method defined here). You could also use str_replace('+', '.', base64_encode($salt));...
I'd also suggest you read the following two:
Fundamental difference between hashing and encrypting
Many hash iterations, append salt every time?
Edit: To Answer the Migration Question
Ok, so I realize that my answer did not address the migration aspect of the original question. So here's how I would solve it.
First, build a temporary function to create a new blowfish hash from the original md5 hash, with a random salt and a prefix so that we can detect this later:
function migrateMD5Password($md5Hash) {
$salt = to64(getRandomBytes(16));
$salt = '$2a$10$' . $salt;
$hash = crypt($md5Hash, $salt);
return '$md5' . $hash;
}
Now, run all the existing md5 hashes through this function and save the result in the database. We put our own prefix in so that we can detect the original password and add the additional md5 step. So now we're all migrated.
Next, create another function to verify passwords, and if necessary update the database with a new hash:
function checkAndMigrateHash($password, $hash) {
if (substr($hash, 0, 4) == '$md5') {
// Migrate!
$hash = substr($hash, 4);
if (!verifyBlowfishHash(md5($password), $hash) {
return false;
}
// valid hash, so let's generate a new one
$newHash = createBlowfishHash($password);
saveUpdatedPasswordHash($newHash);
return true;
} else {
return verifyBlowfishHash($password, $hash);
}
}
This is what I would suggest for a few reasons:
It gets the md5() hashes out of your database immediately.
It eventually (next login for each user) updates the hash to a better alternative (one that's well understood).
It's pretty easy to follow in code.
To answer the comments:
A salt doesn't need to be random - I direct you to RFC 2898 - Password Based Cryptography. Namely, Section 4.1. And I quote:
If there is no concern about interactions between multiple uses
of the same key (or a prefix of that key) with the password-
based encryption and authentication techniques supported for a
given password, then the salt may be generated at random and
need not be checked for a particular format by the party
receiving the salt. It should be at least eight octets (64
bits) long.
Additionally,
Note. If a random number generator or pseudorandom generator is not
available, a deterministic alternative for generating the salt (or
the random part of it) is to apply a password-based key derivation
function to the password and the message M to be processed.
A PseudoRandom Generator is available, so why not use it?
Is your solution the same as bcrypt? I can't find much documentation on what bcrypt actually is? - I'll assume that you already read the bcrypt Wikipedia Article, and try to explain it better.
BCrypt is based off the Blowfish block cipher. It takes the key schedule setup algorithm from the cipher, and uses that to hash the passwords. The reason that it is good, is that the setup algorithm for Blowfish is designed to be very expensive (which is part of what makes blowfish so strong of a cypher). The basic process is as follows:
A 18 element array (called P boxes, 32 bits in size) and 4 2-dimensional arrays (called S boxes, each with 256 entries of 8 bits each) are used to setup the schedule by initializing the arrays with predetermined static values. Additionally, a 64 bit state is initialized to all 0's.
The key passed in is XOred with all 18 P boxes in order (rotating the key if it's too short).
The P boxes are then used to encrypt the state that was previously initialized.
The ciphertext produced by step 3 is used to replace P1 and P2 (the first 2 elements of the P array).
Step 3 is repeated, and the result is put in P3 and P4. This continues until P17 and P18 are populated.
That's the key derivation from the Blowfish Cipher. BCrypt modifies that to this:
The 64 bit state is initialized to an encrypted version of the salt.
Same
The P boxes are then used to encrypt the (state xor part of the salt) that was previously initialized.
Same
Same
The resulting setup is then used to encrypt the password 64 times. That's what's returned by BCrypt.
The point is simple: It's a very expensive algorithm that takes a lot of CPU time. That's the real reason that it should be used.
I hope that clears things up.
Implementation of your new, more secure, password storage should use bcrypt or PBKDF2, as that's really the best solution out there right now.
Don't nest things, as you don't get any real security out of this due to collisions as #Anony-Mousse describes.
What you may want to do it implement a "transition routine" where your app transitions users over from the old MD5-based system to the new more secure system as they log in. When a login request comes in, see if the user is in the new, more secure, system. If so, bcrypt/PBKDF2 the password, compare, and you're good to go. If they are not (no one will be at first), check them using the older MD5-based system. If it matches (password is correct), perform the bcrypt/PBKDF2 transformation of the password (since you now have it), store it in the new system, and delete the old MD5 record. Next time they log in, they have an entry in the new system so you're good to go. Once all of the users have logged in once you implement this, you can remove this transition functionality and just authenticate against the new system.
Do not nest md5 inside your sha512 hash. An md5 collision then implies a hash collision in the outer hash, too (because you are hashing the same values!)
The common way of storing passwords is to use a scheme such as
<method><separator><salt><separator><hash>
When validating the password, you read <method> and <salt> from this field, reapply them to the password, and then check that it produces the same <hash>.
Check the crypt functions you have available. On a modern Linux system, crypt should be able to use sha512 password hashing in a sane way: PHP crypt manual. Do not reinvent the wheel, you probably just screw up more badly than md5, unless you are an expert on cryptographic hashing. It will even take care of above scheme: the Linux standard is to use $ as separator, and $6$ is the method ID for sha512, while $2a$ indicates you want to use blowfish. So you can even have multiple hashes in use in your database. md5 hashes are prefixed with $1$<salt>$ (unless you reinvented md5 hashing, then your hashes may be incompatible).
Seriously, reuse the existing crypt function. It is well checked by experts, extensible, and compatible across many applications.
I looked into this subject a while back and found the following link of great use:
Secure hash and salt for PHP passwords
I also use the following to create a random salt:
public static function getRandomString($length = 20) {
$characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$string = '';
for ($i = 0; $i < $length; $i++) {
$string .= substr($characters, (mt_rand() % strlen($characters)), 1);
}
return $string;
}

Creating salt with Portable PHP password hashing framework

I'd like to use Portable PHP password hashing framework to hash passwords. But I find that its demos don't use salt for hashing a password. But it use a dummy salt for checking password which I find it strange and I don't understand this idea at all,
$dummy_salt = '$2a$08$1234567890123456789012';
if (isset($dummy_salt) && strlen($hash) < 20)
$hash = $dummy_salt;
I wonder, if I want to use convention method which I can generate the unique salt and store it for each user in my database, how can I use Portable PHP password hashing framework to generate salts?
This is the function I use to hash passwords but I have been told that sha512 has the same issue as sha1, wise to trust the expert like Portable PHP password hashing framework,
function hash_sha512($phrase,&$salt = null)
{
//$pepper = '!##$%^&*()_+=-{}][;";/?<>.,';
if ($salt == '')
{
$salt = substr(hash('sha512',uniqid(rand(), true).PEPPER_KEY.microtime()), 0, SALT_LENGTH);
}
else
{
$salt = substr($salt, 0, SALT_LENGTH);
}
return hash('sha512',$salt.PEPPER_KEY.$phrase);
}
Let me know if you have any idea. Thanks.
From the phpass article linked to from that page:
Besides the actual hashing, phpass
transparently generates random salts
when a new password or passphrase is
hashed, and it encodes the hash type,
the salt, and the password stretching
iteration count into the "hash
encoding string" that it returns. When
phpass authenticates a password or
passphrase against a stored hash, it
similarly transparently extracts and
uses the hash type identifier, the
salt, and the iteration count out of
the "hash encoding string". Thus, you
do not need to bother with salting and
stretching on your own - phpass takes
care of these for you.
...so it's not surprising that the examples don't use salting! You may be over-seasoning your code.
The code sample with the dummy salt is an example of how to prevent a timing attack by making sure that whether a user exists or not, the validation of the user takes the same amount of time, effectively by doing a dummy authentication for non-existent users. It needs a dummy salt because if the user doesn't exist, it won't have a stored salt to use.

How can I store my users' passwords safely?

How much more safe is this than plain MD5? I've just started looking into password security. I'm pretty new to PHP.
$salt = 'csdnfgksdgojnmfnb';
$password = md5($salt.$_POST['password']);
$result = mysql_query("SELECT id FROM users
WHERE username = '".mysql_real_escape_string($_POST['username'])."'
AND password = '$password'");
if (mysql_num_rows($result) < 1) {
/* Access denied */
echo "The username or password you entered is incorrect.";
}
else {
$_SESSION['id'] = mysql_result($result, 0, 'id');
#header("Location: ./");
echo "Hello $_SESSION[id]!";
}
The easiest way to get your password storage scheme secure is by using a standard library.
Because security tends to be a lot more complicated and with more invisible screw up possibilities than most programmers could tackle alone, using a standard library is almost always easiest and most secure (if not the only) available option.
The new PHP password API (5.5.0+)
If you are using PHP version 5.5.0 or newer, you can use the new simplified password hashing API
Example of code using PHP's password API:
<?php
// $hash is what you would store in your database
$hash = password_hash($_POST['password'], PASSWORD_DEFAULT, ['cost' => 12]);
// $hash would be the $hash (above) stored in your database for this user
$checked = password_verify($_POST['password'], $hash);
if ($checked) {
echo 'password correct';
} else {
echo 'wrong credentials';
}
(In case you are still using legacy 5.3.7 or newer you can install ircmaxell/password_compat to have access to the build-in functions)
Improving upon salted hashes: add pepper
If you want extra security, the security folks now (2017) recommend adding a 'pepper' to the (automatically) salted password hashes.
There is a simple, drop in class that securely implements this pattern, I recommend:
Netsilik/PepperedPasswords
(github).
It comes with a MIT License, so you can use it however you want, even in proprietary projects.
Example of code using Netsilik/PepperedPasswords:
<?php
use Netsilik/Lib/PepperedPasswords;
// Some long, random, binary string, encoded as hexadecimal; stored in your configuration (NOT in your Database, as that would defeat the entire purpose of the pepper).
$config['pepper'] = hex2bin('012345679ABCDEF012345679ABCDEF012345679ABCDEF012345679ABCDEF');
$hasher = new PepperedPasswords($config['pepper']);
// $hash is what you would store in your database
$hash = $hasher->hash($_POST['password']);
// $hash would be the $hash (above) stored in your database for this user
$checked = $hasher->verify($_POST['password'], $hash);
if ($checked) {
echo 'password correct';
} else {
echo 'wrong credentials';
}
The OLD standard library
Please note: you should not be needing this anymore! This is only here for historical purposes.
Take a look at: Portable PHP password hashing framework: phpass and make sure you use the CRYPT_BLOWFISH algorithm if at all possible.
Example of code using phpass (v0.2):
<?php
require('PasswordHash.php');
$pwdHasher = new PasswordHash(8, FALSE);
// $hash is what you would store in your database
$hash = $pwdHasher->HashPassword( $password );
// $hash would be the $hash (above) stored in your database for this user
$checked = $pwdHasher->CheckPassword($password, $hash);
if ($checked) {
echo 'password correct';
} else {
echo 'wrong credentials';
}
PHPass has been implemented in some quite well known projects:
phpBB3
WordPress 2.5+ as well as bbPress
the Drupal 7 release, (module available for Drupal 5 & 6)
others
The good thing is that you do not need to worry about the details, those details have been programmed by people with experience and reviewed by many folks on the internet.
For more information on password storage schemes, read Jeff`s blog post: You're Probably Storing Passwords Incorrectly
Whatever you do if you go for the 'I'll do it myself, thank you' approach, do not use MD5 or SHA1 anymore. They are nice hashing algorithm, but considered broken for security purposes.
Currently, using crypt, with CRYPT_BLOWFISH is the best practice.
CRYPT_BLOWFISH in PHP is an implementation of the Bcrypt hash. Bcrypt is based on the Blowfish block cipher, making use of it's expensive key setup to slow the algorithm down.
Your users will be much safer if you used parameterized queries instead of concatenating SQL statements. And the salt should be unique for each user and should be stored along with the password hash.
A better way would be for each user to have a unique salt.
The benefit of having a salt is that it makes it harder for an attacker to pre-generate the MD5 signature of every dictionary word. But if an attacker learns that you have a fixed salt, they could then pre-generate the MD5 signature of every dictionary word prefixed by your fixed salt.
A better way is each time a user changes their password, your system generate a random salt and store that salt along with the user record. It makes it a bit more expensive to check the password (since you need to look up the salt before you can generate the MD5 signature) but it makes it much more difficult for an attacker to pre-generate MD5's.
With PHP 5.5 (what I describe is available to even earlier versions, see below) around the corner I'd like to suggest to use its new, built-in solution: password_hash() and password_verify(). It provides several options in order to achieve the level of password security you need (for example by specifying a "cost" parameter through the $options array)
<?php
var_dump(password_hash("my-secret-password", PASSWORD_DEFAULT));
$options = array(
'cost' => 7, // this is the number of rounds for bcrypt
// 'salt' => 'TphfsM82o1uEKlfP9vf1f', // you could specify a salt but it is not recommended
);
var_dump(password_hash("my-secret-password", PASSWORD_BCRYPT, $options));
?>
will return
string(60) "$2y$10$w2LxXdIcqJpD6idFTNn.eeZbKesdu5y41ksL22iI8C4/6EweI7OK."
string(60) "$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d."
As you might see, the string contains the salt as well as the cost that was specified in the options. It also contains the algorithm used.
Therefore, when checking the password (for example when the user logs in), when using the complimentary password_verify() function it will extract the necessary crypto parameters from the password hash itself.
When not specifying a salt, the generated password hash will be different upon every call of password_hash() because the salt is generated randomly. Therefore comparing a previous hash with a newly generated one will fail, even for a correct password.
Verifying works like this:
var_dump(password_verify("my-secret-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K'));
var_dump(password_verify("wrong-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K'));
var_dump(password_verify("my-secret-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.'));
var_dump(password_verify("wrong-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.'));
I hope that providing these built-in functions will soon provide better password security in case of data theft, as it reduces the amount of thought the programmer has to put into a proper implementation.
There is a small library (one PHP file) that will give you PHP 5.5's password_hash in PHP 5.3.7+: https://github.com/ircmaxell/password_compat
That's fine with me. Mr Atwood wrote about the strength of MD5 against rainbow tables, and basically with a long salt like that you're sitting pretty (though some random punctuation/numbers, it could improve it).
You could also look at SHA-1, which seems to be getting more popular these days.
I want to add:
Don't limit users passwords by length
For compatibility with old systems often set a limit for the maximum length of the password. This is a bad security policy: if you set restriction, set it only for the minimum length of passwords.
Don't send user passwords via email
For recovering a forgotten password you should send the address by which user can change the password.
Update the hashes of users passwords
The password hash may be out of date (parameters of the algorithm may be updated). By using the function password_needs_rehash() you can check it out.
Here's a PHP + CouchDB.apache.org login system that doesn't store plaintext passwords.
According to the advice that I've read, it should be totally secure.
CMS login code : https://github.com/nicerapp/nicerapp/blob/24ff0ca317b28c1d91aee66041320976a6d76da7/nicerapp/boot.php#L56
calls
https://github.com/nicerapp/nicerapp/blob/24ff0ca317b28c1d91aee66041320976a6d76da7/nicerapp/functions.php#L171
app(s) specific business code :
https://github.com/nicerapp/nicerapp/blob/24ff0ca317b28c1d91aee66041320976a6d76da7/nicerapp/ajax_login.php#L87
calls
https://github.com/nicerapp/nicerapp/blob/24ff0ca317b28c1d91aee66041320976a6d76da7/nicerapp/functions.php#L230
which in turn calls :
https://github.com/nicerapp/nicerapp/blob/2d479b3e22dce9e7073525481b775f1bf7389634/nicerapp/apps/nicer.app/webmail/recrypt.php#L2
and to edit the webmail app config data into the database :
https://github.com/nicerapp/nicerapp/blob/main/nicerapp/apps/nicer.app/webmail/ajax_editConfig.php

Importing MD5+Salt Passwords to MD5

I'm moving my site from an oscommerce store to a commercial application.
The new application stores its passwords using straight MD5 encryption. Oscommerce stores the password using MD5, but also adds a random 2 digit number (provided in plaintext) to the hash.
Here is what someone posted on a forum:
The two characters added are for creating the hash in such way that
hash=md5(twocharactersPlainPassword)
ie: 2letters: 74
Plain Password: PaSs
hash=md5('74PaSs')=acaa6e689ae0008285320e6617ca8e95:74
Here is the code how Oscommerce encrypts the password:
// This function makes a new password from a plaintext password.
function tep_encrypt_password($plain) {
$password = '';
for ($i=0; $i<10; $i++) {
$password .= tep_rand();
}
$salt = substr(md5($password), 0, 2);
$password = md5($salt . $plain) . ':' . $salt;
return $password;
}
// This funstion validates a plain text password with an encrypted password
function tep_validate_password($plain, $encrypted) {
if (tep_not_null($plain) && tep_not_null($encrypted)) {
// split apart the hash / salt
$stack = explode(':', $encrypted);
if (sizeof($stack) != 2) {
return false;
}
if (md5($stack[1] . $plain) == $stack[0]) {
return true;
}
}
return false;
}
Here is how my new cart encrypts the password:
if ($admin_password_encrypt == 1) {
$password_match = md5($password);
} else {
$password_match = $password;
}
Is there any possible way of importing customer passwords from my oscommerce cart to my new cart.
Do not save plain MD5 hashes in your database. Plain MD5 hashes can be reverse engineered quickly and easily using rainbow tables. However, here's how you solve your problem, no matter how you choose to store the passwords in the future:
Create a column in your new database that specifies the "version" of the password. This is used to determine if the password was generated by the old application or the new one.
Import the old users, setting the aforementioned flag to indicate the password is imported.
Create two methods for validating a password. One method uses the code from your old application, the other uses your new validation method.
When a user is logging in, check the aforementioned flag and use the appropriate validation method.
Anyways, I want to reiterate that plain MD5 hashes are easy to crack for most passwords (since people like short and easy to remember passwords.) Use a salt and/or a more complex algorithm. I'd recommend both, and use a salt that is longer than two characters and not limited to numbers. This will make the passwords really secure.
It appears that you have the source code for your new cart. Since "straight MD5" is a terribly awful way of storing passwords, perhaps you should simply change the to use the same password storage mechanism as OSCommerce.
The answer to your question is no, there is no way of converting the passwords.
No. MD5 is a hash algorithm, which is a one-way function. You cannot reverse the hash on your oscommerce system to remove the salt and rehash. Sorry.
If the passwords are encrypted with md5, you won't be able to decrypt them. Your best possibility can be to check in your login code whether the creation of an account/last password change occurred before a certain date. If so, use OSCommerce's password validation function, if not, use your own.
This way, for all new accounts the passwords will be encrypted with the new method, and for old accounts you'd continue to handle them as usual, so it'll be transparent to users.
Another, and possibly better option is that you continue to use the salting method of OsCommerce. It is more secure, and you'll also get to keep your existing passwords.
There is no method for automatic conversion between hash algorithms. Unfortunately you would likely be stuck picking from one of the following bad options:
Configure or program old cart to store hashes in new format as users login to old system.
Use a password cracker to recover some percentage of old system cart passwords.
Ask new vendor to support old format
Send notification to all users they will need to prepend the salt text to their passwords when using the new system or customize the system to prepend known salts for them.

Categories