mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Move DiscImageChef.Checksums to a separate repository.
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -19,3 +19,6 @@
|
|||||||
[submodule "DiscImageChef.Helpers"]
|
[submodule "DiscImageChef.Helpers"]
|
||||||
path = DiscImageChef.Helpers
|
path = DiscImageChef.Helpers
|
||||||
url = https://github.com/discimagechef/DiscImageChef.Helpers.git
|
url = https://github.com/discimagechef/DiscImageChef.Helpers.git
|
||||||
|
[submodule "DiscImageChef.Checksums"]
|
||||||
|
path = DiscImageChef.Checksums
|
||||||
|
url = https://github.com/discimagechef/DiscImageChef.Checksums.git
|
||||||
|
|||||||
1
DiscImageChef.Checksums
Submodule
1
DiscImageChef.Checksums
Submodule
Submodule DiscImageChef.Checksums added at b06fb9ec7b
@@ -1,178 +0,0 @@
|
|||||||
// /***************************************************************************
|
|
||||||
// The Disc Image Chef
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Filename : Adler32Context.cs
|
|
||||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
||||||
//
|
|
||||||
// Component : Checksums.
|
|
||||||
//
|
|
||||||
// --[ Description ] ----------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Implements an Adler-32 algorithm.
|
|
||||||
//
|
|
||||||
// --[ License ] --------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as
|
|
||||||
// published by the Free Software Foundation; either version 2.1 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful, but
|
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Copyright © 2011-2020 Natalia Portillo
|
|
||||||
// ****************************************************************************/
|
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using DiscImageChef.CommonTypes.Interfaces;
|
|
||||||
|
|
||||||
namespace DiscImageChef.Checksums
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Implements the Adler-32 algorithm
|
|
||||||
/// </summary>
|
|
||||||
public class Adler32Context : IChecksum
|
|
||||||
{
|
|
||||||
const ushort ADLER_MODULE = 65521;
|
|
||||||
ushort sum1, sum2;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the Adler-32 sums
|
|
||||||
/// </summary>
|
|
||||||
public Adler32Context()
|
|
||||||
{
|
|
||||||
sum1 = 1;
|
|
||||||
sum2 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of buffer to hash.</param>
|
|
||||||
public void Update(byte[] data, uint len)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
sum1 = (ushort)((sum1 + data[i]) % ADLER_MODULE);
|
|
||||||
sum2 = (ushort)((sum2 + sum1) % ADLER_MODULE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
public void Update(byte[] data)
|
|
||||||
{
|
|
||||||
Update(data, (uint)data.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a byte array of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public byte[] Final()
|
|
||||||
{
|
|
||||||
uint finalSum = (uint)((sum2 << 16) | sum1);
|
|
||||||
return BigEndianBitConverter.GetBytes(finalSum);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a hexadecimal representation of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public string End()
|
|
||||||
{
|
|
||||||
uint finalSum = (uint)((sum2 << 16) | sum1);
|
|
||||||
StringBuilder adlerOutput = new StringBuilder();
|
|
||||||
|
|
||||||
for(int i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++)
|
|
||||||
adlerOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2"));
|
|
||||||
|
|
||||||
return adlerOutput.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
public static byte[] File(string filename)
|
|
||||||
{
|
|
||||||
File(filename, out byte[] hash);
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file in hexadecimal and as a byte array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string File(string filename, out byte[] hash)
|
|
||||||
{
|
|
||||||
FileStream fileStream = new FileStream(filename, FileMode.Open);
|
|
||||||
|
|
||||||
ushort localSum1 = 1;
|
|
||||||
ushort localSum2 = 0;
|
|
||||||
|
|
||||||
for(int i = 0; i < fileStream.Length; i++)
|
|
||||||
{
|
|
||||||
localSum1 = (ushort)((localSum1 + fileStream.ReadByte()) % ADLER_MODULE);
|
|
||||||
localSum2 = (ushort)((localSum2 + localSum1) % ADLER_MODULE);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint finalSum = (uint)((localSum2 << 16) | localSum1);
|
|
||||||
|
|
||||||
hash = BigEndianBitConverter.GetBytes(finalSum);
|
|
||||||
|
|
||||||
StringBuilder adlerOutput = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) adlerOutput.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
fileStream.Close();
|
|
||||||
|
|
||||||
return adlerOutput.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of the data buffer to hash.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, uint len, out byte[] hash)
|
|
||||||
{
|
|
||||||
ushort localSum1 = 1;
|
|
||||||
ushort localSum2 = 0;
|
|
||||||
|
|
||||||
for(int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
localSum1 = (ushort)((localSum1 + data[i]) % ADLER_MODULE);
|
|
||||||
localSum2 = (ushort)((localSum2 + localSum1) % ADLER_MODULE);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint finalSum = (uint)((localSum2 << 16) | localSum1);
|
|
||||||
|
|
||||||
hash = BigEndianBitConverter.GetBytes(finalSum);
|
|
||||||
|
|
||||||
StringBuilder adlerOutput = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) adlerOutput.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
return adlerOutput.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,611 +0,0 @@
|
|||||||
// /***************************************************************************
|
|
||||||
// The Disc Image Chef
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Filename : CDChecksums.cs
|
|
||||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
||||||
//
|
|
||||||
// Component : Checksums.
|
|
||||||
//
|
|
||||||
// --[ Description ] ----------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Implements CD checksums.
|
|
||||||
//
|
|
||||||
// --[ License ] --------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program.If not, see<http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Copyright © 2011-2020 Natalia Portillo
|
|
||||||
// ECC algorithm from ECM(c) 2002-2011 Neill Corlett
|
|
||||||
// ****************************************************************************/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using DiscImageChef.Console;
|
|
||||||
|
|
||||||
namespace DiscImageChef.Checksums
|
|
||||||
{
|
|
||||||
/// <summary>Implements ReedSolomon and CRC32 algorithms as used by CD-ROM</summary>
|
|
||||||
public static class CdChecksums
|
|
||||||
{
|
|
||||||
static byte[] eccFTable;
|
|
||||||
static byte[] eccBTable;
|
|
||||||
static uint[] edcTable;
|
|
||||||
|
|
||||||
public static bool? CheckCdSector(byte[] buffer)
|
|
||||||
{
|
|
||||||
switch(buffer.Length)
|
|
||||||
{
|
|
||||||
case 2448:
|
|
||||||
{
|
|
||||||
byte[] subchannel = new byte[96];
|
|
||||||
byte[] channel = new byte[2352];
|
|
||||||
|
|
||||||
Array.Copy(buffer, 0, channel, 0, 2352);
|
|
||||||
Array.Copy(buffer, 2352, subchannel, 0, 96);
|
|
||||||
|
|
||||||
bool? channelStatus = CheckCdSectorChannel(channel);
|
|
||||||
bool? subchannelStatus = CheckCdSectorSubChannel(subchannel);
|
|
||||||
bool? status = null;
|
|
||||||
|
|
||||||
if(channelStatus == false ||
|
|
||||||
subchannelStatus == false)
|
|
||||||
status = false;
|
|
||||||
|
|
||||||
switch(channelStatus)
|
|
||||||
{
|
|
||||||
case null when subchannelStatus == true:
|
|
||||||
status = true;
|
|
||||||
|
|
||||||
break;
|
|
||||||
case true when subchannelStatus == null:
|
|
||||||
status = true;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 2352: return CheckCdSectorChannel(buffer);
|
|
||||||
default: return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void EccInit()
|
|
||||||
{
|
|
||||||
eccFTable = new byte[256];
|
|
||||||
eccBTable = new byte[256];
|
|
||||||
edcTable = new uint[256];
|
|
||||||
|
|
||||||
for(uint i = 0; i < 256; i++)
|
|
||||||
{
|
|
||||||
uint edc = i;
|
|
||||||
uint j = (uint)((i << 1) ^ ((i & 0x80) == 0x80 ? 0x11D : 0));
|
|
||||||
eccFTable[i] = (byte)j;
|
|
||||||
eccBTable[i ^ j] = (byte)i;
|
|
||||||
|
|
||||||
for(j = 0; j < 8; j++)
|
|
||||||
edc = (edc >> 1) ^ ((edc & 1) > 0 ? 0xD8018001 : 0);
|
|
||||||
|
|
||||||
edcTable[i] = edc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool CheckEcc(byte[] address, byte[] data, uint majorCount, uint minorCount, uint majorMult,
|
|
||||||
uint minorInc, byte[] ecc)
|
|
||||||
{
|
|
||||||
uint size = majorCount * minorCount;
|
|
||||||
uint major;
|
|
||||||
|
|
||||||
for(major = 0; major < majorCount; major++)
|
|
||||||
{
|
|
||||||
uint index = ((major >> 1) * majorMult) + (major & 1);
|
|
||||||
byte eccA = 0;
|
|
||||||
byte eccB = 0;
|
|
||||||
uint minor;
|
|
||||||
|
|
||||||
for(minor = 0; minor < minorCount; minor++)
|
|
||||||
{
|
|
||||||
byte temp = index < 4 ? address[index] : data[index - 4];
|
|
||||||
index += minorInc;
|
|
||||||
|
|
||||||
if(index >= size)
|
|
||||||
index -= size;
|
|
||||||
|
|
||||||
eccA ^= temp;
|
|
||||||
eccB ^= temp;
|
|
||||||
eccA = eccFTable[eccA];
|
|
||||||
}
|
|
||||||
|
|
||||||
eccA = eccBTable[eccFTable[eccA] ^ eccB];
|
|
||||||
|
|
||||||
if(ecc[major] != eccA ||
|
|
||||||
ecc[major + majorCount] != (eccA ^ eccB))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool? CheckCdSectorChannel(byte[] channel)
|
|
||||||
{
|
|
||||||
EccInit();
|
|
||||||
|
|
||||||
if(channel[0x000] != 0x00 ||
|
|
||||||
channel[0x001] != 0xFF ||
|
|
||||||
channel[0x002] != 0xFF ||
|
|
||||||
channel[0x003] != 0xFF ||
|
|
||||||
channel[0x004] != 0xFF ||
|
|
||||||
channel[0x005] != 0xFF ||
|
|
||||||
channel[0x006] != 0xFF ||
|
|
||||||
channel[0x007] != 0xFF ||
|
|
||||||
channel[0x008] != 0xFF ||
|
|
||||||
channel[0x009] != 0xFF ||
|
|
||||||
channel[0x00A] != 0xFF ||
|
|
||||||
channel[0x00B] != 0x00)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
//DicConsole.DebugWriteLine("CD checksums", "Data sector, address {0:X2}:{1:X2}:{2:X2}", channel[0x00C],
|
|
||||||
// channel[0x00D], channel[0x00E]);
|
|
||||||
|
|
||||||
if(channel[0x00F] == 0x00) // mode (1 byte)
|
|
||||||
{
|
|
||||||
//DicConsole.DebugWriteLine("CD checksums", "Mode 0 sector at address {0:X2}:{1:X2}:{2:X2}",
|
|
||||||
// channel[0x00C], channel[0x00D], channel[0x00E]);
|
|
||||||
for(int i = 0x010; i < 0x930; i++)
|
|
||||||
if(channel[i] != 0x00)
|
|
||||||
{
|
|
||||||
DicConsole.DebugWriteLine("CD checksums",
|
|
||||||
"Mode 0 sector with error at address: {0:X2}:{1:X2}:{2:X2}",
|
|
||||||
channel[0x00C], channel[0x00D], channel[0x00E]);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(channel[0x00F] == 0x01) // mode (1 byte)
|
|
||||||
{
|
|
||||||
//DicConsole.DebugWriteLine("CD checksums", "Mode 1 sector at address {0:X2}:{1:X2}:{2:X2}",
|
|
||||||
// channel[0x00C], channel[0x00D], channel[0x00E]);
|
|
||||||
|
|
||||||
if(channel[0x814] != 0x00 || // reserved (8 bytes)
|
|
||||||
channel[0x815] != 0x00 ||
|
|
||||||
channel[0x816] != 0x00 ||
|
|
||||||
channel[0x817] != 0x00 ||
|
|
||||||
channel[0x818] != 0x00 ||
|
|
||||||
channel[0x819] != 0x00 ||
|
|
||||||
channel[0x81A] != 0x00 ||
|
|
||||||
channel[0x81B] != 0x00)
|
|
||||||
{
|
|
||||||
DicConsole.DebugWriteLine("CD checksums",
|
|
||||||
"Mode 1 sector with data in reserved bytes at address: {0:X2}:{1:X2}:{2:X2}",
|
|
||||||
channel[0x00C], channel[0x00D], channel[0x00E]);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] address = new byte[4];
|
|
||||||
byte[] data = new byte[2060];
|
|
||||||
byte[] data2 = new byte[2232];
|
|
||||||
byte[] eccP = new byte[172];
|
|
||||||
byte[] eccQ = new byte[104];
|
|
||||||
|
|
||||||
Array.Copy(channel, 0x0C, address, 0, 4);
|
|
||||||
Array.Copy(channel, 0x10, data, 0, 2060);
|
|
||||||
Array.Copy(channel, 0x10, data2, 0, 2232);
|
|
||||||
Array.Copy(channel, 0x81C, eccP, 0, 172);
|
|
||||||
Array.Copy(channel, 0x8C8, eccQ, 0, 104);
|
|
||||||
|
|
||||||
bool failedEccP = !CheckEcc(address, data, 86, 24, 2, 86, eccP);
|
|
||||||
bool failedEccQ = !CheckEcc(address, data2, 52, 43, 86, 88, eccQ);
|
|
||||||
|
|
||||||
if(failedEccP)
|
|
||||||
DicConsole.DebugWriteLine("CD checksums",
|
|
||||||
"Mode 1 sector at address: {0:X2}:{1:X2}:{2:X2}, fails ECC P check",
|
|
||||||
channel[0x00C], channel[0x00D], channel[0x00E]);
|
|
||||||
|
|
||||||
if(failedEccQ)
|
|
||||||
DicConsole.DebugWriteLine("CD checksums",
|
|
||||||
"Mode 1 sector at address: {0:X2}:{1:X2}:{2:X2}, fails ECC Q check",
|
|
||||||
channel[0x00C], channel[0x00D], channel[0x00E]);
|
|
||||||
|
|
||||||
uint storedEdc = BitConverter.ToUInt32(channel, 0x810);
|
|
||||||
uint calculatedEdc = ComputeEdc(0, channel, 0x810);
|
|
||||||
|
|
||||||
if(calculatedEdc == storedEdc)
|
|
||||||
return!failedEccP && !failedEccQ;
|
|
||||||
|
|
||||||
DicConsole.DebugWriteLine("CD checksums",
|
|
||||||
"Mode 1 sector at address: {0:X2}:{1:X2}:{2:X2}, got CRC 0x{3:X8} expected 0x{4:X8}",
|
|
||||||
channel[0x00C], channel[0x00D], channel[0x00E], calculatedEdc, storedEdc);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(channel[0x00F] == 0x02) // mode (1 byte)
|
|
||||||
{
|
|
||||||
//DicConsole.DebugWriteLine("CD checksums", "Mode 2 sector at address {0:X2}:{1:X2}:{2:X2}",
|
|
||||||
// channel[0x00C], channel[0x00D], channel[0x00E]);
|
|
||||||
byte[] mode2Sector = new byte[channel.Length - 0x10];
|
|
||||||
Array.Copy(channel, 0x10, mode2Sector, 0, mode2Sector.Length);
|
|
||||||
|
|
||||||
if((channel[0x012] & 0x20) == 0x20) // mode 2 form 2
|
|
||||||
{
|
|
||||||
if(channel[0x010] != channel[0x014] ||
|
|
||||||
channel[0x011] != channel[0x015] ||
|
|
||||||
channel[0x012] != channel[0x016] ||
|
|
||||||
channel[0x013] != channel[0x017])
|
|
||||||
DicConsole.DebugWriteLine("CD checksums",
|
|
||||||
"Subheader copies differ in mode 2 form 2 sector at address: {0:X2}:{1:X2}:{2:X2}",
|
|
||||||
channel[0x00C], channel[0x00D], channel[0x00E]);
|
|
||||||
|
|
||||||
uint storedEdc = BitConverter.ToUInt32(mode2Sector, 0x91C);
|
|
||||||
|
|
||||||
// No CRC stored!
|
|
||||||
if(storedEdc == 0x00000000)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
uint calculatedEdc = ComputeEdc(0, mode2Sector, 0x91C);
|
|
||||||
|
|
||||||
if(calculatedEdc == storedEdc ||
|
|
||||||
storedEdc == 0x00000000)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
DicConsole.DebugWriteLine("CD checksums",
|
|
||||||
"Mode 2 form 2 sector at address: {0:X2}:{1:X2}:{2:X2}, got CRC 0x{3:X8} expected 0x{4:X8}",
|
|
||||||
channel[0x00C], channel[0x00D], channel[0x00E], calculatedEdc, storedEdc);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(channel[0x010] != channel[0x014] ||
|
|
||||||
channel[0x011] != channel[0x015] ||
|
|
||||||
channel[0x012] != channel[0x016] ||
|
|
||||||
channel[0x013] != channel[0x017])
|
|
||||||
DicConsole.DebugWriteLine("CD checksums",
|
|
||||||
"Subheader copies differ in mode 2 form 1 sector at address: {0:X2}:{1:X2}:{2:X2}",
|
|
||||||
channel[0x00C], channel[0x00D], channel[0x00E]);
|
|
||||||
|
|
||||||
byte[] address = new byte[4];
|
|
||||||
byte[] eccP = new byte[172];
|
|
||||||
byte[] eccQ = new byte[104];
|
|
||||||
|
|
||||||
Array.Copy(mode2Sector, 0x80C, eccP, 0, 172);
|
|
||||||
Array.Copy(mode2Sector, 0x8B8, eccQ, 0, 104);
|
|
||||||
|
|
||||||
bool failedEccP = !CheckEcc(address, mode2Sector, 86, 24, 2, 86, eccP);
|
|
||||||
bool failedEccQ = !CheckEcc(address, mode2Sector, 52, 43, 86, 88, eccQ);
|
|
||||||
|
|
||||||
if(failedEccP)
|
|
||||||
DicConsole.DebugWriteLine("CD checksums",
|
|
||||||
"Mode 2 form 1 sector at address: {0:X2}:{1:X2}:{2:X2}, fails ECC P check",
|
|
||||||
channel[0x00C], channel[0x00D], channel[0x00E]);
|
|
||||||
|
|
||||||
if(failedEccQ)
|
|
||||||
DicConsole.DebugWriteLine("CD checksums",
|
|
||||||
"Mode 2 form 1 sector at address: {0:X2}:{1:X2}:{2:X2}, fails ECC Q check",
|
|
||||||
channel[0x00C], channel[0x00D], channel[0x00E]);
|
|
||||||
|
|
||||||
uint storedEdc = BitConverter.ToUInt32(mode2Sector, 0x808);
|
|
||||||
uint calculatedEdc = ComputeEdc(0, mode2Sector, 0x808);
|
|
||||||
|
|
||||||
if(calculatedEdc == storedEdc)
|
|
||||||
return!failedEccP && !failedEccQ;
|
|
||||||
|
|
||||||
DicConsole.DebugWriteLine("CD checksums",
|
|
||||||
"Mode 1 sector at address: {0:X2}:{1:X2}:{2:X2}, got CRC 0x{3:X8} expected 0x{4:X8}",
|
|
||||||
channel[0x00C], channel[0x00D], channel[0x00E], calculatedEdc, storedEdc);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DicConsole.DebugWriteLine("CD checksums", "Unknown mode {0} sector at address: {1:X2}:{2:X2}:{3:X2}",
|
|
||||||
channel[0x00F], channel[0x00C], channel[0x00D], channel[0x00E]);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint ComputeEdc(uint edc, IReadOnlyList<byte> src, int size)
|
|
||||||
{
|
|
||||||
int pos = 0;
|
|
||||||
|
|
||||||
for(; size > 0; size--)
|
|
||||||
edc = (edc >> 8) ^ edcTable[(edc ^ src[pos++]) & 0xFF];
|
|
||||||
|
|
||||||
return edc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool? CheckCdSectorSubChannel(IReadOnlyList<byte> subchannel)
|
|
||||||
{
|
|
||||||
bool? status = true;
|
|
||||||
byte[] qSubChannel = new byte[12];
|
|
||||||
byte[] cdTextPack1 = new byte[18];
|
|
||||||
byte[] cdTextPack2 = new byte[18];
|
|
||||||
byte[] cdTextPack3 = new byte[18];
|
|
||||||
byte[] cdTextPack4 = new byte[18];
|
|
||||||
byte[] cdSubRwPack1 = new byte[24];
|
|
||||||
byte[] cdSubRwPack2 = new byte[24];
|
|
||||||
byte[] cdSubRwPack3 = new byte[24];
|
|
||||||
byte[] cdSubRwPack4 = new byte[24];
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for(int j = 0; j < 12; j++)
|
|
||||||
qSubChannel[j] = 0;
|
|
||||||
|
|
||||||
for(int j = 0; j < 18; j++)
|
|
||||||
{
|
|
||||||
cdTextPack1[j] = 0;
|
|
||||||
cdTextPack2[j] = 0;
|
|
||||||
cdTextPack3[j] = 0;
|
|
||||||
cdTextPack4[j] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int j = 0; j < 24; j++)
|
|
||||||
{
|
|
||||||
cdSubRwPack1[j] = 0;
|
|
||||||
cdSubRwPack2[j] = 0;
|
|
||||||
cdSubRwPack3[j] = 0;
|
|
||||||
cdSubRwPack4[j] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int j = 0; j < 12; j++)
|
|
||||||
{
|
|
||||||
qSubChannel[j] = (byte)(qSubChannel[j] | ((subchannel[i++] & 0x40) << 1));
|
|
||||||
qSubChannel[j] = (byte)(qSubChannel[j] | (subchannel[i++] & 0x40));
|
|
||||||
qSubChannel[j] = (byte)(qSubChannel[j] | ((subchannel[i++] & 0x40) >> 1));
|
|
||||||
qSubChannel[j] = (byte)(qSubChannel[j] | ((subchannel[i++] & 0x40) >> 2));
|
|
||||||
qSubChannel[j] = (byte)(qSubChannel[j] | ((subchannel[i++] & 0x40) >> 3));
|
|
||||||
qSubChannel[j] = (byte)(qSubChannel[j] | ((subchannel[i++] & 0x40) >> 4));
|
|
||||||
qSubChannel[j] = (byte)(qSubChannel[j] | ((subchannel[i++] & 0x40) >> 5));
|
|
||||||
qSubChannel[j] = (byte)(qSubChannel[j] | ((subchannel[i++] & 0x40) >> 6));
|
|
||||||
}
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
for(int j = 0; j < 18; j++)
|
|
||||||
{
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack1[j] = (byte)(cdTextPack1[j] | ((subchannel[i++] & 0x3F) << 2));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack1[j] = (byte)(cdTextPack1[j++] | ((subchannel[i] & 0xC0) >> 4));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack1[j] = (byte)(cdTextPack1[j] | ((subchannel[i++] & 0x0F) << 4));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack1[j] = (byte)(cdTextPack1[j++] | ((subchannel[i] & 0x3C) >> 2));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack1[j] = (byte)(cdTextPack1[j] | ((subchannel[i++] & 0x03) << 6));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack1[j] = (byte)(cdTextPack1[j] | (subchannel[i++] & 0x3F));
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int j = 0; j < 18; j++)
|
|
||||||
{
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack2[j] = (byte)(cdTextPack2[j] | ((subchannel[i++] & 0x3F) << 2));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack2[j] = (byte)(cdTextPack2[j++] | ((subchannel[i] & 0xC0) >> 4));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack2[j] = (byte)(cdTextPack2[j] | ((subchannel[i++] & 0x0F) << 4));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack2[j] = (byte)(cdTextPack2[j++] | ((subchannel[i] & 0x3C) >> 2));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack2[j] = (byte)(cdTextPack2[j] | ((subchannel[i++] & 0x03) << 6));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack2[j] = (byte)(cdTextPack2[j] | (subchannel[i++] & 0x3F));
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int j = 0; j < 18; j++)
|
|
||||||
{
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack3[j] = (byte)(cdTextPack3[j] | ((subchannel[i++] & 0x3F) << 2));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack3[j] = (byte)(cdTextPack3[j++] | ((subchannel[i] & 0xC0) >> 4));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack3[j] = (byte)(cdTextPack3[j] | ((subchannel[i++] & 0x0F) << 4));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack3[j] = (byte)(cdTextPack3[j++] | ((subchannel[i] & 0x3C) >> 2));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack3[j] = (byte)(cdTextPack3[j] | ((subchannel[i++] & 0x03) << 6));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack3[j] = (byte)(cdTextPack3[j] | (subchannel[i++] & 0x3F));
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int j = 0; j < 18; j++)
|
|
||||||
{
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack4[j] = (byte)(cdTextPack4[j] | ((subchannel[i++] & 0x3F) << 2));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack4[j] = (byte)(cdTextPack4[j++] | ((subchannel[i] & 0xC0) >> 4));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack4[j] = (byte)(cdTextPack4[j] | ((subchannel[i++] & 0x0F) << 4));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack4[j] = (byte)(cdTextPack4[j++] | ((subchannel[i] & 0x3C) >> 2));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack4[j] = (byte)(cdTextPack4[j] | ((subchannel[i++] & 0x03) << 6));
|
|
||||||
|
|
||||||
if(j < 18)
|
|
||||||
cdTextPack4[j] = (byte)(cdTextPack4[j] | (subchannel[i++] & 0x3F));
|
|
||||||
}
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
for(int j = 0; j < 24; j++)
|
|
||||||
cdSubRwPack1[j] = (byte)(subchannel[i++] & 0x3F);
|
|
||||||
|
|
||||||
for(int j = 0; j < 24; j++)
|
|
||||||
cdSubRwPack2[j] = (byte)(subchannel[i++] & 0x3F);
|
|
||||||
|
|
||||||
for(int j = 0; j < 24; j++)
|
|
||||||
cdSubRwPack3[j] = (byte)(subchannel[i++] & 0x3F);
|
|
||||||
|
|
||||||
for(int j = 0; j < 24; j++)
|
|
||||||
cdSubRwPack4[j] = (byte)(subchannel[i++] & 0x3F);
|
|
||||||
|
|
||||||
switch(cdSubRwPack1[0])
|
|
||||||
{
|
|
||||||
case 0x00:
|
|
||||||
DicConsole.DebugWriteLine("CD checksums", "Detected Zero Pack in subchannel");
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 0x08:
|
|
||||||
DicConsole.DebugWriteLine("CD checksums", "Detected Line Graphics Pack in subchannel");
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 0x09:
|
|
||||||
DicConsole.DebugWriteLine("CD checksums", "Detected CD+G Pack in subchannel");
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 0x0A:
|
|
||||||
DicConsole.DebugWriteLine("CD checksums", "Detected CD+EG Pack in subchannel");
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 0x14:
|
|
||||||
DicConsole.DebugWriteLine("CD checksums", "Detected CD-TEXT Pack in subchannel");
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 0x18:
|
|
||||||
DicConsole.DebugWriteLine("CD checksums", "Detected CD+MIDI Pack in subchannel");
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 0x38:
|
|
||||||
DicConsole.DebugWriteLine("CD checksums", "Detected User Pack in subchannel");
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
DicConsole.DebugWriteLine("CD checksums",
|
|
||||||
"Detected unknown Pack type in subchannel: mode {0}, item {1}",
|
|
||||||
Convert.ToString(cdSubRwPack1[0] & 0x38, 2),
|
|
||||||
Convert.ToString(cdSubRwPack1[0] & 0x07, 2));
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ushort qSubChannelCrc = BigEndianBitConverter.ToUInt16(qSubChannel, 10);
|
|
||||||
byte[] qSubChannelForCrc = new byte[10];
|
|
||||||
Array.Copy(qSubChannel, 0, qSubChannelForCrc, 0, 10);
|
|
||||||
ushort calculatedQcrc = CRC16CCITTContext.Calculate(qSubChannelForCrc);
|
|
||||||
|
|
||||||
if(qSubChannelCrc != calculatedQcrc)
|
|
||||||
{
|
|
||||||
DicConsole.DebugWriteLine("CD checksums", "Q subchannel CRC 0x{0:X4}, expected 0x{1:X4}",
|
|
||||||
calculatedQcrc, qSubChannelCrc);
|
|
||||||
|
|
||||||
status = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((cdTextPack1[0] & 0x80) == 0x80)
|
|
||||||
{
|
|
||||||
ushort cdTextPack1Crc = BigEndianBitConverter.ToUInt16(cdTextPack1, 16);
|
|
||||||
byte[] cdTextPack1ForCrc = new byte[16];
|
|
||||||
Array.Copy(cdTextPack1, 0, cdTextPack1ForCrc, 0, 16);
|
|
||||||
ushort calculatedCdtp1Crc = CRC16CCITTContext.Calculate(cdTextPack1ForCrc);
|
|
||||||
|
|
||||||
if(cdTextPack1Crc != calculatedCdtp1Crc &&
|
|
||||||
cdTextPack1Crc != 0)
|
|
||||||
{
|
|
||||||
DicConsole.DebugWriteLine("CD checksums", "CD-Text Pack 1 CRC 0x{0:X4}, expected 0x{1:X4}",
|
|
||||||
cdTextPack1Crc, calculatedCdtp1Crc);
|
|
||||||
|
|
||||||
status = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if((cdTextPack2[0] & 0x80) == 0x80)
|
|
||||||
{
|
|
||||||
ushort cdTextPack2Crc = BigEndianBitConverter.ToUInt16(cdTextPack2, 16);
|
|
||||||
byte[] cdTextPack2ForCrc = new byte[16];
|
|
||||||
Array.Copy(cdTextPack2, 0, cdTextPack2ForCrc, 0, 16);
|
|
||||||
ushort calculatedCdtp2Crc = CRC16CCITTContext.Calculate(cdTextPack2ForCrc);
|
|
||||||
|
|
||||||
DicConsole.DebugWriteLine("CD checksums", "Cyclic CDTP2 0x{0:X4}, Calc CDTP2 0x{1:X4}", cdTextPack2Crc,
|
|
||||||
calculatedCdtp2Crc);
|
|
||||||
|
|
||||||
if(cdTextPack2Crc != calculatedCdtp2Crc &&
|
|
||||||
cdTextPack2Crc != 0)
|
|
||||||
{
|
|
||||||
DicConsole.DebugWriteLine("CD checksums", "CD-Text Pack 2 CRC 0x{0:X4}, expected 0x{1:X4}",
|
|
||||||
cdTextPack2Crc, calculatedCdtp2Crc);
|
|
||||||
|
|
||||||
status = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if((cdTextPack3[0] & 0x80) == 0x80)
|
|
||||||
{
|
|
||||||
ushort cdTextPack3Crc = BigEndianBitConverter.ToUInt16(cdTextPack3, 16);
|
|
||||||
byte[] cdTextPack3ForCrc = new byte[16];
|
|
||||||
Array.Copy(cdTextPack3, 0, cdTextPack3ForCrc, 0, 16);
|
|
||||||
ushort calculatedCdtp3Crc = CRC16CCITTContext.Calculate(cdTextPack3ForCrc);
|
|
||||||
|
|
||||||
DicConsole.DebugWriteLine("CD checksums", "Cyclic CDTP3 0x{0:X4}, Calc CDTP3 0x{1:X4}", cdTextPack3Crc,
|
|
||||||
calculatedCdtp3Crc);
|
|
||||||
|
|
||||||
if(cdTextPack3Crc != calculatedCdtp3Crc &&
|
|
||||||
cdTextPack3Crc != 0)
|
|
||||||
{
|
|
||||||
DicConsole.DebugWriteLine("CD checksums", "CD-Text Pack 3 CRC 0x{0:X4}, expected 0x{1:X4}",
|
|
||||||
cdTextPack3Crc, calculatedCdtp3Crc);
|
|
||||||
|
|
||||||
status = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if((cdTextPack4[0] & 0x80) != 0x80)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
ushort cdTextPack4Crc = BigEndianBitConverter.ToUInt16(cdTextPack4, 16);
|
|
||||||
byte[] cdTextPack4ForCrc = new byte[16];
|
|
||||||
Array.Copy(cdTextPack4, 0, cdTextPack4ForCrc, 0, 16);
|
|
||||||
ushort calculatedCdtp4Crc = CRC16CCITTContext.Calculate(cdTextPack4ForCrc);
|
|
||||||
|
|
||||||
DicConsole.DebugWriteLine("CD checksums", "Cyclic CDTP4 0x{0:X4}, Calc CDTP4 0x{1:X4}", cdTextPack4Crc,
|
|
||||||
calculatedCdtp4Crc);
|
|
||||||
|
|
||||||
if(cdTextPack4Crc == calculatedCdtp4Crc ||
|
|
||||||
cdTextPack4Crc == 0)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
DicConsole.DebugWriteLine("CD checksums", "CD-Text Pack 4 CRC 0x{0:X4}, expected 0x{1:X4}", cdTextPack4Crc,
|
|
||||||
calculatedCdtp4Crc);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
namespace DiscImageChef.Checksums
|
|
||||||
{
|
|
||||||
public class CRC16CCITTContext : Crc16Context
|
|
||||||
{
|
|
||||||
public const ushort CRC16_CCITT_POLY = 0x8408;
|
|
||||||
public const ushort CRC16_CCITT_SEED = 0x0000;
|
|
||||||
static readonly ushort[] _ccittCrc16Table =
|
|
||||||
{
|
|
||||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c,
|
|
||||||
0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318,
|
|
||||||
0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4,
|
|
||||||
0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630,
|
|
||||||
0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4,
|
|
||||||
0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969,
|
|
||||||
0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf,
|
|
||||||
0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
|
|
||||||
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13,
|
|
||||||
0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9,
|
|
||||||
0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046,
|
|
||||||
0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2,
|
|
||||||
0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2,
|
|
||||||
0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e,
|
|
||||||
0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e,
|
|
||||||
0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
|
|
||||||
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1,
|
|
||||||
0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07,
|
|
||||||
0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9,
|
|
||||||
0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
|
|
||||||
};
|
|
||||||
|
|
||||||
public CRC16CCITTContext() : base(CRC16_CCITT_POLY, CRC16_CCITT_SEED, _ccittCrc16Table, true) { }
|
|
||||||
|
|
||||||
/// <summary>Gets the hash of a file</summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
public static byte[] File(string filename)
|
|
||||||
{
|
|
||||||
File(filename, out byte[] hash);
|
|
||||||
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string File(string filename, out byte[] hash) =>
|
|
||||||
File(filename, out hash, CRC16_CCITT_POLY, CRC16_CCITT_SEED, _ccittCrc16Table, true);
|
|
||||||
|
|
||||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of the data buffer to hash.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, uint len, out byte[] hash) =>
|
|
||||||
Data(data, len, out hash, CRC16_CCITT_POLY, CRC16_CCITT_SEED, _ccittCrc16Table, true);
|
|
||||||
|
|
||||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
|
||||||
|
|
||||||
public static ushort Calculate(byte[] buffer) =>
|
|
||||||
Calculate(buffer, CRC16_CCITT_POLY, CRC16_CCITT_SEED, _ccittCrc16Table, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,226 +0,0 @@
|
|||||||
// /***************************************************************************
|
|
||||||
// The Disc Image Chef
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Filename : CRC16Context.cs
|
|
||||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
||||||
//
|
|
||||||
// Component : Checksums.
|
|
||||||
//
|
|
||||||
// --[ Description ] ----------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Implements a CRC16 algorithm.
|
|
||||||
//
|
|
||||||
// --[ License ] --------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as
|
|
||||||
// published by the Free Software Foundation; either version 2.1 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful, but
|
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Copyright © 2011-2020 Natalia Portillo
|
|
||||||
// ****************************************************************************/
|
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using DiscImageChef.CommonTypes.Interfaces;
|
|
||||||
|
|
||||||
namespace DiscImageChef.Checksums
|
|
||||||
{
|
|
||||||
/// <summary>Implements a CRC16 algorithm</summary>
|
|
||||||
public class Crc16Context : IChecksum
|
|
||||||
{
|
|
||||||
protected ushort _finalSeed;
|
|
||||||
protected ushort _hashInt;
|
|
||||||
protected bool _inverse;
|
|
||||||
|
|
||||||
protected ushort[] _table;
|
|
||||||
|
|
||||||
/// <summary>Initializes the CRC16 table with a custom polynomial and seed</summary>
|
|
||||||
public Crc16Context(ushort polynomial, ushort seed, ushort[] table, bool inverse)
|
|
||||||
{
|
|
||||||
_hashInt = seed;
|
|
||||||
_finalSeed = seed;
|
|
||||||
_inverse = inverse;
|
|
||||||
|
|
||||||
_table = table ?? GenerateTable(polynomial, inverse);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Updates the hash with data.</summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of buffer to hash.</param>
|
|
||||||
public void Update(byte[] data, uint len)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
if(_inverse)
|
|
||||||
_hashInt = (ushort)(_table[(_hashInt >> 8) ^ data[i]] ^ (_hashInt << 8));
|
|
||||||
else
|
|
||||||
_hashInt = (ushort)((_hashInt >> 8) ^ _table[data[i] ^ (_hashInt & 0xFF)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Updates the hash with data.</summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
public void Update(byte[] data) => Update(data, (uint)data.Length);
|
|
||||||
|
|
||||||
/// <summary>Returns a byte array of the hash value.</summary>
|
|
||||||
public byte[] Final() => BigEndianBitConverter.GetBytes((ushort)(_hashInt ^ _finalSeed));
|
|
||||||
|
|
||||||
/// <summary>Returns a hexadecimal representation of the hash value.</summary>
|
|
||||||
public string End()
|
|
||||||
{
|
|
||||||
var crc16Output = new StringBuilder();
|
|
||||||
|
|
||||||
ushort final = (ushort)(_hashInt ^ _finalSeed);
|
|
||||||
|
|
||||||
if(_inverse)
|
|
||||||
final = (ushort)~final;
|
|
||||||
|
|
||||||
byte[] finalBytes = BigEndianBitConverter.GetBytes(final);
|
|
||||||
|
|
||||||
for(int i = 0; i < finalBytes.Length; i++)
|
|
||||||
crc16Output.Append(finalBytes[i].ToString("x2"));
|
|
||||||
|
|
||||||
return crc16Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
static ushort[] GenerateTable(ushort polynomial, bool inverseTable)
|
|
||||||
{
|
|
||||||
ushort[] table = new ushort[256];
|
|
||||||
|
|
||||||
if(!inverseTable)
|
|
||||||
for(uint i = 0; i < 256; i++)
|
|
||||||
{
|
|
||||||
uint entry = i;
|
|
||||||
|
|
||||||
for(int j = 0; j < 8; j++)
|
|
||||||
if((entry & 1) == 1)
|
|
||||||
entry = (entry >> 1) ^ polynomial;
|
|
||||||
else
|
|
||||||
entry = entry >> 1;
|
|
||||||
|
|
||||||
table[i] = (ushort)entry;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for(uint i = 0; i < 256; i++)
|
|
||||||
{
|
|
||||||
uint entry = i << 8;
|
|
||||||
|
|
||||||
for(uint j = 0; j < 8; j++)
|
|
||||||
{
|
|
||||||
if((entry & 0x8000) > 0)
|
|
||||||
entry = (entry << 1) ^ polynomial;
|
|
||||||
else
|
|
||||||
entry <<= 1;
|
|
||||||
|
|
||||||
table[i] = (ushort)entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return table;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string File(string filename, out byte[] hash, ushort polynomial, ushort seed, ushort[] table,
|
|
||||||
bool inverse)
|
|
||||||
{
|
|
||||||
var fileStream = new FileStream(filename, FileMode.Open);
|
|
||||||
|
|
||||||
ushort localHashInt = seed;
|
|
||||||
|
|
||||||
ushort[] localTable = table ?? GenerateTable(polynomial, inverse);
|
|
||||||
|
|
||||||
for(int i = 0; i < fileStream.Length; i++)
|
|
||||||
if(inverse)
|
|
||||||
localHashInt =
|
|
||||||
(ushort)(localTable[(localHashInt >> 8) ^ fileStream.ReadByte()] ^ (localHashInt << 8));
|
|
||||||
else
|
|
||||||
localHashInt =
|
|
||||||
(ushort)((localHashInt >> 8) ^ localTable[fileStream.ReadByte() ^ (localHashInt & 0xff)]);
|
|
||||||
|
|
||||||
localHashInt ^= seed;
|
|
||||||
|
|
||||||
if(inverse)
|
|
||||||
localHashInt = (ushort)~localHashInt;
|
|
||||||
|
|
||||||
hash = BigEndianBitConverter.GetBytes(localHashInt);
|
|
||||||
|
|
||||||
var crc16Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash)
|
|
||||||
crc16Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
fileStream.Close();
|
|
||||||
|
|
||||||
return crc16Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of the data buffer to hash.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
/// <param name="polynomial">CRC polynomial</param>
|
|
||||||
/// <param name="seed">CRC seed</param>
|
|
||||||
public static string Data(byte[] data, uint len, out byte[] hash, ushort polynomial, ushort seed,
|
|
||||||
ushort[] table, bool inverse)
|
|
||||||
{
|
|
||||||
ushort localHashInt = seed;
|
|
||||||
|
|
||||||
ushort[] localTable = table ?? GenerateTable(polynomial, inverse);
|
|
||||||
|
|
||||||
for(int i = 0; i < len; i++)
|
|
||||||
if(inverse)
|
|
||||||
localHashInt = (ushort)(localTable[(localHashInt >> 8) ^ data[i]] ^ (localHashInt << 8));
|
|
||||||
else
|
|
||||||
localHashInt = (ushort)((localHashInt >> 8) ^ localTable[data[i] ^ (localHashInt & 0xff)]);
|
|
||||||
|
|
||||||
localHashInt ^= seed;
|
|
||||||
|
|
||||||
if(inverse)
|
|
||||||
localHashInt = (ushort)~localHashInt;
|
|
||||||
|
|
||||||
hash = BigEndianBitConverter.GetBytes(localHashInt);
|
|
||||||
|
|
||||||
var crc16Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash)
|
|
||||||
crc16Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
return crc16Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ushort Calculate(byte[] buffer, ushort polynomial, ushort seed, ushort[] table, bool inverse)
|
|
||||||
{
|
|
||||||
ushort[] localTable = table ?? GenerateTable(polynomial, inverse);
|
|
||||||
|
|
||||||
ushort crc16 =
|
|
||||||
buffer.Aggregate<byte, ushort>(0,
|
|
||||||
(current, b) =>
|
|
||||||
inverse ? (ushort)(localTable[(current >> 8) ^ b] ^ (current << 8))
|
|
||||||
: (ushort)((current >> 8) ^
|
|
||||||
localTable[b ^ (current & 0xff)]));
|
|
||||||
|
|
||||||
crc16 ^= seed;
|
|
||||||
|
|
||||||
if(inverse)
|
|
||||||
crc16 = (ushort)~crc16;
|
|
||||||
|
|
||||||
return crc16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
namespace DiscImageChef.Checksums
|
|
||||||
{
|
|
||||||
public class CRC16IBMContext : Crc16Context
|
|
||||||
{
|
|
||||||
const ushort CRC16_IBM_POLY = 0xA001;
|
|
||||||
const ushort CRC16_IBM_SEED = 0x0000;
|
|
||||||
|
|
||||||
static readonly ushort[] _ibmCrc16Table =
|
|
||||||
{
|
|
||||||
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500,
|
|
||||||
0xC5C1, 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1,
|
|
||||||
0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81,
|
|
||||||
0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1, 0xD581, 0x1540,
|
|
||||||
0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001,
|
|
||||||
0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0,
|
|
||||||
0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80,
|
|
||||||
0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
|
|
||||||
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700,
|
|
||||||
0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 0xA001, 0x60C0,
|
|
||||||
0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480,
|
|
||||||
0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41,
|
|
||||||
0x6900, 0xA9C1, 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01,
|
|
||||||
0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1,
|
|
||||||
0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1, 0x9181,
|
|
||||||
0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
|
|
||||||
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901,
|
|
||||||
0x59C0, 0x5880, 0x9841, 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 0x4E00, 0x8EC1,
|
|
||||||
0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680,
|
|
||||||
0x8641, 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
|
|
||||||
};
|
|
||||||
|
|
||||||
public CRC16IBMContext() : base(CRC16_IBM_POLY, CRC16_IBM_SEED, _ibmCrc16Table, false) { }
|
|
||||||
|
|
||||||
/// <summary>Gets the hash of a file</summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
public static byte[] File(string filename)
|
|
||||||
{
|
|
||||||
File(filename, out byte[] hash);
|
|
||||||
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Gets the hash of a file in hexadecimal and as a byte array.</summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string File(string filename, out byte[] hash) =>
|
|
||||||
File(filename, out hash, CRC16_IBM_POLY, CRC16_IBM_SEED, _ibmCrc16Table, false);
|
|
||||||
|
|
||||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of the data buffer to hash.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, uint len, out byte[] hash) =>
|
|
||||||
Data(data, len, out hash, CRC16_IBM_POLY, CRC16_IBM_SEED, _ibmCrc16Table, false);
|
|
||||||
|
|
||||||
/// <summary>Gets the hash of the specified data buffer.</summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
|
||||||
|
|
||||||
public static ushort Calculate(byte[] buffer) =>
|
|
||||||
Calculate(buffer, CRC16_IBM_POLY, CRC16_IBM_SEED, _ibmCrc16Table, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
// /***************************************************************************
|
|
||||||
// The Disc Image Chef
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Filename : CRC32Context.cs
|
|
||||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
||||||
//
|
|
||||||
// Component : Checksums.
|
|
||||||
//
|
|
||||||
// --[ Description ] ----------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Implements a CRC32 algorithm.
|
|
||||||
//
|
|
||||||
// --[ License ] --------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as
|
|
||||||
// published by the Free Software Foundation; either version 2.1 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful, but
|
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Copyright © 2011-2020 Natalia Portillo
|
|
||||||
// ****************************************************************************/
|
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using DiscImageChef.CommonTypes.Interfaces;
|
|
||||||
|
|
||||||
namespace DiscImageChef.Checksums
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Implements a CRC32 algorithm
|
|
||||||
/// </summary>
|
|
||||||
public class Crc32Context : IChecksum
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the CRC32 table and seed as CRC32-ISO
|
|
||||||
/// </summary>
|
|
||||||
public Crc32Context()
|
|
||||||
{
|
|
||||||
hashInt = CRC32_ISO_SEED;
|
|
||||||
finalSeed = CRC32_ISO_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) ^ CRC32_ISO_POLY;
|
|
||||||
else entry = entry >> 1;
|
|
||||||
|
|
||||||
table[i] = entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the CRC32 table with a custom polynomial and seed
|
|
||||||
/// </summary>
|
|
||||||
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;
|
|
||||||
|
|
||||||
table[i] = entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of buffer to hash.</param>
|
|
||||||
public void Update(byte[] data, uint len)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < len; i++) hashInt = (hashInt >> 8) ^ table[data[i] ^ (hashInt & 0xff)];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
public void Update(byte[] data)
|
|
||||||
{
|
|
||||||
Update(data, (uint)data.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a byte array of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public byte[] Final() => BigEndianBitConverter.GetBytes(hashInt ^ finalSeed);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a hexadecimal representation of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public string End()
|
|
||||||
{
|
|
||||||
StringBuilder crc32Output = new StringBuilder();
|
|
||||||
|
|
||||||
for(int i = 0; i < BigEndianBitConverter.GetBytes(hashInt ^ finalSeed).Length; i++)
|
|
||||||
crc32Output.Append(BigEndianBitConverter.GetBytes(hashInt ^ finalSeed)[i].ToString("x2"));
|
|
||||||
|
|
||||||
return crc32Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
public static byte[] File(string filename)
|
|
||||||
{
|
|
||||||
File(filename, out byte[] hash);
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file in hexadecimal and as a byte array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string File(string filename, out byte[] hash) =>
|
|
||||||
File(filename, out hash, CRC32_ISO_POLY, CRC32_ISO_SEED);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file in hexadecimal and as a byte array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
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++)
|
|
||||||
{
|
|
||||||
uint entry = (uint)i;
|
|
||||||
for(int j = 0; j < 8; j++)
|
|
||||||
if((entry & 1) == 1) entry = (entry >> 1) ^ polynomial;
|
|
||||||
else entry = entry >> 1;
|
|
||||||
|
|
||||||
localTable[i] = entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; i < fileStream.Length; i++)
|
|
||||||
localhashInt = (localhashInt >> 8) ^ localTable[fileStream.ReadByte() ^ (localhashInt & 0xff)];
|
|
||||||
|
|
||||||
localhashInt ^= seed;
|
|
||||||
hash = BigEndianBitConverter.GetBytes(localhashInt);
|
|
||||||
|
|
||||||
StringBuilder crc32Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) crc32Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
fileStream.Close();
|
|
||||||
|
|
||||||
return crc32Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of the data buffer to hash.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, uint len, out byte[] hash) =>
|
|
||||||
Data(data, len, out hash, CRC32_ISO_POLY, CRC32_ISO_SEED);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of the data buffer to hash.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
/// <param name="polynomial">CRC polynomial</param>
|
|
||||||
/// <param name="seed">CRC seed</param>
|
|
||||||
public static string Data(byte[] data, uint len, out byte[] hash, uint polynomial, uint seed)
|
|
||||||
{
|
|
||||||
uint localhashInt = seed;
|
|
||||||
|
|
||||||
uint[] localTable = 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;
|
|
||||||
|
|
||||||
localTable[i] = entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; i < len; i++)
|
|
||||||
localhashInt = (localhashInt >> 8) ^ localTable[data[i] ^ (localhashInt & 0xff)];
|
|
||||||
|
|
||||||
localhashInt ^= seed;
|
|
||||||
hash = BigEndianBitConverter.GetBytes(localhashInt);
|
|
||||||
|
|
||||||
StringBuilder crc32Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) crc32Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
return crc32Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
// /***************************************************************************
|
|
||||||
// The Disc Image Chef
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Filename : CRC64Context.cs
|
|
||||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
||||||
//
|
|
||||||
// Component : Checksums.
|
|
||||||
//
|
|
||||||
// --[ Description ] ----------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Implements a CRC64 algorithm.
|
|
||||||
//
|
|
||||||
// --[ License ] --------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as
|
|
||||||
// published by the Free Software Foundation; either version 2.1 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful, but
|
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Copyright © 2011-2020 Natalia Portillo
|
|
||||||
// ****************************************************************************/
|
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using DiscImageChef.CommonTypes.Interfaces;
|
|
||||||
|
|
||||||
namespace DiscImageChef.Checksums
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Implements a CRC64 algorithm
|
|
||||||
/// </summary>
|
|
||||||
public class Crc64Context : IChecksum
|
|
||||||
{
|
|
||||||
public const ulong CRC64_ECMA_POLY = 0xC96C5795D7870F42;
|
|
||||||
public const ulong CRC64_ECMA_SEED = 0xFFFFFFFFFFFFFFFF;
|
|
||||||
|
|
||||||
readonly ulong finalSeed;
|
|
||||||
readonly ulong[] table;
|
|
||||||
ulong hashInt;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the CRC64 table and seed as CRC64-ECMA
|
|
||||||
/// </summary>
|
|
||||||
public Crc64Context()
|
|
||||||
{
|
|
||||||
hashInt = CRC64_ECMA_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) ^ CRC64_ECMA_POLY;
|
|
||||||
else entry = entry >> 1;
|
|
||||||
|
|
||||||
table[i] = entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
finalSeed = CRC64_ECMA_SEED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the CRC16 table with a custom polynomial and seed
|
|
||||||
/// </summary>
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of buffer to hash.</param>
|
|
||||||
public void Update(byte[] data, uint len)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < len; i++) hashInt = (hashInt >> 8) ^ table[data[i] ^ (hashInt & 0xff)];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
public void Update(byte[] data)
|
|
||||||
{
|
|
||||||
Update(data, (uint)data.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a byte array of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public byte[] Final() => BigEndianBitConverter.GetBytes(hashInt ^= finalSeed);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a hexadecimal representation of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public string End()
|
|
||||||
{
|
|
||||||
StringBuilder crc64Output = new StringBuilder();
|
|
||||||
|
|
||||||
for(int i = 0; i < BigEndianBitConverter.GetBytes(hashInt ^= finalSeed).Length; i++)
|
|
||||||
crc64Output.Append(BigEndianBitConverter.GetBytes(hashInt ^= finalSeed)[i].ToString("x2"));
|
|
||||||
|
|
||||||
return crc64Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
public static byte[] File(string filename)
|
|
||||||
{
|
|
||||||
File(filename, out byte[] localHash);
|
|
||||||
return localHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file in hexadecimal and as a byte array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string File(string filename, out byte[] hash) =>
|
|
||||||
File(filename, out hash, CRC64_ECMA_POLY, CRC64_ECMA_SEED);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file in hexadecimal and as a byte array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
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++)
|
|
||||||
{
|
|
||||||
ulong entry = (ulong)i;
|
|
||||||
for(int j = 0; j < 8; j++)
|
|
||||||
if((entry & 1) == 1) entry = (entry >> 1) ^ polynomial;
|
|
||||||
else entry = entry >> 1;
|
|
||||||
|
|
||||||
localTable[i] = entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; i < fileStream.Length; i++)
|
|
||||||
localhashInt = (localhashInt >> 8) ^ localTable[(ulong)fileStream.ReadByte() ^ (localhashInt & 0xffL)];
|
|
||||||
|
|
||||||
localhashInt ^= seed;
|
|
||||||
hash = BigEndianBitConverter.GetBytes(localhashInt);
|
|
||||||
|
|
||||||
StringBuilder crc64Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) crc64Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
fileStream.Close();
|
|
||||||
|
|
||||||
return crc64Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of the data buffer to hash.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, uint len, out byte[] hash) =>
|
|
||||||
Data(data, len, out hash, CRC64_ECMA_POLY, CRC64_ECMA_SEED);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of the data buffer to hash.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
/// <param name="polynomial">CRC polynomial</param>
|
|
||||||
/// <param name="seed">CRC seed</param>
|
|
||||||
public static string Data(byte[] data, uint len, out byte[] hash, ulong polynomial, ulong seed)
|
|
||||||
{
|
|
||||||
ulong localhashInt = seed;
|
|
||||||
|
|
||||||
ulong[] localTable = 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;
|
|
||||||
|
|
||||||
localTable[i] = entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; i < len; i++)
|
|
||||||
localhashInt = (localhashInt >> 8) ^ localTable[data[i] ^ (localhashInt & 0xff)];
|
|
||||||
|
|
||||||
localhashInt ^= seed;
|
|
||||||
hash = BigEndianBitConverter.GetBytes(localhashInt);
|
|
||||||
|
|
||||||
StringBuilder crc64Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) crc64Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
return crc64Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<PropertyGroup>
|
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
|
||||||
<ProjectGuid>{CC48B324-A532-4A45-87A6-6F91F7141E8D}</ProjectGuid>
|
|
||||||
<OutputType>Library</OutputType>
|
|
||||||
<RootNamespace>DiscImageChef.Checksums</RootNamespace>
|
|
||||||
<AssemblyName>DiscImageChef.Checksums</AssemblyName>
|
|
||||||
<ReleaseVersion>$(Version)</ReleaseVersion>
|
|
||||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
|
||||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
|
||||||
<Version>4.5.99.1693</Version>
|
|
||||||
<Company>Claunia.com</Company>
|
|
||||||
<Copyright>Copyright © 2011-2020 Natalia Portillo</Copyright>
|
|
||||||
<Product>The Disc Image Chef</Product>
|
|
||||||
<Title>DiscImageChef.Checksums</Title>
|
|
||||||
<ApplicationVersion>$(Version)</ApplicationVersion>
|
|
||||||
<TargetFrameworks>net461;netstandard2.0;netcoreapp2.0</TargetFrameworks>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup>
|
|
||||||
<NrtRevisionFormat>$(Version)-{chash:8} built by {mname} in $(Configuration){!:, modified}</NrtRevisionFormat>
|
|
||||||
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
|
|
||||||
<NrtShowRevision>true</NrtShowRevision>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Debug</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<ConsolePause>false</ConsolePause>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<OutputPath>bin\Release</OutputPath>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<ConsolePause>false</ConsolePause>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="System" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="CRC16CCITTContext.cs" />
|
|
||||||
<Compile Include="CRC16IBMContext.cs" />
|
|
||||||
<Compile Include="Register.cs" />
|
|
||||||
<Compile Include="SpamSumContext.cs" />
|
|
||||||
<Compile Include="Adler32Context.cs" />
|
|
||||||
<Compile Include="CDChecksums.cs" />
|
|
||||||
<Compile Include="CRC16Context.cs" />
|
|
||||||
<Compile Include="CRC32Context.cs" />
|
|
||||||
<Compile Include="CRC64Context.cs" />
|
|
||||||
<Compile Include="FletcherContext.cs" />
|
|
||||||
<Compile Include="MD5Context.cs" />
|
|
||||||
<Compile Include="ReedSolomon.cs" />
|
|
||||||
<Compile Include="SHA1Context.cs" />
|
|
||||||
<Compile Include="SHA256Context.cs" />
|
|
||||||
<Compile Include="SHA384Context.cs" />
|
|
||||||
<Compile Include="SHA512Context.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\DiscImageChef.CommonTypes\DiscImageChef.CommonTypes.csproj" />
|
|
||||||
<ProjectReference Include="..\DiscImageChef.Helpers\DiscImageChef.Helpers.csproj">
|
|
||||||
<Project>{F8BDF57B-1571-4CD0-84B3-B422088D359A}</Project>
|
|
||||||
<Name>DiscImageChef.Helpers</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
<ProjectReference Include="..\DiscImageChef.Console\DiscImageChef.Console.csproj">
|
|
||||||
<Project>{CCAA7AFE-C094-4D82-A66D-630DE8A3F545}</Project>
|
|
||||||
<Name>DiscImageChef.Console</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<EmbeddedResource Include="..\LICENSE.LGPL">
|
|
||||||
<Link>LICENSE.LGPL</Link>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Include="..\LICENSE">
|
|
||||||
<Link>LICENSE</Link>
|
|
||||||
</EmbeddedResource>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.3.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ProjectExtensions>
|
|
||||||
<MonoDevelop>
|
|
||||||
<Properties>
|
|
||||||
<Policies>
|
|
||||||
<StandardHeader IncludeInNewFiles="True" Text="/***************************************************************************
The Disc Image Chef
----------------------------------------------------------------------------
 
Filename : ${FileName}
Author(s) : ${AuthorName} <${AuthorEmail}>

Component : Component
 
--[ Description ] ----------------------------------------------------------
 
 Description
 
--[ License ] --------------------------------------------------------------
 
 This library is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as
 published by the Free Software Foundation; either version 2.1 of the
 License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, see <http://www.gnu.org/licenses/>.

----------------------------------------------------------------------------
Copyright © 2011-${Year} ${CopyrightHolder}
****************************************************************************/" />
|
|
||||||
<TextStylePolicy FileWidth="120" TabWidth="4" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" TabsToSpaces="True" scope="text/x-csharp" />
|
|
||||||
<CSharpFormattingPolicy IndentBlock="True" IndentBraces="False" IndentSwitchSection="True" IndentSwitchCaseSection="True" LabelPositioning="OneLess" NewLinesForBracesInTypes="True" NewLinesForBracesInMethods="True" NewLinesForBracesInProperties="True" NewLinesForBracesInAccessors="True" NewLinesForBracesInAnonymousMethods="True" NewLinesForBracesInControlBlocks="True" NewLinesForBracesInAnonymousTypes="True" NewLinesForBracesInObjectCollectionArrayInitializers="True" NewLinesForBracesInLambdaExpressionBody="True" NewLineForElse="True" NewLineForCatch="True" NewLineForFinally="True" NewLineForMembersInObjectInit="True" NewLineForMembersInAnonymousTypes="True" NewLineForClausesInQuery="True" SpacingAfterMethodDeclarationName="False" SpaceWithinMethodDeclarationParenthesis="False" SpaceBetweenEmptyMethodDeclarationParentheses="False" SpaceAfterMethodCallName="False" SpaceWithinMethodCallParentheses="False" SpaceBetweenEmptyMethodCallParentheses="False" SpaceWithinExpressionParentheses="False" SpaceWithinCastParentheses="False" SpaceWithinOtherParentheses="False" SpaceAfterCast="False" SpacesIgnoreAroundVariableDeclaration="False" SpaceBeforeOpenSquareBracket="False" SpaceBetweenEmptySquareBrackets="False" SpaceWithinSquareBrackets="False" SpaceAfterColonInBaseTypeDeclaration="True" SpaceAfterComma="True" SpaceAfterDot="False" SpaceAfterSemicolonsInForStatement="True" SpaceBeforeColonInBaseTypeDeclaration="True" SpaceBeforeComma="False" SpaceBeforeDot="False" SpaceBeforeSemicolonsInForStatement="False" SpacingAroundBinaryOperator="Single" WrappingPreserveSingleLine="True" WrappingKeepStatementsOnSingleLine="True" PlaceSystemDirectiveFirst="True" SpaceAfterControlFlowStatementKeyword="False" scope="text/x-csharp" />
|
|
||||||
</Policies>
|
|
||||||
</Properties>
|
|
||||||
</MonoDevelop>
|
|
||||||
</ProjectExtensions>
|
|
||||||
<PropertyGroup Condition="$(TargetFramework.StartsWith('net4')) and '$(OS)' == 'Unix'">
|
|
||||||
<!-- When compiling .NET SDK 2.0 projects targeting .NET 4.x on Mono using 'dotnet build' you -->
|
|
||||||
<!-- have to teach MSBuild where the Mono copy of the reference asssemblies is -->
|
|
||||||
<!-- Look in the standard install locations -->
|
|
||||||
<BaseFrameworkPathOverrideForMono Condition="'$(BaseFrameworkPathOverrideForMono)' == '' AND EXISTS('/Library/Frameworks/Mono.framework/Versions/Current/lib/mono')">/Library/Frameworks/Mono.framework/Versions/Current/lib/mono</BaseFrameworkPathOverrideForMono>
|
|
||||||
<BaseFrameworkPathOverrideForMono Condition="'$(BaseFrameworkPathOverrideForMono)' == '' AND EXISTS('/usr/lib/mono')">/usr/lib/mono</BaseFrameworkPathOverrideForMono>
|
|
||||||
<BaseFrameworkPathOverrideForMono Condition="'$(BaseFrameworkPathOverrideForMono)' == '' AND EXISTS('/usr/local/lib/mono')">/usr/local/lib/mono</BaseFrameworkPathOverrideForMono>
|
|
||||||
<!-- If we found Mono reference assemblies, then use them -->
|
|
||||||
<FrameworkPathOverride Condition="'$(BaseFrameworkPathOverrideForMono)' != '' AND '$(TargetFramework)' == 'net40'">$(BaseFrameworkPathOverrideForMono)/4.0-api</FrameworkPathOverride>
|
|
||||||
<FrameworkPathOverride Condition="'$(BaseFrameworkPathOverrideForMono)' != '' AND '$(TargetFramework)' == 'net45'">$(BaseFrameworkPathOverrideForMono)/4.5-api</FrameworkPathOverride>
|
|
||||||
<FrameworkPathOverride Condition="'$(BaseFrameworkPathOverrideForMono)' != '' AND '$(TargetFramework)' == 'net451'">$(BaseFrameworkPathOverrideForMono)/4.5.1-api</FrameworkPathOverride>
|
|
||||||
<FrameworkPathOverride Condition="'$(BaseFrameworkPathOverrideForMono)' != '' AND '$(TargetFramework)' == 'net452'">$(BaseFrameworkPathOverrideForMono)/4.5.2-api</FrameworkPathOverride>
|
|
||||||
<FrameworkPathOverride Condition="'$(BaseFrameworkPathOverrideForMono)' != '' AND '$(TargetFramework)' == 'net46'">$(BaseFrameworkPathOverrideForMono)/4.6-api</FrameworkPathOverride>
|
|
||||||
<FrameworkPathOverride Condition="'$(BaseFrameworkPathOverrideForMono)' != '' AND '$(TargetFramework)' == 'net461'">$(BaseFrameworkPathOverrideForMono)/4.6.1-api</FrameworkPathOverride>
|
|
||||||
<FrameworkPathOverride Condition="'$(BaseFrameworkPathOverrideForMono)' != '' AND '$(TargetFramework)' == 'net462'">$(BaseFrameworkPathOverrideForMono)/4.6.2-api</FrameworkPathOverride>
|
|
||||||
<FrameworkPathOverride Condition="'$(BaseFrameworkPathOverrideForMono)' != '' AND '$(TargetFramework)' == 'net47'">$(BaseFrameworkPathOverrideForMono)/4.7-api</FrameworkPathOverride>
|
|
||||||
<FrameworkPathOverride Condition="'$(BaseFrameworkPathOverrideForMono)' != '' AND '$(TargetFramework)' == 'net471'">$(BaseFrameworkPathOverrideForMono)/4.7.1-api</FrameworkPathOverride>
|
|
||||||
<EnableFrameworkPathOverride Condition="'$(BaseFrameworkPathOverrideForMono)' != ''">true</EnableFrameworkPathOverride>
|
|
||||||
<!-- Add the Facades directory. Not sure how else to do this. Necessary at least for .NET 4.5 -->
|
|
||||||
<AssemblySearchPaths Condition="'$(BaseFrameworkPathOverrideForMono)' != ''">$(FrameworkPathOverride)/Facades;$(AssemblySearchPaths)</AssemblySearchPaths>
|
|
||||||
</PropertyGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -1,320 +0,0 @@
|
|||||||
// /***************************************************************************
|
|
||||||
// The Disc Image Chef
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Filename : FletcherContext.cs
|
|
||||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
||||||
//
|
|
||||||
// Component : Checksums.
|
|
||||||
//
|
|
||||||
// --[ Description ] ----------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Implements Fletcher-32 and Fletcher-16 algorithms.
|
|
||||||
//
|
|
||||||
// --[ License ] --------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as
|
|
||||||
// published by the Free Software Foundation; either version 2.1 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful, but
|
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Copyright © 2011-2020 Natalia Portillo
|
|
||||||
// ****************************************************************************/
|
|
||||||
|
|
||||||
// Disabled because the speed is abnormally slow
|
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using DiscImageChef.CommonTypes.Interfaces;
|
|
||||||
|
|
||||||
namespace DiscImageChef.Checksums
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Implements the Fletcher-32 algorithm
|
|
||||||
/// </summary>
|
|
||||||
public class Fletcher32Context : IChecksum
|
|
||||||
{
|
|
||||||
const ushort FLETCHER_MODULE = 0xFFFF;
|
|
||||||
ushort sum1, sum2;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the Fletcher-32 sums
|
|
||||||
/// </summary>
|
|
||||||
public Fletcher32Context()
|
|
||||||
{
|
|
||||||
sum1 = 0xFFFF;
|
|
||||||
sum2 = 0xFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of buffer to hash.</param>
|
|
||||||
public void Update(byte[] data, uint len)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
sum1 = (ushort)((sum1 + data[i]) % FLETCHER_MODULE);
|
|
||||||
sum2 = (ushort)((sum2 + sum1) % FLETCHER_MODULE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
public void Update(byte[] data)
|
|
||||||
{
|
|
||||||
Update(data, (uint)data.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a byte array of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public byte[] Final()
|
|
||||||
{
|
|
||||||
uint finalSum = (uint)((sum2 << 16) | sum1);
|
|
||||||
return BigEndianBitConverter.GetBytes(finalSum);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a hexadecimal representation of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public string End()
|
|
||||||
{
|
|
||||||
uint finalSum = (uint)((sum2 << 16) | sum1);
|
|
||||||
StringBuilder fletcherOutput = new StringBuilder();
|
|
||||||
|
|
||||||
for(int i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++)
|
|
||||||
fletcherOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2"));
|
|
||||||
|
|
||||||
return fletcherOutput.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
public static byte[] File(string filename)
|
|
||||||
{
|
|
||||||
File(filename, out byte[] hash);
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file in hexadecimal and as a byte array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string File(string filename, out byte[] hash)
|
|
||||||
{
|
|
||||||
FileStream fileStream = new FileStream(filename, FileMode.Open);
|
|
||||||
|
|
||||||
ushort localSum1 = 0xFFFF;
|
|
||||||
ushort localSum2 = 0xFFFF;
|
|
||||||
|
|
||||||
for(int i = 0; i < fileStream.Length; i++)
|
|
||||||
{
|
|
||||||
localSum1 = (ushort)((localSum1 + fileStream.ReadByte()) % FLETCHER_MODULE);
|
|
||||||
localSum2 = (ushort)((localSum2 + localSum1) % FLETCHER_MODULE);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint finalSum = (uint)((localSum2 << 16) | localSum1);
|
|
||||||
|
|
||||||
hash = BigEndianBitConverter.GetBytes(finalSum);
|
|
||||||
|
|
||||||
StringBuilder fletcherOutput = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) fletcherOutput.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
fileStream.Close();
|
|
||||||
|
|
||||||
return fletcherOutput.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of the data buffer to hash.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, uint len, out byte[] hash)
|
|
||||||
{
|
|
||||||
ushort localSum1 = 0xFFFF;
|
|
||||||
ushort localSum2 = 0xFFFF;
|
|
||||||
|
|
||||||
for(int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
localSum1 = (ushort)((localSum1 + data[i]) % FLETCHER_MODULE);
|
|
||||||
localSum2 = (ushort)((localSum2 + localSum1) % FLETCHER_MODULE);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint finalSum = (uint)((localSum2 << 16) | localSum1);
|
|
||||||
|
|
||||||
hash = BigEndianBitConverter.GetBytes(finalSum);
|
|
||||||
|
|
||||||
StringBuilder adlerOutput = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) adlerOutput.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
return adlerOutput.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Implements the Fletcher-16 algorithm
|
|
||||||
/// </summary>
|
|
||||||
public class Fletcher16Context : IChecksum
|
|
||||||
{
|
|
||||||
const byte FLETCHER_MODULE = 0xFF;
|
|
||||||
byte sum1, sum2;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the Fletcher-16 sums
|
|
||||||
/// </summary>
|
|
||||||
public Fletcher16Context()
|
|
||||||
{
|
|
||||||
sum1 = 0xFF;
|
|
||||||
sum2 = 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of buffer to hash.</param>
|
|
||||||
public void Update(byte[] data, uint len)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
sum1 = (byte)((sum1 + data[i]) % FLETCHER_MODULE);
|
|
||||||
sum2 = (byte)((sum2 + sum1) % FLETCHER_MODULE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
public void Update(byte[] data)
|
|
||||||
{
|
|
||||||
Update(data, (uint)data.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a byte array of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public byte[] Final()
|
|
||||||
{
|
|
||||||
ushort finalSum = (ushort)((sum2 << 8) | sum1);
|
|
||||||
return BigEndianBitConverter.GetBytes(finalSum);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a hexadecimal representation of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public string End()
|
|
||||||
{
|
|
||||||
ushort finalSum = (ushort)((sum2 << 8) | sum1);
|
|
||||||
StringBuilder fletcherOutput = new StringBuilder();
|
|
||||||
|
|
||||||
for(int i = 0; i < BigEndianBitConverter.GetBytes(finalSum).Length; i++)
|
|
||||||
fletcherOutput.Append(BigEndianBitConverter.GetBytes(finalSum)[i].ToString("x2"));
|
|
||||||
|
|
||||||
return fletcherOutput.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
public static byte[] File(string filename)
|
|
||||||
{
|
|
||||||
File(filename, out byte[] hash);
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file in hexadecimal and as a byte array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string File(string filename, out byte[] hash)
|
|
||||||
{
|
|
||||||
FileStream fileStream = new FileStream(filename, FileMode.Open);
|
|
||||||
|
|
||||||
byte localSum1 = 0xFF;
|
|
||||||
byte localSum2 = 0xFF;
|
|
||||||
|
|
||||||
for(int i = 0; i < fileStream.Length; i++)
|
|
||||||
{
|
|
||||||
localSum1 = (byte)((localSum1 + fileStream.ReadByte()) % FLETCHER_MODULE);
|
|
||||||
localSum2 = (byte)((localSum2 + localSum1) % FLETCHER_MODULE);
|
|
||||||
}
|
|
||||||
|
|
||||||
ushort finalSum = (ushort)((localSum2 << 8) | localSum1);
|
|
||||||
|
|
||||||
hash = BigEndianBitConverter.GetBytes(finalSum);
|
|
||||||
|
|
||||||
StringBuilder fletcherOutput = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) fletcherOutput.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
fileStream.Close();
|
|
||||||
|
|
||||||
return fletcherOutput.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of the data buffer to hash.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, uint len, out byte[] hash)
|
|
||||||
{
|
|
||||||
byte localSum1 = 0xFF;
|
|
||||||
byte localSum2 = 0xFF;
|
|
||||||
|
|
||||||
for(int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
localSum1 = (byte)((localSum1 + data[i]) % FLETCHER_MODULE);
|
|
||||||
localSum2 = (byte)((localSum2 + localSum1) % FLETCHER_MODULE);
|
|
||||||
}
|
|
||||||
|
|
||||||
ushort finalSum = (ushort)((localSum2 << 8) | localSum1);
|
|
||||||
|
|
||||||
hash = BigEndianBitConverter.GetBytes(finalSum);
|
|
||||||
|
|
||||||
StringBuilder adlerOutput = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) adlerOutput.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
return adlerOutput.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
// /***************************************************************************
|
|
||||||
// The Disc Image Chef
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Filename : MD5Context.cs
|
|
||||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
||||||
//
|
|
||||||
// Component : Checksums.
|
|
||||||
//
|
|
||||||
// --[ Description ] ----------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Wraps up .NET MD5 implementation to a Init(), Update(), Final() context.
|
|
||||||
//
|
|
||||||
// --[ License ] --------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as
|
|
||||||
// published by the Free Software Foundation; either version 2.1 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful, but
|
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Copyright © 2011-2020 Natalia Portillo
|
|
||||||
// ****************************************************************************/
|
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using DiscImageChef.CommonTypes.Interfaces;
|
|
||||||
|
|
||||||
namespace DiscImageChef.Checksums
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Wraps up .NET MD5 implementation to a Init(), Update(), Final() context.
|
|
||||||
/// </summary>
|
|
||||||
public class Md5Context : IChecksum
|
|
||||||
{
|
|
||||||
MD5 md5Provider;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the MD5 hash provider
|
|
||||||
/// </summary>
|
|
||||||
public Md5Context()
|
|
||||||
{
|
|
||||||
md5Provider = MD5.Create();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of buffer to hash.</param>
|
|
||||||
public void Update(byte[] data, uint len)
|
|
||||||
{
|
|
||||||
md5Provider.TransformBlock(data, 0, (int)len, data, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
public void Update(byte[] data)
|
|
||||||
{
|
|
||||||
Update(data, (uint)data.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a byte array of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public byte[] Final()
|
|
||||||
{
|
|
||||||
md5Provider.TransformFinalBlock(new byte[0], 0, 0);
|
|
||||||
return md5Provider.Hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a hexadecimal representation of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public string End()
|
|
||||||
{
|
|
||||||
md5Provider.TransformFinalBlock(new byte[0], 0, 0);
|
|
||||||
StringBuilder md5Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in md5Provider.Hash) md5Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
return md5Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
public static byte[] File(string filename)
|
|
||||||
{
|
|
||||||
MD5 localMd5Provider = MD5.Create();
|
|
||||||
FileStream fileStream = new FileStream(filename, FileMode.Open);
|
|
||||||
byte[] result = localMd5Provider.ComputeHash(fileStream);
|
|
||||||
fileStream.Close();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file in hexadecimal and as a byte array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string File(string filename, out byte[] hash)
|
|
||||||
{
|
|
||||||
MD5 localMd5Provider = MD5.Create();
|
|
||||||
FileStream fileStream = new FileStream(filename, FileMode.Open);
|
|
||||||
hash = localMd5Provider.ComputeHash(fileStream);
|
|
||||||
StringBuilder md5Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) md5Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
fileStream.Close();
|
|
||||||
|
|
||||||
return md5Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of the data buffer to hash.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, uint len, out byte[] hash)
|
|
||||||
{
|
|
||||||
MD5 localMd5Provider = MD5.Create();
|
|
||||||
hash = localMd5Provider.ComputeHash(data, 0, (int)len);
|
|
||||||
StringBuilder md5Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) md5Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
return md5Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,625 +0,0 @@
|
|||||||
// /***************************************************************************
|
|
||||||
// The Disc Image Chef
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Filename : ReedSolomon.cs
|
|
||||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
||||||
//
|
|
||||||
// Component : Checksums.
|
|
||||||
//
|
|
||||||
// --[ Description ] ----------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Calculates a Reed-Solomon.
|
|
||||||
//
|
|
||||||
// --[ License ] --------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as
|
|
||||||
// published by the Free Software Foundation, either version 3 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Copyright © 2011-2020 Natalia Portillo
|
|
||||||
// Copyright (C) 1996 Phil Karn
|
|
||||||
// Copyright (C) 1995 Robert Morelos-Zaragoza
|
|
||||||
// Copyright (C) 1995 Hari Thirumoorthy
|
|
||||||
// ****************************************************************************/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reed-Solomon coding and decoding
|
|
||||||
* Phil Karn (karn at ka9q.ampr.org) September 1996
|
|
||||||
*
|
|
||||||
* This file is derived from the program "new_rs_erasures.c" by Robert
|
|
||||||
* Morelos-Zaragoza (robert at spectra.eng.hawaii.edu) and Hari Thirumoorthy
|
|
||||||
* (harit at spectra.eng.hawaii.edu), Aug 1995
|
|
||||||
*
|
|
||||||
* I've made changes to improve performance, clean up the code and make it
|
|
||||||
* easier to follow. Data is now passed to the encoding and decoding functions
|
|
||||||
* through arguments rather than in global arrays. The decode function returns
|
|
||||||
* the number of corrected symbols, or -1 if the word is uncorrectable.
|
|
||||||
*
|
|
||||||
* This code supports a symbol size from 2 bits up to 16 bits,
|
|
||||||
* implying a block size of 3 2-bit symbols (6 bits) up to 65535
|
|
||||||
* 16-bit symbols (1,048,560 bits). The code parameters are set in rs.h.
|
|
||||||
*
|
|
||||||
* Note that if symbols larger than 8 bits are used, the type of each
|
|
||||||
* data array element switches from unsigned char to unsigned int. The
|
|
||||||
* caller must ensure that elements larger than the symbol range are
|
|
||||||
* not passed to the encoder or decoder.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using DiscImageChef.Console;
|
|
||||||
|
|
||||||
namespace DiscImageChef.Checksums
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Implements the Reed-Solomon algorithm
|
|
||||||
/// </summary>
|
|
||||||
public class ReedSolomon
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Alpha exponent for the first root of the generator polynomial
|
|
||||||
/// </summary>
|
|
||||||
const int B0 = 1;
|
|
||||||
/// <summary>
|
|
||||||
/// No legal value in index form represents zero, so we need a special value for this purpose
|
|
||||||
/// </summary>
|
|
||||||
int a0;
|
|
||||||
/// <summary>
|
|
||||||
/// index->polynomial form conversion table
|
|
||||||
/// </summary>
|
|
||||||
int[] alpha_to;
|
|
||||||
/// <summary>
|
|
||||||
/// Generator polynomial g(x) Degree of g(x) = 2*TT has roots @**B0, @**(B0+1), ... ,@^(B0+2*TT-1)
|
|
||||||
/// </summary>
|
|
||||||
int[] gg;
|
|
||||||
/// <summary>
|
|
||||||
/// Polynomial->index form conversion table
|
|
||||||
/// </summary>
|
|
||||||
int[] index_of;
|
|
||||||
bool initialized;
|
|
||||||
int mm, kk, nn;
|
|
||||||
/// <summary>
|
|
||||||
/// Primitive polynomials - see Lin & Costello, Error Control Coding Appendix A, and Lee & Messerschmitt, Digital
|
|
||||||
/// Communication p. 453.
|
|
||||||
/// </summary>
|
|
||||||
int[] pp;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the Reed-Solomon with RS(n,k) with GF(2^m)
|
|
||||||
/// </summary>
|
|
||||||
public void InitRs(int n, int k, int m)
|
|
||||||
{
|
|
||||||
switch(m)
|
|
||||||
{
|
|
||||||
case 2:
|
|
||||||
pp = new[] {1, 1, 1};
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
pp = new[] {1, 1, 0, 1};
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
pp = new[] {1, 1, 0, 0, 1};
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
pp = new[] {1, 0, 1, 0, 0, 1};
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
pp = new[] {1, 1, 0, 0, 0, 0, 1};
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
pp = new[] {1, 0, 0, 1, 0, 0, 0, 1};
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
pp = new[] {1, 0, 1, 1, 1, 0, 0, 0, 1};
|
|
||||||
break;
|
|
||||||
case 9:
|
|
||||||
pp = new[] {1, 0, 0, 0, 1, 0, 0, 0, 0, 1};
|
|
||||||
break;
|
|
||||||
case 10:
|
|
||||||
pp = new[] {1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1};
|
|
||||||
break;
|
|
||||||
case 11:
|
|
||||||
pp = new[] {1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
|
|
||||||
break;
|
|
||||||
case 12:
|
|
||||||
pp = new[] {1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1};
|
|
||||||
break;
|
|
||||||
case 13:
|
|
||||||
pp = new[] {1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
|
|
||||||
break;
|
|
||||||
case 14:
|
|
||||||
pp = new[] {1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1};
|
|
||||||
break;
|
|
||||||
case 15:
|
|
||||||
pp = new[] {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
|
|
||||||
break;
|
|
||||||
case 16:
|
|
||||||
pp = new[] {1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1};
|
|
||||||
break;
|
|
||||||
default: throw new ArgumentOutOfRangeException(nameof(m), "m must be between 2 and 16 inclusive");
|
|
||||||
}
|
|
||||||
|
|
||||||
mm = m;
|
|
||||||
kk = k;
|
|
||||||
nn = n;
|
|
||||||
a0 = n;
|
|
||||||
alpha_to = new int[n + 1];
|
|
||||||
index_of = new int[n + 1];
|
|
||||||
|
|
||||||
gg = new int[nn - kk + 1];
|
|
||||||
|
|
||||||
generate_gf();
|
|
||||||
gen_poly();
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Modnn(int x)
|
|
||||||
{
|
|
||||||
while(x >= nn)
|
|
||||||
{
|
|
||||||
x -= nn;
|
|
||||||
x = (x >> mm) + (x & nn);
|
|
||||||
}
|
|
||||||
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int Min(int a, int b) => a < b ? a : b;
|
|
||||||
|
|
||||||
static void Clear(ref int[] a, int n)
|
|
||||||
{
|
|
||||||
int ci;
|
|
||||||
for(ci = n - 1; ci >= 0; ci--) a[ci] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Copy(ref int[] a, ref int[] b, int n)
|
|
||||||
{
|
|
||||||
int ci;
|
|
||||||
for(ci = n - 1; ci >= 0; ci--) a[ci] = b[ci];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Copydown(ref int[] a, ref int[] b, int n)
|
|
||||||
{
|
|
||||||
int ci;
|
|
||||||
for(ci = n - 1; ci >= 0; ci--) a[ci] = b[ci];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m]
|
|
||||||
lookup tables: index->polynomial form alpha_to[] contains j=alpha**i;
|
|
||||||
polynomial form -> index form index_of[j=alpha**i] = i
|
|
||||||
alpha=2 is the primitive element of GF(2**m)
|
|
||||||
HARI's COMMENT: (4/13/94) alpha_to[] can be used as follows:
|
|
||||||
Let @ represent the primitive element commonly called "alpha" that
|
|
||||||
is the root of the primitive polynomial p(x). Then in GF(2^m), for any
|
|
||||||
0 <= i <= 2^m-2,
|
|
||||||
@^i = a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
|
|
||||||
where the binary vector (a(0),a(1),a(2),...,a(m-1)) is the representation
|
|
||||||
of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for
|
|
||||||
example the polynomial representation of @^5 would be given by the binary
|
|
||||||
representation of the integer "alpha_to[5]".
|
|
||||||
Similarily, index_of[] can be used as follows:
|
|
||||||
As above, let @ represent the primitive element of GF(2^m) that is
|
|
||||||
the root of the primitive polynomial p(x). In order to find the power
|
|
||||||
of @ (alpha) that has the polynomial representation
|
|
||||||
a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
|
|
||||||
we consider the integer "i" whose binary representation with a(0) being LSB
|
|
||||||
and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry
|
|
||||||
"index_of[i]". Now, @^index_of[i] is that element whose polynomial
|
|
||||||
representation is (a(0),a(1),a(2),...,a(m-1)).
|
|
||||||
NOTE:
|
|
||||||
The element alpha_to[2^m-1] = 0 always signifying that the
|
|
||||||
representation of "@^infinity" = 0 is (0,0,0,...,0).
|
|
||||||
Similarily, the element index_of[0] = A0 always signifying
|
|
||||||
that the power of alpha which has the polynomial representation
|
|
||||||
(0,0,...,0) is "infinity".
|
|
||||||
|
|
||||||
*/
|
|
||||||
void generate_gf()
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
int mask = 1;
|
|
||||||
alpha_to[mm] = 0;
|
|
||||||
for(i = 0; i < mm; i++)
|
|
||||||
{
|
|
||||||
alpha_to[i] = mask;
|
|
||||||
index_of[alpha_to[i]] = i;
|
|
||||||
/* If Pp[i] == 1 then, term @^i occurs in poly-repr of @^MM */
|
|
||||||
if(pp[i] != 0) alpha_to[mm] ^= mask; /* Bit-wise EXOR operation */
|
|
||||||
mask <<= 1; /* single left-shift */
|
|
||||||
}
|
|
||||||
|
|
||||||
index_of[alpha_to[mm]] = mm;
|
|
||||||
/*
|
|
||||||
* Have obtained poly-repr of @^MM. Poly-repr of @^(i+1) is given by
|
|
||||||
* poly-repr of @^i shifted left one-bit and accounting for any @^MM
|
|
||||||
* term that may occur when poly-repr of @^i is shifted.
|
|
||||||
*/
|
|
||||||
mask >>= 1;
|
|
||||||
for(i = mm + 1; i < nn; i++)
|
|
||||||
{
|
|
||||||
if(alpha_to[i - 1] >= mask) alpha_to[i] = alpha_to[mm] ^ ((alpha_to[i - 1] ^ mask) << 1);
|
|
||||||
else alpha_to[i] = alpha_to[i - 1] << 1;
|
|
||||||
index_of[alpha_to[i]] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
index_of[0] = a0;
|
|
||||||
alpha_to[nn] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Obtain the generator polynomial of the TT-error correcting, length
|
|
||||||
* NN=(2**MM -1) Reed Solomon code from the product of (X+@**(B0+i)), i = 0,
|
|
||||||
* ... ,(2*TT-1)
|
|
||||||
*
|
|
||||||
* Examples:
|
|
||||||
*
|
|
||||||
* If B0 = 1, TT = 1. deg(g(x)) = 2*TT = 2.
|
|
||||||
* g(x) = (x+@) (x+@**2)
|
|
||||||
*
|
|
||||||
* If B0 = 0, TT = 2. deg(g(x)) = 2*TT = 4.
|
|
||||||
* g(x) = (x+1) (x+@) (x+@**2) (x+@**3)
|
|
||||||
*/
|
|
||||||
void gen_poly()
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
gg[0] = alpha_to[B0];
|
|
||||||
gg[1] = 1; /* g(x) = (X+@**B0) initially */
|
|
||||||
for(i = 2; i <= nn - kk; i++)
|
|
||||||
{
|
|
||||||
gg[i] = 1;
|
|
||||||
/*
|
|
||||||
* Below multiply (Gg[0]+Gg[1]*x + ... +Gg[i]x^i) by
|
|
||||||
* (@**(B0+i-1) + x)
|
|
||||||
*/
|
|
||||||
for(int j = i - 1; j > 0; j--)
|
|
||||||
if(gg[j] != 0)
|
|
||||||
gg[j] = gg[j - 1] ^ alpha_to[Modnn(index_of[gg[j]] + B0 + i - 1)];
|
|
||||||
else
|
|
||||||
gg[j] = gg[j - 1];
|
|
||||||
/* Gg[0] can never be zero */
|
|
||||||
gg[0] = alpha_to[Modnn(index_of[gg[0]] + B0 + i - 1)];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* convert Gg[] to index form for quicker encoding */
|
|
||||||
for(i = 0; i <= nn - kk; i++) gg[i] = index_of[gg[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* take the string of symbols in data[i], i=0..(k-1) and encode
|
|
||||||
* systematically to produce NN-KK parity symbols in bb[0]..bb[NN-KK-1] data[]
|
|
||||||
* is input and bb[] is output in polynomial form. Encoding is done by using
|
|
||||||
* a feedback shift register with appropriate connections specified by the
|
|
||||||
* elements of Gg[], which was generated above. Codeword is c(X) =
|
|
||||||
* data(X)*X**(NN-KK)+ b(X)
|
|
||||||
*/
|
|
||||||
/// <summary>
|
|
||||||
/// Takes the symbols in data to output parity in bb.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Returns -1 if an illegal symbol is found.</returns>
|
|
||||||
/// <param name="data">Data symbols.</param>
|
|
||||||
/// <param name="bb">Outs parity symbols.</param>
|
|
||||||
public int encode_rs(int[] data, out int[] bb)
|
|
||||||
{
|
|
||||||
if(!initialized) throw new UnauthorizedAccessException("Trying to calculate RS without initializing!");
|
|
||||||
|
|
||||||
int i;
|
|
||||||
bb = new int[nn - kk];
|
|
||||||
|
|
||||||
Clear(ref bb, nn - kk);
|
|
||||||
for(i = kk - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if(mm != 8)
|
|
||||||
if(data[i] > nn)
|
|
||||||
return -1; /* Illegal symbol */
|
|
||||||
|
|
||||||
int feedback = index_of[data[i] ^ bb[nn - kk - 1]];
|
|
||||||
if(feedback != a0)
|
|
||||||
{
|
|
||||||
/* feedback term is non-zero */
|
|
||||||
for(int j = nn - kk - 1; j > 0; j--)
|
|
||||||
if(gg[j] != a0)
|
|
||||||
bb[j] = bb[j - 1] ^ alpha_to[Modnn(gg[j] + feedback)];
|
|
||||||
else
|
|
||||||
bb[j] = bb[j - 1];
|
|
||||||
|
|
||||||
bb[0] = alpha_to[Modnn(gg[0] + feedback)];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* feedback term is zero. encoder becomes a
|
|
||||||
* single-byte shifter */
|
|
||||||
for(int j = nn - kk - 1; j > 0; j--) bb[j] = bb[j - 1];
|
|
||||||
|
|
||||||
bb[0] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Performs ERRORS+ERASURES decoding of RS codes. If decoding is successful,
|
|
||||||
* writes the codeword into data[] itself. Otherwise data[] is unaltered.
|
|
||||||
*
|
|
||||||
* Return number of symbols corrected, or -1 if codeword is illegal
|
|
||||||
* or uncorrectable.
|
|
||||||
*
|
|
||||||
* First "no_eras" erasures are declared by the calling program. Then, the
|
|
||||||
* maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2).
|
|
||||||
* If the number of channel errors is not greater than "t_after_eras" the
|
|
||||||
* transmitted codeword will be recovered. Details of algorithm can be found
|
|
||||||
* in R. Blahut's "Theory ... of Error-Correcting Codes".
|
|
||||||
*/
|
|
||||||
/// <summary>
|
|
||||||
/// Decodes the RS. If decoding is successful outputs corrected data symbols.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Returns corrected symbols, -1 if illegal or uncorrectable</returns>
|
|
||||||
/// <param name="data">Data symbols.</param>
|
|
||||||
/// <param name="erasPos">Position of erasures.</param>
|
|
||||||
/// <param name="noEras">Number of erasures.</param>
|
|
||||||
public int eras_dec_rs(ref int[] data, out int[] erasPos, int noEras)
|
|
||||||
{
|
|
||||||
if(!initialized) throw new UnauthorizedAccessException("Trying to calculate RS without initializing!");
|
|
||||||
|
|
||||||
erasPos = new int[nn - kk];
|
|
||||||
int i, j;
|
|
||||||
int q, tmp;
|
|
||||||
int[] recd = new int[nn];
|
|
||||||
int[] lambda = new int[nn - kk + 1]; /* Err+Eras Locator poly */
|
|
||||||
int[] s = new int[nn - kk + 1]; /* syndrome poly */
|
|
||||||
int[] b = new int[nn - kk + 1];
|
|
||||||
int[] t = new int[nn - kk + 1];
|
|
||||||
int[] omega = new int[nn - kk + 1];
|
|
||||||
int[] root = new int[nn - kk];
|
|
||||||
int[] reg = new int[nn - kk + 1];
|
|
||||||
int[] loc = new int[nn - kk];
|
|
||||||
int count;
|
|
||||||
|
|
||||||
/* data[] is in polynomial form, copy and convert to index form */
|
|
||||||
for(i = nn - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if(mm != 8)
|
|
||||||
if(data[i] > nn)
|
|
||||||
return -1; /* Illegal symbol */
|
|
||||||
|
|
||||||
recd[i] = index_of[data[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* first form the syndromes; i.e., evaluate recd(x) at roots of g(x)
|
|
||||||
* namely @**(B0+i), i = 0, ... ,(NN-KK-1)
|
|
||||||
*/
|
|
||||||
int synError = 0;
|
|
||||||
for(i = 1; i <= nn - kk; i++)
|
|
||||||
{
|
|
||||||
tmp = 0;
|
|
||||||
for(j = 0; j < nn; j++)
|
|
||||||
if(recd[j] != a0) /* recd[j] in index form */
|
|
||||||
tmp ^= alpha_to[Modnn(recd[j] + (B0 + i - 1) * j)];
|
|
||||||
|
|
||||||
synError |= tmp; /* set flag if non-zero syndrome =>
|
|
||||||
* error */
|
|
||||||
/* store syndrome in index form */
|
|
||||||
s[i] = index_of[tmp];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(synError == 0) return 0;
|
|
||||||
|
|
||||||
Clear(ref lambda, nn - kk);
|
|
||||||
lambda[0] = 1;
|
|
||||||
if(noEras > 0)
|
|
||||||
{
|
|
||||||
/* Init lambda to be the erasure locator polynomial */
|
|
||||||
lambda[1] = alpha_to[erasPos[0]];
|
|
||||||
for(i = 1; i < noEras; i++)
|
|
||||||
{
|
|
||||||
int u = erasPos[i];
|
|
||||||
for(j = i + 1; j > 0; j--)
|
|
||||||
{
|
|
||||||
tmp = index_of[lambda[j - 1]];
|
|
||||||
if(tmp != a0) lambda[j] ^= alpha_to[Modnn(u + tmp)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
/* find roots of the erasure location polynomial */
|
|
||||||
for(i = 1; i <= noEras; i++) reg[i] = index_of[lambda[i]];
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
for(i = 1; i <= nn; i++)
|
|
||||||
{
|
|
||||||
q = 1;
|
|
||||||
for(j = 1; j <= noEras; j++)
|
|
||||||
if(reg[j] != a0)
|
|
||||||
{
|
|
||||||
reg[j] = Modnn(reg[j] + j);
|
|
||||||
q ^= alpha_to[reg[j]];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(q != 0) continue;
|
|
||||||
|
|
||||||
/* store root and error location
|
|
||||||
* number indices
|
|
||||||
*/
|
|
||||||
root[count] = i;
|
|
||||||
loc[count] = nn - i;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(count != noEras)
|
|
||||||
{
|
|
||||||
DicConsole.DebugWriteLine("Reed Solomon", "\n lambda(x) is WRONG\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
DicConsole.DebugWriteLine("Reed Solomon",
|
|
||||||
"\n Erasure positions as determined by roots of Eras Loc Poly:\n");
|
|
||||||
for(i = 0; i < count; i++) DicConsole.DebugWriteLine("Reed Solomon", "{0} ", loc[i]);
|
|
||||||
|
|
||||||
DicConsole.DebugWriteLine("Reed Solomon", "\n");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0; i < nn - kk + 1; i++) b[i] = index_of[lambda[i]];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Begin Berlekamp-Massey algorithm to determine error+erasure
|
|
||||||
* locator polynomial
|
|
||||||
*/
|
|
||||||
int r = noEras;
|
|
||||||
int el = noEras;
|
|
||||||
while(++r <= nn - kk)
|
|
||||||
{
|
|
||||||
/* r is the step number */
|
|
||||||
/* Compute discrepancy at the r-th step in poly-form */
|
|
||||||
int discrR = 0;
|
|
||||||
for(i = 0; i < r; i++)
|
|
||||||
if(lambda[i] != 0 && s[r - i] != a0)
|
|
||||||
discrR ^= alpha_to[Modnn(index_of[lambda[i]] + s[r - i])];
|
|
||||||
|
|
||||||
discrR = index_of[discrR]; /* Index form */
|
|
||||||
if(discrR == a0)
|
|
||||||
{
|
|
||||||
/* 2 lines below: B(x) <-- x*B(x) */
|
|
||||||
Copydown(ref b, ref b, nn - kk);
|
|
||||||
b[0] = a0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
|
|
||||||
t[0] = lambda[0];
|
|
||||||
for(i = 0; i < nn - kk; i++)
|
|
||||||
if(b[i] != a0)
|
|
||||||
t[i + 1] = lambda[i + 1] ^ alpha_to[Modnn(discrR + b[i])];
|
|
||||||
else
|
|
||||||
t[i + 1] = lambda[i + 1];
|
|
||||||
|
|
||||||
if(2 * el <= r + noEras - 1)
|
|
||||||
{
|
|
||||||
el = r + noEras - el;
|
|
||||||
/*
|
|
||||||
* 2 lines below: B(x) <-- inv(discr_r) *
|
|
||||||
* lambda(x)
|
|
||||||
*/
|
|
||||||
for(i = 0; i <= nn - kk; i++)
|
|
||||||
b[i] = lambda[i] == 0 ? a0 : Modnn(index_of[lambda[i]] - discrR + nn);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* 2 lines below: B(x) <-- x*B(x) */
|
|
||||||
Copydown(ref b, ref b, nn - kk);
|
|
||||||
b[0] = a0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Copy(ref lambda, ref t, nn - kk + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert lambda to index form and compute deg(lambda(x)) */
|
|
||||||
int degLambda = 0;
|
|
||||||
for(i = 0; i < nn - kk + 1; i++)
|
|
||||||
{
|
|
||||||
lambda[i] = index_of[lambda[i]];
|
|
||||||
if(lambda[i] != a0) degLambda = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Find roots of the error+erasure locator polynomial. By Chien
|
|
||||||
* Search
|
|
||||||
*/
|
|
||||||
int temp = reg[0];
|
|
||||||
Copy(ref reg, ref lambda, nn - kk);
|
|
||||||
reg[0] = temp;
|
|
||||||
count = 0; /* Number of roots of lambda(x) */
|
|
||||||
for(i = 1; i <= nn; i++)
|
|
||||||
{
|
|
||||||
q = 1;
|
|
||||||
for(j = degLambda; j > 0; j--)
|
|
||||||
if(reg[j] != a0)
|
|
||||||
{
|
|
||||||
reg[j] = Modnn(reg[j] + j);
|
|
||||||
q ^= alpha_to[reg[j]];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(q != 0) continue;
|
|
||||||
|
|
||||||
/* store root (index-form) and error location number */
|
|
||||||
root[count] = i;
|
|
||||||
loc[count] = nn - i;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
DicConsole.DebugWriteLine("Reed Solomon", "\n Final error positions:\t");
|
|
||||||
for(i = 0; i < count; i++) DicConsole.DebugWriteLine("Reed Solomon", "{0} ", loc[i]);
|
|
||||||
|
|
||||||
DicConsole.DebugWriteLine("Reed Solomon", "\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(degLambda != count) return -1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
|
|
||||||
* x**(NN-KK)). in index form. Also find deg(omega).
|
|
||||||
*/
|
|
||||||
int degOmega = 0;
|
|
||||||
for(i = 0; i < nn - kk; i++)
|
|
||||||
{
|
|
||||||
tmp = 0;
|
|
||||||
j = degLambda < i ? degLambda : i;
|
|
||||||
for(; j >= 0; j--)
|
|
||||||
if(s[i + 1 - j] != a0 && lambda[j] != a0)
|
|
||||||
tmp ^= alpha_to[Modnn(s[i + 1 - j] + lambda[j])];
|
|
||||||
|
|
||||||
if(tmp != 0) degOmega = i;
|
|
||||||
omega[i] = index_of[tmp];
|
|
||||||
}
|
|
||||||
|
|
||||||
omega[nn - kk] = a0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
|
|
||||||
* inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form
|
|
||||||
*/
|
|
||||||
for(j = count - 1; j >= 0; j--)
|
|
||||||
{
|
|
||||||
int num1 = 0;
|
|
||||||
for(i = degOmega; i >= 0; i--)
|
|
||||||
if(omega[i] != a0)
|
|
||||||
num1 ^= alpha_to[Modnn(omega[i] + i * root[j])];
|
|
||||||
|
|
||||||
int num2 = alpha_to[Modnn(root[j] * (B0 - 1) + nn)];
|
|
||||||
int den = 0;
|
|
||||||
|
|
||||||
/* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
|
|
||||||
for(i = Min(degLambda, nn - kk - 1) & ~1; i >= 0; i -= 2)
|
|
||||||
if(lambda[i + 1] != a0)
|
|
||||||
den ^= alpha_to[Modnn(lambda[i + 1] + i * root[j])];
|
|
||||||
|
|
||||||
if(den == 0)
|
|
||||||
{
|
|
||||||
DicConsole.DebugWriteLine("Reed Solomon", "\n ERROR: denominator = 0\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Apply error to data */
|
|
||||||
if(num1 != 0) data[loc[j]] ^= alpha_to[Modnn(index_of[num1] + index_of[num2] + nn - index_of[den])];
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
// /***************************************************************************
|
|
||||||
// The Disc Image Chef
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Filename : Register.cs
|
|
||||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
||||||
//
|
|
||||||
// Component : Core algorithms.
|
|
||||||
//
|
|
||||||
// --[ Description ] ----------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Registers all plugins in this assembly.
|
|
||||||
//
|
|
||||||
// --[ License ] --------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
// copy of this software and associated documentation files (the
|
|
||||||
// "Software"), to deal in the Software without restriction, including
|
|
||||||
// without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
// permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
// the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included
|
|
||||||
// in all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
||||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
//
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Copyright © 2011-2020 Natalia Portillo
|
|
||||||
// ****************************************************************************/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using DiscImageChef.CommonTypes.Interfaces;
|
|
||||||
|
|
||||||
namespace DiscImageChef.Checksums
|
|
||||||
{
|
|
||||||
public class Register : IPluginRegister
|
|
||||||
{
|
|
||||||
public List<Type> GetAllChecksumPlugins()
|
|
||||||
{
|
|
||||||
return Assembly.GetExecutingAssembly().GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IChecksum)))
|
|
||||||
.Where(t => t.IsClass).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Type> GetAllFilesystemPlugins() => null;
|
|
||||||
|
|
||||||
public List<Type> GetAllFilterPlugins() => null;
|
|
||||||
|
|
||||||
public List<Type> GetAllFloppyImagePlugins() => null;
|
|
||||||
|
|
||||||
public List<Type> GetAllMediaImagePlugins() => null;
|
|
||||||
|
|
||||||
public List<Type> GetAllPartitionPlugins() => null;
|
|
||||||
|
|
||||||
public List<Type> GetAllReadOnlyFilesystemPlugins() => null;
|
|
||||||
|
|
||||||
public List<Type> GetAllWritableFloppyImagePlugins() => null;
|
|
||||||
|
|
||||||
public List<Type> GetAllWritableImagePlugins() => null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
// /***************************************************************************
|
|
||||||
// The Disc Image Chef
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Filename : SHA1Context.cs
|
|
||||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
||||||
//
|
|
||||||
// Component : Checksums.
|
|
||||||
//
|
|
||||||
// --[ Description ] ----------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Wraps up .NET SHA1 implementation to a Init(), Update(), Final() context.
|
|
||||||
//
|
|
||||||
// --[ License ] --------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as
|
|
||||||
// published by the Free Software Foundation; either version 2.1 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful, but
|
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Copyright © 2011-2020 Natalia Portillo
|
|
||||||
// ****************************************************************************/
|
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using DiscImageChef.CommonTypes.Interfaces;
|
|
||||||
|
|
||||||
namespace DiscImageChef.Checksums
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Wraps up .NET SHA1 implementation to a Init(), Update(), Final() context.
|
|
||||||
/// </summary>
|
|
||||||
public class Sha1Context : IChecksum
|
|
||||||
{
|
|
||||||
SHA1 sha1Provider;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the SHA1 hash provider
|
|
||||||
/// </summary>
|
|
||||||
public Sha1Context()
|
|
||||||
{
|
|
||||||
sha1Provider = SHA1.Create();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of buffer to hash.</param>
|
|
||||||
public void Update(byte[] data, uint len)
|
|
||||||
{
|
|
||||||
sha1Provider.TransformBlock(data, 0, (int)len, data, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
public void Update(byte[] data)
|
|
||||||
{
|
|
||||||
Update(data, (uint)data.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a byte array of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public byte[] Final()
|
|
||||||
{
|
|
||||||
sha1Provider.TransformFinalBlock(new byte[0], 0, 0);
|
|
||||||
return sha1Provider.Hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a hexadecimal representation of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public string End()
|
|
||||||
{
|
|
||||||
sha1Provider.TransformFinalBlock(new byte[0], 0, 0);
|
|
||||||
StringBuilder sha1Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in sha1Provider.Hash) sha1Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
return sha1Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
public static byte[] File(string filename)
|
|
||||||
{
|
|
||||||
SHA1 localSha1Provider = SHA1.Create();
|
|
||||||
FileStream fileStream = new FileStream(filename, FileMode.Open);
|
|
||||||
byte[] result = localSha1Provider.ComputeHash(fileStream);
|
|
||||||
fileStream.Close();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file in hexadecimal and as a byte array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string File(string filename, out byte[] hash)
|
|
||||||
{
|
|
||||||
SHA1 localSha1Provider = SHA1.Create();
|
|
||||||
FileStream fileStream = new FileStream(filename, FileMode.Open);
|
|
||||||
hash = localSha1Provider.ComputeHash(fileStream);
|
|
||||||
StringBuilder sha1Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) sha1Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
fileStream.Close();
|
|
||||||
|
|
||||||
return sha1Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of the data buffer to hash.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, uint len, out byte[] hash)
|
|
||||||
{
|
|
||||||
SHA1 localSha1Provider = SHA1.Create();
|
|
||||||
hash = localSha1Provider.ComputeHash(data, 0, (int)len);
|
|
||||||
StringBuilder sha1Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) sha1Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
return sha1Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
// /***************************************************************************
|
|
||||||
// The Disc Image Chef
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Filename : SHA256Context.cs
|
|
||||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
||||||
//
|
|
||||||
// Component : Checksums.
|
|
||||||
//
|
|
||||||
// --[ Description ] ----------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Wraps up .NET SHA256 implementation to a Init(), Update(), Final() context.
|
|
||||||
//
|
|
||||||
// --[ License ] --------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as
|
|
||||||
// published by the Free Software Foundation; either version 2.1 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful, but
|
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Copyright © 2011-2020 Natalia Portillo
|
|
||||||
// ****************************************************************************/
|
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using DiscImageChef.CommonTypes.Interfaces;
|
|
||||||
|
|
||||||
namespace DiscImageChef.Checksums
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Wraps up .NET SHA256 implementation to a Init(), Update(), Final() context.
|
|
||||||
/// </summary>
|
|
||||||
public class Sha256Context : IChecksum
|
|
||||||
{
|
|
||||||
SHA256 sha256Provider;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the SHA256 hash provider
|
|
||||||
/// </summary>
|
|
||||||
public Sha256Context()
|
|
||||||
{
|
|
||||||
sha256Provider = SHA256.Create();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of buffer to hash.</param>
|
|
||||||
public void Update(byte[] data, uint len)
|
|
||||||
{
|
|
||||||
sha256Provider.TransformBlock(data, 0, (int)len, data, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
public void Update(byte[] data)
|
|
||||||
{
|
|
||||||
Update(data, (uint)data.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a byte array of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public byte[] Final()
|
|
||||||
{
|
|
||||||
sha256Provider.TransformFinalBlock(new byte[0], 0, 0);
|
|
||||||
return sha256Provider.Hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a hexadecimal representation of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public string End()
|
|
||||||
{
|
|
||||||
sha256Provider.TransformFinalBlock(new byte[0], 0, 0);
|
|
||||||
StringBuilder sha256Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in sha256Provider.Hash) sha256Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
return sha256Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
public static byte[] File(string filename)
|
|
||||||
{
|
|
||||||
SHA256 localSha256Provider = SHA256.Create();
|
|
||||||
FileStream fileStream = new FileStream(filename, FileMode.Open);
|
|
||||||
byte[] result = localSha256Provider.ComputeHash(fileStream);
|
|
||||||
fileStream.Close();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file in hexadecimal and as a byte array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string File(string filename, out byte[] hash)
|
|
||||||
{
|
|
||||||
SHA256 localSha256Provider = SHA256.Create();
|
|
||||||
FileStream fileStream = new FileStream(filename, FileMode.Open);
|
|
||||||
hash = localSha256Provider.ComputeHash(fileStream);
|
|
||||||
StringBuilder sha256Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) sha256Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
fileStream.Close();
|
|
||||||
|
|
||||||
return sha256Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of the data buffer to hash.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, uint len, out byte[] hash)
|
|
||||||
{
|
|
||||||
SHA256 localSha256Provider = SHA256.Create();
|
|
||||||
hash = localSha256Provider.ComputeHash(data, 0, (int)len);
|
|
||||||
StringBuilder sha256Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) sha256Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
return sha256Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
// /***************************************************************************
|
|
||||||
// The Disc Image Chef
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Filename : SHA384Context.cs
|
|
||||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
||||||
//
|
|
||||||
// Component : Checksums.
|
|
||||||
//
|
|
||||||
// --[ Description ] ----------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Wraps up .NET SHA384 implementation to a Init(), Update(), Final() context.
|
|
||||||
//
|
|
||||||
// --[ License ] --------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as
|
|
||||||
// published by the Free Software Foundation; either version 2.1 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful, but
|
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Copyright © 2011-2020 Natalia Portillo
|
|
||||||
// ****************************************************************************/
|
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using DiscImageChef.CommonTypes.Interfaces;
|
|
||||||
|
|
||||||
namespace DiscImageChef.Checksums
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Wraps up .NET SHA384 implementation to a Init(), Update(), Final() context.
|
|
||||||
/// </summary>
|
|
||||||
public class Sha384Context : IChecksum
|
|
||||||
{
|
|
||||||
SHA384 sha384Provider;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the SHA384 hash provider
|
|
||||||
/// </summary>
|
|
||||||
public Sha384Context()
|
|
||||||
{
|
|
||||||
sha384Provider = SHA384.Create();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of buffer to hash.</param>
|
|
||||||
public void Update(byte[] data, uint len)
|
|
||||||
{
|
|
||||||
sha384Provider.TransformBlock(data, 0, (int)len, data, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
public void Update(byte[] data)
|
|
||||||
{
|
|
||||||
Update(data, (uint)data.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a byte array of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public byte[] Final()
|
|
||||||
{
|
|
||||||
sha384Provider.TransformFinalBlock(new byte[0], 0, 0);
|
|
||||||
return sha384Provider.Hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a hexadecimal representation of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public string End()
|
|
||||||
{
|
|
||||||
sha384Provider.TransformFinalBlock(new byte[0], 0, 0);
|
|
||||||
StringBuilder sha384Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in sha384Provider.Hash) sha384Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
return sha384Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
public static byte[] File(string filename)
|
|
||||||
{
|
|
||||||
SHA384 localSha384Provider = SHA384.Create();
|
|
||||||
FileStream fileStream = new FileStream(filename, FileMode.Open);
|
|
||||||
byte[] result = localSha384Provider.ComputeHash(fileStream);
|
|
||||||
fileStream.Close();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file in hexadecimal and as a byte array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string File(string filename, out byte[] hash)
|
|
||||||
{
|
|
||||||
SHA384 localSha384Provider = SHA384.Create();
|
|
||||||
FileStream fileStream = new FileStream(filename, FileMode.Open);
|
|
||||||
hash = localSha384Provider.ComputeHash(fileStream);
|
|
||||||
StringBuilder sha384Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) sha384Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
fileStream.Close();
|
|
||||||
|
|
||||||
return sha384Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of the data buffer to hash.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, uint len, out byte[] hash)
|
|
||||||
{
|
|
||||||
SHA384 localSha384Provider = SHA384.Create();
|
|
||||||
hash = localSha384Provider.ComputeHash(data, 0, (int)len);
|
|
||||||
StringBuilder sha384Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) sha384Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
return sha384Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
// /***************************************************************************
|
|
||||||
// The Disc Image Chef
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Filename : SHA512Context.cs
|
|
||||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
||||||
//
|
|
||||||
// Component : Checksums.
|
|
||||||
//
|
|
||||||
// --[ Description ] ----------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Wraps up .NET SHA512 implementation to a Init(), Update(), Final() context.
|
|
||||||
//
|
|
||||||
// --[ License ] --------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as
|
|
||||||
// published by the Free Software Foundation; either version 2.1 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful, but
|
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Copyright © 2011-2020 Natalia Portillo
|
|
||||||
// ****************************************************************************/
|
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using DiscImageChef.CommonTypes.Interfaces;
|
|
||||||
|
|
||||||
namespace DiscImageChef.Checksums
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Wraps up .NET SHA512 implementation to a Init(), Update(), Final() context.
|
|
||||||
/// </summary>
|
|
||||||
public class Sha512Context : IChecksum
|
|
||||||
{
|
|
||||||
SHA512 sha512Provider;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the SHA512 hash provider
|
|
||||||
/// </summary>
|
|
||||||
public Sha512Context()
|
|
||||||
{
|
|
||||||
sha512Provider = SHA512.Create();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of buffer to hash.</param>
|
|
||||||
public void Update(byte[] data, uint len)
|
|
||||||
{
|
|
||||||
sha512Provider.TransformBlock(data, 0, (int)len, data, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
public void Update(byte[] data)
|
|
||||||
{
|
|
||||||
Update(data, (uint)data.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a byte array of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public byte[] Final()
|
|
||||||
{
|
|
||||||
sha512Provider.TransformFinalBlock(new byte[0], 0, 0);
|
|
||||||
return sha512Provider.Hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a hexadecimal representation of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public string End()
|
|
||||||
{
|
|
||||||
sha512Provider.TransformFinalBlock(new byte[0], 0, 0);
|
|
||||||
StringBuilder sha512Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in sha512Provider.Hash) sha512Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
return sha512Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
public static byte[] File(string filename)
|
|
||||||
{
|
|
||||||
SHA512 localSha512Provider = SHA512.Create();
|
|
||||||
FileStream fileStream = new FileStream(filename, FileMode.Open);
|
|
||||||
byte[] result = localSha512Provider.ComputeHash(fileStream);
|
|
||||||
fileStream.Close();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file in hexadecimal and as a byte array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string File(string filename, out byte[] hash)
|
|
||||||
{
|
|
||||||
SHA512 localSha512Provider = SHA512.Create();
|
|
||||||
FileStream fileStream = new FileStream(filename, FileMode.Open);
|
|
||||||
hash = localSha512Provider.ComputeHash(fileStream);
|
|
||||||
StringBuilder sha512Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) sha512Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
fileStream.Close();
|
|
||||||
|
|
||||||
return sha512Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of the data buffer to hash.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, uint len, out byte[] hash)
|
|
||||||
{
|
|
||||||
SHA512 localSha512Provider = SHA512.Create();
|
|
||||||
hash = localSha512Provider.ComputeHash(data, 0, (int)len);
|
|
||||||
StringBuilder sha512Output = new StringBuilder();
|
|
||||||
|
|
||||||
foreach(byte h in hash) sha512Output.Append(h.ToString("x2"));
|
|
||||||
|
|
||||||
return sha512Output.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,484 +0,0 @@
|
|||||||
// /***************************************************************************
|
|
||||||
// The Disc Image Chef
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Filename : SpamSumContext.cs
|
|
||||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
||||||
//
|
|
||||||
// Component : Checksums.
|
|
||||||
//
|
|
||||||
// --[ Description ] ----------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Implements the SpamSum fuzzy hashing algorithm.
|
|
||||||
//
|
|
||||||
// --[ License ] --------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as
|
|
||||||
// published by the Free Software Foundation; either version 2.1 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful, but
|
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
||||||
//
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Copyright © 2011-2020 Natalia Portillo
|
|
||||||
// ****************************************************************************/
|
|
||||||
|
|
||||||
// Based on ssdeep
|
|
||||||
// Copyright (C) 2002 Andrew Tridgell <tridge@samba.org>
|
|
||||||
// Copyright (C) 2006 ManTech International Corporation
|
|
||||||
// Copyright (C) 2013 Helmut Grohne <helmut@subdivi.de>
|
|
||||||
//
|
|
||||||
// Earlier versions of this code were named fuzzy.c and can be found at:
|
|
||||||
// http://www.samba.org/ftp/unpacked/junkcode/spamsum/
|
|
||||||
// http://ssdeep.sf.net/
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text;
|
|
||||||
using DiscImageChef.CommonTypes.Interfaces;
|
|
||||||
|
|
||||||
namespace DiscImageChef.Checksums
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Implements the SpamSum fuzzy hashing algorithm.
|
|
||||||
/// </summary>
|
|
||||||
public class SpamSumContext : IChecksum
|
|
||||||
{
|
|
||||||
const uint ROLLING_WINDOW = 7;
|
|
||||||
const uint MIN_BLOCKSIZE = 3;
|
|
||||||
const uint HASH_PRIME = 0x01000193;
|
|
||||||
const uint HASH_INIT = 0x28021967;
|
|
||||||
const uint NUM_BLOCKHASHES = 31;
|
|
||||||
const uint SPAMSUM_LENGTH = 64;
|
|
||||||
const uint FUZZY_MAX_RESULT = 2 * SPAMSUM_LENGTH + 20;
|
|
||||||
//"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
||||||
readonly byte[] b64 =
|
|
||||||
{
|
|
||||||
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51,
|
|
||||||
0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
|
|
||||||
0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
|
|
||||||
0x7A, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F
|
|
||||||
};
|
|
||||||
|
|
||||||
FuzzyState self;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the SpamSum structures
|
|
||||||
/// </summary>
|
|
||||||
public SpamSumContext()
|
|
||||||
{
|
|
||||||
self = new FuzzyState {Bh = new BlockhashContext[NUM_BLOCKHASHES]};
|
|
||||||
for(int i = 0; i < NUM_BLOCKHASHES; i++) self.Bh[i].Digest = new byte[SPAMSUM_LENGTH];
|
|
||||||
|
|
||||||
self.Bhstart = 0;
|
|
||||||
self.Bhend = 1;
|
|
||||||
self.Bh[0].H = HASH_INIT;
|
|
||||||
self.Bh[0].Halfh = HASH_INIT;
|
|
||||||
self.Bh[0].Digest[0] = 0;
|
|
||||||
self.Bh[0].Halfdigest = 0;
|
|
||||||
self.Bh[0].Dlen = 0;
|
|
||||||
self.TotalSize = 0;
|
|
||||||
roll_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of buffer to hash.</param>
|
|
||||||
public void Update(byte[] data, uint len)
|
|
||||||
{
|
|
||||||
self.TotalSize += len;
|
|
||||||
for(int i = 0; i < len; i++) fuzzy_engine_step(data[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the hash with data.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
public void Update(byte[] data)
|
|
||||||
{
|
|
||||||
Update(data, (uint)data.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a byte array of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public byte[] Final() => throw new NotImplementedException("SpamSum does not have a binary representation.");
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a base64 representation of the hash value.
|
|
||||||
/// </summary>
|
|
||||||
public string End()
|
|
||||||
{
|
|
||||||
FuzzyDigest(out byte[] result);
|
|
||||||
|
|
||||||
return CToString(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
void roll_init()
|
|
||||||
{
|
|
||||||
self.Roll = new RollState {Window = new byte[ROLLING_WINDOW]};
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* a rolling hash, based on the Adler checksum. By using a rolling hash
|
|
||||||
* we can perform auto resynchronisation after inserts/deletes
|
|
||||||
|
|
||||||
* internally, h1 is the sum of the bytes in the window and h2
|
|
||||||
* is the sum of the bytes times the index
|
|
||||||
|
|
||||||
* h3 is a shift/xor based rolling hash, and is mostly needed to ensure that
|
|
||||||
* we can cope with large blocksize values
|
|
||||||
*/
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
void roll_hash(byte c)
|
|
||||||
{
|
|
||||||
self.Roll.H2 -= self.Roll.H1;
|
|
||||||
self.Roll.H2 += ROLLING_WINDOW * c;
|
|
||||||
|
|
||||||
self.Roll.H1 += c;
|
|
||||||
self.Roll.H1 -= self.Roll.Window[self.Roll.N % ROLLING_WINDOW];
|
|
||||||
|
|
||||||
self.Roll.Window[self.Roll.N % ROLLING_WINDOW] = c;
|
|
||||||
self.Roll.N++;
|
|
||||||
|
|
||||||
/* The original spamsum AND'ed this value with 0xFFFFFFFF which
|
|
||||||
* in theory should have no effect. This AND has been removed
|
|
||||||
* for performance (jk) */
|
|
||||||
self.Roll.H3 <<= 5;
|
|
||||||
self.Roll.H3 ^= c;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
uint roll_sum() => self.Roll.H1 + self.Roll.H2 + self.Roll.H3;
|
|
||||||
|
|
||||||
/* A simple non-rolling hash, based on the FNV hash. */
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
static uint sum_hash(byte c, uint h) => (h * HASH_PRIME) ^ c;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
static uint SSDEEP_BS(uint index) => MIN_BLOCKSIZE << (int)index;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
void fuzzy_try_fork_blockhash()
|
|
||||||
{
|
|
||||||
if(self.Bhend >= NUM_BLOCKHASHES) return;
|
|
||||||
|
|
||||||
if(self.Bhend == 0) // assert
|
|
||||||
throw new Exception("Assertion failed");
|
|
||||||
|
|
||||||
uint obh = self.Bhend - 1;
|
|
||||||
uint nbh = self.Bhend;
|
|
||||||
self.Bh[nbh].H = self.Bh[obh].H;
|
|
||||||
self.Bh[nbh].Halfh = self.Bh[obh].Halfh;
|
|
||||||
self.Bh[nbh].Digest[0] = 0;
|
|
||||||
self.Bh[nbh].Halfdigest = 0;
|
|
||||||
self.Bh[nbh].Dlen = 0;
|
|
||||||
++self.Bhend;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
void fuzzy_try_reduce_blockhash()
|
|
||||||
{
|
|
||||||
if(self.Bhstart >= self.Bhend) throw new Exception("Assertion failed");
|
|
||||||
|
|
||||||
if(self.Bhend - self.Bhstart < 2)
|
|
||||||
/* Need at least two working hashes. */ return;
|
|
||||||
if((ulong)SSDEEP_BS(self.Bhstart) * SPAMSUM_LENGTH >= self.TotalSize)
|
|
||||||
/* Initial blocksize estimate would select this or a smaller
|
|
||||||
* blocksize. */ return;
|
|
||||||
if(self.Bh[self.Bhstart + 1].Dlen < SPAMSUM_LENGTH / 2)
|
|
||||||
/* Estimate adjustment would select this blocksize. */ return;
|
|
||||||
|
|
||||||
/* At this point we are clearly no longer interested in the
|
|
||||||
* start_blocksize. Get rid of it. */
|
|
||||||
++self.Bhstart;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
void fuzzy_engine_step(byte c)
|
|
||||||
{
|
|
||||||
uint i;
|
|
||||||
/* At each character we update the rolling hash and the normal hashes.
|
|
||||||
* When the rolling hash hits a reset value then we emit a normal hash
|
|
||||||
* as a element of the signature and reset the normal hash. */
|
|
||||||
roll_hash(c);
|
|
||||||
ulong h = roll_sum();
|
|
||||||
|
|
||||||
for(i = self.Bhstart; i < self.Bhend; ++i)
|
|
||||||
{
|
|
||||||
self.Bh[i].H = sum_hash(c, self.Bh[i].H);
|
|
||||||
self.Bh[i].Halfh = sum_hash(c, self.Bh[i].Halfh);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = self.Bhstart; i < self.Bhend; ++i)
|
|
||||||
{
|
|
||||||
/* With growing blocksize almost no runs fail the next test. */
|
|
||||||
if(h % SSDEEP_BS(i) != SSDEEP_BS(i) - 1)
|
|
||||||
/* Once this condition is false for one bs, it is
|
|
||||||
* automatically false for all further bs. I.e. if
|
|
||||||
* h === -1 (mod 2*bs) then h === -1 (mod bs). */ break;
|
|
||||||
|
|
||||||
/* We have hit a reset point. We now emit hashes which are
|
|
||||||
* based on all characters in the piece of the message between
|
|
||||||
* the last reset point and this one */
|
|
||||||
if(0 == self.Bh[i].Dlen) fuzzy_try_fork_blockhash();
|
|
||||||
self.Bh[i].Digest[self.Bh[i].Dlen] = b64[self.Bh[i].H % 64];
|
|
||||||
self.Bh[i].Halfdigest = b64[self.Bh[i].Halfh % 64];
|
|
||||||
if(self.Bh[i].Dlen < SPAMSUM_LENGTH - 1)
|
|
||||||
{
|
|
||||||
/* We can have a problem with the tail overflowing. The
|
|
||||||
* easiest way to cope with this is to only reset the
|
|
||||||
* normal hash if we have room for more characters in
|
|
||||||
* our signature. This has the effect of combining the
|
|
||||||
* last few pieces of the message into a single piece
|
|
||||||
* */
|
|
||||||
self.Bh[i].Digest[++self.Bh[i].Dlen] = 0;
|
|
||||||
self.Bh[i].H = HASH_INIT;
|
|
||||||
if(self.Bh[i].Dlen >= SPAMSUM_LENGTH / 2) continue;
|
|
||||||
|
|
||||||
self.Bh[i].Halfh = HASH_INIT;
|
|
||||||
self.Bh[i].Halfdigest = 0;
|
|
||||||
}
|
|
||||||
else fuzzy_try_reduce_blockhash();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CLAUNIA: Flags seems to never be used in ssdeep, so I just removed it for code simplicity
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
uint FuzzyDigest(out byte[] result)
|
|
||||||
{
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
uint bi = self.Bhstart;
|
|
||||||
uint h = roll_sum();
|
|
||||||
int remain = (int)(FUZZY_MAX_RESULT - 1); /* Exclude terminating '\0'. */
|
|
||||||
result = new byte[FUZZY_MAX_RESULT];
|
|
||||||
/* Verify that our elimination was not overeager. */
|
|
||||||
if(!(bi == 0 || (ulong)SSDEEP_BS(bi) / 2 * SPAMSUM_LENGTH < self.TotalSize))
|
|
||||||
throw new Exception("Assertion failed");
|
|
||||||
|
|
||||||
int resultOff = 0;
|
|
||||||
|
|
||||||
/* Initial blocksize guess. */
|
|
||||||
while((ulong)SSDEEP_BS(bi) * SPAMSUM_LENGTH < self.TotalSize)
|
|
||||||
{
|
|
||||||
++bi;
|
|
||||||
if(bi >= NUM_BLOCKHASHES) throw new OverflowException("The input exceeds data types.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Adapt blocksize guess to actual digest length. */
|
|
||||||
while(bi >= self.Bhend) --bi;
|
|
||||||
while(bi > self.Bhstart && self.Bh[bi].Dlen < SPAMSUM_LENGTH / 2) --bi;
|
|
||||||
|
|
||||||
if(bi > 0 && self.Bh[bi].Dlen < SPAMSUM_LENGTH / 2) throw new Exception("Assertion failed");
|
|
||||||
|
|
||||||
sb.AppendFormat("{0}:", SSDEEP_BS(bi));
|
|
||||||
int i = Encoding.ASCII.GetBytes(sb.ToString()).Length;
|
|
||||||
if(i <= 0)
|
|
||||||
/* Maybe snprintf has set errno here? */ throw new OverflowException("The input exceeds data types.");
|
|
||||||
if(i >= remain) throw new Exception("Assertion failed");
|
|
||||||
|
|
||||||
remain -= i;
|
|
||||||
|
|
||||||
Array.Copy(Encoding.ASCII.GetBytes(sb.ToString()), 0, result, 0, i);
|
|
||||||
|
|
||||||
resultOff += i;
|
|
||||||
|
|
||||||
i = (int)self.Bh[bi].Dlen;
|
|
||||||
if(i > remain) throw new Exception("Assertion failed");
|
|
||||||
|
|
||||||
Array.Copy(self.Bh[bi].Digest, 0, result, resultOff, i);
|
|
||||||
resultOff += i;
|
|
||||||
remain -= i;
|
|
||||||
if(h != 0)
|
|
||||||
{
|
|
||||||
if(remain <= 0) throw new Exception("Assertion failed");
|
|
||||||
|
|
||||||
result[resultOff] = b64[self.Bh[bi].H % 64];
|
|
||||||
if(i < 3 || result[resultOff] != result[resultOff - 1] ||
|
|
||||||
result[resultOff] != result[resultOff - 2] ||
|
|
||||||
result[resultOff] != result[resultOff - 3])
|
|
||||||
{
|
|
||||||
++resultOff;
|
|
||||||
--remain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(self.Bh[bi].Digest[i] != 0)
|
|
||||||
{
|
|
||||||
if(remain <= 0) throw new Exception("Assertion failed");
|
|
||||||
|
|
||||||
result[resultOff] = self.Bh[bi].Digest[i];
|
|
||||||
if(i < 3 || result[resultOff] != result[resultOff - 1] ||
|
|
||||||
result[resultOff] != result[resultOff - 2] ||
|
|
||||||
result[resultOff] != result[resultOff - 3])
|
|
||||||
{
|
|
||||||
++resultOff;
|
|
||||||
--remain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(remain <= 0) throw new Exception("Assertion failed");
|
|
||||||
|
|
||||||
result[resultOff++] = 0x3A; // ':'
|
|
||||||
--remain;
|
|
||||||
if(bi < self.Bhend - 1)
|
|
||||||
{
|
|
||||||
++bi;
|
|
||||||
i = (int)self.Bh[bi].Dlen;
|
|
||||||
if(i > remain) throw new Exception("Assertion failed");
|
|
||||||
|
|
||||||
Array.Copy(self.Bh[bi].Digest, 0, result, resultOff, i);
|
|
||||||
resultOff += i;
|
|
||||||
remain -= i;
|
|
||||||
|
|
||||||
if(h != 0)
|
|
||||||
{
|
|
||||||
if(remain <= 0) throw new Exception("Assertion failed");
|
|
||||||
|
|
||||||
h = self.Bh[bi].Halfh;
|
|
||||||
result[resultOff] = b64[h % 64];
|
|
||||||
if(i < 3 || result[resultOff] != result[resultOff - 1] ||
|
|
||||||
result[resultOff] != result[resultOff - 2] ||
|
|
||||||
result[resultOff] != result[resultOff - 3])
|
|
||||||
{
|
|
||||||
++resultOff;
|
|
||||||
--remain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
i = self.Bh[bi].Halfdigest;
|
|
||||||
if(i != 0)
|
|
||||||
{
|
|
||||||
if(remain <= 0) throw new Exception("Assertion failed");
|
|
||||||
|
|
||||||
result[resultOff] = (byte)i;
|
|
||||||
if(i < 3 || result[resultOff] != result[resultOff - 1] ||
|
|
||||||
result[resultOff] != result[resultOff - 2] ||
|
|
||||||
result[resultOff] != result[resultOff - 3])
|
|
||||||
{
|
|
||||||
++resultOff;
|
|
||||||
--remain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(h != 0)
|
|
||||||
{
|
|
||||||
if(self.Bh[bi].Dlen != 0) throw new Exception("Assertion failed");
|
|
||||||
if(remain <= 0) throw new Exception("Assertion failed");
|
|
||||||
|
|
||||||
result[resultOff++] = b64[self.Bh[bi].H % 64];
|
|
||||||
/* No need to bother with FUZZY_FLAG_ELIMSEQ, because this
|
|
||||||
* digest has length 1. */
|
|
||||||
--remain;
|
|
||||||
}
|
|
||||||
|
|
||||||
result[resultOff] = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
public static byte[] File(string filename) =>
|
|
||||||
throw new NotImplementedException("SpamSum does not have a binary representation.");
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of a file in hexadecimal and as a byte array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">File path.</param>
|
|
||||||
/// <param name="hash">Byte array of the hash value.</param>
|
|
||||||
public static string File(string filename, out byte[] hash) =>
|
|
||||||
throw new NotImplementedException("Not yet implemented.");
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="len">Length of the data buffer to hash.</param>
|
|
||||||
/// <param name="hash">null</param>
|
|
||||||
/// <returns>Base64 representation of SpamSum $blocksize:$hash:$hash</returns>
|
|
||||||
public static string Data(byte[] data, uint len, out byte[] hash)
|
|
||||||
{
|
|
||||||
SpamSumContext fuzzyContext = new SpamSumContext();
|
|
||||||
|
|
||||||
fuzzyContext.Update(data, len);
|
|
||||||
|
|
||||||
hash = null;
|
|
||||||
|
|
||||||
return fuzzyContext.End();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the hash of the specified data buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Data buffer.</param>
|
|
||||||
/// <param name="hash">null</param>
|
|
||||||
/// <returns>Base64 representation of SpamSum $blocksize:$hash:$hash</returns>
|
|
||||||
public static string Data(byte[] data, out byte[] hash) => Data(data, (uint)data.Length, out hash);
|
|
||||||
|
|
||||||
// Converts an ASCII null-terminated string to .NET string
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
static string CToString(byte[] cString)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
|
||||||
// LINQ is six times slower
|
|
||||||
foreach(byte c in cString)
|
|
||||||
{
|
|
||||||
if(c == 0) break;
|
|
||||||
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Encoding.ASCII.GetString(cString, 0, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RollState
|
|
||||||
{
|
|
||||||
public byte[] Window;
|
|
||||||
// ROLLING_WINDOW
|
|
||||||
public uint H1;
|
|
||||||
public uint H2;
|
|
||||||
public uint H3;
|
|
||||||
public uint N;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* A blockhash contains a signature state for a specific (implicit) blocksize.
|
|
||||||
* The blocksize is given by SSDEEP_BS(index). The h and halfh members are the
|
|
||||||
* FNV hashes, where halfh stops to be reset after digest is SPAMSUM_LENGTH/2
|
|
||||||
* long. The halfh hash is needed be able to truncate digest for the second
|
|
||||||
* output hash to stay compatible with ssdeep output. */
|
|
||||||
struct BlockhashContext
|
|
||||||
{
|
|
||||||
public uint H;
|
|
||||||
public uint Halfh;
|
|
||||||
public byte[] Digest;
|
|
||||||
// SPAMSUM_LENGTH
|
|
||||||
public byte Halfdigest;
|
|
||||||
public uint Dlen;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FuzzyState
|
|
||||||
{
|
|
||||||
public uint Bhstart;
|
|
||||||
public uint Bhend;
|
|
||||||
public BlockhashContext[] Bh;
|
|
||||||
//NUM_BLOCKHASHES
|
|
||||||
public ulong TotalSize;
|
|
||||||
public RollState Roll;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user