196 lines
7.0 KiB
C#
196 lines
7.0 KiB
C#
#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
|
|
{
|
|
/// <summary>Implements a 32-bits cyclic redundancy check (CRC) hash algorithm.</summary>
|
|
/// <remarks>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.</remarks>
|
|
public class Crc32 : HashAlgorithm
|
|
{
|
|
#region Fields
|
|
|
|
/// <summary>Gets the default polynomial (used in WinZip, Ethernet, etc.)</summary>
|
|
/// <remarks>The default polynomial is a bit-reflected version of the standard polynomial 0x04C11DB7 used by WinZip, Ethernet, etc.</remarks>
|
|
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<uint, uint[]> _crc32TablesCache;
|
|
|
|
#endregion Fields
|
|
|
|
#region Constructors
|
|
|
|
/// <summary>Creates a CRC32 object using the <see cref="DefaultPolynomial"/>.</summary>
|
|
public Crc32()
|
|
: this(DefaultPolynomial)
|
|
{
|
|
}
|
|
|
|
/// <summary>Creates a CRC32 object using the specified polynomial.</summary>
|
|
/// <remarks>The polynomial should be supplied in its bit-reflected form. <see cref="DefaultPolynomial"/>.</remarks>
|
|
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<uint, uint[]>();
|
|
}
|
|
|
|
#endregion Constructors
|
|
|
|
#region Public Methods
|
|
|
|
/// <summary>Computes the CRC32 value for the given ASCII string using the <see cref="DefaultPolynomial"/>.</summary>
|
|
public static int Compute(string asciiString)
|
|
{
|
|
var crc = new Crc32();
|
|
return ToInt32(crc.ComputeHash(asciiString));
|
|
}
|
|
|
|
/// <summary>Computes the CRC32 value for the given input stream using the <see cref="DefaultPolynomial"/>.</summary>
|
|
public static int Compute(Stream inputStream)
|
|
{
|
|
var crc = new Crc32();
|
|
return ToInt32(crc.ComputeHash(inputStream));
|
|
}
|
|
|
|
/// <summary>Computes the CRC32 value for the input data using the <see cref="DefaultPolynomial"/>.</summary>
|
|
public static int Compute(byte[] buffer)
|
|
{
|
|
var crc = new Crc32();
|
|
return ToInt32(crc.ComputeHash(buffer));
|
|
}
|
|
|
|
/// <summary>Computes the hash value for the input data using the <see cref="DefaultPolynomial"/>.</summary>
|
|
public static int Compute(byte[] buffer, int offset, int count)
|
|
{
|
|
var crc = new Crc32();
|
|
return ToInt32(crc.ComputeHash(buffer, offset, count));
|
|
}
|
|
|
|
/// <summary>Computes the hash value for the given ASCII string.</summary>
|
|
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
|
|
public byte[] ComputeHash(string asciiString)
|
|
{
|
|
byte[] rawBytes = Encoding.ASCII.GetBytes(asciiString);
|
|
return ComputeHash(rawBytes);
|
|
}
|
|
|
|
/// <summary>Computes the hash value for the given input stream.</summary>
|
|
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
|
|
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();
|
|
}
|
|
|
|
/// <summary>Computes the hash value for the input data.</summary>
|
|
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
|
|
public new byte[] ComputeHash(byte[] buffer)
|
|
{
|
|
return ComputeHash(buffer, 0, buffer.Length);
|
|
}
|
|
|
|
/// <summary>Computes the hash value for the input data.</summary>
|
|
/// <remarks>The computation preserves the internal state between the calls, so it can be used for computation of a stream data.</remarks>
|
|
public new byte[] ComputeHash(byte[] buffer, int offset, int count)
|
|
{
|
|
HashCore(buffer, offset, count);
|
|
return HashFinal();
|
|
}
|
|
|
|
/// <summary>Initializes an implementation of HashAlgorithm.</summary>
|
|
public override sealed void Initialize()
|
|
{
|
|
_crc = _allOnes;
|
|
}
|
|
|
|
#endregion Public Methods
|
|
|
|
#region Protected Methods
|
|
|
|
/// <summary>Routes data written to the object into the hash algorithm for computing the hash.</summary>
|
|
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];
|
|
}
|
|
}
|
|
|
|
/// <summary>Finalizes the hash computation after the last data is processed by the cryptographic stream object.</summary>
|
|
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
|
|
}
|
|
} |