System.Security.Cryptography.MD5.Create( ??? )

  • Thread starter Thread starter Jonathan Wood
  • Start date Start date
J

Jonathan Wood

Does anyone know why the documentation for
System.Security.Cryptography.MD5.Create() seems to omit completely any
description of allowed arguments.

I'm trying to convert some C++ code to C# and seem to be getting different
MD5 results. If other algorithms are available, maybe that is related to the
problem I'm having. But the docs for this method don't tell me anything
about what algorithms are supported?

Thanks.
 
Jonathan Wood said:
Does anyone know why the documentation for
System.Security.Cryptography.MD5.Create() seems to omit completely any
description of allowed arguments.

I'm trying to convert some C++ code to C# and seem to be getting different
MD5 results. If other algorithms are available, maybe that is related to the
problem I'm having. But the docs for this method don't tell me anything
about what algorithms are supported?

MD5 *is* the algorithm - the version which accepts names of different
implementations of the algorithm should by and large be ignored.

Could you post a short but complete program which demonstrates the
problem you're having? I wouldn't be surprised if it were to do with
converting the data you've got into a binary form to be hashed in the
first place.
 
Actually, it's part of some rather complex code used to create shareware
authorization licenses so I can't really post a complete program here. But a
key part calculates a 32-bit checksum of a string and looks something like
this (I'm still trying to figure out what's available in the CRT). This is
designed to duplicate some existing C++ code where each character is
converted to a WORD (so I get the same result in both multibyte and Unicode
versions). The result is then computed by adding all four DWORDs of the
result, which is a bit awkward in C#.

UInt32 CalcCheckSum(string s)
{
MD5 md5 = MD5.Create();
// md5.Initialize();
byte[] data = StringToByteArray(s);
data = md5.ComputeHash(data);

UInt32 result = 0;
for (int i = 0; i < data.Length; i += sizeof(UInt32))
result += ByteArrayToDword(data, i);
return result;
}

byte[] StringToByteArray(string s)
{
byte[] b = new byte[s.Length << 1];
for (int i = 0; i < s.Length; i++)
{
b[i << 1] = (byte)s;
b[(i << 1) + 1] = (byte)(s >> 8);
}
return b;
}

UInt32 ByteArrayToDword(byte[] b, int startIndex)
{
return (UInt32)(b[startIndex] |
b[startIndex + 1] << 8 |
b[startIndex + 2] << 16 |
b[startIndex + 3] << 24);
}
 
Jonathan Wood said:
Actually, it's part of some rather complex code used to create shareware
authorization licenses so I can't really post a complete program here. But a
key part calculates a 32-bit checksum of a string and looks something like
this (I'm still trying to figure out what's available in the CRT). This is
designed to duplicate some existing C++ code where each character is
converted to a WORD (so I get the same result in both multibyte and Unicode
versions). The result is then computed by adding all four DWORDs of the
result, which is a bit awkward in C#.

UInt32 CalcCheckSum(string s)
{
MD5 md5 = MD5.Create();
// md5.Initialize();
byte[] data = StringToByteArray(s);
data = md5.ComputeHash(data);

UInt32 result = 0;
for (int i = 0; i < data.Length; i += sizeof(UInt32))
result += ByteArrayToDword(data, i);
return result;
}

So, the first thing to check is whether the data that you're hashing is
exactly the same. My guess is that that's the problem.

I suggest you print out the content of data before calling ComputeHash
- just print each byte out as an integer in both your C++ code and the
C# code.

Now to make your code easier:

StringToByteArray can be replaced with Encoding.Unicode.GetBytes(data)
ByteArrayToDword can be replaced with BitConverter.ToUInt32(data, i)

If you need to do bit conversion with a different endianness, I have an
EndianBitConverter in my misc util library:
http://www.pobox.com/~skeet/csharp/miscutil
 
Dangit! Unbelievably, C++ code that I've been using for several years had a
bug where it only looked at the first 4 bytes of the 16 bytes of MD5 hash
data. After many hours, I managed to isolate this and I get the same result
when I do the same in my C# code.

Thanks!

--
Jonathan Wood
SoftCircuits Programming
http://www.softcircuits.com

Jon Skeet said:
Jonathan Wood said:
Actually, it's part of some rather complex code used to create shareware
authorization licenses so I can't really post a complete program here.
But a
key part calculates a 32-bit checksum of a string and looks something
like
this (I'm still trying to figure out what's available in the CRT). This
is
designed to duplicate some existing C++ code where each character is
converted to a WORD (so I get the same result in both multibyte and
Unicode
versions). The result is then computed by adding all four DWORDs of the
result, which is a bit awkward in C#.

UInt32 CalcCheckSum(string s)
{
MD5 md5 = MD5.Create();
// md5.Initialize();
byte[] data = StringToByteArray(s);
data = md5.ComputeHash(data);

UInt32 result = 0;
for (int i = 0; i < data.Length; i += sizeof(UInt32))
result += ByteArrayToDword(data, i);
return result;
}

So, the first thing to check is whether the data that you're hashing is
exactly the same. My guess is that that's the problem.

I suggest you print out the content of data before calling ComputeHash
- just print each byte out as an integer in both your C++ code and the
C# code.

Now to make your code easier:

StringToByteArray can be replaced with Encoding.Unicode.GetBytes(data)
ByteArrayToDword can be replaced with BitConverter.ToUInt32(data, i)

If you need to do bit conversion with a different endianness, I have an
EndianBitConverter in my misc util library:
http://www.pobox.com/~skeet/csharp/miscutil
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top