Reputation: 6884
I have this code in C++ (AnsiString is a wrapper for char* buffer):
BOOL HashIt(AnsiString &pw,BYTE *buf,BYTE &len)
{
HCRYPTPROV cp;
CryptAcquireContext(&cp,NULL,NULL,PROV_RSA_AES,CRYPT_VERIFYCONTEXT);
HCRYPTHASH ch;
CryptCreateHash(cp,CALG_MD5,0,0,&ch);
CryptHashData(ch,(BYTE*)pw.c_str(),pw.Length(),0);
HCRYPTKEY kc;
CryptDeriveKey(cp,CALG_3DES,ch,CRYPT_EXPORTABLE,&kc);
CryptExportKey(kc,NULL,PLAINTEXTKEYBLOB,0,buf,&dwLen);
len = (BYTE) dwLen;
}
So far I've got this far converting it to .NET:
public static byte[] HashItB(string text)
{
byte[] textBytes = System.Text.Encoding.UTF8.GetBytes(text);
System.Security.Cryptography.MD5CryptoServiceProvider sp = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] hashBytes = sp.ComputeHash(textBytes);
System.Security.Cryptography.PasswordDeriveBytes pdb = new System.Security.Cryptography.PasswordDeriveBytes(hashBytes, new byte[0]);
hashBytes = pdb.CryptDeriveKey("TripleDES", "SHA1", 192, hashBytes);
// Need to export key as plain text blob here, CryptExportKey
return (hashBytes);
}
Assuming the above code is correct, my last step is to translate the CryptExportKey function to .NET. Can someone point me to the function or a sample? I can't change the C++ method and I need my .NET code to match a legacy app. Or should I give up on .NET methods and either create a C++ DLL and call that (not crazy about that due to extra size of shipping another DLL with my tiny app), or pinvoke all of the Crypto functions?
Upvotes: 1
Views: 2096
Reputation: 6884
Thanks for the help, and incase anyone needs this reading this post later, here is what I ended up with. I'm sure the byte array building could be better, but in my case this code doesn't need to be fast so I just went with what was easy for me to read:
public static byte[] HashIt(string text)
{
byte[] textBytes = System.Text.Encoding.UTF8.GetBytes(text);
System.Security.Cryptography.PasswordDeriveBytes pdb = new System.Security.Cryptography.PasswordDeriveBytes(textBytes, new byte[0]);
byte[] hashBytes = pdb.CryptDeriveKey("TripleDES", "MD5", 0, new byte[8]);
byte[] head = new byte[] { 0x08,0x02, 0x00, 0x00, 0x03, 0x66, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00 };
byte[] hashBytesWithHead = new byte[hashBytes.Length + head.Length];
head.CopyTo(hashBytesWithHead,0);
hashBytes.CopyTo(hashBytesWithHead,head.Length);
return (hashBytesWithHead);
}
Upvotes: 1
Reputation: 49619
The .NET method PasswordDeriveBytes.CryptDeriveKey()
is the equivalent to using the Win32 CryptoAPI method to hash the password, call CryptDeriveKey
and finally export the key by calling CryptExportKey
.
Your C++-code is equivalent to:
byte[] textBytes = System.Text.Encoding.Default.GetBytes(text); // Default is the ANSI-code-page
System.Security.Cryptography.PasswordDeriveBytes pdb = new System.Security.Cryptography.PasswordDeriveBytes(textBytes, new byte[0]);
byte[] hashBytes = pdb.CryptDeriveKey("TripleDES", "MD5", 0, new byte[8]);
except that the .NET-code removes some header data from the exported key (a PLAINTEXTKEYBLOB-header). For a 192 bit 3DES key this is "08 02 00 00 03 66 00 00 18 00 00 00"
. You can just prepend it in the .NET-code if you need it.
Upvotes: 3
Reputation: 5836
The PasswordDeriveBytes.CryptDeriveKey Method already returns the derived key, so there is no need to export a key as in your C++ code.
Upvotes: 1