No collision hash of email in php - php

This question has been asked before, but a lot of the threads are very old.
I need to hash email addresses to store in my database. I later need to match a hash, so the hash needs to be the same each time for each unique email. is there a risk of same hash? collision with say md5() or hash() ? what is the recommended way these days (2021)
thanks in advance

As of PHP 7.2 you would use Argon2 like this:
password_hash('your_value', PASSWORD_ARGON2I);
PHP 7.3 comes with an improved algorithm:
password_hash('your_value', PASSWORD_ARGON2ID);
To compare a value to the hash you can just use password_verify like this:
if (password_verify($user_value, $stored_hash)) {
// valid
}
This is normally meant to check hashed passwords, but e-mail addresses can be handled the same way (e.g. for data protection reasons).
The Argon2 algorithm is explained in Wikipedia, the Installation is described on php.net.

It's very simple. The password_hash() is a replacement for md5().
But what you're talking about here is hashing an e-mail. E-mail is not the same as password.
You as administrator don't need to know user passwords in order to give the user access. However you will need to know the user e-mail if you want to send out newsletters, registration confirmation and even provide an option via e-mail to retrieve a lost access to user account. Neither of the above hashing options will help you with that. Because the above options destroy the original data and leave you with crumbs of it.
In any case the password_hash() is 60 characters give or take vs. the md5() of 32 characters. So the password_hash() is the safest option and md5() is long outdated and shouldn't be used. Collisions is not something you should be worried about for passwords. Because users can have same passwords and even same hash data. But since the data belonging to different accounts, without the correct username, the hash is useless for user login.
So it now all boils down to e-mail. That you can achieve using this simple encryption and decryption. In this case since the data is not destroyed and is preserved. That means there is no chance of a collision especially considering that each user should have a different e-mail. But even if the data is exactly the same, the hashing results will still be different each time. So you can't go wrong with this option.
function enc($data, $key, $mode=0){
$cipher = "aes-256-gcm";
if(in_array($cipher, openssl_get_cipher_methods())){
if(!$mode){ // encrypt
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$data = openssl_encrypt($data, $cipher, $key, $options=0, $iv, $tag);
$data = base64_encode($data.'::'.$iv.'::'.$tag);
}else{ // decrypt
list($data, $iv, $tag) = explode('::', base64_decode($data), 3);
$data = openssl_decrypt($data, $cipher, $key, $options=0, $iv, $tag);
}
}
return $data;
}
ENCRYPTING DATA: enc('DATA','KEY'); (where KEY could be a user password) => RETURNS: ENC_KEY
DECRYPTING DATA: enc('ENC_KEY','KEY',1); (where KEY could be a user password) => RETURNS: DATA

Related

Decoding Plesk passwords

First time question.
I have a customer panel that shows the Plesk 12.5 password. For now I put that in manually when I generate the password. But customers change their password, forget it and then everything fails. I use the Plesk API to receive the password, but this is encrypted.
$5$CngpmNFXTsfRswHH$nntnTlj0KLkhEidK.XVWgbyv9HcAE8YV/fog0C6aG17
I found out that the key is found in /etc/psa/private/secret_key.
I tried:
$res_non = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $hash, 'ecb');
$decrypted = $res_non;
$dec_s2 = strlen($decrypted);
$padding = ord($decrypted[$dec_s2-1]);
$decrypted = substr($decrypted, 0, -$padding);
But that doesn't return my password correctly.
Any help is appreciated, Thanks!
This appears to be a sha256crypt hash, without storing the number of rounds (which means it's likely hard-coded). If so, this isn't encrypted. Hashing is not encryption. Hashing is a subtopic of cryptography, but is wholly separate from encryption.
Hashing: one-way transformation of an infinite set of possible values to a value in a large but finite set of possible outputs. Keyless.
Encryption: reversible transformation of information, secured by a secret key (and/or, in certain algorithms, a public key).
Please don't confuse the two.
How about to reset password via "Forgot your password?" on login screen?
Way to decrypt it, indeed, exists, but it is not public, and, probably, it will never be. Even support doesn't know the way to decrypt it.
You can view passwords of mail users via mail_auth_view command. That's all that can be done.
Source - I've worked in Plesk dev for some time.

PHP token-based system

I'm building a login system and I want it to be secure so that I can re-use it on several projects. I'm using the function below to encrypt the given password with my secret key (32 chars).
function Encrypt($key, $payload)
{
$iv = mcrypt_create_iv(IV_SIZE, MCRYPT_DEV_URANDOM);
$crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $payload, MCRYPT_MODE_CBC, $iv);
$combo = $iv . $crypt;
$garble = base64_encode($iv . $crypt);
return $garble;
}
My IV_SIZE is the following:
mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC))
Before you ask I don't allow users to enter a password. I generate a very complicated and long password for them with everything inside (uppercase, lowercase, digits and symbols). I've also implemented a ban system that allows you to insert a wrong password for a verly limited amount of times and, as if it wasn't enough, I also lock the entire account so that you can't try again even when the ban has expired.
This is the decrypt function still pretty standard:
function Decrypt($key, $garble)
{
$combo = base64_decode($garble);
$iv = substr($combo, 0, IV_SIZE);
$crypt = substr($combo, IV_SIZE, strlen($combo));
$payload = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $crypt, MCRYPT_MODE_CBC, $iv);
return $payload;
}
Said that it's 2 hours that I'm trying to figure out what's the best approach to issue a login session/cookie. I want to adopt a token-based approach like follows.
As soon as login is successful, I want to store in a cookie the first part of an hash. The entire hash is stored in my DB and it is unique. The second part of it would be something like a salt + sha/md5/base64 (...) of userid, email, timestamp etc. Is it a good approach?
No.
Unless you need to have access to the plain-text password (e.g. if it's a password for a configured SMTP server that you'd use), you MUST NOT encrypt passwords, but hash them.
And use password_hash() (bcrypt) to hash them; it is specifically designed for this purpose.
Also, it is not made clear in your question what these hashes are for, but it sounds like a flawed choice at best - MD5 and SHA1 shouldn't be used for any kind of security mechanisms today, and if you want to verify the authenticity of something, you should be using a keyed hash function like hash_hmac() instead anyway.
Use a generic PHP session to maintain the login state.
It seems to me that you're over-thinking the problem at hand and in turn over-engineering the solution. Keep it simple.

Unable to decrypt password

I have decided recently to use a more secure encrytion for my password. I have no problem encrypting my password, after calling mc_encrypt($encrypt) the method returns an encrypted password.
When doing decryption by calling mc_decrypt($decrypt), the method returns false. As you can see in the mc_decrypt($decrypt) method, there is an if statement near the bottom. I cannot get the if statement to pass. Does anyone know what I can change to get $calcmac!==$mac to return true? Thanks
<?php
class Encrypt {
public $encryptionKey = 'xxxxxxx';
public function __construct() {
define('ENCRYPTION_KEY', $this->encryptionKey);
}
// Encrypt Function
public function mc_encrypt($encrypt){
$encrypt = serialize($encrypt);
$iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_DEV_URANDOM);
$key = pack('H*', $this->encryptionKey);
$mac = hash_hmac('sha256', $encrypt, substr(bin2hex($key), -32));
$passcrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $encrypt.$mac, MCRYPT_MODE_CBC, $iv);
$encoded = base64_encode($passcrypt).'|'.base64_encode($iv);
return $encoded;
}
// Decrypt Function
public function mc_decrypt($decrypt){
$decrypt = explode('|', $decrypt);
$decoded = base64_decode($decrypt[0]);
$iv = base64_decode($decrypt[1]);
$key = pack('H*', $this->encryptionKey);
$decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $decoded, MCRYPT_MODE_CBC, $iv));
$mac = substr($decrypted, -64);
$decrypted = substr($decrypted, 0, -64);
$calcmac = hash_hmac('sha256', $decrypted, substr(bin2hex($key), -32));
if($calcmac!==$mac){ return false; }
$decrypted = unserialize($decrypted);
return $decrypted;
}
}
?>
Sorry, encrypting passwords with a secret stored on the server
isn't secure: If an intruder breaks into your codebase, intruder can retrieve
each and any password using your codebase and the stored password
(somewhere in code or your persistent store).
OWASP, the Online Web Application Security Project, provides well prepared documents: Password Storage Cheat Sheet, Authentication Cheat Sheet and PHP Security Cheat Sheet. Have a look!
The way to go is a salted hash.
How to handle newly created passwords
If you create a new password, compute hash = HashFunction( password, salt ) with a random salt
Save hash and salt in your database along to the user's ID
How to verify password
Locate the userID's record in your database
retrieve hash and salt from the record
Based on the password, that user entered to log in, compute hash = HashFunction( enteredPassword, salt )
Finally, verify if the hash retrieved from store is identical to the one computed.
Why use a hash operation?
A hash operation is a so called trapdoor function: While you can compute the function easily, it's hard to compute the reverse function.
Corollary: It's easy to compute a password-hash from a password, but it's hard to compute the password from the password-hash.
PHP's hash functions
These days, PHP's PBKDF2 is first choice for password hashes [Wikipedia on PBKDF2].
If your PHP installation is too old, even salted hashes with md5() are better than two-encrypted password. But only in case definitely nothing else is available!
Sample of PBKDF2 usage
function getHashAndSaltFromString( $password ) {
// choose a sufficiently long number of iterations
// ... to make the operation COSTLY
$iterations = 1000;
// Generate a random IV using mcrypt_create_iv(),
// openssl_random_pseudo_bytes() or another suitable source of randomness
$salt = mcrypt_create_iv(16, MCRYPT_DEV_RANDOM);
$hash = hash_pbkdf2("sha256", $password, $salt, $iterations, 20);
return array( $hash, $salt );
}
Beautiful side effect of hash usage
Many websites do restrict the length of passwords to a certain length - quite likely due to the length of the underlying persistent storage [= length of field in a database table].
If you use the hash-based password storage technique, your users might use passwords of arbitrary length!
Since the hash is of constant length and you only persist password and
salt, the length restriction is superfluous. Support long passwords in your web-app!
At an extreme case, you could even allow users to upload a file - e.g. a picture of their home - as a credential [=password].
Side note on random sources in PHP's MCRYPT functions
Note, that PHP does provide two sources of randomness MCRYPT_DEV_RANDOM and MCRYPT_DEV_URANDOM.
MCRYPT_DEV_RANDOM gets its randomness from /dev/random
MCRYPT_DEV_URANDOM gets its randomness from /dev/urandom
/dev/urandom provides random data immediately and non-blocking each time you query it, /dev/random might block (take some time to return).
Therefore, at first sight, /dev/urandom and MCRYPT_DEV_URANDOM might be better suited for random number generation. In fact, it is not!
/dev/random might block request up to a point of time, at which sufficiently much entropy has been collected. Thus /dev/random and MCRYPT_DEV_RANDOM effectively collects randomness.
If you need to do strong crypto operations, use MCRYPT_DEV_RANDOM or
/dev/random.
You shouldn't rely on two-way encryption for passwords. If someone can get the cyphertext, they can usually also get the key to decrypt them.
Instead, you should use hashing or key derivation like blowfish or pbkdf2, those are one-way functions that are designed to be hard to crack.
Please, never ever encrypt passwords this way.
If you are using PHP >= 5.3.7, you should use the password_comp library which was written by guys involved in PHP and it utilizes BCRYPT which is the strongest algorithm available for PHP as of yet.
It's very simple and easy to use.
https://github.com/ircmaxell/password_compat
Hash the password simply
$hash = password_hash($password, PASSWORD_BCRYPT);
Verify the given password against the stored password hash
if (password_verify($password, $hash)) {
/* Valid */
} else {
/* Invalid */
}
Pretty simple stuff, like they say no need to rewrite was has already been written especially when it comes to security and written by the experts.

User decryption/encryption in PHP | storing key in session

so I have this website that allows users to write every day. It then get stocked in a database in plain text. It's not a blog so everything is private, and the biggest complain I regularly get is that "I" could still read what they wrote. It was still not "perfectly" private. Also I don't want to be the one who leaked thousand of private diaries.
So here is my train of thought on how to rend it private only to them.
When they log in : key = sha1(salt + password) and store this key in a SESSION (how secure is that ?)
When they save their text : encrypt it with their $_SESSION['key'] before saving it to the database
When they read something they've saved, decrypt it with their $_SESSION['key'] before displaying it.
Is that secure ? Also what is the best way to encrypt/decrypt UTF-8 ?
Also if someone changes its password it has to decrypt/re-crypt everything.
You should instead store the hash of the password in the SESSION.
Never store plain passwords anywhere - anywhere!!
Also, consider reading this stackoverflow thread: Secure hash and salt for PHP passwords
To hash the password, you can use this approach:
Generate a salt for a particular user (a salt is a random string of characters), and store it somewhere, or generate a global salt (in your use case)
Use the following function to generate a hash for the password, and store that hash in the SESSION
function generate_hash($password) {
$salt = "<some random string of characters>"; // do not change it later.
return md5($salt . $password);
}
For the encryption, you can use the mCrypt library. A typical algorithm can be:
$key = 'password to (en/de)crypt';
$string = 'string to be encrypted';
$encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $string, MCRYPT_MODE_CBC, md5(md5($key))));
$decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($encrypted), MCRYPT_MODE_CBC, md5(md5($key))), "\0");
var_dump($encrypted);
var_dump($decrypted);
You should be using some form of encryption. PHP provides mCrypt for this purpose. Point by Point:
Saving a password in the clear in a $_SESSION is inherently insecure. At the very least, hash it in both the session and the database. Then you can compare the hashes to one another. Sensitive data should never be stored in the clear anywhere.
You can simplify this by using mCrypt. However, I think the focus here is incorrect. Rather than hashing all of this "diary" text, I think you should be more focused on abstracting the user information from the text itself.
No need to use their password. Just use a common key and use mcrypt for this.
I hope this helps!
Do not use password to encrypt the key, password should never be used anywhere in the logic, and should only be read on login as a hash not plain text. You can user other things like user email to generate a key.

how to use mcrypt decryption

i have made a login and register page. but my passwords aren't encrypted yet. people told me that's a bad idea and that i should encrypt them. so i have been searching around on how to encrypt and decrypt my passwords. i have found an example on how to encrypt my passwords but i do not know how to decrypt it again for my login page. here is my encrypt code:
$key = "some random security key";
$input = $password;
$td = mcrypt_module_open('tripledes', '', 'ecb', '');
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$password = mcrypt_generic($td, $input);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
so my question is: can someone tell me what codes i need to decrypt the strings i get from the code above.
You can encrypt and decrypt stuff like this:
//this is some config for a good security level of mcrypt
define('SAFETY_CIPHER', MCRYPT_RIJNDAEL_256);
define('SAFETY_MODE', MCRYPT_MODE_CFB);
//this has to be defined somewhere in the application.
define('APPLICATION_WIDE_PASSPHRASE', 'put-something-secure-here');
define('ENCRYPTION_DIVIDER_TOKEN', '$$');
//some "example" data as if provided by the user
$password = 'this-is-your-data-you-need-to-encrypt';
//this key is then cut to the maximum key length
$key = substr(md5(APPLICATION_WIDE_PASSPHRASE), 0, mcrypt_get_key_size(SAFETY_CIPHER, SAFETY_MODE));
//this is needed to initialize the mcrypt algorythm
$initVector = mcrypt_create_iv(mcrypt_get_iv_size(SAFETY_CIPHER, SAFETY_MODE), MCRYPT_RAND);
//encrypt the password
$encrypted = mcrypt_encrypt(SAFETY_CIPHER, $key, $password, SAFETY_MODE, $initVector);
//show it (store it in db in this form
echo base64_encode($initVector) . ENCRYPTION_DIVIDER_TOKEN . base64_encode($encrypted) . '<br/>';
//decrypt an show it again
echo mcrypt_decrypt(SAFETY_CIPHER, $key, $encrypted, SAFETY_MODE, $initVector) . '<br/>';
But as stated before, passwords should not be recoverable from their hashed representation, so don't do this for passwords!
I see you're a bit confused with how this works. Read this article and you'll come to know all about encryption, decryption, hashing and their use in a login system.
http://net.tutsplus.com/tutorials/php/understanding-hash-functions-and-keeping-passwords-safe/
So basically, you hash a password into a hexadecimal string on registration and store it in the database. Each time the user wants to login you take his current i/p password, hash that and store it in a variable like $temp.
Now, you retrieve the original password's hash from the server and simple compare the two hashes.
...if they're same then access granted!
The many reasons you don't want to keep encrypting and decrypting a password are as follows:
When being passed to the server the user entered password is in plain
text or can be easily stolen/sniffed.
The server has to compute the process of decrypting the password stored in the database each time it is required, as opposed to
hashing where we just do a logical compare.
If the file containing the encyption algorithm is compromised w/ the database, all passwords are lost in plain text. As users may use
same passwords on multiple sites, the threat is extended.
You should not try to decrypt passwords just compair the hashed passwords.
By the way if you do that in the right way it is impossible to restore the original password. You should also add a so called salt to make the password more complex.

Categories