This question already has answers here:
Two-way encryption: I need to store passwords that can be retrieved
(8 answers)
Closed 9 years ago.
Possible Duplicate:
Best way to use PHP to encrypt and decrypt passwords?
I've been doing a lot with PHP recently and want to make my first login/registration system. As such I've been doing a lot of reading online to figure out the best method(s) for doing this. I've come across a couple of guides and I'm confused on a few instances and I'd like to be sure before I start down this road.
My question is how exactly do I use blowfish? I've read that crypt() will auto select blowfish if an appropriate salt is provided. If that is the case, What makes a salt blowfish appropriate?
Right now, I have a script that makes a salt out of the date and time, a random number, then hash that for the salt. Is that something I can use with blowfish or not?
In short: don't build it yourself. Use a library.
In PHP 5.5, there will be a new API available to make this process easier on you. Here's the RFC for it.
I've also created a backwards-compatibility library for it here: password-compat:
$hash = password_hash($password, PASSWORD_BCRYPT);
And then to verify:
if (password_verify($password, $hash)) {
/* Valid */
} else {
/* Invalid */
}
And if you want another library, check out phpass
In short, don't do it yourself. There's no need. Just import the library and be done with it...
Take a look at http://php.net/manual/en/function.crypt.php
If you scroll down about 1/3, you should see the heading: Example #3 Using crypt() with different hash types. Hopefully this will help! and your salt should be fine!
Try this - its untested, I just whipped it up to show how to use the BLOWFISH algo with PHP
<?php
class cipher {
private static $mode = 'MCRYPT_BLOWFISH';
private static $key = 'q!2wsd#45^532dfgTgf56njUhfrthu&^&ygsrwsRRsf';
public static function encrypt($buffer){
$iv = mcrypt_create_iv(mcrypt_get_iv_size(constant(self::$mode), MCRYPT_MODE_ECB), MCRYPT_RAND);
$passcrypt = mcrypt_encrypt(constant(self::$mode), self::$key, $buffer, MCRYPT_MODE_ECB, $iv);
$encode = base64_encode($passcrypt);
return $encode;
}
public static function decrypt($buffer){
$decoded = base64_decode($buffer);
$iv = mcrypt_create_iv(mcrypt_get_iv_size(constant(self::$mode), MCRYPT_MODE_ECB), MCRYPT_RAND);
$decrypted = mcrypt_decrypt(constant(self::$mode), self::$key, $decoded, MCRYPT_MODE_ECB, $iv);
return $decrypted;
}
}
?>
IMPORTANT!! CHANGE THE $key VALUE TO ANOTHER RANDOM STRING!
Usage:
To Encrypt:
$mystring = 'a quick brown fox jumped over the lazy llama';
$mystring = cipher::encrypt($mystring);
To Decrypt:
$mystring = cipher::decrypt($myencryptedstring);
Related
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.
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.
I always use crypt function to create http auth password but i can't decrypt it but with mcrypt_cbc i can decrypt it, is there a way to create the password using mcrypt_cbc?
thanks.
crypt() is used for hashing in php, which is why it is not intended to be 'decrypted'. The mcrypt functions give access to native block ciphers, they are not used for hashing in the same general sense, so the short answer is no.
The mcrypt functions take a mode flag;
To encrypt;
$ciphertext = mcrypt_cbc(MCRYPT_SERPENT_256, $secret_key, $plaintext, MCRYPT_ENCRYPT);
And to decrypt;
$plaintext = mcrypt_cbc(MCRYPT_SERPENT_256, $secret_key, $ciphertext, MCRYPT_DECRYPT);
However, you should not be encrypting or decrypting passwords in pretty much any circumstances!
In PHP, which (decryptable) encryption algorithm is most secure one?
I mean MD5 can't be decrypted back right?
I've found full working class with mcrypt (then encoded with base64 again) which can encrypt and decrypt back.
Sample mcrypt (Encrypt):
function encrypt($value) {
if(!$value){return false;}
$text = $value;
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->key, $text, MCRYPT_MODE_ECB, $iv);
return trim($this->safe_b64encode($crypttext));
}
Then encode again with base64:
function safe_b64encode($string) {
$data = base64_encode($string);
$data = str_replace(array('+','/','='),array('-','_',''),$data);
return $data;
}
(Sorry for the code just with the encrypt, without decrypt. I just giving sample.)
But I just want to know if there other more secure algorithm then using mcrypt.
You probably want MCRYPT_RIJNDAEL_256. Rijndael with blocksizes of 128, 192 and 256 bit is a generalization of AES which only supports a blocksize of 128 bit.
See: http://us.php.net/manual/en/mcrypt.ciphers.php and http://us.php.net/manual/en/book.mcrypt.php
Just to clarify: MD and SHA algorithms are HASH algorithms: they calculate a check sum of given data so you can later verify that it hasn't been altered. Think of it like this:
Your data is 592652. You want a checksum to know this hasnt been altered so, you do something like:
5+9+2+6+5+2=29
2+9=11
1+1=2
Now, when you want to check your data, you can put it through same calculation and see if you get the same result:
2
However there is no way to take that 2 and get back your original data: 592652.
Of course real calculations hash algoriths are different, this example is just a demonstration of the general idea. This is not encryption.
As for encryption, AES family of algorithms is probably most secure these days, I'd go AES-512. As others noted RIJNDAEL should be preferred. (AES and Rijndael are used exchangably, theyre almost the same thing: Rijndael is the name of the algorithm while AES is the name of the encryption standard that adops Rijndael as its method).
Base64 is not an encryption algorithm.
On PHP you can use the mcrypt extension to securely encrypt and decrypt data.
Blowfish is one of the most secure (and the default in mcrypt) algorithms supported by PHP.
See the full list of supported algorithms here.
Given that the question changed, this would be the new answer:
mcrypt is not an encryption algorithm. It's a library that provides an interface to different encryption algorithms to encrypt arbitrary data.
In a PHP context this is more or less the only decent thing you have to encrypt data.
This question already has answers here:
How do you Encrypt and Decrypt a PHP String?
(10 answers)
Closed 8 years ago.
I'm looking for some functions to encrypt and decrypt strings in php using a key specified.
Thanks!
A basic openssl implementation I've used before:
class MyEncryption
{
public $pubkey = '...public key here...';
public $privkey = '...private key here...';
public function encrypt($data)
{
if (openssl_public_encrypt($data, $encrypted, $this->pubkey))
$data = base64_encode($encrypted);
else
throw new Exception('Unable to encrypt data. Perhaps it is bigger than the key size?');
return $data;
}
public function decrypt($data)
{
if (openssl_private_decrypt(base64_decode($data), $decrypted, $this->privkey))
$data = $decrypted;
else
$data = '';
return $data;
}
}
You would need to generate the RSA key pair. See here for information on how to do that. Storing the private key in the file itself is a bad idea. This is just an example. Ideally you would want the user to supply the private key at decryption time
Start with this: http://www.ibm.com/developerworks/opensource/library/os-php-encrypt/
After that, have a look at Pascal MARTIN's answer in How do I encrypt a string in PHP?
have you tried mcrypt?
I assume you meant symmetric key encryption. mcrypt does support several algorithms (Like AES, Tripel DES). There is one catch though, it doesn't support any padding algorithm so you wouldn't be able to get the original length back. You have 2 options to get around this issue,
Add a length field in front of your clear-text. Say use first 4 bytes as length.
Do PKCS#5 padding yourself. There are code examples on this page: http://www.php.net/manual/en/function.mcrypt-encrypt.php