Kao sto sam sto je zombie rekao, a i ja sam otkrio, ceo problem je u enkodovanju stringa.
Naime, default implementacija MD5 algoritma podrazumeva da jedan karakter ima 1 bajt. I to je sve radilo super dok se nije pojavio Unicode. E sad on za kodovanje jednog karaktera ne koristi 1 nego 2 bajta iliti 16 bita. "Tamo" negde, nezavisno od svega ovoga, Intel je skontao da mu ne odgovara da reci (16 nekada, sada 32, sutra 64 bitne) ne predstavlja onako kako smo ucili u skolama (bajt najvece tezine ide prvi pa tako dalje sve do bajta najmanje tezine), vec uvodi novu konvenciju koju naziva "Little-Endian" i koja propisuje da bajt najmanje tezine ide prvi pa tako dalje sve do bajta najvise tezine. Ove konvencije se takodje pridrzava i default implementacija MD5 algoritma R. Rivest-a. Samo da napomenem da u okviru bajta i dalje ostaje da se bit najvece tezine nalazi prvi itd. do bita najmanje tezine.
Primer:
Code:
4275878552:
Little-Endian: 98 BA DC FE
Po "skolama" : FE DC BA 98
Sta je to sve prouzrokovalo? Dobili smo dva nacina Unicode kodovanja karaktera. Prvi, vec navedeni, "Little-Endian" (inace default unicode encoding u .NET Framework-u) i onaj drugi, "po skolama", nazvan "Big-Endian", tj. bajt najvece tezine prvi itd. do bajta najmanje tezine. Samim tim, jedan karakter se moze kodirati na tri nacina: ANSI, i dve vrste Unicode-a.
Primer:
Code:
karakter 'h':
ANSI: 0x68
Unicode, Little-Endian: 0x6800
Unicode, Big-Endian: 0x0068
E bas na to ja nisam obratio paznju kada sam poceo da se igram sa MD5CryptoServiceProvider-om. Klasa radi OK i za ono sto joj uneses daje OK rezultat, ali ja nisam obracao paznju na to sta sam unosio, vec sam lupio ono na sta sam naisao u prvom primeru, aha, rekoh, daj da to uporedim i sa nekim drugim implementacijama, kad tamo... Alarm! No, nakon malo proucavanja i razmatranja, video sam da je jako bitno da znas sta dajes da se hash-uje i da ce samo tako rezultati da se "potrefe". I tako, evo ispod jednog primercica koji demonstrira sve gore navedeno i otklanja sve nedoumice.
Code:
using System;
using System.Text;
using System.Security.Cryptography;
namespace MD5Test
{
class TestApp
{
static void Main(string[] args)
{
if (args.Length == 0)
{
ShowHashes("havramm");
}
else
{
ShowHashes(args[0]);
}
}
private static void ShowHashes(string stringToHash)
{
MD5CryptoServiceProvider md5Csp = new MD5CryptoServiceProvider();
byte[] dataToHash = Encoding.Default.GetBytes(stringToHash);
byte[] hash = md5Csp.ComputeHash(dataToHash);
// ANSI Encoding
Console.WriteLine(Encoding.Default.EncodingName + ":");
ShowData(dataToHash);
ShowHash(hash);
Console.WriteLine();
// Unicode encoding, Little-Endian
UnicodeEncoding ue = new UnicodeEncoding();
dataToHash = ue.GetBytes(stringToHash);
hash = md5Csp.ComputeHash(dataToHash);
Console.WriteLine(ue.EncodingName + ":");
ShowData(dataToHash);
ShowHash(hash);
Console.WriteLine();
// Unicode encoding, Big-Endian
ue = new UnicodeEncoding(true, true);
dataToHash = ue.GetBytes(stringToHash);
hash = md5Csp.ComputeHash(dataToHash);
Console.WriteLine(ue.EncodingName + ":");
ShowData(dataToHash);
ShowHash(hash);
}
private static void ShowData(byte[] data)
{
Console.Write("\tData To Hash:\t");
foreach (byte b in data)
{
Console.Write("{0:x2} ", b);
}
Console.WriteLine();
}
private static void ShowHash(byte[] hash)
{
Console.Write("\tHash:\t\t");
foreach (byte b in hash)
{
Console.Write("{0:x2}", b);
}
Console.WriteLine();
}
}
}
Rezultat primera:
Code:
Western European (Windows):
Data To Hash: 68 61 76 72 61 6d 6d
Hash: d8d48d5b8d4a391d88498bbf59a2acfe
Unicode:
Data To Hash: 68 00 61 00 76 00 72 00 61 00 6d 00 6d 00
Hash: e57298b7f1cd3646b3a0993aed065b04
Unicode (Big-Endian):
Data To Hash: 00 68 00 61 00 76 00 72 00 61 00 6d 00 6d
Hash: fc597671180dd7f9cd98a6052bd64026
I tako, stvarno ogroman post, nadam se da ce nekom koristiti, u svakom slucaju, ne skodi, a sto ne skodi, znaci... :)
If it's a girl then they're gonna call it Sigourney, after an actress. If it's a boy, then they're gonna call it Rodney, after Dave!