views:

233

answers:

3

We were sent this formula to encrypt a string written in Java:

String        myInput = "test1234";
MessageDigest      md = MessageDigest.getInstance("SHA");
byte[]            myD = md.digest(myInput.getBytes());
BASE64Encoder    en64 = new BASE64Encoder();
String       myOutput = new String ( 
                            Java.net.URLEncoder.encode( en64.encode(myD)));
// myOutput becomes "F009U%2Bx99bVTGwS3cQdHf%2BJcpCo%3D"

Our attempt at writing this in C# is:

System.Security.Cryptography.SHA1 sha1 = 
    new System.Security.Cryptography.SHA1CryptoServiceProvider();
string myOutput = HttpUtility.UrlEncode( 
                      Convert.ToBase64String( 
                          sha1.ComputeHash( 
                              ASCIIEncoding.Default.GetBytes(myInput))));

However the output is no where near the same. It doesn't even have percent signs in it. Any chance anyone would know where we are going wrong?

+4  A: 

In your C# version, I would suggest trying UTF8Encoding, UnicodeEncoding or UTF32Encoding rather than your current ASCIIEncoding.

Java's String.getBytes method uses the platform's default encoding if you don't specify one (and you don't). The platform's default encoding is unlikely to be ASCII.

LukeH
+2  A: 

I would suggest you break this down.

1- Compare what you get back from the Java String.getBytes() and .NET Encoding.GetBytes() Here is some .NET code that will dump the bytes for your string for every encoding, compare the results with those from Java.

string myInput = "test1234";
foreach (EncodingInfo ei in Encoding.GetEncodings())
{
  byte[] bytes = ei.GetEncoding().GetBytes(myInput);
  Console.WriteLine("{0}\t\t{1}", 
    BitConverter.ToString(bytes), ei.DisplayName);
}

2- If you find the right encoding from step 1, move to the next step. Compare the SHA1 hashes for the same bytes in Java and .NET. This should match, but I like to be methodical and never seldom make assumptions especially when they are quick and easy to verify.

3- Once you have shown you have the same SHA1 bytes, you can do the Base 64 encoding and compare.

4- Finally perform the Url encoding, if you got this far I suspect you will find a difference in casing. IIRC .NET Url encode uses lower case, and from your sample I see Java is using upper case, for example %3D in Java will probably be %3d in .NET.

Chris Taylor
+2  A: 

Like LukeH says you can try changing the encoding in the C# version to Encoding.Default.GetBytes(myInput) if you run both the Java version and the C# version on the same machine.

If that fails or isn't an option you can always try printing the byte values and compare it to the respective step in Java just to find out where the error lies:

String myInput = "test1234";
System.Security.Cryptography.SHA1 crypto = new System.Security.Cryptography.SHA1CryptoServiceProvider();
Byte[] myInputBytes = Encoding.Default.GetBytes(myInput);
Console.WriteLine(BitConverter.ToString(myInputBytes));
Byte[] hash = crypto.ComputeHash(myInputBytes);
Console.WriteLine(BitConverter.ToString(hash));
Don