1

Answered with the help of @JonSkeet

Given this code:

    Dim data1ToHash As Byte() = (New UnicodeEncoding).GetBytes(input)
    ' 2. Hash the byte array
    Dim hashvalue1 As Byte() = CType(CryptoConfig.CreateFromName("MD5"), HashAlgorithm).ComputeHash(data1ToHash)

Shouldn't this PHP produce the correct hash?

$md5 = (md5(utf8_encode($signature), true));

I tried, but the md5sums aren't matching up. I assumed it was encoding, but perhaps it has to do with the byte array, can anyone shed some light on this? FYI I can't change the VB

To compare the results:

in .Net

For Each b As Byte In hashvalue1
  tb.Text = tb.Text & b.ToString() & ","
Next
tb.Text = tb.Text.Trim(",")

in PHP

print_r(unpack('C*', pack('H*', md5($signature))))

as per another question

2

2 Answers 2

4

It's not clear how you're comparing the results, but the encoding is *definitely a problem - you're using UTF-16 in the VB code, and UTF-8 in the PHP. You can change the VB code like this:

Dim data1ToHash As Byte() = Encoding.UTF8.GetBytes(input)

The MD5 part can also be simplified, giving this result:

Dim unhashed As Byte() = Encoding.UTF8.GetBytes(input)
Dim hashed As Byte() = MD5.Create().ComputeHash(unhashed)

EDIT: If you can't change the VB, you need to change the PHP to use UTF-16, potentially with mbstring as suggested in comments. You'll need to know what the existing encoding is, of course...

Sign up to request clarification or add additional context in comments.

6 Comments

Good point, I'll update the post, but I'm afraid I can't change the VB.
@scottkf You could probably use mbstring from your PHP to convert from UTF8 to UTF16.
@jon-skeet then shouldn't the following produce correct results? $string = mb_convert_encoding(utf8_encode($signature), 'UTF-8', 'UTF-16'); $md5 = (md5($string, true));
@scottkf: No, because you're then still encoding the UTF-16 version as UTF-8 (in a way which is broken, actually, as the input to utf8_encode expects iso-8859-1) before passing it to md5. Without the final utf8_encode that might be okay. But I don't know enough about PHP's string representation to know for sure.
@JonSkeet: The problem was in the representation of the bytes. VB.net was using LE for UTF-16, whereas PHP's UTF-16 is actually big endian. The solution is: $string = mb_convert_encoding($signature, 'UTF-16LE', 'UTF-8'); $encoded_signature = base64_encode(md5($string, true)); It was verified by doing: $raw = unpack('C*', $string); print_r($raw);
|
0

The solution had to do with byte ordering: .NET in UTF-16 was Little Endian, whereas PHP's default UTF-16 encoding is Big Endian. So the answer is:

mb_internal_encoding('UTF-8');
$string = mb_convert_encoding($signature, 'UTF-16LE', 'UTF-8');
$encoded_signature = base64_encode(md5($string, true));

To verify, I compared the UTF-16 encoded bytes in PHP and .NET:

print_r(unpack('C*', $string));

Just that simple. Thanks to everyone who helped, especially @JonSkeet.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.