SHA-1 algorithm for Compact Framework
Compact Framework lacks of Cryptography support. If you have to hash a string you can't use SHA1CryptoServiceProvider since it isn't supported on CF. One of the available workaround is to use Win.CE (2.10 and later) SDK functions through P/Invoke.
I developed a simple helper function that get a string as parameter and returns it's hashed value. I want to share here the code so that if somebody else will encounter the same issue can save some times :-D
Here is the code:
public static string HashString(string textToHash)
{
string hashValue = string.Empty;
if(textToHash == null || textToHash == string.Empty)
throw new ArgumentNullException("textToHash", "The text to hash cannot be null.");
const int PROV_RSA_FULL = 1;
const int CALG_SHA1 = 0x8004;
const int HP_HASHSIZE = 0x0004;
const int HP_HASHVAL = 0x0002;
IntPtr hHash = IntPtr.Zero;
IntPtr hProv = IntPtr.Zero;
// Obtain handle to the default key container
if(!HashNative.CryptAcquireContext(ref hProv, null, "Microsoft Base Cryptographic Provider v1.0", PROV_RSA_FULL, 0))
throw new Win32Exception(Marshal.GetLastWin32Error());
else
{
try
{
// Obtain handle to hash object.
if(!HashNative.CryptCreateHash(hProv, CALG_SHA1, IntPtr.Zero, 0, ref hHash))
throw new Win32Exception(Marshal.GetLastWin32Error());
else
{
byte[] buffer = System.Text.Encoding.ASCII.GetBytes(textToHash);
// Hash data.
if(!HashNative.CryptHashData(hHash, buffer, buffer.Length, 0))
throw new Win32Exception(Marshal.GetLastWin32Error());
// Get size of hash value.
int bufLen = Marshal.SizeOf(typeof(uint));
byte[] hashBuf = new byte[bufLen];
HashNative.CryptGetHashParam(hHash, HP_HASHSIZE, hashBuf, ref bufLen, 0);
// Get hash value.
bufLen = hashBuf[0];
hashBuf = new byte[bufLen];
if(!HashNative.CryptGetHashParam(hHash, HP_HASHVAL, hashBuf, ref bufLen, 0))
throw new Win32Exception(Marshal.GetLastWin32Error());
// Convert to base 64 string
hashValue = Convert.ToBase64String(hashBuf, 0, bufLen);
}
}
finally
{
// Release hash object.
if(hHash != IntPtr.Zero)
HashNative.CryptDestroyHash(hHash);
// Release context object
if(hProv != IntPtr.Zero)
HashNative.CryptReleaseContext(hProv, 0);
}
}
return hashValue;
}
The native declarations are:
internal class HashNative
{
[DllImport("CoreDLL.Dll", SetLastError=true)]
internal extern static bool CryptAcquireContext(ref IntPtr hCryptProv, string containerName, string providerName,
int providerType, uint providerFlags);
[DllImport("CoreDLL.Dll", SetLastError=true)]
internal extern static bool CryptReleaseContext(IntPtr hCryptProv, uint providerFlags);
[DllImport("CoreDLL.Dll", SetLastError=true)]
internal extern static bool CryptCreateHash(IntPtr hProv, int algId, IntPtr hKey, uint dwFlags, ref IntPtr phHash);
[DllImport("CoreDLL.Dll", SetLastError=true)]
internal extern static bool CryptDestroyHash(IntPtr phHash);
[DllImport("CoreDLL.Dll", SetLastError=true)]
internal extern static bool CryptHashData(IntPtr hHash, byte[] pbData, int dwDataLen, uint dwFlags);
[DllImport("CoreDLL.Dll", SetLastError=true)]
internal extern static bool CryptGetHashParam(IntPtr hHash, int dwParam, [in,Out] byte[] pbData, ref int pdwDataLen, uint dwFlags);
}
Note that the above code is for demo purpose only and I don't have any responsability for it's usage. You can use and modify it freely.