From 4fc2e234b02dee94207d27b657872af0dfa6bff6 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Tue, 19 May 2015 06:04:21 +0100 Subject: [PATCH] Implement "entropy" command. --- DiscImageChef/ChangeLog | 8 ++ DiscImageChef/Commands/Entropy.cs | 180 +++++++++++++++++++++++++++++ DiscImageChef/DiscImageChef.csproj | 1 + DiscImageChef/Main.cs | 6 + DiscImageChef/Options.cs | 22 ++++ 5 files changed, 217 insertions(+) create mode 100644 DiscImageChef/Commands/Entropy.cs diff --git a/DiscImageChef/ChangeLog b/DiscImageChef/ChangeLog index 0ea06dfa3..8038b319c 100644 --- a/DiscImageChef/ChangeLog +++ b/DiscImageChef/ChangeLog @@ -1,3 +1,11 @@ +2015-05-19 Natalia Portillo + + * Main.cs: + * Options.cs: + * Commands/Entropy.cs: + * DiscImageChef.csproj: + Implement "entropy" command. + 2015-04-24 Natalia Portillo * ImagePlugins/VHD.cs: diff --git a/DiscImageChef/Commands/Entropy.cs b/DiscImageChef/Commands/Entropy.cs new file mode 100644 index 000000000..02249e374 --- /dev/null +++ b/DiscImageChef/Commands/Entropy.cs @@ -0,0 +1,180 @@ +/*************************************************************************** +The Disc Image Chef +---------------------------------------------------------------------------- + +Filename : Checksum.cs +Version : 1.0 +Author(s) : Natalia Portillo + +Component : Verbs. + +Revision : $Revision$ +Last change by : $Author$ +Date : $Date$ + +--[ Description ] ---------------------------------------------------------- + +Implements the 'checksum' verb. + +--[ 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-2014 Claunia.com +****************************************************************************/ +//$Id$ +using System; +using DiscImageChef.ImagePlugins; +using DiscImageChef.Checksums; +using System.Collections.Generic; + +namespace DiscImageChef.Commands +{ + public static class Entropy + { + public static void doEntropy(EntropySubOptions options) + { + if (MainClass.isDebug) + { + Console.WriteLine("--debug={0}", options.Debug); + Console.WriteLine("--verbose={0}", options.Verbose); + Console.WriteLine("--separated-tracks={0}", options.SeparatedTracks); + Console.WriteLine("--whole-disc={0}", options.WholeDisc); + Console.WriteLine("--input={0}", options.InputFile); + Console.WriteLine("--duplicated-sectors={0}", options.DuplicatedSectors); + } + + ImagePlugin inputFormat = ImageFormat.Detect(options.InputFile); + + if (inputFormat == null) + { + Console.WriteLine("Unable to recognize image format, not checksumming"); + return; + } + + inputFormat.OpenImage(options.InputFile); + + if (options.SeparatedTracks) + { + try + { + List inputTracks = inputFormat.GetTracks(); + + foreach (Track currentTrack in inputTracks) + { + SHA1Context sha1ctxTrack = new SHA1Context(); + ulong[] entTable = new ulong[256]; + ulong trackSize = 0; + List uniqueSectorsPerTrack = new List(); + + ulong sectors = currentTrack.TrackEndSector - currentTrack.TrackStartSector + 1; + Console.WriteLine("Track {0} has {1} sectors", currentTrack.TrackSequence, sectors); + + for (ulong i = currentTrack.TrackStartSector; i <= currentTrack.TrackEndSector; i++) + { + Console.Write("\rEntropying sector {0} of track {1}", i + 1, currentTrack.TrackSequence); + byte[] sector = inputFormat.ReadSector(i, currentTrack.TrackSequence); + + if(options.DuplicatedSectors) + { + byte[] garbage; + string sectorHash = sha1ctxTrack.Data(sector, out garbage); + if(!uniqueSectorsPerTrack.Contains(sectorHash)) + uniqueSectorsPerTrack.Add(sectorHash); + } + + foreach(byte b in sector) + entTable[b]++; + + trackSize += (ulong)sector.LongLength; + } + + double entropy = 0; + foreach(ulong l in entTable) + { + double frequency = (double)l/(double)trackSize; + entropy += -(frequency * Math.Log(frequency, 2)); + } + + Console.WriteLine("Entropy for track {0} is {1:F4}.", currentTrack.TrackSequence, entropy); + + if(options.DuplicatedSectors) + Console.WriteLine("Track {0} has {1} unique sectors ({1:P3})", currentTrack.TrackSequence, uniqueSectorsPerTrack.Count, (double)uniqueSectorsPerTrack.Count/(double)sectors); + + Console.WriteLine(); + } + } + catch (Exception ex) + { + if (options.Debug) + Console.WriteLine("Could not get tracks because {0}", ex.Message); + else + Console.WriteLine("Unable to get separate tracks, not calculating their entropy"); + } + } + + + if (options.WholeDisc) + { + SHA1Context sha1Ctx = new SHA1Context(); + ulong[] entTable = new ulong[256]; + ulong diskSize = 0; + List uniqueSectors = new List(); + + ulong sectors = inputFormat.GetSectors(); + Console.WriteLine("Sectors {0}", sectors); + + sha1Ctx.Init(); + + for (ulong i = 0; i < sectors; i++) + { + Console.Write("\rEntropying sector {0}", i + 1); + byte[] sector = inputFormat.ReadSector(i); + + if(options.DuplicatedSectors) + { + byte[] garbage; + string sectorHash = sha1Ctx.Data(sector, out garbage); + if(!uniqueSectors.Contains(sectorHash)) + uniqueSectors.Add(sectorHash); + } + + foreach(byte b in sector) + entTable[b]++; + + diskSize += (ulong)sector.LongLength; + + } + + double entropy = 0; + foreach(ulong l in entTable) + { + double frequency = (double)l/(double)diskSize; + entropy += -(frequency * Math.Log(frequency, 2)); + } + + Console.WriteLine(); + + Console.WriteLine("Entropy for disk is {0:F4}.", entropy); + + if(options.DuplicatedSectors) + Console.WriteLine("Disk has {0} unique sectors ({1:P3})", uniqueSectors.Count, (double)uniqueSectors.Count/(double)sectors); + + + } + } + } +} + diff --git a/DiscImageChef/DiscImageChef.csproj b/DiscImageChef/DiscImageChef.csproj index 8d3b57866..8777c66cb 100644 --- a/DiscImageChef/DiscImageChef.csproj +++ b/DiscImageChef/DiscImageChef.csproj @@ -114,6 +114,7 @@ + diff --git a/DiscImageChef/Main.cs b/DiscImageChef/Main.cs index 186f725be..48ba147ad 100644 --- a/DiscImageChef/Main.cs +++ b/DiscImageChef/Main.cs @@ -99,6 +99,12 @@ namespace DiscImageChef isVerbose = ChecksumOptions.Verbose; Commands.Checksum.doChecksum(ChecksumOptions); break; + case "entropy": + EntropySubOptions entropyOptions = (EntropySubOptions)invokedVerbInstance; + isDebug = entropyOptions.Debug; + isVerbose = entropyOptions.Verbose; + Commands.Entropy.doEntropy(entropyOptions); + break; case "verify": VerifySubOptions VerifyOptions = (VerifySubOptions)invokedVerbInstance; isDebug = VerifyOptions.Debug; diff --git a/DiscImageChef/Options.cs b/DiscImageChef/Options.cs index 17f3dad65..a076bd3fe 100644 --- a/DiscImageChef/Options.cs +++ b/DiscImageChef/Options.cs @@ -138,6 +138,24 @@ namespace DiscImageChef public string InputFile { get; set; } } + public class EntropySubOptions : CommonSubOptions + { + [Option('p', "duplicated-sectors", DefaultValue = true, + HelpText = "Calculates how many sectors are duplicated (have same exact data in user area).")] + public bool DuplicatedSectors { get; set; } + + [Option('t', "separated-tracks", DefaultValue = true, + HelpText = "Calculates entropy for each track separately.")] + public bool SeparatedTracks { get; set; } + + [Option('w', "whole-disc", DefaultValue = true, + HelpText = "Calculates entropy for the whole disc.")] + public bool WholeDisc { get; set; } + + [Option('i', "input", Required = true, HelpText = "Disc image.")] + public string InputFile { get; set; } + } + public class VerifySubOptions : CommonSubOptions { [Option('w', "verify-disc", DefaultValue = true, @@ -207,6 +225,7 @@ namespace DiscImageChef AnalyzeVerb = new AnalyzeSubOptions(); CompareVerb = new CompareSubOptions(); ChecksumVerb = new ChecksumSubOptions(); + EntropyVerb = new EntropySubOptions(); VerifyVerb = new VerifySubOptions(); FormatsVerb = new FormatsSubOptions(); PrintHexVerb = new PrintHexSubOptions(); @@ -222,6 +241,9 @@ namespace DiscImageChef [VerbOption("checksum", HelpText = "Checksums an image.")] public ChecksumSubOptions ChecksumVerb { get; set; } + [VerbOption("entropy", HelpText = "Calculates entropy and/or duplicated sectors of an image.")] + public EntropySubOptions EntropyVerb { get; set; } + [VerbOption("verify", HelpText = "Verifies a disc image integrity, and if supported, sector integrity.")] public VerifySubOptions VerifyVerb { get; set; }