//*************************************************************** // // HashStream // Demonstrates streamed hashing for .NET Framework 1.0/1.1 // by P/Invoke to CryptoAPI // // Copyright (C) 2003. Michel I. Gallant // //*************************************************************** using System; using System.IO; using System.Text; using System.Security; using System.Security.Cryptography; using System.Runtime.InteropServices; namespace JavaScience { //--- P/Invoke CryptoAPI wrapper classes ----- public class Win32 { [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] public static extern bool CryptAcquireContext( ref IntPtr hProv, string pszContainer, string pszProvider, uint dwProvType, uint dwFlags) ; [DllImport("advapi32.dll")] public static extern bool CryptReleaseContext( IntPtr hProv, uint dwFlags) ; [DllImport("advapi32.dll")] public static extern bool CryptCreateHash( IntPtr hProv, uint Algid, IntPtr hKey, uint dwFlags, ref IntPtr pHash) ; [DllImport("advapi32.dll")] public static extern bool CryptHashData( IntPtr pHash, byte[] pData, int dwDataLen, uint dwFlags) ; [DllImport("advapi32.dll")] public static extern bool CryptGetHashParam( IntPtr pHash, uint dwParam, [Out] byte[] hashvalue, ref uint hashvaluesize, uint dwFlags) ; [DllImport("advapi32.dll")] public static extern bool CryptDestroyHash( IntPtr pHash) ; } public class HashStream{ const uint CALG_MD5 = 0x00008003; const uint CALG_SHA1 = 0x00008004; const uint HP_ALGID = 0x00000001; // Hash algorithm const uint HP_HASHVAL = 0x00000002; // Hash value const uint HP_HASHSIZE = 0x00000004; // Hash value size const uint PROV_RSA_FULL = 0x00000001; const uint CRYPT_VERIFYCONTEXT = 0xF0000000; //no private key access flag const uint X509_ASN_ENCODING = 0x00000001; const uint PKCS_7_ASN_ENCODING = 0x00010000; public static void Main(String[] args) { if(args.Length<2) { Console.WriteLine("Usage: HashStream "); return; } String filetohash = args[0]; int buffsize = 0; if (!File.Exists(filetohash)) { Console.WriteLine("File '{0}' not found.", filetohash); return; } try{ buffsize = Int32.Parse(args[1]); } catch { //number format exceptions; Console.WriteLine("Not a valid number"); return; } byte[] hashvalue = HashStream.SHA1StreamHash(filetohash, buffsize) ; if(hashvalue == null || hashvalue.Length !=20) { Console.WriteLine("Invalid SHA1 hash"); return; } HashStream.showBytes("SHA-1 Hash", hashvalue); } //------- SHA-1 Hash via buffered streaming and P/Invoke -------- private static byte[] SHA1StreamHash(String content, int buffersize) { String provider = null ; //default provider String container = null; //required for CRYPT_VERIFYCONTEXT uint provtype = PROV_RSA_FULL ; uint cspflags = CRYPT_VERIFYCONTEXT ; //no private key access required. uint hashsize = 20; //20 bytes for SHA-1 IntPtr hProv = IntPtr.Zero; IntPtr pHash = IntPtr.Zero; if (!File.Exists(content)) { Console.WriteLine("File '{0}' not found.", content); return null; } if(buffersize<1 || buffersize>1000000) //limit buffer size return null; FileStream fin = new FileStream(content, FileMode.Open, FileAccess.Read); byte[] buff = new byte[buffersize]; //hash buffer int lenread = 0; byte[] hashvalue = null; if(!Win32.CryptAcquireContext(ref hProv, container, provider, provtype, cspflags)) return null; // failed to acquire CSP //------ Create a CryptoAPI hash object ------- if(!Win32.CryptCreateHash(hProv, CALG_SHA1, IntPtr.Zero, 0, ref pHash)) { Console.WriteLine("Couldn't create CryptoAPI hash"); Win32.CryptReleaseContext(hProv, 0); return null; } try { Console.WriteLine("Got hash object ...") ; while( (lenread = fin.Read(buff, 0, buffersize))>0) { Win32.CryptHashData(pHash, buff, lenread, 0); } fin.Close() ; hashvalue = new byte[hashsize] ; Win32.CryptGetHashParam(pHash, HP_HASHVAL, hashvalue, ref hashsize, 0); return hashvalue ; } catch(Exception exc) { Console.WriteLine("Problem during hashing\n{0}", exc.Message); return null; } finally { if(hProv != IntPtr.Zero) Win32.CryptReleaseContext(hProv, 0); if(pHash != IntPtr.Zero) Win32.CryptDestroyHash(pHash) ; } } private static void showBytes(String info, byte[] data){ Console.WriteLine("{0} [{1} bytes]", info, data.Length); for(int i=1; i<=data.Length; i++){ Console.Write("{0:X2} ", data[i-1]) ; if(i%16 == 0) Console.WriteLine(); } Console.WriteLine(); } } }