2

I have a java program (third party so can't edit) that is generating a Base64 encoded string from a MD5 hash. It's not being used for security reasons in this instance, more to get a unique value for the string provided for easy comparison later on.

I'm trying to generate the same Base64 string in my C# application so I can also use it for comparison later.

Here's the code and then I'll go into what I've tried.

Relevant parts of the Java program (pulled from the IntelliJ decompiler):

String encodedValue = 
encode("Lot#: 9999  ExpDate: Mar 6, 2020  Date: Apr 1, 2020  QtyD: 0.56  Chk: True  Int: 120  Mon: $90.00");


public static String encode(String password) throws IOException, NoSuchAlgorithmException, MessagingException {

ByteArrayOutputStream out = new ByteArrayOutputStream();

try {
    OutputStream encoder = MimeUtility.encode(out, "base64");
    try {
        byte[] encrypted = encrypt(password);
        encoder.write(encrypted);
        encoder.flush();
        return new String(out.toByteArray());
    catch(...) {}
catch(...){}
}


private static byte[] encrypt(String password) throws NoSuchAlgorithmException {
    MessageDigest algorithm = MessageDigest.getInstance("MD5");
    algorithm.reset();
    algorithm.update(password.getBytes());
    return algorithm.digest();
}

C# section

string input = 
"Lot#: 9999  ExpDate: Mar 6, 2020  Date: Apr 1, 2020  QtyD: 0.56  Chk: True  Int: 120  Mon: $90.00";

using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
{
    byte[] inputBytes = Encoding.GetEncoding(28591).GetBytes(input); //matches Java so far
    byte[] hashBytes = md5.ComputeHash(inputBytes);
    string base64 = Convert.ToBase64String(hashBytes);
}

If I run both input byte[] (password.getBytes() and Encoding.GetEncoding(28591).GetBytes(input)) through the Base 64 encoder, they both return the same value.

TG90IzogOTk5OSAgRXhwRGF0ZTogTWFyIDYsIDIwMjAgIERhdGU6IEFwciAxLCAyMDIwICBRdHlEOiAwLjU2ICBDaGs6IFRydWUgIEludDogMTIwICBNb246ICQ5MC4wMA==

This leads me to believe the encoding is correct between both of them.

If I inspect the encrypted byte[], the values don't match

Java byte[] value

C# byte[] value

Based on this and this I realized that Java uses signed numbers so the display output on the debugger really isn't going to match, but the actual values still should.

I tried using

for (byte b : bytes) {
    System.out.println(b & 0xFF);
}

to view the signed counterpart in c#, C# signed array but the arrays don't match still.

And for the final output, the base64 encoded strings

Java
0mfvZiQ7tDOnMsP/qH8CLQ==

C#
W2afrKbW3jHPMv7HHnc8nw==

I'm not sure if the MessageDigest is doing something additional in the encryption that I can't see to replicate, or if I'm missing something entirely.

I'm able to debug both sides so if any additional information would be helpful, let me know.

Any help would be greatly appreciated!

uni_brian
  • 31
  • 5
  • Out of curiosity, why are you using Base64 rather than the built in way of outputting bytes as hexadecimal characters? That would be done in a foreach loop with `String.format(%02X", b)` on the Java side and `b.ToString("x2")` on the C# side. – Powerlord Mar 06 '20 at 17:15
  • As a side note, I get "W2afrKbW3jHPMv7HHnc8nw==" from both Java 11 and C# 8 (using .NET Core 3.1) when testing this code. I'm using the most recent JavaMail jar from Github if that makes a difference. – Powerlord Mar 06 '20 at 17:43
  • `Encoding.GetEncoding(28591).GetBytes(input)` encodes the string as bytes [using the ISO 8859-1 charset](https://learn.microsoft.com/en-us/dotnet/api/system.text.encoding?view=netframework-4.8). `password.getBytes()` uses the system’s default charset—which usually is a cp-125x charset on Windows, but there is no guarantee of that. Try `Encoding.Default.GetBytes(input)` instead, to match the Java code’s behavior exactly. (I assume both the C# and the Java code are running on the same system.) – VGR Mar 06 '20 at 18:45
  • @Powerlord On the java side, that's what they chose to do, unfortunately I;m unable to make any changes to that code. This is using Java 8 and I'm using .NET Standard 2.0 currently. This could be changed to Core if necessary. – uni_brian Mar 06 '20 at 19:19
  • @VGR This is both on the same system, I'll give your suggestion a shot. I picked GetEncoding(28591) because when I dug into the java.lang.StringCoding that password.getBytes() pointed to, the encoding it returned was ISO-8859-1 – uni_brian Mar 06 '20 at 19:22

0 Answers0