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:

  1. Read the file's data
  2. Compute the file's checksum
  3. Read the (expected) checksum from file
  4. Compare the two values
  5. 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!");
    }
}

Download the solution file