From 299b3073f51cdfc88693b43e1b1f2dd3901c878d Mon Sep 17 00:00:00 2001 From: Brandon Scott Date: Mon, 3 Jul 2017 01:43:27 -0500 Subject: [PATCH] Initial commit. --- .gitignore | 288 ++++++++++++++++++ FileHashCalculator.sln | 20 ++ .../CustomHashAlgorithms/MD2.cs | 113 +++++++ FileHashCalculator/FileHashCalculator.csproj | 89 ++++++ FileHashCalculator/MainForm.Designer.cs | 142 +++++++++ FileHashCalculator/MainForm.cs | 130 ++++++++ FileHashCalculator/MainForm.resx | 120 ++++++++ FileHashCalculator/Program.cs | 21 ++ FileHashCalculator/Properties/AssemblyInfo.cs | 36 +++ .../Properties/Resources.Designer.cs | 71 +++++ FileHashCalculator/Properties/Resources.resx | 117 +++++++ .../Properties/Settings.Designer.cs | 30 ++ .../Properties/Settings.settings | 7 + FileHashCalculator/Utilities.cs | 24 ++ LICENSE | 21 ++ README.md | 17 ++ Screenshot.png | Bin 0 -> 34111 bytes 17 files changed, 1246 insertions(+) create mode 100644 .gitignore create mode 100644 FileHashCalculator.sln create mode 100644 FileHashCalculator/CustomHashAlgorithms/MD2.cs create mode 100644 FileHashCalculator/FileHashCalculator.csproj create mode 100644 FileHashCalculator/MainForm.Designer.cs create mode 100644 FileHashCalculator/MainForm.cs create mode 100644 FileHashCalculator/MainForm.resx create mode 100644 FileHashCalculator/Program.cs create mode 100644 FileHashCalculator/Properties/AssemblyInfo.cs create mode 100644 FileHashCalculator/Properties/Resources.Designer.cs create mode 100644 FileHashCalculator/Properties/Resources.resx create mode 100644 FileHashCalculator/Properties/Settings.Designer.cs create mode 100644 FileHashCalculator/Properties/Settings.settings create mode 100644 FileHashCalculator/Utilities.cs create mode 100644 LICENSE create mode 100644 README.md create mode 100644 Screenshot.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..940794e --- /dev/null +++ b/.gitignore @@ -0,0 +1,288 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Typescript v1 declaration files +typings/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs diff --git a/FileHashCalculator.sln b/FileHashCalculator.sln new file mode 100644 index 0000000..fe7baf7 --- /dev/null +++ b/FileHashCalculator.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileHashCalculator", "FileHashCalculator\FileHashCalculator.csproj", "{F20C029B-AEE7-4676-BF46-B6E59FB9C78E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F20C029B-AEE7-4676-BF46-B6E59FB9C78E}.Debug|x86.ActiveCfg = Debug|x86 + {F20C029B-AEE7-4676-BF46-B6E59FB9C78E}.Debug|x86.Build.0 = Debug|x86 + {F20C029B-AEE7-4676-BF46-B6E59FB9C78E}.Release|x86.ActiveCfg = Release|x86 + {F20C029B-AEE7-4676-BF46-B6E59FB9C78E}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/FileHashCalculator/CustomHashAlgorithms/MD2.cs b/FileHashCalculator/CustomHashAlgorithms/MD2.cs new file mode 100644 index 0000000..b47d7a6 --- /dev/null +++ b/FileHashCalculator/CustomHashAlgorithms/MD2.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Security.Cryptography; + +namespace FileHashCalculator.CustomHashAlgorithms +{ + public class MD2 + { + byte[] data = new byte[16]; + byte[] state = new byte[48]; + byte[] checksum = new byte[16]; + int len; + + private byte[] s = new byte[] { 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, + 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, + 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, + 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, + 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, + 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, + 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, + 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, + 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, + 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, + 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, + 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, + 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, + 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, + 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, + 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, + 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, + 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 + }; + + public void Initialize() + { + int i; + + for (i = 0; i < 48; ++i) + this.state[i] = 0; + + for (i = 0; i < 16; ++i) + this.checksum[i] = 0; + + this.len = 0; + } + + public void Transform(byte[] data) + { + int j, k, t; + + for (j = 0; j < 16; ++j) + { + this.state[j + 16] = data[j]; + this.state[j + 32] = (byte)(this.state[j + 16] ^ this.state[j]); + } + + t = 0; + for (j = 0; j < 18; ++j) + { + for (k = 0; k < 48; ++k) + { + this.state[k] ^= s[t]; + t = this.state[k]; + } + t = (t + j) & 0xFF; + } + + t = this.checksum[15]; + for (j = 0; j < 16; ++j) + { + this.checksum[j] ^= s[data[j] ^ t]; + t = this.checksum[j]; + } + } + + public void Update(byte[] data, int len) + { + int t,i; + for (i=0; i < len; ++i) { + this.data[this.len] = data[i]; + this.len++; + if (this.len == 16) { + Transform(this.data); + this.len = 0; + } + } + } + + public byte[] Final() + { + int to_pad = 16 - this.len; + byte[] output = new byte[16]; + + while (this.len < 16) + this.data[this.len++] = (byte)to_pad; + + Transform(this.data); + Transform(this.checksum); + + Array.Copy(this.state, output, 16); + return output; + } + + public byte[] Compute(byte[] data) + { + Initialize(); + Update(data, data.Length); + return Final(); + } + } +} diff --git a/FileHashCalculator/FileHashCalculator.csproj b/FileHashCalculator/FileHashCalculator.csproj new file mode 100644 index 0000000..ce64990 --- /dev/null +++ b/FileHashCalculator/FileHashCalculator.csproj @@ -0,0 +1,89 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {F20C029B-AEE7-4676-BF46-B6E59FB9C78E} + WinExe + Properties + FileHashCalculator + FileHashCalculator + v4.0 + Client + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + Form + + + MainForm.cs + + + + + + MainForm.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + \ No newline at end of file diff --git a/FileHashCalculator/MainForm.Designer.cs b/FileHashCalculator/MainForm.Designer.cs new file mode 100644 index 0000000..b2bdc38 --- /dev/null +++ b/FileHashCalculator/MainForm.Designer.cs @@ -0,0 +1,142 @@ +namespace FileHashCalculator +{ + partial class MainForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.generateHashesButton = new System.Windows.Forms.Button(); + this.fileTextBox = new System.Windows.Forms.TextBox(); + this.browseButton = new System.Windows.Forms.Button(); + this.hashProgressBar = new System.Windows.Forms.ProgressBar(); + this.hashListView = new System.Windows.Forms.ListView(); + this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.hashPercentageLabel = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // generateHashesButton + // + this.generateHashesButton.Location = new System.Drawing.Point(352, 40); + this.generateHashesButton.Name = "generateHashesButton"; + this.generateHashesButton.Size = new System.Drawing.Size(88, 24); + this.generateHashesButton.TabIndex = 0; + this.generateHashesButton.Text = "Generate"; + this.generateHashesButton.UseVisualStyleBackColor = true; + this.generateHashesButton.Click += new System.EventHandler(this.generateHashesButton_Click); + // + // fileTextBox + // + this.fileTextBox.Location = new System.Drawing.Point(8, 8); + this.fileTextBox.Name = "fileTextBox"; + this.fileTextBox.ReadOnly = true; + this.fileTextBox.Size = new System.Drawing.Size(336, 20); + this.fileTextBox.TabIndex = 1; + // + // browseButton + // + this.browseButton.Location = new System.Drawing.Point(352, 8); + this.browseButton.Name = "browseButton"; + this.browseButton.Size = new System.Drawing.Size(88, 24); + this.browseButton.TabIndex = 2; + this.browseButton.Text = "Browse"; + this.browseButton.UseVisualStyleBackColor = true; + this.browseButton.Click += new System.EventHandler(this.browseButton_Click); + // + // hashProgressBar + // + this.hashProgressBar.Location = new System.Drawing.Point(8, 32); + this.hashProgressBar.Name = "hashProgressBar"; + this.hashProgressBar.Size = new System.Drawing.Size(288, 16); + this.hashProgressBar.TabIndex = 3; + // + // hashListView + // + this.hashListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader1, + this.columnHeader2}); + this.hashListView.FullRowSelect = true; + this.hashListView.GridLines = true; + this.hashListView.Location = new System.Drawing.Point(8, 72); + this.hashListView.Name = "hashListView"; + this.hashListView.Size = new System.Drawing.Size(432, 248); + this.hashListView.TabIndex = 4; + this.hashListView.UseCompatibleStateImageBehavior = false; + this.hashListView.View = System.Windows.Forms.View.Details; + // + // columnHeader1 + // + this.columnHeader1.Text = "Algorithm"; + this.columnHeader1.Width = 73; + // + // columnHeader2 + // + this.columnHeader2.Text = "Hash"; + this.columnHeader2.Width = 327; + // + // hashPercentageLabel + // + this.hashPercentageLabel.AutoSize = true; + this.hashPercentageLabel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.hashPercentageLabel.Location = new System.Drawing.Point(304, 34); + this.hashPercentageLabel.Name = "hashPercentageLabel"; + this.hashPercentageLabel.Size = new System.Drawing.Size(23, 15); + this.hashPercentageLabel.TabIndex = 5; + this.hashPercentageLabel.Text = "0%"; + // + // MainForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(449, 330); + this.Controls.Add(this.hashPercentageLabel); + this.Controls.Add(this.hashListView); + this.Controls.Add(this.hashProgressBar); + this.Controls.Add(this.browseButton); + this.Controls.Add(this.fileTextBox); + this.Controls.Add(this.generateHashesButton); + this.Name = "MainForm"; + this.Text = "File Hash Generator"; + this.Load += new System.EventHandler(this.MainForm_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button generateHashesButton; + private System.Windows.Forms.TextBox fileTextBox; + private System.Windows.Forms.Button browseButton; + private System.Windows.Forms.ProgressBar hashProgressBar; + private System.Windows.Forms.ListView hashListView; + private System.Windows.Forms.ColumnHeader columnHeader1; + private System.Windows.Forms.ColumnHeader columnHeader2; + private System.Windows.Forms.Label hashPercentageLabel; + + } +} + diff --git a/FileHashCalculator/MainForm.cs b/FileHashCalculator/MainForm.cs new file mode 100644 index 0000000..14a68dc --- /dev/null +++ b/FileHashCalculator/MainForm.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using System.Security.Cryptography; +using System.IO; +using System.Threading; + +namespace FileHashCalculator +{ + public partial class MainForm : Form + { + private string[] _algoList = new string[] { "MD5", "SHA1", "SHA256", "SHA384", "SHA512" }; + private FileStream _file; + private Thread _hashThread; + private bool _started; + + const int BUFFER_SIZE = 4096; + + public MainForm() + { + InitializeComponent(); + } + + private void browseButton_Click(object sender, EventArgs e) + { + using (OpenFileDialog openFile = new OpenFileDialog()) + { + openFile.Filter = "All files (*.*)|*.*"; + + if (openFile.ShowDialog() == DialogResult.OK) + { + try + { + _file = (FileStream)openFile.OpenFile(); + fileTextBox.Text = openFile.FileName; + } + catch (ArgumentNullException ex) + { + Console.WriteLine(ex.Message); + } + } + } + } + + private void generateHashesButton_Click(object sender, EventArgs e) + { + hashListView.Items.Clear(); + + if (_file == null) + return; + + if (_hashThread == null || _hashThread.IsAlive == false) + _hashThread = new Thread(new ThreadStart(HashThreadProc)); + + if (_started) + return; + + _hashThread.Start(); + } + + private void MainForm_Load(object sender, EventArgs e) + { + + } + + private void HashThreadProc() + { + _started = true; + + foreach (string hashAlgoName in _algoList) + { + // create a new hash object for the algorithm + HashAlgorithm hashAlgoObject = HashAlgorithm.Create(hashAlgoName); + // updates form with progress updates and returns hash + byte[] hash = CalculateHashWithProgress(_file, hashAlgoObject); + // just to make this look a little cleaner + string hashString = BitConverter.ToString(hash).Replace("-", "").ToLower(); + // thread safe call to add it to the list. + AddHashToList(hashAlgoName, hashString); + } + + _started = false; + } + + private byte[] CalculateHashWithProgress(Stream input, HashAlgorithm algorithm) + { + byte[] buffer = new byte[BUFFER_SIZE]; + int readCount; + long streamSize = input.Length; + long totalBytesRead = 0; + + input.Position = 0; // reset position to beginning of the file. + + while ((readCount = input.Read(buffer, 0, BUFFER_SIZE)) > 0) + { + algorithm.TransformBlock(buffer, 0, readCount, buffer, 0); + totalBytesRead += readCount; + UpdateProgress((int)((double)totalBytesRead * 100 / streamSize)); + } + + algorithm.TransformFinalBlock(buffer, 0, readCount); + UpdateProgress((int)((double)totalBytesRead * 100 / streamSize)); + + return algorithm.Hash; + } + + private void UpdateProgress(int progress) + { + this.Invoke(new MethodInvoker(delegate + { + hashProgressBar.Value = progress; + hashPercentageLabel.Text = String.Format("{0}%", progress); + })); + } + + private void AddHashToList(string algo, string hash) + { + this.Invoke(new MethodInvoker(delegate { + ListViewItem lvi = new ListViewItem(algo); + lvi.SubItems.Add(hash); + hashListView.Items.Add(lvi); + })); + } + } +} diff --git a/FileHashCalculator/MainForm.resx b/FileHashCalculator/MainForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/FileHashCalculator/MainForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/FileHashCalculator/Program.cs b/FileHashCalculator/Program.cs new file mode 100644 index 0000000..52f7df0 --- /dev/null +++ b/FileHashCalculator/Program.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace FileHashCalculator +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new MainForm()); + } + } +} diff --git a/FileHashCalculator/Properties/AssemblyInfo.cs b/FileHashCalculator/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..03a1607 --- /dev/null +++ b/FileHashCalculator/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("FileHashCalculator")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Xeon Productions")] +[assembly: AssemblyProduct("FileHashCalculator")] +[assembly: AssemblyCopyright("Copyright © Xeon Productions 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c0999fe5-3a2f-4fa4-b935-d7d4be896245")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/FileHashCalculator/Properties/Resources.Designer.cs b/FileHashCalculator/Properties/Resources.Designer.cs new file mode 100644 index 0000000..6a133b9 --- /dev/null +++ b/FileHashCalculator/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.269 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace FileHashCalculator.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("FileHashCalculator.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/FileHashCalculator/Properties/Resources.resx b/FileHashCalculator/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/FileHashCalculator/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/FileHashCalculator/Properties/Settings.Designer.cs b/FileHashCalculator/Properties/Settings.Designer.cs new file mode 100644 index 0000000..a7e8ecb --- /dev/null +++ b/FileHashCalculator/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.269 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace FileHashCalculator.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/FileHashCalculator/Properties/Settings.settings b/FileHashCalculator/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/FileHashCalculator/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/FileHashCalculator/Utilities.cs b/FileHashCalculator/Utilities.cs new file mode 100644 index 0000000..0fe4920 --- /dev/null +++ b/FileHashCalculator/Utilities.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Security.Cryptography; +using System.IO; + +namespace FileHashCalculator +{ + class Utilities + { + public static string Md5Hash(string fileName) + { + using (MD5 md5 = new MD5CryptoServiceProvider()) + { + using (FileStream file = new FileStream(fileName, FileMode.Open)) + { + byte[] retVal = md5.ComputeHash(file); + return BitConverter.ToString(retVal).Replace("-", ""); // hex string + } + } + } + } +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d378d57 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Brandon Scott + +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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..665283e --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# File Hash Calculator + +## Author + +Brandon Scott + +## About + +This is a file hash calculator I made to familiarize myself with TransformBlock and TransformFinalBlock, it uses C#, WinForms, and multi-threading. It supports MD5, SHA1, SHA256, SHA384, and SHA512. + +## Screenshot + +![Alt text](/Screenshot.png?raw=true "Screenshot") + +## License + +All code in this project is licensed under the MIT license. \ No newline at end of file diff --git a/Screenshot.png b/Screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..3632f88472723f0b6e5c39bde641a00bbd263678 GIT binary patch literal 34111 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