#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
}
}