#region Header // Tamir Khason http://khason.net/ // // Released under MS-PL : 6-Apr-09 #endregion Header using System; using System.Collections; using System.Collections.Concurrent; using System.IO; using System.Security.Cryptography; using System.Text; namespace PacketDotNet.Utils { /// Implements a 32-bits cyclic redundancy check (CRC) hash algorithm. /// This class is not intended to be used for security purposes. For security applications use MD5, SHA1, SHA256, SHA384, /// or SHA512 in the System.Security.Cryptography namespace. public class Crc32 : HashAlgorithm { #region Fields /// Gets the default polynomial (used in WinZip, Ethernet, etc.) /// The default polynomial is a bit-reflected version of the standard polynomial 0x04C11DB7 used by WinZip, Ethernet, etc. public static readonly uint DefaultPolynomial = 0xEDB88320; // Bitwise reflection of 0x04C11DB7; private const uint _allOnes = 0xffffffff; private uint _crc; private readonly uint[] _crc32Table; private static readonly ConcurrentDictionary _crc32TablesCache; #endregion Fields #region Constructors /// Creates a CRC32 object using the . public Crc32() : this(DefaultPolynomial) { } /// Creates a CRC32 object using the specified polynomial. /// The polynomial should be supplied in its bit-reflected form. . public Crc32(uint polynomial) { HashSizeValue = 32; if (!_crc32TablesCache.TryGetValue(polynomial, out _crc32Table)) { _crc32Table = BuildCrc32Table(polynomial); _crc32TablesCache.TryAdd(polynomial, _crc32Table); } Initialize(); } // static constructor static Crc32() { _crc32TablesCache = new ConcurrentDictionary(); } #endregion Constructors #region Public Methods /// Computes the CRC32 value for the given ASCII string using the . public static int Compute(string asciiString) { var crc = new Crc32(); return ToInt32(crc.ComputeHash(asciiString)); } /// Computes the CRC32 value for the given input stream using the . public static int Compute(Stream inputStream) { var crc = new Crc32(); return ToInt32(crc.ComputeHash(inputStream)); } /// Computes the CRC32 value for the input data using the . public static int Compute(byte[] buffer) { var crc = new Crc32(); return ToInt32(crc.ComputeHash(buffer)); } /// Computes the hash value for the input data using the . public static int Compute(byte[] buffer, int offset, int count) { var crc = new Crc32(); return ToInt32(crc.ComputeHash(buffer, offset, count)); } /// Computes the hash value for the given ASCII string. /// The computation preserves the internal state between the calls, so it can be used for computation of a stream data. public byte[] ComputeHash(string asciiString) { byte[] rawBytes = Encoding.ASCII.GetBytes(asciiString); return ComputeHash(rawBytes); } /// Computes the hash value for the given input stream. /// The computation preserves the internal state between the calls, so it can be used for computation of a stream data. public new byte[] ComputeHash(Stream inputStream) { var buffer = new byte[4096]; int bytesRead; while ((bytesRead = inputStream.Read(buffer, 0, 4096)) > 0) { HashCore(buffer, 0, bytesRead); } return HashFinal(); } /// Computes the hash value for the input data. /// The computation preserves the internal state between the calls, so it can be used for computation of a stream data. public new byte[] ComputeHash(byte[] buffer) { return ComputeHash(buffer, 0, buffer.Length); } /// Computes the hash value for the input data. /// The computation preserves the internal state between the calls, so it can be used for computation of a stream data. public new byte[] ComputeHash(byte[] buffer, int offset, int count) { HashCore(buffer, offset, count); return HashFinal(); } /// Initializes an implementation of HashAlgorithm. public override sealed void Initialize() { _crc = _allOnes; } #endregion Public Methods #region Protected Methods /// Routes data written to the object into the hash algorithm for computing the hash. protected override void HashCore(byte[] buffer, int offset, int count) { for (int i = offset; i < count; i++) { ulong ptr = (_crc & 0xFF) ^ buffer[i]; _crc >>= 8; _crc ^= _crc32Table[ptr]; } } /// Finalizes the hash computation after the last data is processed by the cryptographic stream object. protected override byte[] HashFinal() { var finalHash = new byte[4]; ulong finalCrc = _crc ^ _allOnes; finalHash[3] = (byte)((finalCrc >> 0) & 0xFF); finalHash[2] = (byte)((finalCrc >> 8) & 0xFF); finalHash[1] = (byte)((finalCrc >> 16) & 0xFF); finalHash[0] = (byte)((finalCrc >> 24) & 0xFF); return finalHash; } #endregion Protected Methods #region Private Methods // Builds a crc32 table given a polynomial private static uint[] BuildCrc32Table(uint polynomial) { var table = new uint[256]; // 256 values representing ASCII character codes. for (int i = 0; i < 256; i++) { var crc = (uint)i; for (int j = 8; j > 0; j--) { if ((crc & 1) == 1) crc = (crc >> 1) ^ polynomial; else crc >>= 1; } table[i] = crc; } return table; } private static int ToInt32(byte[] buffer) { return BitConverter.ToInt32(buffer, 0); } #endregion Private Methods } }