MD5加密PHP手册
MD5是在Web应用程序中最常用的密码加密算法。由于MD5是不可逆的,因而经过MD5计算得到后的密文,不能通过逆向算法得到原文。
回顾在Web应用程序中使用MD5加密文本密码的初衷,就是为了防止数据库中保存的密码不幸泄露后被直接获得。但攻击者不但拥有数据量巨大的密码字典,而且建立了很多MD5原文/密文对照数据库,能快速地找到常用密码的MD5密文,是破译MD5密文的高效途径。然而,MD5密文数据库所使用的是最常规的MD5加密算法:原文-->MD5-->密文。因此,我们可以使用变换的MD5算法,使现成的MD5密文数据库无所作为。
下面演示一些变换算法的例子
当然,在其它的Web开发语言中,也大同小异,完全能得到相同的结果。
变换一:循环MD5
最容易理解的变换就是对一个密码进行多次的MD5运算。自定义一个函数,它接受$data和$times两个形参,第一个是要加密的密码,第二个是重复加密的次数。实现这种变换有两种算法——
<?php
//迭代算法
function md5_1_1($data, $times = 32)
{
//循环使用MD5
for ($i = 0; $i < $times; $i++) {
$data = md5($data);
}
return $data;
}
//递归算法
function md5_1_2($data, $times = 32)
{
if ($times > 0) {
$data = md5($data);
$times--;
return md5_1_2($data, $times); //实现递归
} else {
return $data;
}
}
?>
变换二:密文分割MD5
尽管用户的密码是不确定的字符串,但是只要经过一次MD5运算后,就会得到一个由32个字符组成的字符串,这时可以再针对这个定长字符串变换。有点BT的算法是,把这段密文分割成若干段,对每段都进行一次MD5运算,然后把这堆密文连成一个超长的字符串,最后再进行一次MD5运算,得到仍然是长度为32位的密文。
<?php
//把密文分割成两段,每段16个字符
function md5_2_1($data)
{
//先把密码加密成长度为32字符的密文
$data = md5($data);
//把密码分割成两段
$left = substr($data, 0, 16);
$right = substr($data, 16, 16);
//分别加密后再合并
$data = md5($left).md5($right);
//最后把长字串再加密一次,成为32字符密文
return md5($data);
}
//把密文分割成32段,每段1个字符
function md5_2_2($data)
{
$data = md5($data);
//循环地截取密文中的每个字符并进行加密、连接
for ($i = 0; $i < 32; $i++) {
$data .= md5($data{$i});
}
//这时$data长度为1024个字符,再进行一次MD5运算
return md5($data);
}
?>
当然,这种密文分割的具体算法是数之不尽的,比如可以把原密文分割成16段每段两字符、8段每段4字符,或者每一段的字符数不相等……
变换三:附加字符串干涉
在加密过程的一个步骤中,附加一个内容确定的字符串(比如说用户名),干涉被加密的数据。不可以用随机字串,因为这样会使原算法无法重现。这种算法在某些情况下是很具有优势的,比如说用于大量的用户密码加密,可以把用户名作为附加干涉字串,这样攻击者就算知道你的算法,也很难从他们手中的字典中一下子生成海量的对照表,然后大量地破译用户密码,只能有针对性的穷举为数不多的用户。
<?php
//附加字符串在原数据的尾部
function md5_3_1($data, $append)
{
return md5($data.$append);
}
//附加字符串在原数据的头部
function md5_3_2($data, $append)
{
return md5($append.$data);
}
//附加字符串在原数据的头尾
function md5_3_3($data, $append)
{
return md5($append.$data.$append);
}
?>
变换四:大小写变换干涉
由于PHP所提供的md5()函数返回的密文中的英文字母全部都是小写的,因此我们可以把它们全部转为大写,然后再进行一次MD5运算。
<?php
function md5_4($data)
{
//先得到密码的密文
$data = md5($data);
//再把密文中的英文母全部转为大写
$data = strtotime($data);
//最后再进行一次MD5运算并返回
return md5($data);
}
?>
变换五:字符串次序干涉
把MD5运算后的密文字符串的顺序调转后,再进行一次MD5运算。
<?php
function md5_5($data)
{
//得到数据的密文
$data = md5($data);
//再把密文字符串的字符顺序调转
$data = strrev($data);
//最后再进行一次MD5运算并返回
return md5($data);
}
?>
变换六、变换七、变换八……
MD5变换算法是数之不尽的,甚至无须自己再去创造,就用上面的五个互相组合就可以搞出很BT的算法。比如说先循环加密后再分割,并在每一段上附加一个字符串再分别加密,然后变换大小写并颠倒字符串顺序后连成一个长字符串再进行MD5运算……
如果真的很不幸,由于某些漏洞,比如说SQL Injection或者文件系统中的数据库被下载而异致用户密码数据暴露,那么MD5变换算法就能大大地增加破译出密码原文的难度,首先就是使网上很多的MD5原文/密文对照数据库(要知道,这是破译MD5最高效的方法)没有用了,然后就是使攻击者用常规算法去穷举一串由变换算法得到的密文而搞得焦头烂额。当然,MD5变换算法特别适合用于非开源的Web程序使用,虽说用在开源的程序中优势会被削弱(大家都知道算法),但是也能抑制MD5原文/密文对照数据库的作用。要进行这些复杂的变换运算,当然就要花费的更多的系统开销了,然而对于安全性要求很严格的系统来说,多付出一些来换取高一点的安全性,是完全值得的。
md5
(PHP 3, PHP 4, PHP 5)
md5 -- Calculate the md5 hash of a string
Description
string md5 ( string str [, bool raw_output] )
Calculates the MD5 hash of str using the RSA Data
Security, Inc. MD5 Message-Digest Algorithm, and returns
that hash. The hash is a 32-character hexadecimal
number. If the optional raw_output is set to TRUE,
then the md5 digest is instead returned in raw binary
format with a length of 16.
注: The optional raw_output parameter was added in
PHP 5.0.0 and defaults to FALSE
例子 1. A md5() example
<?php
$str = 'apple';
if (md5($str) === '1f3870be274f6c49b3e31a0c6728957f')
{
echo "Would you like a green or red apple?";
exit;
}
?>
See also crc32(), md5_file(), and sha1().
add a note User Contributed Notes
tszming at gmail dot com
31-Oct-2006 12:47
The following method, is about 3x faster than md5('apple');
$hash = bin2hex( md5('apple', true) ) ;
squeegee
11-Oct-2006 01: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
09-Oct-2006 01: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
07-Oct-2006 02: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-May-2006 08: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-May-2006 06: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
25-Jan-2006 04: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
21-Dec-2005 01: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 )
18-Dec-2005 02: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
03-Dec-2005 12: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-Nov-2005 10: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
17-Oct-2005 03: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
20-Sep-2005 04: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
01-Aug-2005 05: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
01-Jul-2005 02: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
04-May-2005 03: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-Apr-2005 10: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.
gigabyte0 at NOSPAM dot gmail dot com
07-Mar-2005 03:22
I would think that this would create a slightly mode
secure hash by using this:
<?php
function hash($text){
$hashtext = "string";
return md5($text.$hashtext)
}
?>
If you can keep the $hashtext secure.
Anonymous
20-Feb-2005 08: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
17-Feb-2005 04: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.
functionifelse at gmail dot com
10-Dec-2004 12:34
Here is a function to convert raw md5 to hex md5:
<?
function raw2hex($s){
for($i = 0; $i < strlen($s); $i++){
$op .= str_pad(dechex(ord($s[$i])),2,"0",STR_PAD_LEFT);
}
return $op;
}
?>
Where $s is the raw md5 input.
John S.
04-Dec-2004 03: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
01-Jul-2004 04: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
27-Feb-2004 03: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-Feb-2004 12: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-Feb-2004 12: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-Sep-2003 08: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.
marc at NOSPAM dot giombetti dot com
08-Aug-2003 12:18
I use md5 to create a string that will be valid for
X seconds!
One may use this function for cacheing reasons or
even timeout functionality in a script.
/**
* valid_for_x_minutes() : Gernates an md5 hash that
will be the same for $timeout minutes
* This function was intitialy used in combination
with jpGraph to allow cacheing of multiple
* charts for a specified time.
*
* @param $timeout - Timeout in minutes
* @param $optional - An optional string to include
to in the md5 string
* @return
*/
function valid_for_x_minutes($timeout,$optional){
if($timeout != "0"){
$hours = date("H");
$minutes = date("i");
$tmpval = ceil($minutes/$timeout)*$timeout;
if(!empty($optional)){
return md5("$tmpval$optional");
}else{
return md5("$tmpval");
}
}else{
return md5(time());
}
}
paj at pajhome dot org dot uk
22-May-2003 06: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-Apr-2003 11: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
03-Dec-2002 06: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
karlos dot gustavo at terra dot com dot br
01-Oct-2002 12:09
simple slappaswd MD5 hash generation:
$ldap_passwd = "{md5}".base64_encode(pack("H*",md5($password)));
mbabcock-php at fibrespeed dot net
28-Jun-2001 05: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.
|