I don't know much about hashing passwords, but I'd like to know. I'd like to know how good the following algorithm is for a normal site without credit card information or something like that, and I also want to know how to improve it.
The algorithm is:
hash('sha512', crypt(hash('whirlpool', $password.$username), base64_encode(md5(strlen($password)))))
Don't mix more than one hash, each one is optimized to work best by itself.
Depending on what you are using that hash for it's also a very bad idea to put $password in it. If it is being stored on the user's computer that is, like in a cookie. You don't want that in there.
If you store the hash in a database you can also make it better by adding a dynamic random string before using the hashing algorithm. Then a new hash will be generated for the user each visit.
I would highly recommend using a well-known, tested, vetted hash/crypt function over any home-grown algorithm.
Here is a class that I created to store a id/password combos for an api I integrate with. Each user can have their own unique credentials. I do not advise storing any credit card data on a non PCI compliant computer.
This is my exact class but you have some missing pieces so I have commented those. Please note that the vector is unique (Think of it as a hash) and I store that in the database along with the encrypted data.
The key is out of the public directory which goes to another topic of securing your box.
<?php
// This is on my index page but added here so you see all constants.
define('DIR', dirname(__FILE__) . '/');
class locker {
private $algorithm = MCRYPT_RIJNDAEL_256;
private $key;
private $mode = MCRYPT_MODE_CBC;
public $iv; // Public so we can change to the one used to encrypt it.
public function __construct()
{
// Lets include our key
// The key is located Outside of the public directory.
$this->key = file_get_contents(DIR .'../keys/passphrase.key');
// Create the initialization vector for added security.
$this->iv = mcrypt_create_iv(mcrypt_get_iv_size($this->algorithm, MCRYPT_MODE_ECB), MCRYPT_RAND);
}
public function encrypt($string)
{
return base64_encode(mcrypt_encrypt($this->algorithm, $this->key, base64_encode($string), $this->mode, $this->iv));
}
public function decrypt($string)
{
return base64_decode(mcrypt_decrypt($this->algorithm, $this->key, base64_decode($string), $this->mode, $this->iv));
}
// Helper functions so you can see what you can do on your own box.
public function list_modes()
{
print_r(mcrypt_list_modes());
}
public function list_algorithms()
{
print_r(mcrpt_list_algorithms());
}
}
?>
<?php
//Example usage
$locker = new locker;
$pass = $locker->encrypt('passwordvalue');
$iv = $locker->iv;
// Decrypt it
$locker = new locker;
$locker->iv = $iv;
$pass = $locker->decrypt($pass);
?>
If you want something strong. you have to
- never save the password but a hash (don't need so much) to avoid db hack use of password.
and never ask for the password but for a hash of the pasword hash + salt (the date for example) to avoid playback attack
try this (very easy to use) class I wrote which includes automatic algorithm detection to get the most secure algorithm that your server supports: http://netentwicklung.wordpress.com/2012/06/17/87/
Related
I want to store data from users so that they become useless even if the database gets leaked somehow. I also don't want to be able to encrypt the data, so I encrypt all my data via `openssl_encrypt' like this:
$passCode = base64_encode($this->get('session')->get('_pk'));
if (strlen($passCode) <= 16) {
$iv = str_pad($passCode, 16, '0');
} else {
$iv = substr($passCode, 0, 16);
}
$ciphertext = openssl_encrypt('whatevervalue', 'AES-256-CBC', $passCode, 0, $iv);
$test = new Test();
$test->setValue($ciphertext);
...
$em->persist($test);
$em->flush();
...
The $passCode is actually their password, which I put into the session var like this:
SecurityListener.php
<?php
namespace AppBundle\Listener;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
class SecurityListener
{
public function __construct($security, Session $session)
{
$this->security = $security;
$this->session = $session;
}
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
$this->session->set('_pk', base64_encode($event->getRequest()->get('_password')));
}
}
2 Problems:
Storing the $passCode (whitout knowing actually that much about sessions) seems to be a security issue possibly?
What happens if a user changes the password. With the current way I'd need to decrypt and re-encrypt all his DB data with the new password, so that does not seem like a proper solution. What if he looses his password?
Maybe it is easier to understand what I want to here:
I want to encrypt all data in my database that the user himself enters there. I want it to be a "feature" that even the admin(s) cannot read the data without the key. I know the latter is not 100% possible (as there will be ways to intercept passwords/keys if entered through a web interface, but at least that invloves some change of code). Is something like that even possible at all? Any open source porjects I can have a look at?
Thank you!
Have some invariants for each user that will be used to generate the private key: user ID, account creation date, some random generated salt...
Write a hashing function that will generate the private key.
Obfuscate the code of the function.
This is not perfect, since people with access to the code and the database will be able to decipher the data, but it should be safe against database leaks and it doesn't have the problems you mention.
The only safer solution I can think of is to have users generate their own private keys and encrypt the data on client side, then send the encrypted data to the server. Otherwise, if the server has the tools necessary to decrypt, there will always be the way for someone with complete access to the system to decrypt the sensitive data.
I'm no expert in this matter and please tell me if I'm wrong.
I Have the following class to validate the user Login,
class Validation_model extends CI_Model {
public function validateLogin($userid,$userpass){
$this->load->library('encrypt');
$this->load->database();
$encrypted_string = $this->encrypt->encode($userpass);
$this->db->select('*');
$this->db->from('ecom-user');
$this->db->where('userid', $userid);
$this->db->where('userpassword', $encrypted_string);
$result = $this->db->get();
echo $result->num_rows();
}
}
But when even I entered a valid userid & password it returns the row count as 0, Please help me with this, where I have done the mistake?
It does not work because you are encrypting the password.
The encryption function used by CodeIgniter uses a random initialization vector (IV) every time it encrypts something, which means that the cipher-text (the encrypted text) will be different every time it is encrypted.
When dealing with passwords you need to hash them, not encrypt them. They are related but they are not the same thing.
Wikipedia article on cryptographic hash functions
Page on PHP.net on password hashing
Documentation on PHP's native password hashing API
Compatibility library for the native API (if you have PHP <5.5.0)
PHPass implementation for CodeIgniter on Github (if you have PHP <5.5.0)
If you have PHP >=5.5.0 then you can do:
$hashed_password = password_hash($userpass, PASSWORD_DEFAULT);
// ...
$this->db->where('userpassword', $hashed_password);
For this to work you also need to re-hash the passwords in your database.
I'm currently going over my user registration code. The part I'm focusing on right now is the password hashing part.
What I do is get a static_salt from a config file, and use mt_rand() to generate a dynamic_salt. What I want to do is have this dynamic_salt stored in my database.
But if I pass the dynamic_salt() method to the create method in order to send it to the salt column of a table in my database it will just run the method again and create a different result from the one produced in my hashed() method.
What would be the best way to achieve what I'm trying to achieve, could you show me an example if possible?
public function create() {
$dbcolumn->password = $this->hashed();
$dbcolumn->salt = $this->dynamic_salt;
$this->db->insert('users', $dbcolumn);
}
public function dynamic_salt() {
$get_dynamic_salt = mt_rand();
return $get_dynamic_salt;
}
public function hashed() { //hashing method, that also makes
// sha1 and salt password
$static_salt = $this->config->item('encryption_key'); //grab static salt from config file
$dynamic_salt = $this->dynamic_salt();
$password = $this->encrypt->sha1($this->input->post('password')); //encrypt user password
$hashed = sha1($dynamic_salt . $password . $static_salt);
return $hashed;
}
I recommend that you don't use a dynamic salt, as it will reduce your applications flexibility and is likely not to work in it's current form.
The purpose of a salt is to prevent against dictionary attacks that someone could do if they obtained your user database. In that regard, a static salt is definitely a good idea to implement in your application.
Adding a dynamic salt to each user would mean that you will have to hit a datastore to retrieve the dynamic salt and the hashed version of the user's password, then you will have to perform the CPU intensive hash function (in your code, twice -- you are hashing a hash which is less secure and more likely to have collisions).
Having a simple known, static salt, and a hashed password will allow you to use key/value storage systems like memcache should you application grow. Store the userid as the key and the users hashed password as the value and you will have a lightening fast authentication system.
Try this:
public function dynamic_salt() {
if(!isset($this->dyn_salt))
$this->dyn_salt = mt_rand();
return $this->dyn_salt;
}
If the dyn_salt instance variable doesn't already exist, it will assign it the result of mt_rand(), else it will just return the previous value.
I'm using Zend_Auth with setCredentialTreatment to set the hash method and salt. I see all examples doing something like this, where the salt seems to be inserted as a text.
->setCredentialTreatment('SHA1(CONCAT(?,salt))'
but my salt is stored in the database. I could retrieve it first then use it in setCredentialTreatment but is there a way I could define it directly as a field name, so setCredentialTreatment would know to get it from that field? sort of like the way we define the field name for the username or password
->setCredentialColumn('password')
A side issue I'm having is that I'd like to use SHA512 not SHA1. Is this possible or is it not available? All the examples I see using SHA1.
I should say I'm fairly new to zend and am porting an existing application, so please go easy on me with the answers.
The example you've given does use the salt as stored in the database. It will work as long as the salt is stored in each row in a field called 'salt'. If the salt was not in the DB and in a PHP variable instead, the code would be something more like:
->setCredentialTreatment("SHA1(CONCAT(?, '$salt'))")
As for using SHA512, this might be a little trickier. Assuming you're using MySQL, SHA1() in this case is a MySQL function, and MySQL does not have a function for SHA512 as far as I can tell, and neither does PHP (edit: I was wrong about the latter, see comments). So you'll have to implement your own PHP SHA512 function, load the salt for the user out of the DB first, hash the result and not do anything to the variable in setCredentialTreatment.
As the other answer suggested you might want to write your own Zend_Auth_Adapter for this. An auth adapter is a class that handles authentication, presumably at the moment you're using Zend_Auth_Adapter_DbTable. You can find some more info about auth adapters in the manual: http://framework.zend.com/manual/en/zend.auth.introduction.html
Here's an example:
class My_Auth_Adapter extends Zend_Auth_Adapter_DbTable
{
public function authenticate()
{
// load salt for the given identity
$salt = $this->_zendDb->fetchOne("SELECT salt FROM {$this->_tableName} WHERE {$this->_identityColumn} = ?", $this->_identity);
if (!$salt) {
// return 'identity not found' error
return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND, $this->_identity);
}
// create the hash using the password and salt
$hash = ''; // SET THE PASSWORD HASH HERE USING $this->_credential and $salt
// replace credential with new hash
$this->_credential = $hash;
// Zend_Auth_Adapter_DbTable can do the rest now
return parent::authenticate();
}
}
You can write your own Zend_Auth_Adapter.
I am building my own small framework for my final year project at university and I am very confused about best practices here. I have read quiet a lot of articles and have a general idea but some clarification would be better.
I really like the new sodium extension in PHP But I am a bit confused.
I am creating a split token authentication thing both for long term persistent cookies and password resets.
I am using Libsodium as much as possible as it seems very secure, all be it new and not very well documented.
I am creating a split token like selector:validator.
What I want to do is basically use the selector to query the DB,
Then I want to either compare the two hashes VS Hash the plain text version from the cookie and then compare (But the latter means keeping a key somewhere which creates an issue)
I have heard across many articles especially with Paragone suggest that it is preferable to store the hashed version of a token in the Database and the plain version in the cookie or token.
Is there any real benefit of this?
I have created a simple Token class:
class SplitToken extends Token
{
protected $selector;
protected $validator;
function __construct($selector=14, $validator=18)
{
$this->selector = bin2hex(random_bytes($selector));
$this->validator = bin2hex(random_bytes($validator));
$this->key = random_bytes(SODIUM_CRYPTO_AUTH_KEYBYTES);
$this->tokenHash = sodium_crypto_auth($this->validator, $this->key);
}
public function Set()
{
$this->token = $this->selector.':'.$this->validator;
return $this;
}
public function Get()
{
return $this->token;
}
$sptoken = new SplitToken();
$token = $sptoken->set()->Get();
$dt = new DateTime('+ 2 months');
$expiry = $dt->getTimestamp();
//Gets bin2hex version of validator side of token for DB
$validatorHash = $token->GetValidatorHashHex();
$key = $token->GetKey();
//Store token In DB:
$query = "UPDATE Users SET Selector, Validator, Expiry
WHERE Selector = :Selector and Validator = :Validator and Expiry = :Expiry;
$stmt = $pdo->prepare($query);
$stmt->execute(
['Selector' => $token->GetSelector(),
'Validator' => $validatorHash,
'Expiry' => $expiry]);
Now that the temp token is in the DB. Now it is time to set the cookie (The same can apply to PW Reset with a different expiry of course.
Here I am getting confused and I have two options:
Option 1:
//Store the hexed version of selector:validator in the cookie (but not hashed)
setcookie('auth_token', $token, $expiry, '/', 'CONST_DOMAIN', true, true);
//Where do I store the key?
//So far I am using JSON fuNCTION which gets key from the folder where it is stored:
$storedKey = Key::GetFromVault('auth_token');
if(isset($_COOKIE['auth_token')){
$cookie = explode(':', $_COOKIE['auth_token'];
//Gets the User from the DB Where Selector = Selector
$user = DB::SelectUser($user);
//If User exists
if($user){
//*** Checks the Hash separate from the query to avoid timing attack ***
var_dump(sodium_crypto_auth_verify($user->Validator, $cookie[1], $storedKey);
}
}
Option 2:
Seems a bit simpler and cleaner because I am simply comparing two hashes and there is no need to worry about the key later but it means that I have to store the hashed version of the validator in the cookie:
$hashedToken = $token->GetSelector.':'.$token->GetValidatorHashHex();
setcookie('auth_token', $hashedToken, $expiry, '/', 'CONST_DOMAIN', true, true);
//Now On Request:
if(isset($_COOKIE['auth_token')){
$cookie = explode(':', $_COOKIE['auth_token'];
$user = DB::SelectUser($user);
if($user){
//Checks the Hash separate from the query to avoid timing attack
var_dump(hash_equals($user->Validator, $cookie[1]);
}
}
I know this probably sounds silly and it does not make much difference,
But In option 1 I am comparing a plain text token to a hashed version and comparing it with the sodium function
And with Option 2 I am comparing two hashes
If I compare the same two hashes with the sodium function it returns false and if I compare the plain text to the hashed with hash_equals even though the token before the hash is the same it returns false.
So basically:
1) Does this make much of a difference?
2) I would like to find a neat solution for Key storage and then store plain in the cookie but not sure how
Any advice would be greatly appreciated.
Happy to clarify my question
Thanks
It doesn't make any difference.
What sodium_crypto_auth_verify() does is compute the hash, and compare it with the provided one.
As long as the comparison is in constant time, there is no difference between this and doing it yourself.