PHP Doku:: Errechnet den MD5-Hash eines Strings - function.md5.html

Verlauf / Chronik / History: (1) anzeigen

Sie sind hier:
Doku-StartseitePHP-HandbuchFunktionsreferenzTextverarbeitungZeichenkettenString-Funktionenmd5

Ein Service von Reinhard Neidl - Webprogrammierung.

String-Funktionen

<<md5_file

metaphone>>

md5

(PHP 4, PHP 5)

md5Errechnet den MD5-Hash eines Strings

Beschreibung

string md5 ( string $str [, bool $raw_output = false ] )

Berechnet den MD5-Hash von str unter Verwendung des » RSA Data Security, Inc. MD5 Message-Digest Algorithm und gibt das Ergebnis zurück.

Parameter-Liste

str

Die Zeichenkette.

raw_output

Wurde der optionale Parameter raw_output mit TRUE angegeben, wird der MD5-Wert im Raw Binary Format mit einer Länge von 16 Zeichen zurückgegeben.

Rückgabewerte

Gibt den Hash als 32 Zeichen lange Hexadezimalzahl zurück.

Changelog

Version Beschreibung
5.0.0 Der Parameter raw_output wurde hinzugefügt.

Beispiele

Beispiel #1 Ein md5()-Beispiel

<?php
$str 
'apple';

if (
md5($str) === '1f3870be274f6c49b3e31a0c6728957f') {
    echo 
"Haetten Sie lieber einen gruenen oder einen roten Apfel?";
}
?>

Siehe auch

  • md5_file() - Berechnet den MD5-Code einer Datei
  • sha1_file() - Berechnet den SHA1-Hash einer Datei
  • crc32() - Berechnet den polynomischen CRC32-Wert eines Strings
  • sha1() - Berechnet den SHA1-Hash eines Strings
  • hash() - Berechnet den Hash einer Nachricht


70 BenutzerBeiträge:
- Beiträge aktualisieren...
harrisjason10 at yahoo dot com
6.01.2011 11:27
Here is a good encryption function im building for my custom CMS and decided to share with the community

<?php
function eliteEncrypt($string) {
   
// Create a salt
   
$salt = md5($string."%*4!#$;\.k~'(_@");
   
   
// Hash the string
   
$string = md5("$salt$string$salt");
   
    return
$string;
}
?>

If you are like me, and prefer sha1() hashing, just change "md5" to "sha1".
fpnjie at gmail dot com
24.08.2010 14:34
Very ugly way to combine.

<?php

$salt
= md5("1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
$password = hash( 'MD5',$salt );
$hash = $password . $salt;
$rand = rand(1, 256)%4;

for (
$i = 0; $i < $rand; $i++ ) {
 
$hash = hash('md5',$hash );
}
echo
$hash, '<br>';
echo (
microtime(1)-$time)*10000,': time in ms';
?>
Anonymous
8.06.2010 22:36
Here's a relatively simple function I designed to hash out passwords using MD5.  Assumes max length of user supplied password (20) max length of database field (40).

<?php
define
('SALT_ONE', 'some_random_123_collection_&$^%_of_stuff');
define ('SALT_TWO', 'another_random_%*!_collection_ANbu_of_stuff');

$password = 'dragon';

function
generate_encrypted_password($str) {
$new_pword = '';

if(
defined('SALT_ONE') ):
  
$new_pword .= md5(SALT_ONE);
endif;

$new_pword .= md5($str);

if(
defined('SALT_TWO') ):
  
$new_pword .= md5(SALT_TWO);
endif;

return
substr($new_pword, strlen($str), 40);
}

echo
generate_encrypted_password($password);
?>
guy dot baconniere at swisscom dot com
16.03.2010 15:19
If you want to use md5() to generate PostgreSQL compatible md5 password use this :

<?php

printf
("md5%s", md5($_POST['password'].$_POST['username']));

?>

Best Regards,
Guy Baconniere
John
18.11.2009 0:08
If you want to hash a large amount of data you can use the hash_init/hash_update/hash_final functions.

This allows you to hash chunks/parts/incremental or whatever you like to call it.
gigatop100 at Hotmail dot com
1.11.2009 14:23
look my own created super password function :)

<?
function enchsetenev($toencode,$times)
{
   
$salt = 's+(_a*';
    for(
$zo=0;$zo<$times;$zo=$zo+1)
    {
       
$toencode = hash('sha512',salt.$toencode);
       
$toencode = md5($toencode.$salt);
    }
    return
$toencode;
}

?>

how to use it ?
simply..
<?

$password
="this password is super ultra mega secure and noone would decrypt it for atleast 10 years.. or even alot more :)";

$supersecurepassword=enchsetenev($password,1000);

?>

now 1000 is a somehow a fast processed password, i mean it won't take much time to encode it... in most cases about 100-200ms (depends..)

however if you put 10000 (10 000 times encrypted with hash sha512 and md5 ) that would take about 1 second to process
netom at elte dot hu
22.09.2009 17:44
Salt isn't just preventig hash-value pair reuse.

Salt is for preventig rainbow table attacks. Rainbow tables are only useful for short passwords (6-8-10 characters, or so). If you salt your passwords, you increase the length of the hashed string dramatically, so they will not match anything in the rainbow table.

The fact, that 8 character length passwords can be bruteforced with a PC is not the fault of the MD5 algorithm. sha1, or whatever hashes can be broken in a same way (brute force). The problem is that these hashes a "too fast". They can ben done billions of times per second.

To prevent (slow down) brute force attacks, one can construct a hash function that is very hard to compute. This can be done easily:

<?php
$hash
= $password . $salt;

for (
$i = 0; $i < 10000; $i++ ) {
 
$hash = md5( $hash );
}

//Store your $hash
?>

This is an implementation of the PBKDF2 function wich is described in the PKCS #5 v2 document.
Anonymous
25.04.2009 0:20
8 character passwords from a set of 76 characters have 1,127,875,251,287,710 possibilities

Passwords are rarely random, hence we have heuristics.

It is very easy to generate 500,000,000 MD5/s on a desktop machine with a decent GPU

A quad core with a four cheap 8800GT's could probably do nearly 2 Billion per second

At this rate it would take less than 7 days to break all possible hashes made from passwords using this charset and of length <= 8

It is also important to observe moore's law. Software isn't written to last a day and migration from one system to another is a pain in the ass. In 10 years time MD5 will be an awful algorithm to use to hash passwords. We will probably have enough computing power on a desktop machine to find a collision for most hashes within 5-10 years (2^64)

Put into perspective changes in technology and distributed efforts and MD5 becomes weak. Why use MD5 when you can use SHA-1 and save yourself a lot of hassle?
2me21 at mail dot ru
6.04.2009 23:43
About password and md5

- small letters         26
- big letters            26
- digits                  10

total 62 possible simbols in 1 sign of password.
if you force your user to use in their password such signs as
!
@
#
$
%
^
&
*
(
)
-
=
_
+
you increase the password security + 14 signs
So total 76

Now while generating of all possible passwords with above mentioned digits and length up to 8 simbols you will have a table with
!!! 1 370 114 371  MILLIONS rows!!!
!!! 1 370 114 371  000 000  rows!!!

for getting of all MD5 hash you will have to have a table with 1 400 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 rows.

Check what google means in wikipedia and see that humanity is not able to create anything what is able to generate ans store all md5 hashs.
matrebatre
6.12.2008 22:10
I don't think encrypting the passwords multiple times is a good idea. It will reduce the number of possibilities. I think the best way to protect the passwords is by using two different salts, and do something like this:

<?php
$hash
= md5($salt1.$password.$salt2);
?>

Because of the way md5 hashes are calculated, it is also important to use salts that are NOT 64 characters, because MD5 will split the string in blocks of 64 bytes each (16 'words').
sandaimespaceman at gmail dot com
2.11.2008 19:06
I usually MD5 the username, password and IP to set login cookie. MD5ing IP will make cookie thief on other computers fail.

<?php

//... connect to database, load list of users, etc...

$username = $_POST['username'];
$password = $_POST['password'];
 
/*
  $cookie may look like this:
   variables
    $username = "username"
    $password = "password"
    _SERVER['REMOTE_ADDR'] = 42.52.56.24
   before md5:
    "usernamepassword42.52.56.24"
   after md5:
    "a3470ce826283eca7ce3360d0f26b230"
 */
 
$cookie = md5 (
   
$username .
   
$password .
   
$_SERVER['REMOTE_ADDR']
 );

setcookie ("login", $cookie);

//when the log in cookie is SET...
if (isset($_COOKIE['login']) )
{
    foreach (
$user_list as $user => $pass)
    {
       
//match the user list with the cookie
       
if (
            
md5 (
                 
$user .
                 
$password .
                 
$_SERVER['REMOTE_ADDR']
                  )
             ==
$_COOKIE['login']
            )
        {
           
header("Location: index.php");
            die(
"logged in");
        }
    }
   
//when login is wrong
   
header("Location: login.php");
    die(
"wrong username/password");
}
?>
has been thinking dot com
3.10.2008 0:15
I think rainbow tables are useful if the hackers managed to grab a user name and md5 hashed password from a particular server run that trough their rainbow table and get the original value. then use that in all databases that they want.

now if that server uses a different type of salt. that password will not match that user name's hashed password on other servers. because the one that was unhashed was salted.

that is if the hacker is planning to use log-in forms. after infiltrating a server by force.
stevish at gmail dot com
1.10.2008 22:41
This is partly in response to postfix at bk dot ru, concerning rainbow tables and the security of md5 as a password hash.

The idea behind rainbow tables is to, over time, create a database that contains all the possible md5 hashes. They don't need to contain every possible *password* because if they find a 3 letter word that produces the same hash (known as a "collision") as your 46 digit, alpha-numeric password that includes english, russian, and japanese characters... they can just use the 3 digit one instead. Now I'm not certain, but I think that with regular md5 hashes (unsalted) there is already a complete rainbow table in existence. This is why salts are useful.

Adding a salt to the password before hashing it forces attackers to create a brand new rainbow table, because the existing ones are useless. And if you go a step further with a script that uses a different salt for each user, they can only crack one password at a time.

And speaking of time... that is another important factor. The quicker a computer is able to hash a password, the more passwords it can try per second. A simple md5, for instance, can be calculated several hundred times per second on an average server. If, however, your script hashes the password 2,000 times, it will take a brute force attack at least 5 seconds per password (which means it would take roughly 33,109 years to run every 8 digit password using only lower case letters).

So... straight md5 = practically plain-text to a determined attacker.

Unique salts, and more server intensive hashes = a long life of boredom to a determined attacker.
MD5 is secure
25.08.2008 13:04
That's just a database of common words or phrases MD5'd, it doesn't decrypt them - you may need to read up on what a hash is - try decrypting "530b4a0ae65148d112537bc0eafba9c9" with it, and it'll return no results because it's key hasn't been added to the database yet, where as something common like "9cdfb439c7876e703e307864c9167a15" will return lol
joacorock at gmail dot com
21.08.2008 15:39
You are right i never think that... sorry...

now the function can be:

<?php
//Function made by L2inside.org
function encrypt($v1,$v2=''){
   
$token = md5(sha1(md5(base64_decode($v1.$v2)).$v2).$v1);
    return
$token;
}
?>
Concerned Party
21.08.2008 15:18
The code from "joacorock at gmail dot com" isn't good.
Read the comments from other users regarding hashing hashes.
goober
19.08.2008 22:02
I hope you're aware that using crc32() effectively reduces the number of possible outcomes to about four billions, right?
joacorock at gmail dot com
15.08.2008 15:01
Here is my Encryption function...

I saw some encryption functions who uses random numbers... thats not a good function...

Here is mine, using a Salt or not, and with some special chars to a better encrypt

<?php
//Function made by L2inside.org
function encrypt($v1,$v2=''){
   
$token = md5(sha1(crc32(md5(base64_decode($v1.$v2)).$v2)));
    return
$token;
}
?>

First it was finished in sha1 but it is too long to have in a database with more than 100,000 records so i added the md5 encrypt to got a more small hash
pegler [at] googleemaildomain [dot] com
10.08.2008 5:14
I have been playing around with coming up with some sort of more secure md5 encryption.  This combines several techniques described so far.  First it will encrypt the password using md5.  Then rotate the text using the length of the original password, then encrypt the password again using md5 while adding a salt.

My reasoning for only rotating the hash around hex characters is to make the rotated hash a possible hash itself.  If we rotated around all characters, it would be possible to guess the original hash by looking at non-hex characters in the rotated hash.  Combining this hash with a fairly large salt should minimize collisions when hashing again.

See the other comments as to why double encrypting a password is usually a bad idea.

For the salt I am using a 128 character randomly generated string.

<?php
function hashPassword($password)
{
 
$salt = "some_long_random_string";
 
//encrypt the password, rotate characters by length of original password
 
$len = strlen($password);
 
$password = md5($password);
 
$password = rotateHEX($password,$len);
  return
md5($salt.$password);
}

function
rotateHEX($string, $n)
{
 
//for more security, randomize this string
 
$chars="abcdef1234567890";
 
$str="";
  for (
$i=0;$i<strlen($string);$i++)
  {
   
$pos = strpos($chars,$string[$i]);
   
$pos += $n;
    if (
$pos>=strlen($chars))
     
$pos = $pos % strlen($chars);
   
$str.=$chars[$pos];
  }
  return
$str;
}
?>
postfix at bk dot ru
17.07.2008 13:23
if you afraid of rainbow hash tables you should use passwords with more than 12 characters and consisting of random symbols. not double hashing nor using salt would not save your password if it _is_ in crackers dictionary. it just can increase cracking time to brutforce your pass with dictionary or build new tables.
Serge
21.05.2008 0:19
To convert an MD5 to 22 chars that contains only letters and numeric

<?php
define
('HEX_CHARS',    '0123456789abcdef');
define('BASE62_CHARS', '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');
 
/*********************************************/
function ConvertFromArbitraryBase($Str, $Chars)
/*********************************************/
{
   
/*
        Converts from an arbitrary-base string to a decimal string
    */
   
   
if (ereg('^[' . $Chars . ']+$', $Str))
    {
       
$Result = '0';
       
        for (
$i=0; $i<strlen($Str); $i++)
        {
            if (
$i != 0) $Result = bcmul($Result, strlen($Chars));
           
$Result = bcadd($Result, strpos($Chars, $Str[$i]));
        }
       
        return
$Result;
    }
   
    return
false;
}
 
/*******************************************/
function ConvertToArbitraryBase($Str, $Chars)
/*******************************************/
{
   
/*
        Converts from a decimal string to an arbitrary-base string
    */
 
   
if (ereg('^[0-9]+$', $Str))
    {
       
$Result = '';
       
        do
        {
           
$Result .= $Chars[bcmod($Str, strlen($Chars))];
           
$Str = bcdiv($Str, strlen($Chars));
        }
        while (
bccomp($Str, '0') != 0);
       
        return
strrev($Result);
    }
   
    return
false;
}
 
/**********************/
function CustomMD5($Str)
/**********************/
{
    return
ConvertToArbitraryBase(ConvertFromArbitraryBase(md5($Str), HEX_CHARS), BASE62_CHARS);
}
?>
taholder at gmail dot com
23.04.2008 23:33
I found that in order to get .NET to match an MD5 with the PHP md5 function you need to use a UTF7 encoding.

See http://ok-cool.com/posts/read/125-php-md5-not-the-same-as-net-md5/ for more details.
Anonymous
29.03.2008 23:45
so that nobody gets confused by karlo1 at gmail's remarks, salting is simply the inclusion of additional characters, like so:

<?php

  $salt
= 'random_stuff_12345';
 
$hash = md5 ($pass . $salt);

?>
KB
11.03.2008 15:02
This is probably well known, but I had a hard time finding a reference to it.

While md5 on a null string returns null, md5 on an EMPTY string does not return null or an empty string.  Rather it returns "d41d8cd98f00b204e9800998ecf8427e"
Stevish at gmail dot com
10.03.2008 19:06
I have sort of devised my own compilation lots of peoples' ideas for creating a secure, custom hash.

In order to keep my real hash-generator safe from prying eyes, I will simply give you the basic idea with random examples.

I started by making three hashes using three salts. If you want, you can use something like "crypto" below (http://us.php.net/manual/en/function.md5.php#70258) for one or more of the hashes.

<?php
$salt1
="something custom";
$salt2="blahblah";
$salt3="differentblah";
$hash1=sha1($salt1.$source)
$hash2=sha1($salt2.$source);
$hash3=md5($salt3.$source);
?>

Then here's where I think my idea is unique:

<?php $h = $hash1.$hash2.$hash3; ?>

Now, you want to shuffle them together, to make them practically impossible to separate. For that, I implemented the "scramble" idea from below (http://us.php.net/manual/en/function.md5.php#59241):

<?php
$scrambledhash
= $h{18} . $h{110} . $h{88} . $h{65}/*...etc*/;
?>

This will scramble the characters of that hash in your predetermined (but supposedly random) order.

ALMOST DONE!

I found the final step at http://phpsec.org/articles/2005/password-hashing.html .

The idea is that when a user enters a new password on registration (or changes their password). The function will create a random salt to help scramble the users password. Then, in order to make it possible to compare passwords in the future (since the salt was randomly created), the salt is appended to the beginning of the hash.

My twist on this is to spread the salt out through the hash. Then to extract the salt, you would use something similar to the scramble function above.

Assuming you use a 5-digit salt (although it really should be longer), which is stored in the 15th, 93rd, 34th, 72nd and 10th digits of your final hash (in that order), this is what it would look like:

<?php
$salt
=$hugeRetrievedHash{14} . $hugeRetrievedHash{92} . $hugeRetrievedHash{33} . $hugeRetrievedHash{71} . $hugeRetrievedHash{9};
?>
Remember that the first character in a string is number 0!

ALL DONE!!!

Now for all that compiled into one function!

<?php
/* When creating a password, use superHash($pass);
** When checking a password, use <?php if(superHash($pass,$hash)==$hash);?>
** where $hash = the hash you are checking against.
*/
function superHash($source, $storedSalt = null)
{
    if (
$storedSalt === null)
    {
       
$salt = substr(md5(uniqid(rand(), true)), 0, 5);
       
/*Note: The number 5 above is the length of the salt. This particular method only allows for a maximum 32 character salt.*/
   
}
    else
    {
       
$salt = $storedSalt{14} . $storedSalt{92} . $storedSalt{33} . $storedSalt{71} . $storedSalt{9};
       
/*This will obviously change based on how you distribute your salt in the hash, and how long it is.*/
   
}
   
$salt1="something custom";
   
$salt2="blahblah";
   
$salt3="differentblah";
   
$hash1=sha1($salt1.$source.$salt);
   
$hash2=sha1($salt2.$source.$salt);
   
$hash3=md5($salt3.$source.$salt);
   
$h = $salt.$hash1.$hash2.$hash3; //add salt to the mix
   
$scrambledhash = $a{70} . $a{43} . $a{37} . $a{52} . $a{91} . $a{29} . $a{10}/*...etc*/;
   
/*Here, we would look for the numbers 0, 1,2, 3 and 4 (which is where $salt was placed), and use their relative location (like 15th, 93rd, 34th, 72nd and 10th), and use those numbers (minus 1) in the statement above.
    Note that there are 117 characters to be accounted for (112 for the hashes + 5 for the salt).*/

   
return $scrambledhash;
}
?>

SECURITY NOTE!
From what I read, it's probably safest to put this function in it's own file outside of the public domain, and simply include() the file in every script that needs to use it.

*Whew* and that, folks, is all I got.
karlo1 at gmail dot com
9.03.2008 14:53
How to properly salt the password.
This actually is very simple.
<?php
$pass
=$_POST['pass'];
$salt='i_always_take_a_sentence_or_two_and_add_some_numbers_8342394';
$salted_md5=md5($pass);
?>

Now it is almost impossible to find the password using rainbow tables.
Of course you shouldn't tell anyone your $salt.
nathan
26.02.2008 5:07
I think the suggestion to double-hash your password is not a good idea.  You are much much better off adding a variable salt to passwords before hashing (such as the username or other field that is dissimilar for every account).

Double hashing is *worse* security than a regular hash.  What you're actually doing is taking some input $passwd, converting it to a string of exactly 32 characters containing only the characters [0-9][A-F], and then hashing *that*. You have just *greatly* increased the odds of a hash collision (ie. the odds that I can guess a phrase that will hash to the same value as your password).

sha1(md5($pass)) makes even less sense, since you're feeding in 128-bits of information to generate a 256-bit hash, so 50% of the resulting data is redundant.  You have not increased security at all.

The wikipedia article linked in the last post advocates using a salt.  No where (that I see) does it advocate using the double hash approach.
heavyraptor
10.02.2008 7:58
If you're afraid of rainbow tables (http://en.wikipedia.org/wiki/Rainbow_tables) listing your md5/sha1 password you might simply hash your password twice or more than two times (with md5 or sha1, or combining both). So save your password hashed more than once in your db to have full security.

Examples:
<?php
$password
= md5(md5($password));
$password = sha1(sha1($password));
$password = sha1(md5($password));
$password = md5(sha1($password));
?>

The following function might help to make it easier:
<?php
function hash_password($s,$t = 2) {
  for (
$i = 0; $i < $t; $i++)
   
$s = md5($s);
  return
$s;
}

/*
hash_password($password,2) = md5(md5($password))
hash_password($password,3) = md5(md5(md5($password)))
etc ...
*/
?>

Actually you might just use a different hash algorithm to hash your password, instead of using md5 or sha1. Most rainbow table list md5 and sha1 passwords, so you won't have problems with a different hash function.
admin at gadelkareem dot com
15.01.2008 5:16
MySQL MD() will not give you the same hash if character set is different.
ex :
<?php
#suppose table_name CHARSET=UTF8
#$md5 = md5('Städte'); # will give you a different hash than MySQL MD5()
#instead use
$md5 = md5(utf8_encode('Städte'));
$r = mysql_query("SELECT *, MD5(`word`) FROM `table_name` WHERE MD5(`word`) LIKE '{$md5}'");
if(
$r)
    while(
$row= mysql_fetch_assoc($r) )
       
print_r($row);

?>
AlexT
30.11.2007 12:51
re: Santa Cruz skelly

It is not actually md5sum that adds the extra newline.  Most (if not all) text editors will add a trailing newline to the file.  You can test this by creating a file (e.g. test.txt) with the word test in it.  Then view a hex dump of the file:

# hexdump -C test.txt
00000000  74 65 73 74 0a                                    |test.|
00000005

that 0a on the end is the newline (\n).

Hope this helps.

Alex
Santa Cruz skelly
17.10.2007 5:18
Re: public at kreinacke dot com

It has long been a point of frustration to me that md5() functions don't produce the same results as the *nix md5sum program. Reading your comments about the incongruity today pushed me over the edge to finally understand why. The answer, I believe I have found, is that md5sum includes an extra newline as the termination of the file content. ugh.

In response I have produced the following function that, at least on my server, produces a result matching the output of md5sum on the command line:

function md5sum($str) { return(md5($str . "\n")); }

Yes, that easy.

My results from typing the string "apples and oranges" into a PHP script using that function and the same string entered into a file on disk using md5sum on the command line to pull it return:

6c1111418017a050006eee9f2bdda2bf

Your `echo -n "apples and oranges | md5sum` method (which suppresses that newline I refer to!) and PHP's normal md5() function also return the same result as one another as you described, but those are string based operations. My solution is a function that reproduces the result of md5sum's assessment of on-disk data based on the contents of the file being in a string, something that's critical to my application.
mark a t metrofindings dto com
21.08.2007 18:38
Here's a better password checker that tries to guess the password in a certain order.  I found that the random guess ones would never do anything more than 3-4 characters because random guesses are never guaranteed to touch all the guesses.

This is a sequential password guesser, it needs to know the length of the target password.  Maybe someone can add on variable length passwords.  All you have to do is adjust the fingerprint size and reset it to all zeros.

it can guess "foo" as the password in 6 seconds on 1.7Ghz athlon (bogomips: 3504)

<?php
 set_time_limit
(0);
 
$_GET['password'] = $argv[1];
 
$_GET['length'] = @$argv[2];

 function
randomkeys($length)
 {
    
$pattern =
"1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    
$pattern .= "abcdefghijklmnopqrstuvwxyz";
    
$key  = $pattern{rand(0,61)};
     for(
$i=1;$i<$length;$i++)
     {
        
$key .= $pattern{rand(0,61)};
     }
     return
$key;
 }

 function
getpwguess($length, &$fingerprint) {
     static
$allchars = array(
'1','2','3','4','5','6','7','8','9','0',
'a','b','c','d',
'e','f','g','h','i','j',
'k','l','m','n',
'o','p','q','r','s','t','u','v',
'w','x','y','z','A','B','C',
'D','E','F','G','H','I','J','K','L',
'M','N','O','P','Q','R','S','T',
'U','V','W','X','Y','Z');
   
$guess = array();
   
$next = false;
    foreach (
$fingerprint as $index => $fing) {

        if (
$next == true) {
           
$fingerprint[$index]++;
           
$fing++;
           
$next = false;
        }

        if (
$fing == 62) {
           
$fingerprint[$index] = 0;
           
$fing = 0;
           
$next = true;
           
$guess[]  = $allchars[$fing];
            continue;
        }

       
$guess[]  = $allchars[$fing];
    }
   
$fingerprint[0]++;

    return
implode('',$guess);

 }
 
 if (isset(
$_GET['password'])){
 
$password = $_GET['password'];
 
$password_length = strlen($password);
 }
 else
 {
 
$password_length = 3;
 if (isset(
$_GET['length'])){
 
$password_length = $_GET['length'];}
 
$password = randomkeys($password_length);
 }
 
 echo
"Password is: $password \n";
 
$password = md5($password);
 
$attempts = 0;
 
$start = microtime(true);
 
$guess = '';
 
$fingerprint = array();
 for (
$x=0; $x < $password_length; $x++) {
    
$fingerprint[$x] = 0;
 }

 while (
$password != $guess){
   
$rndm = getpwguess($password_length,$fingerprint);
   
$guess = md5($rndm);
   
$attempts++;
    
//echo "tried $rndm... (skipping 100)\r\n";
   
if ($attempts % 1000 ==0 ) {
     echo
"tried $rndm... (skipping 1000)\r\n";
    }
   
//if the last bucket is 62, then we've tried them all
   
if ($fingerprint[ ($password_length-1)] == 62) {
        echo
"Tried every combination, maybe password isn't ".$password_length." chars long?\n";
       
//here is where you would increase password length, re-init fingerprint array
        //  if you didn't know the target length.
   
}

 }
 
$end = microtime(true);
 
$time = $end-$start;
 echo
"Password guessed ('".$rndm."') correctly after $attempts attempts and $time seconds";
 
?>

This code was modified from other people work.  I'm not certain what kind of license it's under, I would vote for BSD.
ircmaxell at gmail dot com
14.08.2007 17:48
In Response To AzuMao

I did some speed tests (1000 repetitions), and my results are slightly different (php 5.2.2).  Here's what I got for string 'string' (6 characters):
0.0065789222717285- MD5
0.0078611373901367- SHA1
0.00068497657775879- CRC32
0.0021169185638428- HASH(md5)
0.0026431083679199- HASH(sha1)
0.0014209747314453- HASH(CRC32)

for a 14000 character string however (a standard HTML page), here's the results
0.08871603012085- MD5
0.21350693702698- SHA1
0.062330007553101- CRC32
0.083562850952148- HASH(md5)
0.2072479724884- HASH(sha1)
0.060271978378296- HASH(CRC32)

So actually So actually, MD5 is significantly more efficient than SHA1.  Not to mention, that hash(func) seems to be faster than func...
dionyziz at deviantart dot com
11.08.2007 21:24
Sometimes it's useful to get the actual, binary, md5 digest.
You can use this function for it:

<?php

function md5bin( $target ) {
   
$md5 = md5( $target );
   
$ret = '';

    for (
$i = 0; $i < 32; $i += 2 ) {
       
$ret .= chr( hexdec( $md5{ $i + 1 } ) + hexdec( $md5{ $i } ) * 16 );
    }

    return
$ret;
}

?>
hans at somewhere dot com
27.07.2007 11:51
http://md5.rednoize.com offers a service to reverse engineer md5 hashes. Very useful if you got a md5 hash and need the plain text string of this md5 hash. The website has currently over 47 million hashes stored. It also has support for SHA-1 hashes.
the-master at supanet dot com
23.07.2007 11:33
@ me at dontemailme dot com

Your code takes ages to run mainly because it uses totally random characters, which in some cases don't exist because you have used chr() and rand() which can output very large numbers.

I think most people only use alphanumeric passwords so here is a code which is far quicker.  Where yours took 16 seconds mine took 2.  It still takes ages for large passwords though which is reassuring!  Also a hacker shouldn't know the password length meaning that the passwords are very secure with hashing.

<?php
set_time_limit
(0);

function
randomkeys($length)
{
   
$pattern = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
   
$key  = $pattern{rand(0,61)};
    for(
$i=1;$i<$length;$i++)
    {
       
$key .= $pattern{rand(0,61)};
    }
    return
$key;
}

if (isset(
$_GET['password'])){
$password = $_GET['password'];
$password_length = strlen($password);
}
else
{
$password_length = 3;
if (isset(
$_GET['length'])){
$password_length = $_GET['length'];}
$password = randomkeys($password_length);
}

echo
"Password is: $password <br />";
$password = md5($password);
$attempts = 0;
$start = microtime(true);
while (
$password != $guess){
$guess = md5(randomkeys($password_length));
$attempts++;
}
$end = microtime(true);
$time = $end-$start;
echo
"Password guessed correctly after $attempts attempts and $time seconds";
?>

I think this code is correct but hopefully someone will tell me if it isn't or change it.
AzuMao at gmail dot com
29.06.2007 3:53
Here is a far more accurate test if you are not going to be doing it over and over.

<?php
$time
=microtime(1);
hash('md5', 'string');
echo (
microtime(1)-$time)*10000,': hash/md5<br>';

$time=microtime(1);
md5('string');
echo (
microtime(1)-$time)*10000,': md5<br>';

$time=microtime(1);
hash('sha1', 'string');
echo (
microtime(1)-$time)*10000,': hash/sha1<br>';

$time=microtime(1);
sha1('string');
echo (
microtime(1)-$time)*10000,': sha1<br>';
?>

Outputs
0.11920928955078: hash/md5
0.090599060058594: md5
0.14066696166992: hash/sha1
0.050067901611328: sha1

Refresh it a few times and you will see that it is indeed consistant. sha1 is faster if you are not going to be using it over and over. I'm using this for etags in PHP and only need to use it once, so for me sha1 is faster.

Note that these times are all times by 10000 so that it shows up as a real number instead of something like

1.1920928955078E-5: hash/md5
8.1062316894531E-6: md5
1.4066696166992E-5: hash/sha1
5.9604644775391E-6: sha1

(to negative powers)
prodigysim
13.06.2007 23:35
I ran a small speed test of my own based on comments by sebastian dot haller at freesurf dot ch and tszming at gmail dot com.

bin2hex(md5('string', true)) performs faster than md5('string').

However, this binary speed boost does not apply for the hash() function.

<?php
$time
=microtime(1);
for (
$i=0;$i<100000;$i++)
  
hash('md5', 'string');
echo
microtime(1)-$time,': hash/md5<br>';

$time=microtime(1);
for (
$i=0;$i<100000;$i++)
  
md5('string');
echo
microtime(1)-$time,': md5<br>';

$time=microtime(1);
for (
$i=0;$i<100000;$i++)
  
bin2hex(hash('md5', 'string', TRUE));
echo
microtime(1)-$time,': bin/hash/md5<br>';

$time=microtime(1);
for (
$i=0;$i<100000;$i++)
  
bin2hex(md5('string', TRUE));
echo
microtime(1)-$time,': bin/md5<br>';
?>
Returns:
0.392316102982: hash/md5
0.725342035294: md5
0.421605110168: bin/hash/md5
0.483132839203: bin/md5
sebastian dot haller at freesurf dot ch
7.04.2007 9:06
It has been found, that hash('md5', 'string'); is faster than md5($string):

http://www.php.net/manual/en/function.hash.php
public at kreinacke dot com
29.03.2007 7:39
PHP's md5() function returns the exact same hash value as MySQL's MD5() function and other than stated before as the md5sum command line tool on most Linux/UNIX systems.
Note that trailing line feeds do matter, when you apply md5sum on a text file:

shell> php -r 'echo md5("test");'
--> 098f6bcd4621d373cade4e832627b4f6

mysql> select md5('test');
--> 098f6bcd4621d373cade4e832627b4f6

shell> echo -n test | md5sum
--> 098f6bcd4621d373cade4e832627b4f6

In the third example, note the '-n' option, which prevents echo from appending a line feed.
jlinkels at linkels dot net
27.03.2007 14:47
The PHP MD5() function does not encrypt a string in the same way as the standard *nix MD5SUM function.

If you want to access an encrypted string in a  MySQL database from different programs in *nix, and also from PHP, use the MySQL MD5() function, as in:

UPDATE users SET pwd=md5('mypass') WHERE user='myuser';

This will generate the same encrypted string as in PHP md5('mypass').

I am sure it has some security issues, especially if the traffic between the other application and MySQL can be eavesdropped, but for simple encrypted storage it works fine.
nicholas at nicholaswilliams dot info
15.11.2006 7:35
Agreed, tszming at gmail dot com. I did my own test using simple (letters) and complex (letters, numbers, symbols) strings of short, (6 characters), medium (a sentence), and long (three paragraphs) lengths. Overall, using

<?php

echo bin2hex( md5( $str, TRUE ) );

?>

versus just

<?php

echo md5( $str );

?>

ranges between 2x and 3x faster and yet return identical results. Good catch.
squeegee
11.10.2006 7:01
Regarding the md5_base64 function posted below, since the encoded string will never be longer than 64 characters (the maximum length of a base64 encoded line), and the fact that base64 strings only insert the '=' pad character at the end of an encoded line, instead of using preg_replace, you can just use rtrim.

$myhash=rtrim(base64_encode(pack("H*",md5($data))),"=");

This will result in a string of 22 characters, suitable for inserting in mysql or whatever. Also, if you are testing against the string in a query in mysql, make sure to use the keyword BINARY, as case matters.

The reason for the function in the first place (for me):
If you're currently using an md5 hash for a unique index, this will save at least 20 bytes for every record on disk (index + data) and 10 bytes in memory. If you have millions of rows, that can really add up (100 million rows would require about 1 less gigabyte of memory for your key_buffer_size variable in mysql).
maximius at gmail dot com
9.10.2006 7:38
This is just something I made while looking into MD5 and SHA-1, how they can be exploited, and whatnot.

   /**
    * crypto - Generates a hash made up of 40 letters and digits
    * by passing a source variable through a custom algorithm.
    * First it determines the CRC32, customizable crypt, and MD5
    * hashes for the source variable, and implodes them into one
    * string. This string can be seperated by another customizable
    * salt variable. Finally the SHA-1 hash of the original source
    * variable is calculated, with the imploded string appended
    * to the end of the source variable.
    */
   function crypto($source){
        $salt[0] = "something  here!";   // Limit this to 16 characters
        $salt[1] = "abcd";             // Limit this to 8 characters
        $crypt[0] = crc32($source);
        $crypt[1] = crypt($source, $salt[0]);
        $crypt[2] = md5($source);
        $crypt = implode($salt[1], $crypt);
        return sha1($source.$crypt);
    }

It works really well if you need a secure, custom hashing function. I hope it works for whatever you use it for!
seth at interwebforce dot com
6.10.2006 20:36
I made this simple script to beat MD5 crackers and it worked, so have fun. Its simple and effective.

<?php
$pass
= str_split("mypassword");
foreach (
$pass as $hashpass) {
$majorsalt .= md5($hashpass);
}
$corehash = md5($majorsalt);
echo
$corehash;
?>

Tested against rednoise and gdata md5 crackers.
coryostrudel at godcomplex dot com
17.05.2006 14:45
If you are storing your passwords with and MD5 hash and are worried about collisions, an approach I have used was to store two passwords for the user.

credentials
----------
userName
password
passwordChk

Where:
$input - users input password
$key - a site based key stored out of public folders

password = MD5($key.strrev($input))
passwordChk = MD5($input{0}.substr($input,(floor(strlen($input))/2),strlen))

This will stored the users password in the database as an MD5 hash of the string reversed plus a site based key stored out of public folders.

It also stores a check value to check that the input is the true input and not a colliding value.  The check takes the first character appends a substring of the input taking the last half of the input string and creates and MD5.

I think this is pretty secure.  It takes a modified salt & pepper approach, and follows up with a check on the original input to make sure it is not a colliding value, while also not storing the original password in plain text.
marzetti dot marco at NOSPAM dot gmail dot com
16.05.2006 12:12
The complement of raw2hex

<?php

function hex2raw( $str ){
 
$chunks = str_split($str, 2);
  for(
$i = 0; $i < sizeof($chunks); $i++ ) {
       
$op .= chr( hexdec( $chunks[$i] ) );
    }
    return
$op;
}

?>
mina86 at projektcode dot org
24.01.2006 21:01
Re: Andrew Nelless

I believe that HMAC was designed for some reason. I believe the reason was that <?php hmac_md5($salt, $password); ?> is more secure then <?php md5($salt . $password); ?>

Re: nathan at nathanbolender dot com

The 'Salt & Pepper Encrypter' is no more secure then standard sha1() function. It only adds some random chars to the hash but does nothing with the password's hash. In particular, its enought to remove 32 or 40 characters (depending on the length of the whole hash - 74 or 82 characters acordingly) from the hash starting with the character at position stored at the end of hash (last two digits). We get a 42-char long string which first 40 characters are SHA-1 of the password.
rick.gaither
20.12.2005 18:14
This is a nifty function to help in securing your web-forms.

If no argument is passed the function will return an encrypted hex code representing the second it was called. If the same hex code is passed to the function it will return the number of seconds that have elapsed. The php script can then check the time between accessing the web-page and submitting the POST. This thwarts script ran web-form submissions. The program can verify a suitable period has elapsed for expected manual entries. The time check can be from 1 second to about 17 hours.

The function requires the latest PEAR Blowfish Encryption module.

This would go in the form:
<?php  print "<input type='hidden' value='" . FormTimer() . "' name='FormCode'>"?>

This would go in the main php (post) script:
<?php
$seconds
= FormTimer($_POST['FormCode']);
if ((
$seconds < 10) || ($seconds > 1900)) { die "Your entry time took less than 10 seconds or more than 30 minutes"; }
?>

Function...
<?php
function FormTimer($CodeID="") {

    require (
'Blowfish.php');
    require (
'Blowfish/DefaultKey.php');

   
$key = "Secret^Word";
   
$bf = new Crypt_Blowfish($key);
    
$current = substr(sprintf("%d", (time()+1)),-8);

    if (!
$CodeID) { return bin2hex($bf->encrypt($current)); }

   
$len = strlen($CodeID); $cValue = -1;
    for (
$i=0;$i<$len;$i+=2) $Crypt.=chr(hexdec(substr($CodeID,$i,2)));

    if (
$Crypt) {
       
$time_called = $bf->decrypt($Crypt);
        if (
$time_called) { $cValue = (intval($current) - intval($time_called)); }
    }
    return
$cValue;
}
?>
Andrew Nelless ( anelless _ gmail _com )
17.12.2005 19:04
"mina86 at tlen dot pl"'s (19-Sept-05) HMAC-MD5 implementation is correct but his example usage provides little practical advantage over the simple concatenation and hash approach to salting.

$hash = md5($salt . $password);

On the other hand, a good use for a MAC (with a server side private key) would be to store one in the users cookie in order to verify that cookie's (or parts of them) you issue haven't been changed manually (or for that matter, by any other website (maybe via a XSS browser exploit?), MITM attack or evil proxy).

Such a trick allows you to put mildly critical data about a user, that you don't want changed by anyone but you, in their cookie rather than in your database. This could have advantages (openness, not needing to store user email addresses at the server side once they have been verified by email, even do away with the need to store data about a poster in a server side database altogether but still being able to allow these almost anonymous posters to come along and edit their submissions with confidence) and be rather entertaining (users trying to crack their cookie code to elevate their stats and/or permissions).

This is like issueing a passport. The traveller can see all of it,  get it stamped (~customise parts of it) but can also invalidate it and have it revoked. It can also save on expensive and time consuming nationality/immigration checks (~using the database) at the airport (~the server side).
Jon Watte
3.12.2005 5:11
Scrambling the md5 adds no security, because it only adds obscurity. md5 is a reasonably strong hash function, although it's recently been shown to be weaker than previously thought. If hashing your password with md5 isn't good enough for you, then you should use a stronger hash like Tiger instead -- not apply amateurish obfuscation that only serves to give you a false sense of security.

I don't know of an implementation of Tiger for PHP, but the algorithm is pretty simple (and secure) so you could probably write it in plain PHP code.
karig at karig dot net
30.11.2005 15:38
Scramble your hashes.

If you are worried about whether these hash functions are "good enough" for security and are tempted to combine hash functions to try to increase security, but you know that combining hashes might be counterproductive, then why not use md5() to get your hash string, then use a custom scramble function to rearrange the digits in that hash string?

Use this scramble function whenever a user is logging in: Encrypt the password with md5(), then with your scramble function, and compare the result with the pre-encrypted password stored on your server for that user.

Here is an example (you might decide to scramble the digits in a different order):

<?php
function scramble($p) {
   
// Assumes that $p is going to be 32 characters long

   
$q = $p{13} . $p{30} . $p{5} . $p{17} . $p{23} . $p{0}
        .
$p{28} . $p{4} . $p{18} . $p{25} . $p{6} . $p{20}
        .
$p{14} . $p{9} . $p{31} . $p{11} . $p{24} . $p{29}
        .
$p{10} . $p{3} . $p{15} . $p{26} . $p{8} . $p{12}
        .
$p{21} . $p{27} . $p{1} . $p{16} . $p{22} . $p{7}
        .
$p{19} . $p{2};
    return
$q;
}

$p = $_POST['password'];
// If the password is blank or too short, do something here.

$p = scramble(md5($p));
// Now set $s = scrambled password stored on server.
// If $p == $s then we have a match.
?>

You could even make the scramble function more elaborate by repeating certain arbitrary characters an arbitrary number of times, e.g., having scramble() insert $p(19) into $q three or four times, thus producing a string longer than 32 characters.
nathan at nathanbolender dot com
16.10.2005 21:31
If you're a security freak you might want to take a look at the 2 functions I have posted at http://code.nathanbolender.com/PHP/salt_pepper/ . It uses a hardcoded "key" and hashes it one of 2 ways, so you are always left with a random 'hash' to store in your database. The other function will check the hash against the original string to make sure that it is correct. If you want to see an example of the debug output you can at http://code.nathanbolender.com/PHP/salt/ . Note that on that page the "key" is random only to demonstrate the possibility for so much variations.

I know that a simple md5() would normally be enough, but I came up with this and I wanted to share it.
mina86 at tlen dot pl
19.09.2005 22:41
It seems that the best solution would be to use HMAC-MD5. An implementation of HMAC-SHA1 was posted by mark on 30-Jan-2004 02:28 as a user comment to sha1() function (-> http://php.net/manual/function.sha1.php#39492). Here's how it would look like (some other optimizations/modifications are included as well):

<?php
// Calculate HMAC according to RFC2104
// http://www.ietf.org/rfc/rfc2104.txt
function hmac($key, $data, $hash = 'md5', $blocksize = 64) {
  if (
strlen($key)>$blocksize) {
   
$key = pack('H*', $hash($key));
  }
 
$key  = str_pad($key, $blocksize, chr(0));
 
$ipad = str_repeat(chr(0x36), $blocksize);
 
$opad = str_repeat(chr(0x5c), $blocksize);
  return
$hash(($key^$opad) . pack('H*', $hash(($key^$ipad) . $data)));
}

// Remember to initialize MT (using mt_srand() ) if required
function pw_encode($password) {
 
$seed = substr('00' . dechex(mt_rand()), -3) .
   
substr('00' . dechex(mt_rand()), -3) .
   
substr('0' . dechex(mt_rand()), -2);
  return
hmac($seed, $password, 'md5', 64) . $seed;
}

function
pw_check($password, $stored_value) {
 
$seed = substr($stored_value, 32, 8);
  return
hmac($seed, $password, 'md5', 64) . $seed==$stored_value;
}

// Test
$password = 'foobar';
$encoded  = pw_encode($password);
$result   = pw_check ($password, $encoded) ? 'true' : 'false';
echo<<<END
password: $password
encoded :
$encoded
rsult   :
$result

END;
?>
eric at opelousas dot org
31.07.2005 23:57
Setting raw_output to TRUE has the same effect using pack('H*', md5($string)) in php 4

pack( 'H*' , md5( $string) ) ) == md5($string, TRUE)
Helpful Harry
30.06.2005 20:29
check out these functions to fake a sha1 entry using md5.  Very, very secure if attackers get your password file...
also, it encrypts differently for the same string, every time

function pw_encode($password)
{
   for ($i = 1; $i <= 8; $i++)
   $seed .= substr('0123456789abcdef', rand(0,15), 1);
   return md5($seed.$password).$seed;
}
function pw_check($password,$stored_value)
{
   $stored_seed = substr($stored_value,32,8);
   if (md5($stored_seed.$password).$stored_seed == $stored_value)
      return TRUE;
   else
      return FALSE;
}
tommiboy
3.05.2005 21:32
Regarding those many posts about MD5 and this-or-that hash function being "broken" or insecure because it has collisions, please note the following:
1. Every hash function has collisions, that is what hash functions are made for. MD5, as an example, turns N bits of input into 128 bits of output. Obviously, whenever N > 128 bits, then there MUST be collisions. This does not mean the function is broken, it means that the function does EXACTLY what you want it to do - it makes a secret unrecoverable.
The important thing about "secure" hash functions is that it is hard to calculate an input that will produce a certain output (e.g. the same output as another user's password). It is impossible to reconstruct a password from a hash if the password has more than 128 bits since several passwords necessarily map to the same hash. No matter which supercomputers you use, you have a set of equations with several unknowns. It is possible to find SOME password that produces a valid hash, though.
For every reasonable scenario, however, MD5 will do just fine. If you are concerned, store the password length as well.
2. Chaining the hash function means 128 bits of input producing 128 bits of output, this does not make sense, really. In fact, you greatly increase the likelihood of finding SOME password that produces the same double-hash.
3. Chaining MD5 with SHA makes little sense, too, as you feed 128 bits into a function that returns 256 bits. So the information that you keep around is 50% redundant. Security is in no way enhanced.
4. You can add "salt", i.e. a constant or variable string (for example calculated from the user id) that is concatenated to the input of the hash function, but that does not really make things a lot better. It does make a dictionary attack against a stolen password database harder, if nothing else.
5. Concerns about this-or-that hash being not good enough are rather silly since there are a lot of other ways which are by several orders of magnitude cheaper and easier to break into your system. It is not likely that any sane person will attempt to find collisions of a hash function to break into one single account. Users are only too happy to give out their password to "the administator who must verify that their password is correct".
6. What happens if two users accidentially choose passwords that have a hash collision? First, this will probably never happen, and second, if it does happen, then there is not much harm. Two users can have the same password and none of them will ever notice.
terry _at_ scribendi_com
29.04.2005 4:39
Do not use the hex strings returned by md5() as a key for MCrypt 256-bit encryption.  Hex characters only represent four bits each, so when you take 32 hex characters, you are only really using a 128-bit key, not a 256-bit one. 

Using an alphanumeric key generator [A-Za-z0-9] will also only provide a 192-bit key in 32 characters.

Two different MD5s concatenated in raw binary form, or mcrypt_create_iv(32,MCRYPT_DEV_RANDOM) will give you a true 256-bit key string.
Anonymous
20.02.2005 13:06
In response to the person who suggested concatenation of hashes, I believe that the hashing of a hash would be a better option.

$str = "secret";
$doublehash = sha1(md5($str));
ian at ianalbert dot com
16.02.2005 21:41
Concatenating two different hashes will decrease security.  Instead of an attacker having to crack one hash algorithm they now have the option of cracking either.  It's like a crime scene having one clue or several clues.  In security simplicity is usually the better approach.
John S.
3.12.2004 20:42
If you want to replicate CPAN Digest::MD5's function md5_base64 in PHP, use this code:

<?php

function md5_base64 ( $data )
{
    return
preg_replace('/=+$/','',base64_encode(pack('H*',md5($data))));
}

?>
Alexander Valyalkin
30.06.2004 22:41
Below is MD5-based block cypher (MDC-like), which works in 128bit CFB mode. It is very useful to encrypt secret data before transfer it over the network.
$iv_len - initialization vector's length.
0 <= $iv_len <= 512

<?php

function get_rnd_iv($iv_len)
{
   
$iv = '';
    while (
$iv_len-- > 0) {
       
$iv .= chr(mt_rand() & 0xff);
    }
    return
$iv;
}

function
md5_encrypt($plain_text, $password, $iv_len = 16)
{
   
$plain_text .= "\x13";
   
$n = strlen($plain_text);
    if (
$n % 16) $plain_text .= str_repeat("\0", 16 - ($n % 16));
   
$i = 0;
   
$enc_text = get_rnd_iv($iv_len);
   
$iv = substr($password ^ $enc_text, 0, 512);
    while (
$i < $n) {
       
$block = substr($plain_text, $i, 16) ^ pack('H*', md5($iv));
       
$enc_text .= $block;
       
$iv = substr($block . $iv, 0, 512) ^ $password;
       
$i += 16;
    }
    return
base64_encode($enc_text);
}

function
md5_decrypt($enc_text, $password, $iv_len = 16)
{
   
$enc_text = base64_decode($enc_text);
   
$n = strlen($enc_text);
   
$i = $iv_len;
   
$plain_text = '';
   
$iv = substr($password ^ substr($enc_text, 0, $iv_len), 0, 512);
    while (
$i < $n) {
       
$block = substr($enc_text, $i, 16);
       
$plain_text .= $block ^ pack('H*', md5($iv));
       
$iv = substr($block . $iv, 0, 512) ^ $password;
       
$i += 16;
    }
    return
preg_replace('/\\x13\\x00*$/', '', $plain_text);
}

/******************************************/
$plain_text = 'very secret string';
$password = 'very secret password';
echo
"plain text is: [${plain_text}]<br />\n";
echo
"password is: [${password}]<br />\n";

$enc_text = md5_encrypt($plain_text, $password);
echo
"encrypted text is: [${enc_text}]<br />\n";

$plain_text2 = md5_decrypt($enc_text, $password);
echo
"decrypted text is: [${plain_text2}]<br />\n";

?>
mina86 at tlen dot pl
26.02.2004 20:14
In respons to Emin Sadykhov at 14-Oct-2003 12:47:
The function presented by Emin isn't IMO simple, simpler is:
<?php
if (!function_exists('is_md5')) {
  function
is_md5($var) {
    return
preg_match('/^[A-Fa-f0-9]{32}$/',$var);
  }
}
?>
Morover (as I proved somewhere else) it's faster 'cuz preg_match() is faster then ereg()
brian_bisaillon at rogers dot com
26.02.2004 5:17
Source code to create SSHA passwords...

public function HashPassword($password)
{
  mt_srand((double)microtime()*1000000);
  $salt = mhash_keygen_s2k(MHASH_SHA1, $password, substr(pack('h*', md5(mt_rand())), 0, 8), 4);
  $hash = "{SSHA}".base64_encode(mhash(MHASH_SHA1, $password.$salt).$salt);
  return $hash;
}

Source code to validate SSHA passwords...

public function ValidatePassword($password, $hash)
{
  $hash = base64_decode(substr($hash, 6));
  $original_hash = substr($hash, 0, 20);
  $salt = substr($hash, 20);
  $new_hash = mhash(MHASH_SHA1, $password . $salt);
   if (strcmp($original_hash, $new_hash) == 0)
     ... do something because your password is valid ...
  else
    echo 'Unauthorized: Authorization has been refused for the credentials you provided. Please login with a valid username and password.';
    ... be sure to clear your session data ...
}

Note: The format is compatible with OpenLDAP's SSHA scheme if I'm not mistaken.
silasjpalmer at optusnet dot com dot au
14.02.2004 5:17
A user friendly example of hkmaly's XOR encryption / decryption functions which use MD5 hashing on the key.

<?php

 
function bytexor($a,$b,$l)
  {
   
$c="";
    for(
$i=0;$i<$l;$i++) {
     
$c.=$a{$i}^$b{$i};
    }
    return(
$c);
  }

  function
binmd5($val)
  {
    return(
pack("H*",md5($val)));
  }

  function
decrypt_md5($msg,$heslo)
  {
   
$key=$heslo;$sifra="";
   
$key1=binmd5($key);
    while(
$msg) {
     
$m=substr($msg,0,16);
     
$msg=substr($msg,16);
     
$sifra.=$m=bytexor($m,$key1,16);
     
$key1=binmd5($key.$key1.$m);
    }
    echo
"\n";
    return(
$sifra);
  }

  function
crypt_md5($msg,$heslo)
  {
   
$key=$heslo;$sifra="";
   
$key1=binmd5($key);
    while(
$msg) {
     
$m=substr($msg,0,16);
     
$msg=substr($msg,16);
     
$sifra.=bytexor($m,$key1,16);
     
$key1=binmd5($key.$key1.$m);
    }
    echo
"\n";
    return(
$sifra);
  }

// Example of usage...

$message = "This is a very long message, but it is very secret and important
and we need to keep the contents hidden from nasty people who might want to steal it."
;

$key = "secret key";

$crypted = crypt_md5($message, $key);
echo
"Encoded = $crypted<BR>"; // returns = `<H {.1{ɑђJV+߳je

$uncrypted = decrypt_md5($crypted, $key);
echo
"Unencoded = $uncrypted"; // returns This is a very long message (etc)

?>
mina86 at tlen dot pl
13.09.2003 2:41
In respons to paj at pajhome dot org dot uk @ 21-May-2003 03:20:
In many cases, there is only hash of password saved on server, so JavaScript script must return:  md5(md5(password) + random)  and server must compare it with  md5(saved_md5 + random).
However, it might be less secure then sending plain password. Let say someone gaind read only access to your database (it doesn't matter how he did it). With such access he can read each user's reacord so he knows each user username and hash of password. With that knowledge, all he must do to hack your site is connect to server, read the random number, calculate  md5(hash_of_password_which_he_has_stolen + random)   and send it to server. Be aware of this issue if you think your database is not secure enought.
paj at pajhome dot org dot uk
22.05.2003 0:20
Hi,

You can use the MD5 function in combination with a similar JavaScript function to protect user passwords for logins. The arrangement goes like this:

When the user requests the login page, the server generates a random number. It stores this in a session variable as well as sending to the client.

When the user clicks submit, JavaScript in the client computes md5(password + random).

The server can also generate this hash, because it already knows the password and random number. It uses this to check that the user entered the correct password.

The password has not been transmitted in the clear, and next login the random number will be different, so an attacker can't use a "replay attack".

JavaScript MD5 is available here: http://pajhome.org.uk/crypt/md5/

Paul
Shane Allen
15.04.2003 5:53
From the documentation on Digest::MD5:
md5($data,...)
This function will concatenate all arguments, calculate the MD5 digest of this "message", and return it in binary form.

md5_hex($data,...)
Same as md5(), but will return the digest in hexadecimal form.

PHP's function returns the digest in hexadecimal form, so my guess is that you're using md5() instead of md5_hex(). I have verified that md5_hex() generates the same string as PHP's md5() function.

(original comment snipped in various places)
>Hexidecimal hashes generated with Perl's Digest::MD5 module WILL
>NOT equal hashes generated with php's md5() function if the input
>text contains any non-alphanumeric characters.
>
>$phphash = md5('pa$$');
>echo "php original hash from text: $phphash";
>echo "md5 hash from perl: " . $myrow['password'];
>
>outputs:
>
>php original hash from text: 0aed5d740d7fab4201e885019a36eace
>hash from perl: c18c9c57cb3658a50de06491a70b75cd
dmarsh dot no dot spam dot please at spscc dot ctc dot edu
2.12.2002 23:27
Recommended readed: OpenSSL from O'reilly! It has chapters on SSL and PHP!! but it also covers cryptography in more depth (chapters 1 and 2 are highly recommended to all here!). It has lots of good information! Talks in depth about lots of stuff that I cannot begin to explain here.

MD5 is a repeatable hashes / digest process. Taking something of unknown size or content and reducing it to a known size but retaining a high degree of unknown content. A good hash / digest is said to alter the output significantly
changing ~50% of the bits in the "fixed-in-size" output stream) in the event of changing one bit (at random) from the "unknown-in-size" input stream (or even changing the length of the input stream by one bit*/byte, *=with padding if necessary)

MD5 is such a hash / digest. Other than that, it doesn't do much on it's own.

MD5 is a cheap way to test a file transfer (like a CRC32). If either the file or the MD5 is downloaded with errors, the chances that the MD5 of the file and the "PUBLIC" copy of the MD5 will match is highly unlikely. Both would have to error in a highly unpredictable way. However relying of MD5s as a way to validate that the file hasn't been tamptered with (tainted) is not good. If you can download the file from one place and a public MD5 from a second place, you at least are using a 3rd party method to attempt to validate the file's contents against tainting.

MD5 can ONLY be used to validate the contents against tainting if there is something secret (private) between the two end-points.

Lets examine MD5 in a typical and extremely effective email validating process. The two parties via a trusted method exchange a word / phrase / password (something private) that hopefully nobody else knows.

The first party publically composes an email with an MD5. But instead of sending that MD5. the MD5 is used against this word / phrase / password (private) in a Message Authentication Code (MAC), or better Hash-MAC (HMAC) (see http://www.rsasecurity.com/rsalabs/faq/2-1-7.html)

One way would be to MD5 the word / phrase / password (private) part and the public part (the message body) as two different MD5's. the MD5 the two MD5s together as a single MD5 and send the composite MD5 in the public.

The receiver can (using all available parts, the private part, public part and the composite MD5) authenicate (testing against the computed part) the message hasn't been tampered during transit. The message body and the composite MD5 is sent in plain text, yet the contents have been authenicated with a high level of confidence. No encryption was used.

MD5 is often used to authenicate parts of encrypted streams and thus is the reason why many confuse MD5 as encryption (or even authenication) rather than what it is. A hash / digest.

An alternate to MD5 is SHA1. The output size of SHA1 is a little bigger (I think 164bits). More bits, means a higher degree of complexity. 128 bits is concidered minimim by experts in the field.... For cipher lengths and symmetric key sizes (due to computational power now available for brute force attacks).

--Doug
mbabcock-php at fibrespeed dot net
27.06.2001 23:06
I must point out to all the people who read the notes this far that MD5 is _not_ encryption in a traditional sense.  Creating an MD5 digest (or hash) of a message simply creates 128 bits that can be used to almost positively identify that message or object in the future.  You use MD5 if you want to validate that information is true.  For example, you may ask a user to submit a message through a browser POST and save an MD5 of that message in a database for a preview function.  When the user submits it the second time, running the MD5 hash of the new version of the text and comparing it to the original MD5 in the database will tell you if the text has changed at all.  This is how MD5 is used -- it is _not_ for encrypting things so as to get the data back afterward -- the MD5 hash version does _not_ contain the data of the original in a new form.



PHP Powered Diese Seite bei php.net
The PHP manual text and comments are covered by the Creative Commons Attribution 3.0 License © the PHP Documentation Group - Impressum - mail("TO:Reinhard Neidl",...)