I didn't like how crypt "formatted" the salt string, that reduces the randomness of the salt and gives an attacker clues as to what's going on. It easy to "roll your own" crypt with the function below. The resultant hash only contains hex digits, making it easy to store, pass on the URL, etc without giving any clues about what it is or how it was generated.
<?php
function mycrypt($clear, $hashed = NULL) {
$salt_len = 100;
if (empty($hashed))
for($salt = '', $x = 0; $x++ < $salt_len; $salt .= bin2hex(chr(mt_rand(0,255)))); // make a new salt
else
$salt = substr($hashed, 0, $salt_len*2); // extract existing salt
return $salt . hash('whirlpool', $salt . $clear);
}
?>
You can adjust the salt length and hash algorithm as you desire - whirlpool is a pretty good hash and much more secure than crypt()'s MD5. Using/adding uniq(), microtime(), ip address, uuid, etc to the salt only weakens security by reducing it's randmoness. If you think your OS can provide better random numbers, use that instead of mt_rand().
crypt
(PHP 4, PHP 5)
crypt — Einweg-String-Verschlüsselung (Hashbildung)
Beschreibung
crypt() einen String zurück, der unter Verwendung des Unix-Standard-Verschlüsselungsalgorithmus DES erstellt wurde. Dieser Algorithmus muss auf dem System verfügbar sein.
Einige Betriebssystem unterstützen mehr als eine Methode zur Verschlüsselung. So wird manchmal der DES- durch einen MD5-Algorithmus ersetzt. Der verwendete Schlüssel wird durch das Salt-Argument bestimmt. Zum Installationszeitpunkt untersucht PHP die vorhandenen Möglichkeiten und wird, abhängig vom Ergebnis dieser Prüfung, auch andere Schlüssel-Typen zulassen. Wird kein Salt unterstützt, erzeugt PHP per Voreinstellung einen 2-Zeichen DES-Salt, es sei denn, auf ihrem System ist MD5 der Standardverschlüsselungstyp. In diesem Fall wird PHP einen zufälligen MD5-kompatiblen Salt generieren. PHP setzt eine Konstante namens CRYPT_SALT_LENGTH, die Ihnen sagt, ob ihr System einen regulären 2-Zeichen-Salt oder den längeren 12-Zeichen-Salt unterstützt.
Die Standard-DES-Verschlüsselung crypt() enthält den Salt als erste 2 Zeichen der Ausgabe. Ebenso werden nur die ersten acht Zeichen von str berücksichtigt; verwenden Sie also einen längeren String, der mit den gleichen 8 Buchstaben beginnt, so erhalten Sie denselben Rückgabewert (sofern Sie ebenfalls den gleichen Salt nutzen).
Auf Systemen, wo die crypt()-Funktion mehrere Verschlüsselungsarten unterstützt, werden die folgenden Konstanten auf 0 oder 1 gesetzt, je nachdem, ob der entsprechende Typ verfügbar ist:
- CRYPT_STD_DES - Standard DES-Schlüssel mit 2-Zeichen-Salt
- CRYPT_EXT_DES - Erweiterte DES-basierte Verschlüsselung mit einem 9-Zeichen-Salt
- CRYPT_MD5 - MD5-Verschlüsselung mit 12-Zeichen-Salt, beginnend mit $1$
- CRYPT_BLOWFISH - Blowfish-Verschlüsselung mit 16-Zeichen-Salt, beginnend mit $2$ oder $2a$
Hinweis: Seit PHP 5.3.0 enthält PHP eine eigene Implementation und verwendet diese, wenn das System einen oder mehrere der Algorithmen nicht unterstützt.
Parameter-Liste
- str
-
Die zu verschlüsselnde Zeichenkette.
- salt
-
Ein optionaler Salt-String, der die Schlüsselbasis bildet. Sofern nicht angegeben, wird von PHP ein zufälliger Wert bei jedem Aufruf der Funktion generiert.
Wenn Sie das gegebene Salt benutzen, sollten Sie beachten, dass dieser Wert nur einmal bestimmt wird. Rufen Sie diese Funktion nun mehrmals auf, beeinträchtigt das nicht nur das Ergebnis, sondern unter Umständen auch die Sicherheit.
Rückgabewerte
Gibt die verschlüsselte Zeichenkette zurück.
Changelog
| Version | Beschreibung |
|---|---|
| 5.3.0 | PHP enthält jetzt eine eigene Implementation der MD5-Crypt, Standard DES, Extended DES und des Blowfish-Algorithmus und verwendet diese, wenn das System eine oder mehrere der Algorithmen nicht unterstützt. |
Beispiele
Beispiel #1 crypt()-Beispiele
<?php
$passwort = crypt('mein_Pwd'); // Der Salt wird automatisch generiert
/* Sie sollten das vollständige Ergebnis von crypt() als Salt zum
Passwort-Vergleich übergeben, um Problemen mit unterschiedlichen
Hash-Algorithmen vorzubeugen. (Wie bereits ausgeführt, verwendet
ein Standard-DES-Passwort-Hash einen 2-Zeichen-Salt, ein
MD5-basierter hingegen nutzt 12 Zeichen. */
if (crypt($benutzer_eingabe, $passwort) == $passwort) {
echo "Passwort stimmt überein!";
}
?>
Beispiel #2 Verwendung von crypt() für htpasswd
<?php
// Passwort setzen
$passwort = 'mein_Pwd';
// Hash mit automatisch erstelltem Salt generieren
$hash = crypt($passwort);
?>
Beispiel #3 Verwendung von crypt() mit verschiedenen Verschlüsselungsarten
<?php
if (CRYPT_STD_DES == 1) {
echo 'Standard DES: ' . crypt('rasmuslerdorf', 'rl') . "\n";
}
if (CRYPT_EXT_DES == 1) {
echo 'Extended DES: ' . crypt('rasmuslerdorf', '_J9..rasm') . "\n";
}
if (CRYPT_MD5 == 1) {
echo 'MD5: ' . crypt('rasmuslerdorf', '$1$rasmusle$') . "\n";
}
if (CRYPT_BLOWFISH == 1) {
echo 'Blowfish: ' . crypt('rasmuslerdorf', '$2a$07$rasmuslerd...........$') . "\n";
}
?>
Das oben gezeigte Beispiel erzeugt eine ähnliche Ausgabe wie:
Standard DES: rl.3StKT.4T8M Extended DES: _J9..rasmBYk8r9AiWNc MD5: $1$rasmusle$rISCgZzpwk3UhDidwXvin0 Blowfish: $2a$07$rasmuslerd............nIdrcHdxcUxWomQX9j6kvERCFjTg7Ra
Anmerkungen
Hinweis: Es existiert keine decrypt Funktion, da crypt() eine Einweg-Verschlüsselung ist.
crypt
21-Oct-2009 04:11
27-Aug-2009 02:21
The makesalt() function code below when used to create an MD5 salt, produces a salt with characters not typically in a salt used by operating system crypt functions. Some of these characters may have unintended side effects depending on how they are used - including the following: @ ` ~ \ | {}.
I am using the following to create MD5-Crypt hashes, (yes, I am assuming CRYPT_MD5 support is present).
<?php
function md5crypt($password){
// create a salt that ensures crypt creates an md5 hash
$base64_alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
.'abcdefghijklmnopqrstuvwxyz0123456789+/';
$salt='$1$';
for($i=0; $i<9; $i++){
$salt.=$base64_alphabet[rand(0,63)];
}
// return the crypt md5 password
return crypt($password,$salt.'$');
}
?>
07-Jul-2008 12:26
For the previous poster, you can use the hash function set for SHA encryptions i.e. hash("sha256", $str), providing you have PHP5+ ...
http://uk3.php.net/manual/en/function.hash.php
02-Jun-2008 01:09
What about SHA-256 and SHA-512 crypt?
http://people.redhat.com/drepper/SHA-crypt.txt
13-Jan-2008 09:07
The previous poster (whatnet) is confused about having to store the (random) value used as the original salt when the password is first encrypted. This is not necessary because the output of crypt() includes the salt used to do the encryption, so the encrypted password you store in your user database is exactly what you would feed it back in later.
In order to validate a password, just do what the example above suggests:
<?php
if (crypt($user_input, $encrypted_password) == $encrypted_password) {
echo "Password verified!";
}
?>
20-Aug-2007 09:40
You should be careful when using "random" or "time specific" information to effect the outcome of the encryption. Keep in mind that if it's used for, say a user's password, that you will need to generate the same outcome in order to compare the user's input, to whatever you have in the database.
It might be a suggestion to store your "unique key", with the user's information inside the database.
17-Jul-2007 03:49
ECB is one of the least secure block cipher modes (Wikipedia has some good information about these: http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation) because it is the only mode, out of the one's available for use with MCRYPT, that does not actually use the IV provided. Note: PHP will emit an E_WARNING if the IV is missing or if its length is not equal to the size mandated by mcrypt_get_iv_size().
In response to <addiakogiannis at isds dot gr>, even though the IV is randomly generated in the encryption and decryption functions, the output remains the same given the same plaintext and key because the mode is ECB. If a different mode is used, the IV must be preserved (say, by concatenation with the ciphertext) in order for the ciphertext to be decrypted properly. That is:
<?php
//changing all instances of MCRYPT_MODE_ECB to MCRYPT_MODE_CFB
function RIJNDAEL_encrypt($text){
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CFB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "This is a very secret key";
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CFB, $iv));
}
function RIJNDAEL_decrypt($text){
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CFB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "This is a very secret key";
//I used trim to remove trailing spaces
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($text), MCRYPT_MODE_CFB, $iv));
}
//example
echo RIJNDAEL_decrypt(RIJNDAEL_encrypt('Her name was lola!'));
?>
...will output a random, 18-character string. Thus, the length of the plaintext is preserved, but the data is completely corrupted.
13-Jul-2007 10:46
Two siple functions for encrypting and decrypting with RIJNDAEL 256
function RIJNDAEL_encrypt($text){
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "This is a very secret key";
return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB, $iv));
}
function RIJNDAEL_decrypt($text){
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "This is a very secret key";
//I used trim to remove trailing spaces
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($text), MCRYPT_MODE_ECB, $iv));
}
//example
echo RIJNDAEL_decrypt(RIJNDAEL_encrypt('Her name was lola!'));
06-Apr-2007 02:51
for me(on OpenBSD4.0+Apache 1.3(standard)+php4.3.10) blowfish seems to work if you do something like this:
if (CRYPT_BLOWFISH == 1)
{
$salt="this should really be a long line of salt";
$blowfish_salt = "\$2a\$07\$".substr($salt, 0, CRYPT_SALT_LENGTH);
echo crypt($pass, $blowfish_salt);
}
of course with $salt set as a good long salt.
06-Apr-2007 08:52
I found out that you can use php:s crypt function to change the user/root password in Linux distributions (at least in Slackware).
You just have to change the encrypted password for the user in the /etc/shadow file with the output from crypt("newpassword");
04-Mar-2007 03:47
Are you using Apache2 on f.i. WinXP and want to create .htpasswd files via php? Then you need to use the APR1-MD5 encryption method. Here is a function for that:
<?php
function crypt_apr1_md5($plainpasswd) {
$salt = substr(str_shuffle("abcdefghijklmnopqrstuvwxyz0123456789"), 0, 8);
$len = strlen($plainpasswd);
$text = $plainpasswd.'$apr1$'.$salt;
$bin = pack("H32", md5($plainpasswd.$salt.$plainpasswd));
for($i = $len; $i > 0; $i -= 16) { $text .= substr($bin, 0, min(16, $i)); }
for($i = $len; $i > 0; $i >>= 1) { $text .= ($i & 1) ? chr(0) : $plainpasswd{0}; }
$bin = pack("H32", md5($text));
for($i = 0; $i < 1000; $i++) {
$new = ($i & 1) ? $plainpasswd : $bin;
if ($i % 3) $new .= $salt;
if ($i % 7) $new .= $plainpasswd;
$new .= ($i & 1) ? $bin : $plainpasswd;
$bin = pack("H32", md5($new));
}
for ($i = 0; $i < 5; $i++) {
$k = $i + 6;
$j = $i + 12;
if ($j == 16) $j = 5;
$tmp = $bin[$i].$bin[$k].$bin[$j].$tmp;
}
$tmp = chr(0).chr(0).$bin[11].$tmp;
$tmp = strtr(strrev(substr(base64_encode($tmp), 2)),
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
return "$"."apr1"."$".$salt."$".$tmp;
}
?>
20-Jan-2007 07:19
The following sentences can lead to misunderstandings:
"If the salt argument is not provided, one will be randomly generated by PHP each time you call this function."
Comment: false for DES, true for MD5
...
"If you are using the supplied salt, you should be aware that the salt is generated once. If you are calling this function repeatedly, this may impact both appearance and security."
Comment: true for DES, false for MD5
Two sentences nearby, and they are telling incompatible stories. At least I was confused for quit a time.
My analysis after some tests:
If the parameter 'salt' is omitted, there are two possibilities:
* if the default encryption is Standard DES, there is a static salt provided. If you call crypt() with the same password again, the salt and the hash is the same. Effectively, there is no salt functionality. (untested)
* if the default encryption is crypt MD5, always random salt is added, and multiple calls of crypt with the same password provide different salt and hashes. I have tested this to be true.
Experiment (PHP version: 4.4.0 SuSE 10 and PHP version: 5.1.2 SuSE 11):
<?php
echo 'result: ' . crypt('somepassword');
echo 'result: ' . crypt('somepassword');
echo 'result: ' . crypt('somepassword');
?>
result: $1$K2D8DGwq$b05uO37aMwO4rnDlB9Rsi1
result: $1$aPBvu2y.$213YVEs8/5m.jMCXSScly/
result: $1$dW3Xu2p6$nuCtJe2zzlgBMLxN2oZCx/
I hope, i can prevent some headache.
14-Dec-2006 08:18
Blowfish doesn't use a sixteen character salt, it uses sixteen *bytes* of salt. So (courtesy of the docs for the Crypt::Eksblowfish::Bcrypt Perl module), it's:
"$2", optional "a", "$", two digits, "$", and 22 base 64 digits
If the salt is not long enough, crypt will return "*0" and you will have no idea what is wrong. Interestingly, the example in the documentation with a trailing '$' in the salt does not work. Replace the '$' with a '.', and the output appears as advertised.
21-Sep-2006 08:49
I had problems with ENCRYPT MySQL function when i tried to compare with the encrypted password (with ENCRYPT).
Another solution i read from "UNIX Advanced programming" where i found about the UNIX system call "crypt()":
Password="tB" //The two first letters of encrypted password
SELECT password from users where Password=ENCRYPT('".$_POST['password']."',Password)
mysql> select password from users where password=encrypt('pasword','tB');
+---------------+
| password |
+---------------+
| tBY8OVuabSiTU |
+---------------+
1 row in set (0.01 sec)
Bye.
> topace at lightbox dot org
> 22-Sep-2005 06:34
>
> To authenticate against a stored crypt in MySQL, simply use:
>
> SELECT ................
> AND Password=ENCRYPT('".$_POST['password']."',Password)
24-Dec-2005 07:20
With different password hashing methods supported on different systems and with the need to generate salts with your own PHP code in order to use the more advanced / more secure methods, it takes special knowledge to use crypt() optimally, producing strong password hashes. Other message digest / hashing functions supported by PHP, such as md5() and sha1(), are really no good for password hashing if used naively, resulting in hashes which may be brute-forced at rates much higher than those possible for hashes produced by crypt().
I have implemented a PHP password hashing framework (in PHP, tested with all of PHP 3, 4, and 5) which hides the complexity from your PHP applications (no need for you to worry about salts, etc.), yet does things in almost the best way possible given the constraints of the available functions. The homepage for the framework is:
http://www.openwall.com/phpass/
I have placed this code in the public domain, so there are no copyrights or licensing restrictions to worry about.
P.S. I have 10 years of experience in password (in)security and I've developed several other password security tools and libraries. So most people can feel confident they're getting this done better by using my framework than they could have done it on their own.
16-Nov-2005 03:34
WRONG:
$mypassword = "toto";
$smd5_pass = "{SMD5}......." // in openldap
if (preg_match ("/{SMD5}/i", $smd5_pass))
{
$encrypted = substr($md5_pass, 6);
$hash = base64_decode($encrypted);
$salt = substr($hash,16);
$mhashed = mhash(MHASH_MD5, $mypassword . $salt) ;
$without_salt = explode($salt,$hash_hex);
if ($without_salt[0] == $mhashed) {
echo "Password verified <br>";
} else {
echo "Password Not verified<br>";
}
}
$without_salt = explode($salt,$hash_hex); should be $without_salt = explode($salt,$hash);
RIGHT:
$mypassword = "toto";
$smd5_pass = "{SMD5}......." // in openldap
if (preg_match ("/{SMD5}/i", $smd5_pass))
{
$encrypted = substr($md5_pass, 6);
$hash = base64_decode($encrypted);
$salt = substr($hash,16);
$mhashed = mhash(MHASH_MD5, $mypassword . $salt) ;
$without_salt = explode($salt,$hash);
if ($without_salt[0] == $mhashed) {
echo "Password verified <br>";
} else {
echo "Password Not verified<br>";
}
}
06-Nov-2005 10:16
Note to topace's code: you should not use $_POST['password'] directly in your query as you are open to sql-injects.
Use the quote_smart() function from http://no.php.net/mysql_real_escape_string before adding user-submitted data to the query
22-Sep-2005 04:34
To authenticate against a stored crypt in MySQL, simply use:
SELECT ................
AND Password=ENCRYPT('".$_POST['password']."',Password)
15-Jun-2005 07:53
Since many of you are wondering why when providing salt the characters over the 8th are ignored in the password, I'll clarify it a bit.
By default, PHP will try to use the best encryption method available on your system : MD5 or Simple DES.
Usually this is the MD5 method ($1$).
In this case, the salt must look like : "$1$xxxxxxxx$" where x are random ASCII characters. When you use MD5 passwords, all characters of the password are encrypted in this 34 characters hash.
However if your salt starts with an ASCII character, the system will assume it's a standard DES encrypted password. The main weakness of this system : only the 8 first characters of the password are used.
A correct version of the code :
<?php
function makesalt($type=CRYPT_SALT_LENGTH) {
switch($type) {
case 8:
$saltlen=9; $saltprefix='$1$'; $saltsuffix='$'; break;
case 2:
default: // by default, fall back on Standard DES (should work everywhere)
$saltlen=2; $saltprefix=''; $saltsuffix=''; break;
#
}
$salt='';
while(strlen($salt)<$saltlen) $salt.=chr(rand(64,126));
return $saltprefix.$salt.$saltsuffix;
}
$salt=makesalt();
$longpassword='fez1c89ez1c98ez4c89z4eqf98ez';
$encrypted = crypt($longpassword, $salt);
$encrypted2 = crypt(substr($longpassword, 0, 8), $encrypted);
if ($encrypted == $encrypted2) {
echo 'Match: Weak encryption method (Standard DES)';
} else {
echo 'NoMatch: Strong encryption method (MD5)';
}
?>
If you use makesalt(2) you will force usage of Standard DES method, and the passwords will match. If you just use makesalt() there's great chances you'll have a MD5 password (don't know any system used nowadays which does not support MD5 passwords).
Finally, do not look at md5() PHP function if you want a md5 password, that's not related. UNIX MD5 passwords uses a salt, are 34 character long and start with $1$. The reply from md5() is 32 characters long, and is more adapted for file integrity check (call that a checksum).
Some people use sha1() passwords but without salt. Here's my simple sha1crypt function which will work with standard crypt passwords (by calling crypt()) AND a home-made "sha1" encryption method.
<?php
// NOTE: This function requires PHP 5.0.0 as we use "raw output" option of sha1()
function sha1crypt($password, $salt=null) {
if ( (is_null($salt)) || (strlen($salt)<1) ) {
$salt='';
while(strlen($salt)<10) $salt.=chr(rand(64,126));
$salt='$sha1$'.$salt.'$';
}
if ($salt{0}!='$') return crypt($password, $salt);
$tmp=explode('$',$salt);
if ($tmp[1]!='sha1') return crypt($password, $salt);
$saltstr=$tmp[2];
if (strlen($saltstr) != 10) return crypt($password, $salt);
$encrypt=base64_encode(sha1($saltstr.$password,true));
return '$sha1$'.$saltstr.'$'.$encrypt;
}
// without salt, sha1crypt() will generate on
$pass=sha1crypt('foobar');
echo $pass."\n";
// pass directly password as salt - different output as password is not the same
echo sha1crypt('foobarbaz',$pass)."\n";
// same password - same output
echo sha1crypt('foobar',$pass)."\n";
// Encrypt using MD5 passwords
echo sha1crypt('foobar','$1$blahblahg$')."\n";
?>
will output:
$sha1$oFkYeI|vuu$d3n7D30OnecZSbS6KIbxCch608A=
$sha1$oFkYeI|vuu$iA8KmbCZun1G1gEw2qVr42ELVH4=
$sha1$oFkYeI|vuu$d3n7D30OnecZSbS6KIbxCch608A=
$1$blahblah$/8Hme91aEkHzLaVk0g9EQ0
My sha1-encrypted passwords are 45 characters long.
Remember to read that too before using SHA1 passwords too :
http://www.schneier.com/blog/archives/2005/02/sha1_broken.html
07-Jun-2005 01:03
The people confused about the first 2 characters of the plain-text password being used as the salt are... confused.
AFTER you crypt() your plain-text password, with 2 RANDOM characters, the RESULTING scrambled output with have the 2 randomly-selected characters as its first 2 characters.
Later, to check a password presented by the user, you use the first 2 characters of the SCRAMBLED password as the salt.
So you do not need to remember the salt elsewhere -- it is buried in the encrypted output.
This is by design by very very very clever cryptologists, and in no way, shape, or form decreases the "security" of the algorithm.
The same is true of all the encryption algorithms here -- The salt may be 27 characters long, and embedded in the middle of the crypted string, but it's still there, and that's Good.
I hope this note decreases the confusion caused by the 2 early notes discussing salt.
15-May-2005 08:57
cleaner version of shadow() and with more ascii chars
<?php
function shadow ($input){
for ($n = 0; $n < 9; $n++){
$s .= chr(rand(64,126));
}
$seed = "$1$".$s."$";
$return = crypt($input,$seed);
return $return;
}
>
20-Apr-2005 07:55
Even worse, using the first two letters of the password as the salt removes the whole point of having salt in the first place, which is that without it, it's trivial to create a dictionary of passwords-to-encrypted-passwords. Without salt (or with using a salt directly derived from the password) there's only one possible encrypted password per password. With the two character salt, there's 4096, which makes the idea a lot less feasible.
>icecube at fr dot fm 07-Mar-2002 09:53
>To generate a .htaccess-based authentication with DES,
>you have to use the first two characters of your password
>as salt.
This is a _really_ bad idea, seeing how the two first letters of your password will be reveiled, effectively reducing the quality of your password.
Your example assigns "sonH/h2hpGtHk" to $ht_pass, where "so" of course are the first to letters in something. Try it out for yourself. Switching the password to "icecube" gives "ickJ.ZxzjXpNE" as the output. Get my point?
The salt is always included in the encrypted string. Use a random salt instead.
16-Mar-2005 10:07
I'll take the example from above and take a situation that I've ecountered and show you something that puts this function in a dark shadow of insecurity:
<?php
$password = crypt('postal2600','CyberBoard');
if (crypt('postal26??', $password) == $password) {
echo "Password verified!";
}
?>
Instad of ?? you can put anything an see that allway the password will be verified. So i strongly recomand that the md5 function should be used instead.
31-Dec-2004 04:18
It is likely that the php version of crypt() interfaces relatively directly with the C-library crypt() function, usually contained in libcrypt.
Depending on your implementation and the default salt, you may or may not get the same crypt'd password out of eight characters as you would a longer string starting with those same eight characters.
See crypt(3) on your system for more documentation on how it works based on different encryption types.
29-Nov-2004 01:10
I discovered in the script stated before, when using a salt string the passwords length cannot be longer than 8 characters. However, when not using a salt string, it can exceded that limit.
Modified Example from athony, not using the salt.
<?php
$password = "qwertyuiopasdfghjkl";
// Not using any salts
$encrypted = crypt($password);
// Now do the comparison
$shortPass = substr($password, 0, 8);
if (crypt( $shortPass, $encrypted ) == $encrypted )
echo "The passwords match";
else
echo "The passwords do not match";
?>
This will print: "The passwords do not match"
The check for password would still work if it was correct. Just by shortening the password string to eight, or extending the substr, or decalring the shortpass the same as the pass, it would be: "The passwords do match"
So the eight letter limit only works when using a salt.
26-Nov-2004 04:21
There appears to be a limitation with this function, where it only validates upto a characters, therefore the 9th character onwards can be ommitted, which limits useful passwords to 8 characters only. Example
<?php
$password = "qwertyuiopasdfghjkl";
// Encrypt the password, but let's use a known MD5 hash as the salt
$salt = ""0f2d92cee71e5f93f3abecdc666a6b7d";
$salt = substr($salt, 0, CRYPT_SALT_LENGTH );
$encrypted = crypt($password, $salt);
// Now do the comparison
$shortPass = substr($password, 0, 8);
if (crypt( $shortPass, $encrypted ) == $encrypted )
echo "The passwords match";
else
echo "The passwords do not match";
?>
This will print: "The passwords match" even though $shortPass is "qwertyui" and $password is "qwertyuiopasdfghjkl"
02-Sep-2004 10:34
Here's a little function I wrote to generate MD5 password hashes in the format they're found in /etc/shadow:
function shadow($password)
{
$hash = '';
for($i=0;$i<8;$i++)
{
$j = mt_rand(0,53);
if($j<26)$hash .= chr(rand(65,90));
else if($j<52)$hash .= chr(rand(97,122));
else if($j<53)$hash .= '.';
else $hash .= '/';
}
return crypt($password,'$1$'.$hash.'$');
}
I've written this so that each character in the a-zA-Z./ set has a 1/54 of a chance of being selected (26 + 26 + 2 = 54), thus being statistically even.
05-Jul-2004 02:52
Text_Password allows one to create pronounceable and unpronounceable passwords.
http://pear.php.net/package/text_password
26-Jun-2002 05:17
There's always been a bit of confusion as to what makes a good salt and what doesn't. Remember that it doesn't matter at all how easy a salt is to guess. No one ever HAS to guess the salt: it's already given.
The only only important consideration when generating a salt is to make sure that all salts are unique--that way the same password will be encrypted differently (i.e. the encrypted passwords will look different) for different users.
One of the simplest ways to generate a unique salt is to use some string that will be different every time the procedure is called. Here's a simple example:
<?php
$jumble = md5(time() . getmypid());
$salt = substr($jumble,0,$salt_length);
?>
Given a string consisting of the current time (in seconds) concatinated with the current process id, the string will never be the same twice, assuming that the function is never called more than once per second. Calculating the md5 sum over that string creates another string from which you can extract any substring and still end up with a unique sequence.
If you're going to be generating more than one password per second, just throw a rand($x,$y) in there to add a little more entropy.
