views:

216

answers:

3

I'm trying to create a PHP version of an existing JSP program, however I'm stuck at the password encryption part.

Could you please tell me how to convert this one? I know it tries to get the md5() but after that, I don't get it. I get lost in the Stringbuffer and for() parts.

Can you help me out?

 public static String encryptPassword( String password ) 
 {
     String encrypted = "";
     try
     {
        MessageDigest digest = MessageDigest.getInstance( "MD5" ); 
        byte[] passwordBytes = password.getBytes( ); 

        digest.reset( );
        digest.update( passwordBytes );
        byte[] message = digest.digest( );

        StringBuffer hexString = new StringBuffer();
        for ( int i=0; i < message.length; i++) 
        {
            hexString.append( Integer.toHexString(
                0xFF & message[ i ] ) );
        }
        encrypted = hexString.toString();
     }
     catch( Exception e ) { }
     return encrypted; 
 }
+1  A: 

It converts the MD5 hash to a string hexadecimal numbers of the least significan byte of the character. In Java all chars are 2 bytes.

In practice this means just the ASCII value.

Peter Tillemans
What does it exactly mean in PHP? Is it calling an md5() then an ord() to each character generated from the md5?
Obay
I guess bin2hex(md5(password,true)) should come close
Peter Tillemans
Thanks, but it gives the same output as md5()
Obay
+1  A: 
<?php
$password = "MyPass";
$hash = md5($password);
?>

UPDATE: There are some discrepancies between the two versions. To fix this see @bobince answer.Here is the test code:

Java

package tests;

import java.security.MessageDigest;

/**
 * Created by IntelliJ IDEA.
 * User: Iraklis
 * Date: 2 Ιουν 2010
 * Time: 2:15:03 μμ
 * To change this template use File | Settings | File Templates.
 */
public class Md5Test {
    public static String encryptPassword(String password) {
        String encrypted = "";
        try {
            MessageDigest digest = MessageDigest.getInstance("MD5");
            byte[] passwordBytes = password.getBytes();

            digest.reset();
            digest.update(passwordBytes);
            byte[] message = digest.digest();

            StringBuffer hexString = new StringBuffer();
            for (int i = 0; i < message.length; i++) {
                hexString.append(Integer.toHexString(
                        0xFF & message[i]));
            }
            encrypted = hexString.toString();
        }
        catch (Exception e) {
        }
        return encrypted;
    }

    public static void main(String[] args) {
        System.out.println("Pass1 md5 = " + encryptPassword("Test123FORXTREMEpass"));
        System.out.println("Pass1 md5 = " + encryptPassword("Ijdsaoijds"));
        System.out.println("Pass1 md5 = " + encryptPassword("a"));
        System.out.println("Pass1 md5 = " + encryptPassword(" "));
    }

}


Output:
Pass1 md5 = dc3a7b42a97a3598105936ef22ad2c1
Pass1 md5 = df7ca542bdbf7c4b8776cb21c45e7eef
Pass1 md5 = cc175b9c0f1b6a831c399e269772661
Pass1 md5 = 7215ee9c7d9dc229d2921a40e899ec5f

PHP

<?php
echo "Pass1 md5 = ".md5("Test123FORXTREMEpass")."<BR>";
echo "Pass2 md5 = ".md5("Ijdsaoijds")."<BR>";
echo "Pass3 md5 = ".md5("a")."<BR>";
echo "Pass4 md5 = ".md5(" ")."<BR>";
?>

output:

Pass1 md5 = dc3a7b42a97a35981059036ef22ad2c1
Pass2 md5 = df7ca542bdbf7c4b8776cb21c45e7eef
Pass3 md5 = 0cc175b9c0f1b6a831c399e269772661
Pass4 md5 = 7215ee9c7d9dc229d2921a40e899ec5f
Iraklis
Doesn't seem to be just an md5() because I checked the generated passwords in the database and they aren't 32 characters. the lengths range from 29 to 32..
Obay
was just about to test it . hold on
Iraklis
Obay, you are right some hashes are not identical.
Iraklis
The Java output is clearly wrong, it is missing some `0`​s.
bobince
dude, pass1 and pass3 are not the same. java's pass1 has removed one zero. java's pass3 has removed the first zero.
Obay
+3  A: 

Iraklis should be right. md5() gives you a hex-encoded output string by default. You only get the unencoded bytes like in Java by passing in TRUE for the optional $raw_output argument.

the lengths range from 29 to 32

Then your Java code has a bug. MD5 hashes are always 128 bits (32 hex digits). Here it is:

hexString.append( Integer.toHexString(0xFF & message[ i ] ) );

this will generate 1 instead of 01 for all bytes below 16. What you have stored is a mangled hash, from which you cannot recover the original MD5 value. If you absolutely must keep this broken data, you will have to reproduce the bug in PHP:

function makeBrokenMD5($s) {
    $hash= md5($s, TRUE);
    $bytes= preg_split('//', $hash, -1, PREG_SPLIT_NO_EMPTY);
    $broken= '';
    foreach ($bytes as $byte)
        $broken.= dechex(ord($byte));
    return $broken;
}
bobince
bobince, spot on, just tested it produces the broken java hashes.
Iraklis
i tested too! thanks dude!
Obay