diff --git a/DiscImageChef.Checksums/CRC16Context.cs b/DiscImageChef.Checksums/CRC16Context.cs index cc0617e87..228089c72 100644 --- a/DiscImageChef.Checksums/CRC16Context.cs +++ b/DiscImageChef.Checksums/CRC16Context.cs @@ -9,7 +9,7 @@ // // --[ Description ] ---------------------------------------------------------- // -// Implements a CRC16-CCITT algorithm. +// Implements a CRC16 algorithm. // // --[ License ] -------------------------------------------------------------- // @@ -37,22 +37,26 @@ using System.Text; namespace DiscImageChef.Checksums { /// - /// Implements a CRC16-CCITT algorithm + /// Implements a CRC16 algorithm /// public class Crc16Context : IChecksum { - const ushort CRC16_POLY = 0xA001; - const ushort CRC16_SEED = 0x0000; + public const ushort CRC16_IBM_POLY = 0xA001; + public const ushort CRC16_IBM_SEED = 0x0000; + public const ushort CRC16_CCITT_POLY = 0x8408; + public const ushort CRC16_CCITT_SEED = 0x0000; + readonly ushort finalSeed; readonly ushort[] table; ushort hashInt; /// - /// Initializes the CRC16 table and seed + /// Initializes the CRC16 table and seed as CRC16-IBM /// public Crc16Context() { - hashInt = CRC16_SEED; + hashInt = CRC16_IBM_SEED; + finalSeed = CRC16_IBM_SEED; table = new ushort[256]; for(int i = 0; i < 256; i++) @@ -60,7 +64,29 @@ namespace DiscImageChef.Checksums ushort entry = (ushort)i; for(int j = 0; j < 8; j++) if((entry & 1) == 1) - entry = (ushort)((entry >> 1) ^ CRC16_POLY); + entry = (ushort)((entry >> 1) ^ CRC16_IBM_POLY); + else + entry = (ushort)(entry >> 1); + + table[i] = entry; + } + } + + /// + /// Initializes the CRC16 table with a custom polynomial and seed + /// + public Crc16Context(ushort polynomial, ushort seed) + { + hashInt = seed; + finalSeed = seed; + + table = new ushort[256]; + for(int i = 0; i < 256; i++) + { + ushort entry = (ushort)i; + for(int j = 0; j < 8; j++) + if((entry & 1) == 1) + entry = (ushort)((entry >> 1) ^ polynomial); else entry = (ushort)(entry >> 1); @@ -93,7 +119,7 @@ namespace DiscImageChef.Checksums public byte[] Final() { BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; - return BigEndianBitConverter.GetBytes((ushort)(hashInt ^ CRC16_SEED)); + return BigEndianBitConverter.GetBytes((ushort)(hashInt ^ finalSeed)); } /// @@ -104,8 +130,8 @@ namespace DiscImageChef.Checksums StringBuilder crc16Output = new StringBuilder(); BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; - for(int i = 0; i < BigEndianBitConverter.GetBytes((ushort)(hashInt ^ CRC16_SEED)).Length; i++) - crc16Output.Append(BigEndianBitConverter.GetBytes((ushort)(hashInt ^ CRC16_SEED))[i].ToString("x2")); + for(int i = 0; i < BigEndianBitConverter.GetBytes((ushort)(hashInt ^ finalSeed)).Length; i++) + crc16Output.Append(BigEndianBitConverter.GetBytes((ushort)(hashInt ^ finalSeed))[i].ToString("x2")); return crc16Output.ToString(); } @@ -127,10 +153,19 @@ namespace DiscImageChef.Checksums /// Byte array of the hash value. public static string File(string filename, out byte[] hash) { - FileStream fileStream = new FileStream(filename, FileMode.Open); - ushort localhashInt; + return File(filename, out hash, CRC16_IBM_POLY, CRC16_IBM_SEED); + } - localhashInt = CRC16_SEED; + /// + /// Gets the hash of a file in hexadecimal and as a byte array. + /// + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash, ushort polynomial, ushort seed) + { + FileStream fileStream = new FileStream(filename, FileMode.Open); + + ushort localhashInt = seed; ushort[] localTable = new ushort[256]; for(int i = 0; i < 256; i++) @@ -138,7 +173,7 @@ namespace DiscImageChef.Checksums ushort entry = (ushort)i; for(int j = 0; j < 8; j++) if((entry & 1) == 1) - entry = (ushort)((entry >> 1) ^ CRC16_POLY); + entry = (ushort)((entry >> 1) ^ polynomial); else entry = (ushort)(entry >> 1); @@ -149,8 +184,9 @@ namespace DiscImageChef.Checksums localhashInt = (ushort)((localhashInt >> 8) ^ localTable[fileStream.ReadByte() ^ (localhashInt & 0xff)]); - BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; - hash = BigEndianBitConverter.GetBytes(localhashInt); + localhashInt ^= seed; + BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; + hash = BigEndianBitConverter.GetBytes(localhashInt); StringBuilder crc16Output = new StringBuilder(); @@ -169,7 +205,7 @@ namespace DiscImageChef.Checksums /// Byte array of the hash value. public static string Data(byte[] data, uint len, out byte[] hash) { - return Data(data, len, out hash, CRC16_POLY, CRC16_SEED); + return Data(data, len, out hash, CRC16_IBM_POLY, CRC16_IBM_SEED); } /// @@ -182,9 +218,7 @@ namespace DiscImageChef.Checksums /// CRC seed public static string Data(byte[] data, uint len, out byte[] hash, ushort polynomial, ushort seed) { - ushort localhashInt; - - localhashInt = seed; + ushort localhashInt = seed; ushort[] localTable = new ushort[256]; for(int i = 0; i < 256; i++) @@ -202,8 +236,9 @@ namespace DiscImageChef.Checksums for(int i = 0; i < len; i++) localhashInt = (ushort)((localhashInt >> 8) ^ localTable[data[i] ^ (localhashInt & 0xff)]); - BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; - hash = BigEndianBitConverter.GetBytes(localhashInt); + localhashInt ^= seed; + BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; + hash = BigEndianBitConverter.GetBytes(localhashInt); StringBuilder crc16Output = new StringBuilder(); diff --git a/DiscImageChef.Checksums/CRC32Context.cs b/DiscImageChef.Checksums/CRC32Context.cs index 03e7acea3..e5c9bc339 100644 --- a/DiscImageChef.Checksums/CRC32Context.cs +++ b/DiscImageChef.Checksums/CRC32Context.cs @@ -41,18 +41,22 @@ namespace DiscImageChef.Checksums /// public class Crc32Context : IChecksum { - const uint CRC32_POLY = 0xEDB88320; - const uint CRC32_SEED = 0xFFFFFFFF; + const uint CRC32_ISO_POLY = 0xEDB88320; + const uint CRC32_ISO_SEED = 0xFFFFFFFF; + const uint CRC32_CASTAGNOLI_POLY = 0x8F6E37A0; + const uint CRC32_CASTAGNOLI_SEED = 0xFFFFFFFF; + readonly uint finalSeed; readonly uint[] table; uint hashInt; /// - /// Initializes the CRC32 table and seed + /// Initializes the CRC32 table and seed as CRC32-ISO /// public Crc32Context() { - hashInt = CRC32_SEED; + hashInt = CRC32_ISO_SEED; + finalSeed = CRC32_ISO_SEED; table = new uint[256]; for(int i = 0; i < 256; i++) @@ -60,7 +64,29 @@ namespace DiscImageChef.Checksums uint entry = (uint)i; for(int j = 0; j < 8; j++) if((entry & 1) == 1) - entry = (entry >> 1) ^ CRC32_POLY; + entry = (entry >> 1) ^ CRC32_ISO_POLY; + else + entry = entry >> 1; + + table[i] = entry; + } + } + + /// + /// Initializes the CRC32 table with a custom polynomial and seed + /// + public Crc32Context(uint polynomial, uint seed) + { + hashInt = seed; + finalSeed = seed; + + table = new uint[256]; + for(int i = 0; i < 256; i++) + { + uint entry = (uint)i; + for(int j = 0; j < 8; j++) + if((entry & 1) == 1) + entry = (entry >> 1) ^ polynomial; else entry = entry >> 1; @@ -93,7 +119,7 @@ namespace DiscImageChef.Checksums public byte[] Final() { BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; - return BigEndianBitConverter.GetBytes(hashInt ^ CRC32_SEED); + return BigEndianBitConverter.GetBytes(hashInt ^ finalSeed); } /// @@ -104,8 +130,8 @@ namespace DiscImageChef.Checksums StringBuilder crc32Output = new StringBuilder(); BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; - for(int i = 0; i < BigEndianBitConverter.GetBytes(hashInt ^ CRC32_SEED).Length; i++) - crc32Output.Append(BigEndianBitConverter.GetBytes(hashInt ^ CRC32_SEED)[i].ToString("x2")); + for(int i = 0; i < BigEndianBitConverter.GetBytes(hashInt ^ finalSeed).Length; i++) + crc32Output.Append(BigEndianBitConverter.GetBytes(hashInt ^ finalSeed)[i].ToString("x2")); return crc32Output.ToString(); } @@ -127,10 +153,19 @@ namespace DiscImageChef.Checksums /// Byte array of the hash value. public static string File(string filename, out byte[] hash) { - FileStream fileStream = new FileStream(filename, FileMode.Open); - uint localhashInt; + return File(filename, out hash, CRC32_ISO_POLY, CRC32_ISO_SEED); + } - localhashInt = CRC32_SEED; + /// + /// Gets the hash of a file in hexadecimal and as a byte array. + /// + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash, uint polynomial, uint seed) + { + FileStream fileStream = new FileStream(filename, FileMode.Open); + + uint localhashInt = seed; uint[] localTable = new uint[256]; for(int i = 0; i < 256; i++) @@ -138,7 +173,7 @@ namespace DiscImageChef.Checksums uint entry = (uint)i; for(int j = 0; j < 8; j++) if((entry & 1) == 1) - entry = (entry >> 1) ^ CRC32_POLY; + entry = (entry >> 1) ^ polynomial; else entry = entry >> 1; @@ -146,15 +181,9 @@ namespace DiscImageChef.Checksums } for(int i = 0; i < fileStream.Length; i++) - { - localhashInt = (localhashInt >> 8) ^ - localTable[fileStream.ReadByte() ^ (localhashInt & 0xff)]; - if((localhashInt ^ CRC32_SEED) == 0xB883C628 || - (localhashInt ^ CRC32_SEED) == 0x28C683B8) - System.Console.WriteLine("CRC found at position {0}", fileStream.Position); - } + localhashInt = (localhashInt >> 8) ^ localTable[fileStream.ReadByte() ^ (localhashInt & 0xff)]; - localhashInt ^= CRC32_SEED; + localhashInt ^= seed; BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; hash = BigEndianBitConverter.GetBytes(localhashInt); @@ -175,7 +204,7 @@ namespace DiscImageChef.Checksums /// Byte array of the hash value. public static string Data(byte[] data, uint len, out byte[] hash) { - return Data(data, len, out hash, CRC32_POLY, CRC32_SEED); + return Data(data, len, out hash, CRC32_ISO_POLY, CRC32_ISO_SEED); } /// @@ -208,7 +237,7 @@ namespace DiscImageChef.Checksums for(int i = 0; i < len; i++) localhashInt = (localhashInt >> 8) ^ localTable[data[i] ^ (localhashInt & 0xff)]; - localhashInt ^= CRC32_SEED; + localhashInt ^= seed; BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; hash = BigEndianBitConverter.GetBytes(localhashInt); diff --git a/DiscImageChef.Checksums/CRC64Context.cs b/DiscImageChef.Checksums/CRC64Context.cs index 921362820..0ec97e9b9 100644 --- a/DiscImageChef.Checksums/CRC64Context.cs +++ b/DiscImageChef.Checksums/CRC64Context.cs @@ -37,22 +37,23 @@ using System.Text; namespace DiscImageChef.Checksums { /// - /// Implements a CRC64 (ECMA) algorithm + /// Implements a CRC64 algorithm /// public class Crc64Context : IChecksum { - const ulong CRC64_POLY = 0xC96C5795D7870F42; - const ulong CRC64_SEED = 0xFFFFFFFFFFFFFFFF; + public const ulong CRC64_ECMA_POLY = 0xC96C5795D7870F42; + public const ulong CRC64_ECMA_SEED = 0xFFFFFFFFFFFFFFFF; + readonly ulong finalSeed; readonly ulong[] table; ulong hashInt; /// - /// Initializes the CRC64 table and seed + /// Initializes the CRC64 table and seed as CRC64-ECMA /// public Crc64Context() { - hashInt = CRC64_SEED; + hashInt = CRC64_ECMA_SEED; table = new ulong[256]; for(int i = 0; i < 256; i++) @@ -60,12 +61,37 @@ namespace DiscImageChef.Checksums ulong entry = (ulong)i; for(int j = 0; j < 8; j++) if((entry & 1) == 1) - entry = (entry >> 1) ^ CRC64_POLY; + entry = (entry >> 1) ^ CRC64_ECMA_POLY; else entry = entry >> 1; table[i] = entry; } + + finalSeed = CRC64_ECMA_SEED; + } + + /// + /// Initializes the CRC16 table with a custom polynomial and seed + /// + public Crc64Context(ulong polynomial, ulong seed) + { + hashInt = seed; + + table = new ulong[256]; + for(int i = 0; i < 256; i++) + { + ulong entry = (ulong)i; + for(int j = 0; j < 8; j++) + if((entry & 1) == 1) + entry = (entry >> 1) ^ polynomial; + else + entry = entry >> 1; + + table[i] = entry; + } + + finalSeed = seed; } /// @@ -93,7 +119,7 @@ namespace DiscImageChef.Checksums public byte[] Final() { BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; - return BigEndianBitConverter.GetBytes(hashInt ^= CRC64_SEED); + return BigEndianBitConverter.GetBytes(hashInt ^= finalSeed); } /// @@ -104,8 +130,8 @@ namespace DiscImageChef.Checksums StringBuilder crc64Output = new StringBuilder(); BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; - for(int i = 0; i < BigEndianBitConverter.GetBytes(hashInt ^= CRC64_SEED).Length; i++) - crc64Output.Append(BigEndianBitConverter.GetBytes(hashInt ^= CRC64_SEED)[i].ToString("x2")); + for(int i = 0; i < BigEndianBitConverter.GetBytes(hashInt ^= finalSeed).Length; i++) + crc64Output.Append(BigEndianBitConverter.GetBytes(hashInt ^= finalSeed)[i].ToString("x2")); return crc64Output.ToString(); } @@ -127,10 +153,19 @@ namespace DiscImageChef.Checksums /// Byte array of the hash value. public static string File(string filename, out byte[] hash) { - FileStream fileStream = new FileStream(filename, FileMode.Open); - ulong localhashInt; + return File(filename, out hash, CRC64_ECMA_POLY, CRC64_ECMA_SEED); + } - localhashInt = CRC64_SEED; + /// + /// Gets the hash of a file in hexadecimal and as a byte array. + /// + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash, ulong polynomial, ulong seed) + { + FileStream fileStream = new FileStream(filename, FileMode.Open); + + ulong localhashInt = seed; ulong[] localTable = new ulong[256]; for(int i = 0; i < 256; i++) @@ -138,7 +173,7 @@ namespace DiscImageChef.Checksums ulong entry = (ulong)i; for(int j = 0; j < 8; j++) if((entry & 1) == 1) - entry = (entry >> 1) ^ CRC64_POLY; + entry = (entry >> 1) ^ polynomial; else entry = entry >> 1; @@ -148,7 +183,7 @@ namespace DiscImageChef.Checksums for(int i = 0; i < fileStream.Length; i++) localhashInt = (localhashInt >> 8) ^ localTable[(ulong)fileStream.ReadByte() ^ (localhashInt & 0xffL)]; - localhashInt ^= CRC64_SEED; + localhashInt ^= seed; BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; hash = BigEndianBitConverter.GetBytes(localhashInt); @@ -169,7 +204,7 @@ namespace DiscImageChef.Checksums /// Byte array of the hash value. public static string Data(byte[] data, uint len, out byte[] hash) { - return Data(data, len, out hash, CRC64_POLY, CRC64_SEED); + return Data(data, len, out hash, CRC64_ECMA_POLY, CRC64_ECMA_SEED); } /// @@ -182,9 +217,7 @@ namespace DiscImageChef.Checksums /// CRC seed public static string Data(byte[] data, uint len, out byte[] hash, ulong polynomial, ulong seed) { - ulong localhashInt; - - localhashInt = seed; + ulong localhashInt = seed; ulong[] localTable = new ulong[256]; for(int i = 0; i < 256; i++) @@ -202,7 +235,7 @@ namespace DiscImageChef.Checksums for(int i = 0; i < len; i++) localhashInt = (localhashInt >> 8) ^ localTable[data[i] ^ (localhashInt & 0xff)]; - localhashInt ^= CRC64_SEED; + localhashInt ^= seed; BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian; hash = BigEndianBitConverter.GetBytes(localhashInt);