Verifying MD5 Checksum
Md5 Verifier is a tiny simple application that checks the checksum of a file against its expected checksum. A checksum, as you might already know, essentially lets you verify the file you're downloading hasn't been changed or damaged.
Md5Verifier takes an executable and a file containing the md5 checksum, and lets you know if they match.
To interested parties: md5 hashing is built-in for .NET, so implementing a checksum verifier becomes as easy as:
- Read the file's data
- Compute the file's checksum
- Read the (expected) checksum from file
- Compare the two values
- Display result
Disclaimer: I claim to be no expert in security. If I made any blunders or if there's a better way to do the same, let me know! :)
/// <summary>
/// Reads data from a stream until the end is reached. The
/// data is returned as a byte array. Throws an IOException
/// if any of the underlying IO calls fail.
/// </summary>
/// <param name="path">Path to the file to read</param>
/// <returns>The contents of the file</returns>
private byte[] ReadFully(string path)
{
// Thank you, yoda.arachsys.com
int size = 32768; // Size of the buffer: 32K
int read = 0; // How many bytes did we read?
int chunk = 0; // Bytes read in the current iteration
byte[] buffer = new byte[size]; // Holds the contents of the file
path = Path.GetFullPath(path); // Is this necessary?
using (FileStream stream = File.OpenRead(path))
{
while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0)
{
read = read + chunk;
if (read == buffer.Length)
{
int nextByte = stream.ReadByte();
if (nextByte == -1)
{
// End of stream, so we're done
return buffer;
}
// Still have more information to read, so let's
// resize the buffer.
byte[] newBuffer = new byte[buffer.Length * 2];
Array.Copy(buffer, newBuffer, buffer.Length);
newBuffer[read] = (byte)nextByte;
buffer = newBuffer;
read++;
}
}
}
// Get rid of any empty slots (the size of the file
// doesn't need to be a multiple of 32K).
byte[] contents = new byte[read];
Array.Copy(buffer, contents, read);
return contents;
}
/// <summary>
/// Returns the MD5 hash of the file
/// </summary>
private string Actual
{
get
{
if (string.IsNullOrEmpty(FileTextBox.Text))
{
return string.Empty;
}
byte[] actualBytes = ComputeMd5(ReadFully(FileTextBox.Text));
System.Text.StringBuilder actual = new System.Text.StringBuilder();
foreach (byte b in actualBytes)
{
actual.Append(b.ToString("X2"));
}
return actual.ToString().ToLower();
}
}
/// <summary>
/// Computes the md5 checksum of the contents.
/// </summary>
private byte[] ComputeMd5(byte[] contents)
{
<strong>MD5 md5 = new MD5CryptoServiceProvider();
byte[] hash = md5.ComputeHash(contents);</strong>
return hash;
}
/// <summary>
/// Reads & returns the expected md5 hash
/// </summary>
private string Expected
{
get
{
if (string.IsNullOrEmpty(Md5TextBox.Text))
{
return string.Empty;
}
string expected = string.Empty;
using (StreamReader reader = File.OpenText(Md5TextBox.Text))
{
expected = reader.ReadToEnd();
}
Match m = Regex.Match(expected, @"^[0-9a-z]+", RegexOptions.Multiline);
if (m.Success == false)
{
throw new ArgumentException("Bad MD5 file.");
}
else
{
expected = m.Value;
}
return expected.ToLower();
}
}
/// <summary>
/// Checks the md5 checksum of the file against its
/// expected md5 checksum.
/// </summary>
protected void CheckButton_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(FileTextBox.Text) ||
string.IsNullOrEmpty(Md5TextBox.Text))
{
return;
}
string actual = Actual;
string expected = Expected;
if (string.IsNullOrEmpty(actual) || string.IsNullOrEmpty(expected))
{
return;
}
MessageBox.Show("Expected: " + expected);
MessageBox.Show("Actual: " + actual);
if (expected == actual)
{
MessageBox.Show("Success!");
}
else
{
MessageBox.Show("Failure!");
}
}