5

EDIT

I changed $checksum = md5($someString+$bkey); to $checksum = md5($someString.$bkey);

I need to perform the following operations in Java:

$hexString = '90aa';#sample value
$bkey = pack('H*',$hexString);
$someString='qwe';#sample value
$checksum  = md5($someString.$bkey);
echo $checksum;

I can't convert hexString to bkey in Java to get the same result as php script. Except bkey everything is working properly.

If I remove bkey then:

PHP:

$someString='qwe';#sample value
$checksum  = md5($someString);
echo $checksum;

result: 76d80224611fc919a5d54f0ff9fba446

Java:

String someString = "qwe";
        MessageDigest messageDigest = MessageDigest.getInstance("MD5");
        String checksum = new BigInteger(1, messageDigest.digest(someString
                .getBytes())).toString(16);
        System.out.println(checksum);

result: 76d80224611fc919a5d54f0ff9fba446

As you can see, it works

With bkey:

PHP:

$hexString = '90aa';#sample value
$bkey = pack('H*',$hexString);
$someString='qwe';#sample value
$checksum  = md5($someString.$bkey);
echo $checksum;

result: 18f5f1a9bf898131945dd9e315759fe4

Java:

public static void main(String[] args) throws NoSuchAlgorithmException {
        String hexString = "90aa";
        String bkey = hexToString(hexString);
        String someString = "qwe";
        MessageDigest messageDigest = MessageDigest.getInstance("MD5");
        String input = someString + bkey;
        String checksum = new BigInteger(1, messageDigest.digest(input
                .getBytes())).toString(16);
        System.out.println(checksum);
    }
    public static String hexToString(String hex) {
        StringBuilder output = new StringBuilder();
        for (int i = 0; i < hex.length(); i += 2) {
            String str = hex.substring(i, i + 2);
            output.append((char) Integer.parseInt(str, 16));
        }
        return output.toString();
    }

result: 44bb634dee436833dd65caa5043ffeb9

As you can see results are different.

How to convert hex String to String to get the same result?

Mariusz
  • 1,907
  • 3
  • 24
  • 39
  • 1
    possible duplicate of [Convert a string representation of a hex dump to a byte array using Java?](http://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java) – Joni Sep 22 '13 at 13:40
  • @Joni It also gives different result so it is not duplicate. – Mariusz Sep 22 '13 at 13:51
  • The output of `String.getBytes()` depends on the default charset. You should work directly on byte arrays. – nwellnhof Sep 22 '13 at 14:01
  • @nwellnhof What do you mean? If as input to md5 I use `byte[] result=ArrayUtils.addAll(someString.getBytes(), bkey);` , where `bkey` is byte array then I also get wrong result. To calculate `bkey` I used [Convert a string representation of a hex dump to a byte array using Java?](http://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java) from Joni's comment – Mariusz Sep 22 '13 at 15:10
  • 1
    No, you're converting the hex string to another string first which you convert to a byte array afterwards. Try to convert it directly to a byte array like explained in the other question. – nwellnhof Sep 22 '13 at 15:26
  • @nwellnhof Your answer with rotfil's answer solve my problem. – Mariusz Sep 22 '13 at 15:41

1 Answers1

5

The problem is not actually in your Java code, but in the PHP code.

The line $checksum = md5($someString+$bkey); does not do what you think it does, it should be:

$checksum  = md5($someString . $bkey);  # use concatenate, not sum

Although, that gives abetter PHP MD5, but does not help make the Java code match the PHP

EDIT

The problem on the Java side is in the character encoding. The Java char values for the inoacked versions of 90aa are not valid unicode characters. Thus the toByteArray() ,ethods ar enot doing great things. If you treat all of the Java code at a byte level (and ignore any high-bytes in any chars in the Java), then you get the same result as the PHP:

public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
    String hexString = "90aa";
    byte[] bkey = hexToString(hexString);
    String someString = "qwe";
    MessageDigest messageDigest = MessageDigest.getInstance("MD5");
    byte[] input = join(stringToBytes(someString), bkey);
    String checksum = new BigInteger(1, messageDigest.digest(input)).toString(16);
    System.out.println(checksum);
    System.out.println(Charset.defaultCharset().displayName());
}

private static byte[] join(byte[] a, byte[] b) {
    // join two byte arrays
    final byte[] ret = new byte[a.length + b.length];
    System.arraycopy(a, 0, ret, 0, a.length);
    System.arraycopy(b, 0, ret, a.length, b.length);
    return ret;
}

public static byte[] hexToString(String hex) {
    // hexToString that works at a byte level, not a character level
    byte[] output = new byte[(hex.length() + 1) / 2];
    for (int i = hex.length() - 1; i >= 0; i -= 2) {
        int from = i - 1;
        if (from < 0) {
            from = 0;
        }
        String str = hex.substring(from, i + 1);
        output[i/2] = (byte)Integer.parseInt(str, 16);
    }
    return output;
}
public static byte[] stringToBytes(final String input) {
    // unlike Stirng.toByteArray(), we ignore any high-byte values of the characters.
    byte[] ret = new byte[input.length()];
    for (int i = input.length() - 1; i >=0; i--) {
        ret[i] = (byte)input.charAt(i);
    }
    return ret;
}

The above Java code produces the MD5sum 18f5f1a9bf898131945dd9e315759fe4 which is what PHP gives too

rolfl
  • 17,539
  • 7
  • 42
  • 76
  • Thank you very much, your comment is very important. – Mariusz Sep 22 '13 at 15:27
  • This answer is not complete so I can not accept it. If you could edit your answer that I should use nwellnhof' comment then I will accept your answer. – Mariusz Sep 22 '13 at 15:45
  • Yeah, the problem intrigued me ... I am not a PHP programmer, so I used it as a learning exercise .... the results now match – rolfl Sep 22 '13 at 15:51