I'm trying to move my Cakephp 2 project and I want to keep the same database. I have used a hash 'sha1' and the Cakephp security.salt to encrypt the users passwords:
public static function hash($password, $method = 'sha1', $salt = true) {
return Security::hash($password, $method, $salt);
}
I added (a long time ago) in myproject/app/config/core.php this (with a different password):
Configure::write('Security.salt', 'T4R393b0qyJioxfs2guVoUubWwvniR2G0Fgartge');
Now I don't know how to use this Security.salt code with another framework. So please:
Does anybody know if I could use this encryption in an Angular 2/4 project (e.g.)?
Any other solution?
Thank you!
I found it! Thanks to everybody.
I have to concatenate the salt and the password. After that I do the hash 'sha1'.
e.g.: hash(Security.salt . $password)
Found it in myproject/cake/libs/security.php as 'ndm' said:
function hash($string, $type = null, $salt = false) {
$_this =& Security::getInstance();
if ($salt) {
if (is_string($salt)) {
$string = $salt . $string;
} else {
$string = Configure::read('Security.salt') . $string;
}
}
...
Related
Good day.
Using the encryption library in CodeIgniter, I can encrypt any string by using $this->encryption->encrypt('string'); and that is the easiest way to encrypt the string. However, this method is not the safest way to secure the data I think so I decided to use salt for better encryption. I read the documentation provided by Codeigniter about the Encryption Library and I don't really understand how encryption and salt really work.
Here is my code for encryption.
<?php
defined('BASEPATH') or exit('No direct script access allowed');
class MyEncryption {
//please do not change or delete this saltKey. "5948356750394856"
private static $saltKey = "5948356750394856";
// ================
public $CI;
function __construct()
{
$this->CI =& get_instance();
$this->CI->load->library('encryption');
}
public function encryptStringWithSalt($string) {
$p = $this->CI->encryption->encrypt(
$string,
$this->encryption_config()
);
return $p;
}
public function decryptEncryptedStringWithSalt($encryptedString) {
return $this->CI->encryption->decrypt(
$encryptedString,
$this->encryption_config()
);
}
private function encryption_config(){
$key = $this->CI->config->item('encryption_key');
$hmac_key = $this->CI->encryption->hkdf(
$key,
'sha512',
MyEncryption::$saltKey,
10,
'authentication'
);
return array(
'cipher' => 'aes-128',
'mode' => 'CTR',
'key' => MyEncryption::$saltKey,
'hmac' => true,
'hmac_digest' => 'sha224',
'hmac_key' => $hmac_key
);
}
}
As we can see, I created a function that gathers the encryption configuration. Inside that function, I have called the method $this->CI->encryption->hkdf() to create hmac key as what documentation example says. For clarification, here are the parameters of hkdf() method and the provided example.
Additionally, the return keyword with array data in encryption_config() function is the 2nd parameter of encrypt() method in encryption library. I used encryption->hkdf() because of the parameter salt on it. I am new in encryption with salt in Codeigniter so I'm really struggling on how to achieve this kind of encryption. So what I've done is that the code above really works for encryption and decryption but for some reason I don't really understand why the return value is different from the normal encryption. The difference is, this encryption method $this->encryption->encrypt("some string"); returns but using the code above returns .
Though I can decrypt that symbolic character, this will not save this encrypted data to the database with the data type of varchar but instead, it will be saved as a normal character or string. Here are the data saved to database .
My questions are, I am doing correctly? if not, what is the proper way to implement this library with salt? I want the encrypted data as normal text not a symbolic character, can I achieve that goal? and lastly? is there anyway to check the string if the string is encrypted or not? Please help me. I spend days for this problem only. I watch youtube tutorial related for encryption but no luck.
Okay. after searching on the internet I found a solution without using this CI encryption Library. I achieved my goal by using this code
<?php
defined('BASEPATH') or exit('No direct script access allowed');
/**
*
*/
class SaltEncryption
{
public $CI;
function __construct()
{
$this->CI =& get_instance();
}
public function encrypt($data){
$password = "any string";
$iv = substr(sha1(mt_rand()), 0, 16);
$password = sha1($password);
$salt = sha1(mt_rand());
$saltWithPassword = hash('sha256', $password.$salt);
$encrypted = openssl_encrypt(
"$data", 'aes-256-cbc', "$saltWithPassword", null, $iv
);
$msg_encrypted_bundle = "$iv:$salt:$encrypted";
return $msg_encrypted_bundle;
}
public function decrypt($msg_encrypted_bundle){
$password = "any string";
$password = sha1($password);
$components = explode( ':', $msg_encrypted_bundle );
if (
count($components)=== 3 &&
strlen($components[0]) === 16
) {
$iv = $components[0];
$salt = hash('sha256', $password.$components[1]);
$encrypted_msg = $components[2];
$decrypted_msg = openssl_decrypt(
$encrypted_msg, 'aes-256-cbc', $salt, null, $iv
);
if ( $decrypted_msg === false )
return false;
$msg = substr( $decrypted_msg, 41 );
return $decrypted_msg;
}
return false;
}
}
Currently I have a Laravel application with authentication. I'm wondering if I could have another PHP application (framework independent) that uses the same user table for authentication. I don't want to use Laravel again because it would be a over engineering.
My main concern is how the hashing of the password is done in Laravel. Can I configure the plain PHP application to hash passwords the same way? If so, how can I do this?
Laravel uses password_hash() to create a password hash (see the make() method source code):
password_hash('somePassword555', PASSWORD_BCRYPT);
And password_verify() to check password hash (see the check() method source code):
password_verify('somePassword555', $hashedPasswordFromDB);
This is the file you want to check out
vendor/laravel/framework/src/Illuminate/Hashing/BcryptHasher.php
And these are the functions they are using, password_hash(); and password_verify();
function make($value, array $options = [])
{
$cost = isset($options['rounds']) ? $options['rounds'] : $this->rounds;
$hash = password_hash($value, PASSWORD_BCRYPT, ['cost' => $cost]);
if ($hash === false) {
throw new RuntimeException('Bcrypt hashing not supported.');
}
return $hash;
}
function check($value, $hashedValue, array $options = [])
{
if (strlen($hashedValue) === 0) {
return false;
}
return password_verify($value, $hashedValue);
}
So I'm trying to create a Blowfish encrypted password with a salt using a User class that I have created, which in turns extends an overall database object that uses Late Static Bindings to CRUD from my database. Anyway, I'm trying to get this darn thing to encrypt the password before I call the create() method and inset it onto my database but each time when I do put the information in the form it goes to a blank 'update.php' screen (update.php has all my isset($_POST[]) calls for all my forms) and nothing gets uploaded to my database. Here's the code so far...
Code in update.php
if (isset($_POST["createAdmin"])) {
$user = new Users();
$user->password = $user->password_encrypt($_POST['new_password']);
$user->username = $_POST['new_username'];
$user->first_name = $_POST['first_name'];
$user->last_name = $_POST['last_name'];
if($user->create()) {
$_SESSION['new_admin_message'] = $user->password;
redirect_to("../public/admin/manage_admin.php");
}
else {
$_SESSION['new_admin_message'] ="Admin didn't create successfully";
redirect_to("../public/admin/manage_admin.php");
}
}
Code in user.php (the user class)
<?php
require_once(LIB_PATH.DS.'database.php');
class Users extends DatabaseObject {
protected static $table_name="users";
protected static $db_fields = array('id', 'username', 'password', 'first_name', 'last_name');
public $id;
public $username;
public $password;
public $first_name;
public $last_name;
public static function password_encrypt($password) {
$hashed_format = "2y$10$"; // Tels PHP to use Blowfish with a "cost" of 10
$salt_length = 22; // Blowfish salts should be 22-characters or more
$salt = generate_salt($salt_length);
$format_and_salt = $hash_format . $salt;
$hash = crypt($password, $format_and_salt);
return $hash;
}
private function generate_salt($length) {
// Not 100% unique, not 100% random, but good enoguh for a salt
// MD5 returns 32 characters
$unique_random_string = md5(uniqid(mt_rand(), true));
// Valid caracters for a solt are [a-zA-Z0-9./]
$base64_string = base64_encode($unique_random_string);
// But not '+' which is valid in base64 encoding
$modified_base64_string = str_replace('+', ".", $base64_string);
//Truncate string to the correct length
$salt = substr($modified_base64_string, 0, $length);
return $salt;
}
There's a couple other methods in the class that aren't important for this particular problem. I'm relatively new to OOP and PHP in general so any help would be greatly appreciated. If you could leave a short description on how you fixed the problem that would be awesome too. Thanks!!
There are three things wrong with your code:
You cannot refer to a normal method from a static method. In order for your code to work you also have to make the generate_salt method static.
You use the wrong format variable ($hash_format should be $hashed_format) when concatenating the format and salt.
Your format is wrong. Look at the documentation. The blowfish format is:
$[algo]$[difficulty]$[salt]$
Your format comes out to be:
[algo]$[difficulty]$[salt]
So, change your method to something like this:
public static function password_encrypt($password) {
$format = '$2y$10$'.$this->generate_salt(22).'$';
return crypt($password, $format);
}
Another thing, which is not technically "wrong" but is not a good thing, is your salt method. You should generate your salt from a cryptographically stronger source, such as using the mcrypt extension or, if you are on *nix, even grabbing it from /urandom or /random. Creating a "random" string by calling a mish-mash of functions, and ending up with something that looks random enough, is not a good idea.
The best thing you could do is to use the password library that comes with PHP. It will handle all the password hashing for you, and will protect you from yourself. If you have PHP <5.5.0 then you should use the compatibility library.
In other words, you should change your code to this:
public static function password_encrypt($password) {
return password_hash($password, PASSWORD_BCRYPT, ['cost' => 10]);
}
I want to store secure user passwords in a MySQL database with PHP.
How can I make it better?
My Class:
private static $algo = '$2a';
private static $cost = '$10';
private static $pepper = 'eMI8MHpEByw/M4c9o7sN3d';
public static function generateSalt($length) {
$randomBinaryString = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
$randomEncodedString = str_replace('+', '.', base64_encode($randomBinaryString));
return substr($randomEncodedString, 0, $length);
}
public static function generateHash($password) {
if (!defined('CRYPT_BLOWFISH'))
die('The CRYPT_BLOWFISH algorithm is required (PHP 5.3).');
$password = hash_hmac('sha256', $password, self::$pepper, false);
return crypt($password, self::$algo . self::$cost . '$' . self::generateSalt(22));
}
public static function checkPassword($hash, $password) {
$salt = substr($hash, 0, 29);
$password = hash_hmac('sha256', $password, self::$pepper, false);
$new_hash = crypt($password, $salt);
return ($hash == $new_hash);
}
Either use this answer's suggestions (for PHP >= 5.5), or the following class. Thanks to martinstoeckli for pointing out the password_hash functions. I read the code over, and the only different thing in password_hash that I can see is error-checking and DEV_URANDOM usage from the OS to generate a more random salt.
class PassHash {
public static function rand_str($length) {
$chars = "0123456789./qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
//only allowed chars in the blowfish salt.
$size = strlen($chars);
$str = "";
for ($i = 0; $i < $length; $i++)
$str .= $chars[rand(0, $size - 1)]; // hello zend and C.
return $str;
}
public static function hash($input) {
return crypt($input, "$2y$13$" . self::rand_str(22));
// 2y is an exploit fix, and an improvement over 2a. Only available in 5.4.0+
}
public static function hash_weak($input) {
return crypt($input, "$2a$13$" . self::rand_str(22)); }
// legacy support, Add exception handling and fall back to <= 5.3.0
public static function compare($input, $hash) {
return (crypt($input, $hash) === $hash);
}
}
It's what I've always used. A suggestion is also PHPass. It's tried and tested.
The only downfall in this script is that I generate random numbers from rand(), and not the source from the OS, but that's easily changed.
Also, there is no real reason to be using SHA256 hashing on top of bcrypt. SHA256 is weak, and can be broken with relatively little effort3.
In addition, hashing passwords is essential practice, but for true security, run all input through at least John the Ripper's wordlist1 to remove the most common passwords and inform a user to use a different password. Wordlists are used far more effectively than any bruteforce due to terribly weak passwords.
And as a final note, do not force your users to use symbols, uppercase and numbers, force them to use a long password2.
Length is everything (no humour intended) when it comes to bruteforcing passwords. Pretty much any preset cracker will be set to not go over 12 characters unless a config is edited. If you ever see a site with a "maximum length" on passwords, make sure to never re-use a password there, because they have no security whatsoever4.
1. Arbitrary choice of cracker; pick what you find to work best
2. http://xkcd.com/936/
3. Comparatively (it's several orders of magnitude faster and is technically security through obscurity)
4. I have even seen banks do this. Having a maximum length on their passwords made me switch banks.
I am hashing my passwords in a Zend php application using PHP crypt(). However, I can't think of a solution for using this hash with Zend_Auth_Adapter_DbTable. Assuming I have a password hash stored after being run with crypt()...
//Salt and hash...
$salt = '$2a$07$'.$this->getSalt();
$data['password'] = crypt($user_object->password, $salt);
$this->_db_table->insert($data);
//Authentication...
$dbAdapter = Zend_Db_Table::getDefaultAdapter();
$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
$authAdapter->setTableName('users')
->setIdentityColumn('username')
->setCredentialColumn('password')
//Now what? Possibly...
->setCredentialTreatment(/* But how? */);
How can I use the Zend_Auth_Adapter_DbTable table object with this kind of salting and hashing strategy? I've looked around, but can't really find any solutions outside of MD5 and SHA type hashing...
If you are storing the Salt in the user table, you should create your own adapter
If you have the salt somewhere else you just need to encrypt the password and then just pass it to the adapter with
$authAdapter->setCredential($cryptedPassword);
I have the same issue a couple of weeks ago, i ended up creating my own adapter, extending Zend_Auth_Adapter_DbTable
I actually backported the ZF2 Bcrypt lib but you should be able to use it with crypt method.
Take a look if you want AuthAdapter-DbTableBcrypt
So I wrote my own adapter to overcome this. Just include the file, pass it to a Zend_Auth adapter authenticate function with the details (Here I am using a login with email and a password):
class User_Authenticate_Adapter implements Zend_Auth_Adapter_Interface {
protected $_username;
protected $_password;
public function __construct($email, $password) {
$this->_email = $email;
$this->_password = $password;
}
public function authenticate() {
$dbTable = new Application_Model_DbTable_User();
$select = $dbTable->select()->where('email = ?', $this->_email);
$row = $dbTable->fetchRow($select);
if($row == null) {
return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND,$this->_email);
}
$data = $row->toArray();
if(!crypt($data['password'], $this->_password)) {
return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID,$this->_email);
}
else {
return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS);
}
}
}
Hope that helps somebody.
get the password before and use it as a salt in crypt function
$dbUser = new Application_Model_DbTable_User;
$data = $dbUser->fetchRow(array("username = ?" => $_POST["username"]));
$cryptedPassword = $data->password; // here is the salt
$authAdapter->setIdentity($_POST["username"])
->setCredential(crypt($_POST["password"], $cryptedPassword));