Move DiscImageChef.Checksums to a separate repository.

This commit is contained in:
2020-01-11 22:42:25 +00:00
parent 6b1033317a
commit 8400308a98
19 changed files with 4 additions and 3996 deletions

3
.gitmodules vendored
View File

@@ -19,3 +19,6 @@
[submodule "DiscImageChef.Helpers"]
path = DiscImageChef.Helpers
url = https://github.com/discimagechef/DiscImageChef.Helpers.git
[submodule "DiscImageChef.Checksums"]
path = DiscImageChef.Checksums
url = https://github.com/discimagechef/DiscImageChef.Checksums.git

View File

@@ -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);
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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="/***************************************************************************&#xA;The Disc Image Chef&#xA;----------------------------------------------------------------------------&#xA; &#xA;Filename : ${FileName}&#xA;Author(s) : ${AuthorName} &lt;${AuthorEmail}&gt;&#xA;&#xA;Component : Component&#xA; &#xA;--[ Description ] ----------------------------------------------------------&#xA; &#xA; Description&#xA; &#xA;--[ License ] --------------------------------------------------------------&#xA; &#xA; This library is free software; you can redistribute it and/or modify&#xA; it under the terms of the GNU Lesser General Public License as&#xA; published by the Free Software Foundation; either version 2.1 of the&#xA; License, or (at your option) any later version.&#xA;&#xA; This library is distributed in the hope that it will be useful, but&#xA; WITHOUT ANY WARRANTY; without even the implied warranty of&#xA; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&#xA; Lesser General Public License for more details.&#xA;&#xA; You should have received a copy of the GNU Lesser General Public&#xA; License along with this library; if not, see &lt;http://www.gnu.org/licenses/&gt;.&#xA;&#xA;----------------------------------------------------------------------------&#xA;Copyright © 2011-${Year} ${CopyrightHolder}&#xA;****************************************************************************/" />
<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>

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}
}