AES Encrypt / Decrypt

Is thee a way to do AES Encryption & Decryption from php?

Specifically, I want passwords stored in a MySQL database to be encrypted. Of course they will have to be checked when a user logs in so I'm guessing I would have to decrypt to do a compare?

Thanks
Richard KortsBusiness Owner / Chief DeveloperAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

sdstuberCommented:
ideally you won't encrypt and decrypt a password

instead, use a cryptographically secure hashing algorithm (like bcrypt)
store the hash
when a user logs in, hash their password and compare that to the stored hash.

the reason you do this is, encryption is reversible (hence decryption) but hashing is not.


here's a nice example along with expanded explanations of what I have above.

https://alias.io/2010/01/store-passwords-safely-with-php-and-mysql/
Ray PaseurCommented:
Please see An Afterword About Storing Passwords
http://www.experts-exchange.com/articles/2391/PHP-Client-Registration-Login-Logout-and-Easy-Access-Control.html

Make a Google search for "Correct Horse Battery Staple"

Then if you still want to encrypt and decrypt information, you can use something like this:
<?php // demo/encrypt_decrypt_mcrypt.php
/**
 * Notice: MCrypt is sometimes considered "dead" in 2015
 * but the PHP documents are incomplete for OpenSSL
 *
 * Show how to encrypt and decrypt information
 * with binary-safe transport over the internet
 * Note: ECB may not be the "best" mode
 *
 * http://php.net/manual/en/book.mcrypt.php
 * http://php.net/manual/en/ref.mcrypt.php
 * http://php.net/manual/en/mcrypt.ciphers.php
 *
 * https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
 * https://en.wikipedia.org/wiki/Base64
 *
 * Parallel construction in the encrypt() decrypt() methods
 */
error_reporting(E_ALL);


/**
 * The Interface defines the two main data transformation activities
 */
Interface Encryption_Interface
{
    public function encrypt($text);
    public function decrypt($text);
}

class Mcrypt_Encryption Implements Encryption_Interface
{
    protected $key;

    public function __construct($key='quay')
    {
        // THE KEY MUST BE KNOWN TO BOTH PARTS OF THE ALGORITHM
        $this->key = $key;
    }

    public function encrypt($text)
    {
        // DECLOP WHITESPACE BEFORE ENCRYPTION
        $text = trim($text);

        // ENCRYPT THE DATA
        $data = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->key, $text, MCRYPT_MODE_ECB);

        // MAKE IT base64() STRING SAFE FOR STORAGE AND TRANSMISSION
        return base64_encode($data);
    }

    public function decrypt($text)
    {
        // DECODE THE DATA INTO THE BINARY ENCRYPTED STRING
        $text = base64_decode($text);

        // DECRYPT THE STRING
        $data = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->key, $text, MCRYPT_MODE_ECB);

        // DECLOP NUL-BYTES BEFORE THE RETURN
        return trim($data);
    }
}


// INSTANTIATE AN ENCRYPTION OBJECT FROM THE CLASS
$c = new Mcrypt_Encryption();

// INITIALIZE VARS FOR LATER USE IN THE HTML FORM
$encoded = $decoded = NULL;

// IF ANYTHING WAS POSTED SHOW THE DATA
if (!empty($_POST["clearstring"]))
{
    $encoded = $c->encrypt($_POST["clearstring"]);
    echo "<br/>{$_POST["clearstring"]} YIELDS ENCODED ";
    var_dump($encoded);
}

if (!empty($_POST["cryptstring"]))
{
    $decoded = $c->decrypt($_POST["cryptstring"]);
    echo "<br/>{$_POST["cryptstring"]} YIELDS DECODED ";
    var_dump($decoded);
}

// CREATE THE FORM USING HEREDOC NOTATION
$form = <<<FORM
<form method="post">
<input name="clearstring" value="$decoded" />
<input type="submit" value="ENCRYPT" />
<br/>
<input name="cryptstring" value="$encoded" />
<input type="submit" value="DECRYPT" />
</form>
FORM;

echo $form;

Open in new window

Scott FellDeveloper & EE ModeratorCommented:
There are some articles here for this very thing that will outline what you want to do
 http://www.experts-exchange.com/articles/2391/PHP-Client-Registration-Login-Logout-and-Easy-Access-Control.html

http://www.experts-exchange.com/articles/9739/PHP-MySQL-User-Authentication.html

In simple pseudo code  
newPassword = "FidoMyDogsName"
salt1 = username
salt2 = some_random_string
salt3 = something_else

hashPass = hash(concatenate(newPassword, salt1,salt2,salt3)) //the hash will be a long text string

// store the hashed password to the database

// to test the pass
posted_password = "FidoMyDogsName"
//test the password against what is in the db
salt1 = username
salt2 = some_random_string
salt3 = something_else
password_test = hash(concatenate(posted_password , salt1,salt2,salt3))
if(passwword_test === pass_stored_in_database){
   // password is good
} else {
   // password is bad
}

Open in new window

Expert Spotlight: Joe Anderson (DatabaseMX)

We’ve posted a new Expert Spotlight!  Joe Anderson (DatabaseMX) has been on Experts Exchange since 2006. Learn more about this database architect, guitar aficionado, and Microsoft MVP.

Richard KortsBusiness Owner / Chief DeveloperAuthor Commented:
Scott Fell,

I converted your pseudo code to real php; it works.

But the issue I see is where do I store salt1, salt2 & salt3? In the database? I can see that salt2 can be a different random value for each client.

But if this stuff is in the database and the objective is to avoid database hacking, aren't the "keys" to the kingdom already there in the database?
sdstuberCommented:
a salt isn't a key but is necessary to duplicate the hash.  you would need to store them in the database or someplace where the authenticating code can access them so it can apply the salt to the candidate password and generate the hash for comparison to the stored hash.
Scott FellDeveloper & EE ModeratorCommented:
Exactly, you don't have to use salt, but it helps to create a more secure hash.  In my sample I used the username.  You know the username either from the user entering data or a database result.

You can stop there, but you can add an additional hash key value that is just hardcoded.  Let's say you have hard coded salt2  = "zhsLysk82ka;zkdjhf@svx!"  Just make sure to use the same hard coded information throughout your code.  It is probably best to not store salt keys in your db anyway.  The reason why you are creating the hash is if the db is compromised. If your entire server is compromised, that is is a different story.

There are more advanced ways of dealing with this where the hash is random or changes every log in.  At a minimum I would use something like the username and random string that you hard code.
Richard KortsBusiness Owner / Chief DeveloperAuthor Commented:
Scott,

So you suggest just hard code the salt2 in the few (I think only two) programs where it is needed.  And as you say, if the entire server is compromised, that is a much bigger issue.

Richard
Scott FellDeveloper & EE ModeratorCommented:
That is one way of doing it.

Have a read of the first 2 articles below and they will really help you understand.  I used both of them myself a few years ago. Just know they are old and when they talk about md5 for instance, that is easy to crack with today's computing power. If you can use a random hash, it will be more secure.  The idea of what I outlined is right.

https://crackstation.net/hashing-security.htm  (points to http://php.net/manual/en/function.mcrypt-create-iv.php)

http://arstechnica.com/security/2013/05/how-crackers-make-minced-meat-out-of-your-passwords/

http://arstechnica.com/security/2015/08/cracking-all-hacked-ashley-madison-passwords-could-take-a-lifetime/
Slick812Commented:
greetings Richard Korts, , there are many factors to any security concerns in password database storage, alot of the info on the web about it, is many times outdated, and-or using ideas that the author of the article does not really know, but just read from some other article, that the author of that other one, took info from still another previous article. The way an experienced coder will try an use a way to get passwords, is to "Sign UP" on that site with at least 4 different "User Names" , email addys, and different passwords. Then use an SQL injection procedure to list out all user names, emals and passwords in the user table. Then the 4 user names that they used to "Sign Up" for that site are found, with each DB column entry for the password, if the passwords are all 16 characters in length (after removing the HEX encode), then they pretty much Know, it's a standard PHP MD5 hash, and they just use a 92 keyboard character hash "Look Up Table" for MD5 to find the actual text in the hash, if any of what are incorrectly called "Seeds" here, have been added to beginning, end or middle of a password, it will be a consistent length, and easily used to see and remove in the 4 different known passwords. A real seed needs to be used to actually change the hash method to use a different hash algorithm method, so it produces a non-standard result that can not be looked up in a standard hash "Look Up Table", to do this I always use the PHP  hash_hmac( )  function for any password hashing like -
$ps = hash_hmac('ripemd160', $ps, '*jE!cP)nt~,:lrFd$zO'.chr(197));

the hash_hmac( ) will actually CHANGE the hash output with the seed to a different XOR complied result , not in a standard hash result, and there are not many "Look Up Tables" made for 'ripemd160' anyway, so this is a hundred times more effective hashing for security concerns.
I hope this gives you more info about this.
Richard KortsBusiness Owner / Chief DeveloperAuthor Commented:
To Slick812,

It appears to me that you have the best solution.

I'm a little concerned about some of your comments.

What we need is, when a user registers for our online service, they provide a password. We want to hash it & store the hash value in the database.

Then, the next time they log in, we hash the password they provided & do a lookup in the database comparing the previously hashed value (in the db) with the hash of the currently entered password; if equal, they are in, if not out.

So if I understand this, I would hash the originally entered password ($pwd), like this:

$ps = hash_hmac('ripemd160', $pwd, $key);

$key being some random string I store elsewhere in the database. Then I store $ps in the database, I'm guessing using like varchar(128) (in MySQL syntax).

Then on a subsequent login, I use the SAME  hash on the entered value & compared the hashed result in the database; if equal, they are good.

Is this correct?

Thanks
Slick812Commented:
You have got the most important ideas for doing this,
Just to explain further , In the   hash_hmac( )   the "seed" is used in a similar fashion as an encryption KEY, That makes the result of the hash, a different value than if the same plaintext was use, but a different "Seed" - key, as in encryption you have to use a "Secret" (not known) KEY, or the encryption does not help to hide the value. In a Hash, there is NO procedure to UN hash the value, unlike the reverse an encrypt, with a decrypt, if you use the same key.

As for using a "Random" seed in the hash, , It depends on the level of security, you might want to try and provide. But the seed will need to be known, when doing the first hash into the DB, and when checking the attempted password entry. You can store the random seed in the db, but if your database USER table is dumped, so your security opponents get all of the password hashes, and the seeds, it may not be so effective, since the seeds are also known. As far as I do password hashes, I usually do not used random seeds, I do try and use some NON ASCII numeric characters like  chr(197)  in the seed, and use a seed length equal to the character length of the hash output ( I used a 20 character length seed in the 'ripemd160' hash above, if you do not use the full length for seed, it will be padded out with null characters to the block length anyway.

If I am wanting more security, I will use a longer length hash like "whirlpool" , and hash the passw twice, with two different seeds.

If you just have the seed strings in your PHP files, and not in the user table, then a DB breach will not expose the seed strings, but security is a complex thing, and this is my view on it.

When you get a log in with the password attempt, you will do a SELECT lookup WHERE , in the user table, for just the user name or email, not the hash, you do not need to index the hash, especially if you store it as a binary DB type, just use the email to get the correct hash value, and then hash their attempt string, and compare it to the DB row value.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Slick812Commented:
Oh I forgot about the DB varchar(128) , if you use this -
    hash_hmac('ripemd160', $pwd, $key);
the output will be a HEX string  40 characters long, so for the BD Type you can use  varchar(40)

 there are many hashes available like with hash length (double for HEX) -
sha256    -32 length
sha512    -64 length
ripemd256    -32 length
tiger192,4     -24 length
whirlpool     -64 length
haval224,5     -28 length


the longer the hash, the more difficult it is to try and do a Look Up table to get the plaintext from a hashed string.

You may want to just use this  -
     hash_hmac('ripemd256', $pwd, 'J*&^gbF'.chr(214).'DeW{lO'.chr(177).'(bCzAs:+bFyDv~cK|');
with a 64 length HEX output, for a general security hash.
Richard KortsBusiness Owner / Chief DeveloperAuthor Commented:
Thanks for the wealth of info.

I just hashed all the passwords in our user table & put the hashing in to the new registration (when pwd is first stored) & the the login check program.

One minor (but I thought not good thing) , when I first went to log in myself to test the login, I saw that the hashed password was in the form field for pwd, not my normal value.

I told FireFox (a LONG time ago) to save my password; of course obviously if I had left the hash value there it would have failed by hashing the hash.

Do you know of a way to avoid this? Is this only a FireFox issue (even if so, not good & very confusing to the average person).

Thanks
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.