diff --git a/DiscImageChef/ChangeLog b/DiscImageChef/ChangeLog index c9f3d5aa2..199e85907 100644 --- a/DiscImageChef/ChangeLog +++ b/DiscImageChef/ChangeLog @@ -1,3 +1,11 @@ +2015-04-19 Natalia Portillo + + * Options.cs: + * Commands/Checksum.cs: + * DiscImageChef.csproj: + * Checksums/FletcherContext.cs: + Implemented Fletcher-16 and Fletcher-32 checksum algorithms. + 2015-04-19 Natalia Portillo * Options.cs: diff --git a/DiscImageChef/Checksums/FletcherContext.cs b/DiscImageChef/Checksums/FletcherContext.cs new file mode 100644 index 000000000..3c60d6349 --- /dev/null +++ b/DiscImageChef/Checksums/FletcherContext.cs @@ -0,0 +1,458 @@ +/*************************************************************************** +The Disc Image Chef +---------------------------------------------------------------------------- + +Filename : FletcherContext.cs +Version : 1.0 +Author(s) : Natalia Portillo + +Component : Checksums. + +Revision : $Revision$ +Last change by : $Author$ +Date : $Date$ + +--[ Description ] ---------------------------------------------------------- + +Implements Fletcher-32 and Fletcher-16 algorithms. + +--[ 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 . + +---------------------------------------------------------------------------- +Copyright (C) 2011-2015 Claunia.com +****************************************************************************/ +//$Id$ +using System; +using System.Text; +using System.IO; + +namespace DiscImageChef.Checksums +{ + public class Fletcher32Context + { + UInt16 sum1, sum2; + byte oddValue; + bool inodd; + + /// + /// Initializes the Fletcher32 sums + /// + public void Init() + { + sum1 = 0xFFFF; + sum2 = 0xFFFF; + oddValue = 0; + inodd = false; + } + + /// + /// Updates the hash with data. + /// + /// Data buffer. + /// Length of buffer to hash. + public void Update(byte[] data, uint len) + { + UInt16 block; + if (!inodd) + { + // Odd size + if (len % 2 != 0) + { + oddValue = data[len - 1]; + inodd = true; + + for (int i = 0; i < len - 1; i += 2) + { + block = BigEndianBitConverter.ToUInt16(data, i); + sum1 = (UInt16)((sum1 + block) % 0xFFFF); + sum2 = (UInt16)((sum2 + sum1) % 0xFFFF); + } + } + else + { + inodd = false; + for (int i = 0; i < len; i += 2) + { + block = BigEndianBitConverter.ToUInt16(data, i); + sum1 = (UInt16)((sum1 + block) % 0xFFFF); + sum2 = (UInt16)((sum2 + sum1) % 0xFFFF); + } + } + } + // Carrying odd + else + { + byte[] oddData = new byte[2]; + oddData[0] = oddValue; + oddData[1] = data[0]; + + block = BigEndianBitConverter.ToUInt16(oddData, 0); + sum1 = (UInt16)((sum1 + block) % 0xFFFF); + sum2 = (UInt16)((sum2 + sum1) % 0xFFFF); + + // Even size, carrying odd + if (len % 2 == 0) + { + oddValue = data[len - 1]; + inodd = true; + + for (int i = 1; i < len - 1; i += 2) + { + block = BigEndianBitConverter.ToUInt16(data, i); + sum1 = (UInt16)((sum1 + block) % 0xFFFF); + sum2 = (UInt16)((sum2 + sum1) % 0xFFFF); + } + } + else + { + inodd = false; + for (int i = 1; i < len; i += 2) + { + block = BigEndianBitConverter.ToUInt16(data, i); + sum1 = (UInt16)((sum1 + block) % 0xFFFF); + sum2 = (UInt16)((sum2 + sum1) % 0xFFFF); + } + } + } + } + + /// + /// Updates the hash with data. + /// + /// Data buffer. + public void Update(byte[] data) + { + Update(data, (uint)data.Length); + } + + /// + /// Returns a byte array of the hash value. + /// + public byte[] Final() + { + UInt32 finalSum = (UInt32)(sum1 + (sum2 << 16)); + return BigEndianBitConverter.GetBytes(finalSum); + } + + /// + /// Returns a hexadecimal representation of the hash value. + /// + public string End() + { + UInt32 finalSum = (UInt32)(sum1 + (sum2 << 16)); + 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(); + } + + /// + /// Gets the hash of a file + /// + /// File path. + public static byte[] File(string filename) + { + byte[] hash; + File(filename, out hash); + return hash; + } + + /// + /// Gets the hash of a file in hexadecimal and as a byte array. + /// + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash) + { + FileStream fileStream = new FileStream(filename, FileMode.Open); + UInt16 localSum1, localSum2, block; + UInt32 finalSum; + byte[] blockBytes; + + localSum1 = 0xFFFF; + localSum2 = 0xFFFF; + block = 0; + + if (fileStream.Length % 2 == 0) + { + for (int i = 0; i < fileStream.Length; i += 2) + { + blockBytes = new byte[2]; + fileStream.Read(blockBytes, 0, 2); + block = BigEndianBitConverter.ToUInt16(blockBytes, 0); + localSum1 = (UInt16)((localSum1 + block) % 0xFFFF); + localSum2 = (UInt16)((localSum2 + localSum1) % 0xFFFF); + } + } + else + { + for (int i = 0; i < fileStream.Length - 1; i += 2) + { + blockBytes = new byte[2]; + fileStream.Read(blockBytes, 0, 2); + block = BigEndianBitConverter.ToUInt16(blockBytes, 0); + localSum1 = (UInt16)((localSum1 + block) % 0xFFFF); + localSum2 = (UInt16)((localSum2 + localSum1) % 0xFFFF); + } + + byte[] oddData = new byte[2]; + oddData[0] = (byte)fileStream.ReadByte(); + oddData[1] = 0; + + block = BigEndianBitConverter.ToUInt16(oddData, 0); + localSum1 = (UInt16)((localSum1 + block) % 0xFFFF); + localSum2 = (UInt16)((localSum2 + localSum1) % 0xFFFF); + } + + finalSum = (UInt32)(localSum1 + (localSum2 << 16)); + + hash = BitConverter.GetBytes(finalSum); + + StringBuilder fletcherOutput = new StringBuilder(); + + for (int i = 0; i < hash.Length; i++) + { + fletcherOutput.Append(hash[i].ToString("x2")); + } + + return fletcherOutput.ToString(); + } + + /// + /// Gets the hash of the specified data buffer. + /// + /// Data buffer. + /// Length of the data buffer to hash. + /// Byte array of the hash value. + public static string Data(byte[] data, uint len, out byte[] hash) + { + UInt16 localSum1, localSum2, block; + UInt32 finalSum; + + localSum1 = 0xFFFF; + localSum2 = 0xFFFF; + block = 0; + + if (len % 2 == 0) + { + for (int i = 0; i < len; i += 2) + { + block = BigEndianBitConverter.ToUInt16(data, i); + localSum1 = (UInt16)((localSum1 + block) % 0xFFFF); + localSum2 = (UInt16)((localSum2 + localSum1) % 0xFFFF); + } + } + else + { + for (int i = 0; i < len - 1; i += 2) + { + block = BigEndianBitConverter.ToUInt16(data, i); + localSum1 = (UInt16)((localSum1 + block) % 0xFFFF); + localSum2 = (UInt16)((localSum2 + localSum1) % 0xFFFF); + } + + byte[] oddData = new byte[2]; + oddData[0] = data[len - 1]; + oddData[1] = 0; + + block = BigEndianBitConverter.ToUInt16(oddData, 0); + localSum1 = (UInt16)((localSum1 + block) % 0xFFFF); + localSum2 = (UInt16)((localSum2 + localSum1) % 0xFFFF); + } + + finalSum = (UInt32)(localSum1 + (localSum2 << 16)); + + hash = BitConverter.GetBytes(finalSum); + + StringBuilder fletcherOutput = new StringBuilder(); + + for (int i = 0; i < hash.Length; i++) + { + fletcherOutput.Append(hash[i].ToString("x2")); + } + + return fletcherOutput.ToString(); + } + + /// + /// Gets the hash of the specified data buffer. + /// + /// Data buffer. + /// Byte array of the hash value. + public static string Data(byte[] data, out byte[] hash) + { + return Data(data, (uint)data.Length, out hash); + } + } + + public class Fletcher16Context + { + byte sum1, sum2; + + /// + /// Initializes the Fletcher16 sums + /// + public void Init() + { + sum1 = 0xFF; + sum2 = 0xFF; + } + + /// + /// Updates the hash with data. + /// + /// Data buffer. + /// Length of buffer to hash. + public void Update(byte[] data, uint len) + { + for (int i = 0; i < len; i++) + { + sum1 = (byte)((sum1 + data[i]) % 0xFF); + sum2 = (byte)((sum2 + sum1) % 0xFF); + } + } + + /// + /// Updates the hash with data. + /// + /// Data buffer. + public void Update(byte[] data) + { + Update(data, (uint)data.Length); + } + + /// + /// Returns a byte array of the hash value. + /// + public byte[] Final() + { + UInt16 finalSum = (UInt16)(sum1 + (sum2 << 8)); + return BigEndianBitConverter.GetBytes(finalSum); + } + + /// + /// Returns a hexadecimal representation of the hash value. + /// + public string End() + { + UInt16 finalSum = (UInt16)(sum1 + (sum2 << 8)); + 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(); + } + + /// + /// Gets the hash of a file + /// + /// File path. + public static byte[] File(string filename) + { + byte[] hash; + File(filename, out hash); + return hash; + } + + /// + /// Gets the hash of a file in hexadecimal and as a byte array. + /// + /// File path. + /// Byte array of the hash value. + public static string File(string filename, out byte[] hash) + { + FileStream fileStream = new FileStream(filename, FileMode.Open); + byte localSum1, localSum2, block; + UInt16 finalSum; + + localSum1 = 0xFF; + localSum2 = 0xFF; + block = 0; + + for (int i = 0; i < fileStream.Length; i += 2) + { + block = (byte)fileStream.ReadByte(); + localSum1 = (byte)((localSum1 + block) % 0xFF); + localSum2 = (byte)((localSum2 + localSum1) % 0xFF); + } + + finalSum = (UInt16)(localSum1 + (localSum2 << 8)); + + hash = BitConverter.GetBytes(finalSum); + + StringBuilder fletcherOutput = new StringBuilder(); + + for (int i = 0; i < hash.Length; i++) + { + fletcherOutput.Append(hash[i].ToString("x2")); + } + + return fletcherOutput.ToString(); + } + + /// + /// Gets the hash of the specified data buffer. + /// + /// Data buffer. + /// Length of the data buffer to hash. + /// Byte array of the hash value. + public static string Data(byte[] data, uint len, out byte[] hash) + { + byte localSum1, localSum2; + UInt16 finalSum; + + localSum1 = 0xFF; + localSum2 = 0xFF; + + for (int i = 0; i < len; i++) + { + localSum1 = (byte)((localSum1 + data[i]) % 0xFF); + localSum2 = (byte)((localSum2 + localSum1) % 0xFF); + } + + finalSum = (UInt16)(localSum1 + (localSum2 << 8)); + + hash = BitConverter.GetBytes(finalSum); + + StringBuilder fletcherOutput = new StringBuilder(); + + for (int i = 0; i < hash.Length; i++) + { + fletcherOutput.Append(hash[i].ToString("x2")); + } + + return fletcherOutput.ToString(); + } + + /// + /// Gets the hash of the specified data buffer. + /// + /// Data buffer. + /// Byte array of the hash value. + public static string Data(byte[] data, out byte[] hash) + { + return Data(data, (uint)data.Length, out hash); + } + } +} + diff --git a/DiscImageChef/Commands/Checksum.cs b/DiscImageChef/Commands/Checksum.cs index bcdcb2c35..f015bb007 100644 --- a/DiscImageChef/Commands/Checksum.cs +++ b/DiscImageChef/Commands/Checksum.cs @@ -87,6 +87,8 @@ namespace DiscImageChef.Commands CRC16Context crc16ctxTrack = new CRC16Context(); CRC32Context crc32ctxTrack = new CRC32Context(); CRC64Context crc64ctxTrack = new CRC64Context(); + Fletcher16Context fletcher16ctxTrack = new Fletcher16Context(); + Fletcher32Context fletcher32ctxTrack = new Fletcher32Context(); MD5Context md5ctxTrack = new MD5Context(); RIPEMD160Context ripemd160ctxTrack = new RIPEMD160Context(); SHA1Context sha1ctxTrack = new SHA1Context(); @@ -102,6 +104,10 @@ namespace DiscImageChef.Commands crc32ctxTrack.Init(); if (options.DoCRC64) crc64ctxTrack.Init(); + if (options.DoFletcher16) + fletcher16ctxTrack.Init(); + if (options.DoFletcher32) + fletcher32ctxTrack.Init(); if (options.DoMD5) md5ctxTrack.Init(); if (options.DoRIPEMD160) @@ -130,6 +136,10 @@ namespace DiscImageChef.Commands crc32ctxTrack.Update(sector); if (options.DoCRC64) crc64ctxTrack.Update(sector); + if (options.DoFletcher16) + fletcher16ctxTrack.Update(sector); + if (options.DoFletcher32) + fletcher32ctxTrack.Update(sector); if (options.DoMD5) md5ctxTrack.Update(sector); if (options.DoRIPEMD160) @@ -154,6 +164,10 @@ namespace DiscImageChef.Commands Console.WriteLine("Track {0}'s CRC32: 0x{1}", currentTrack.TrackSequence, crc32ctxTrack.End()); if (options.DoCRC64) Console.WriteLine("Track {0}'s CRC64 (ECMA): 0x{1}", currentTrack.TrackSequence, crc64ctxTrack.End()); + if (options.DoFletcher16) + Console.WriteLine("Track {0}'s Fletcher-16: 0x{1}", currentTrack.TrackSequence, fletcher16ctxTrack.End()); + if (options.DoFletcher32) + Console.WriteLine("Track {0}'s Fletcher-32: 0x{1}", currentTrack.TrackSequence, fletcher32ctxTrack.End()); if (options.DoMD5) Console.WriteLine("Track {0}'s MD5: {1}", currentTrack.TrackSequence, md5ctxTrack.End()); if (options.DoRIPEMD160) @@ -184,6 +198,8 @@ namespace DiscImageChef.Commands CRC16Context crc16ctx = new CRC16Context(); CRC32Context crc32ctx = new CRC32Context(); CRC64Context crc64ctx = new CRC64Context(); + Fletcher16Context fletcher16ctx = new Fletcher16Context(); + Fletcher32Context fletcher32ctx = new Fletcher32Context(); MD5Context md5ctx = new MD5Context(); RIPEMD160Context ripemd160ctx = new RIPEMD160Context(); SHA1Context sha1ctx = new SHA1Context(); @@ -199,6 +215,10 @@ namespace DiscImageChef.Commands crc32ctx.Init(); if (options.DoCRC64) crc64ctx.Init(); + if (options.DoFletcher16) + fletcher16ctx.Init(); + if (options.DoFletcher32) + fletcher32ctx.Init(); if (options.DoMD5) md5ctx.Init(); if (options.DoRIPEMD160) @@ -227,6 +247,10 @@ namespace DiscImageChef.Commands crc32ctx.Update(sector); if (options.DoCRC64) crc64ctx.Update(sector); + if (options.DoFletcher16) + crc64ctx.Update(sector); + if (options.DoFletcher32) + crc64ctx.Update(sector); if (options.DoMD5) md5ctx.Update(sector); if (options.DoRIPEMD160) @@ -251,6 +275,10 @@ namespace DiscImageChef.Commands Console.WriteLine("Disk's CRC32: 0x{0}", crc32ctx.End()); if (options.DoCRC64) Console.WriteLine("Disk's CRC64 (ECMA): 0x{0}", crc64ctx.End()); + if (options.DoFletcher16) + Console.WriteLine("Disk's Fletcher-16: 0x{0}", fletcher16ctx.End()); + if (options.DoFletcher32) + Console.WriteLine("Disk's Fletcher-32: 0x{0}", fletcher32ctx.End()); if (options.DoMD5) Console.WriteLine("Disk's MD5: {0}", md5ctx.End()); if (options.DoRIPEMD160) diff --git a/DiscImageChef/DiscImageChef.csproj b/DiscImageChef/DiscImageChef.csproj index 7a7338e29..488a1e64c 100644 --- a/DiscImageChef/DiscImageChef.csproj +++ b/DiscImageChef/DiscImageChef.csproj @@ -107,6 +107,7 @@ + diff --git a/DiscImageChef/Options.cs b/DiscImageChef/Options.cs index eea3746ab..51bb38e17 100644 --- a/DiscImageChef/Options.cs +++ b/DiscImageChef/Options.cs @@ -98,6 +98,14 @@ namespace DiscImageChef HelpText = "Calculates CRC64 (ECMA).")] public bool DoCRC64 { get; set; } + [Option("fletcher16", DefaultValue = false, + HelpText = "Calculates Fletcher-16.")] + public bool DoFletcher16 { get; set; } + + [Option("fletcher32", DefaultValue = false, + HelpText = "Calculates Fletcher-32.")] + public bool DoFletcher32 { get; set; } + [Option('m', "md5", DefaultValue = true, HelpText = "Calculates MD5.")] public bool DoMD5 { get; set; } diff --git a/README.md b/README.md index 79e66a79c..60c7c74fe 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,8 @@ Supported checksums * CRC-16 * CRC-32 * CRC-64 +* Fletcher-16 +* Fletcher-32 * MD5 * RMD160 * SHA-1