Checksum programs. Can I make one?

Android O downloads and various other downloads on the internet provide checksums along with files that you are downloading. For tons of information about what a checksum is, you can visit here.

Tl; DR; https://github.com/aasierra/acg

To get started I just created a standard Java with gradle build project and created a class called ChecksumGenerator such as below.

  	
package com.anthonysierra;

import java.io.File;
import java.io.FileInputStream;

public class ChecksumGenerator {
}

  	
  

The two main classes we are going to use are FileInputStream as well as MessageDigest

The FileInputStream as it sounds will read the file and MessageDigest is what will be used to do the actual hashing. So to get started lets create the function that our tests will call along with the FileInputStream and have the function take in a File object. Resulting in the below code.

	
package com.anthonysierra;

import java.io.File;
import java.io.FileInputStream;

public class ChecksumGenerator {

    public static String generateSha256(final File file) {
        final StringBuilder bldr = new StringBuilder();
        try (final FileInputStream stream = new FileInputStream(file)) {

        } catch (Exception e) {

        }
        return bldr.toString();
    }
}

	

As you can see we are using the Java 7 try with resources here. If you get an error saying Try-with-resources is not supported at this language level. Then you will need to (At least on intellij) go to Preferences -> Build, Execution, Deployment -> Compiler -> Java Compiler. And change the target bytecode version to 1.7

Before

After

If the file is still showing you issues then you will need to go to module settings and change the level to 1.7.

Before

After

Now that our stream is setup we can go ahead and setup our MessageDigest class and start to read the file and update our message digest resulting in the below code.

		
package com.anthonysierra;

import java.io.File;
import java.io.FileInputStream;
import java.security.MessageDigest;
public class ChecksumGenerator {

    public static String generateSha256(final File file) {
        final StringBuilder bldr = new StringBuilder();
        try (final FileInputStream stream = new FileInputStream(file)) {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            final byte[] bytes = new byte[1024];
            int amountToRead;
            while ((amountToRead = stream.read(bytes)) != -1) {
                digest.update(bytes, 0, amountToRead);
            }
        } catch (Exception e) {

        }
        return bldr.toString();
    }
}

		
	

As you can see we setup our message digest to use (at least in this example) the SHA-256 algorithm. From there we will start reading through the FileInputStream like normal. An important note is the way we are calling update. Notice we have the amountToRead integer. That is there so that if we get to the end of the file and the bytes array’s 1024 bytes are not filled from the new read, then we only update the digest with the last portion of the file. So for instance if the files contents contained “Hello” that would obviously not fill the byte array, so we only want to update the digest with Hello and not the extra 0s that would be in the rest of the 1019 spaces.

Now that we have that we call the digest message on our message digest and begin to iterate through the digests output and turn it into a 0 padded hex string representation. Giving us the SHA-256 checksum hashes seen all over the internet. Below is the code with this modification.

		
package com.anthonysierra;

import java.io.File;
import java.io.FileInputStream;
import java.security.MessageDigest;

public class ChecksumGenerator {

    public static String generateSha256(final File file) {
        final StringBuilder bldr = new StringBuilder();
        try (final FileInputStream stream = new FileInputStream(file)) {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            final byte[] bytes = new byte[1024];
            int amountToRead;
            while ((amountToRead = stream.read(bytes)) != -1) {
                digest.update(bytes, 0, amountToRead);
            }
            final byte[] messageDigest = digest.digest();
            for (int i =0; i < messageDigest.length; i++) {
                bldr.append(Integer.toString((messageDigest[i] & 0xff) + 0x100, 16).substring(1));
            }
        } catch (Exception e) {

        }
        return bldr.toString();
    }
}

		
	

As you can see we go through the messageDigest (result of digest.digest() call) and then turn it into hex as well as pad it with 0s if need be. To more understand the point of 0xff go here and then the 0x100 is for padding.

So now that we think we have working code, lets verify it how all great programmers should and write a test.

Junit should already come as a dependency if you used the gradle setup for IntelliJ if not then you will need to go elsewhere to learn how to setup testing for whatever you are using.

When you are finally setup to write a test you will want to create the file resource we will be testing against. So add to your test resources a file called basic.txt and put inside of it a larger value. Maybe Hello world copied a thousand times. Take the file and visit this web page http://hash.online-convert.com/sha256-generator and upload your file. Make sure it is under 1gb therwise they will not take it, hence the reason for me writing my own checksum program.

Then once that is done you should have a hash to compare against.

Now that you have a hash to compare against lets write our test to look like the code below.

		
package com.anthonysierra;

import org.junit.Test;

import java.io.File;

import static org.junit.Assert.assertEquals;

public class ChecksumGeneratorTests {

    @Test
    public void testMyChecksum() {
        final String output = ChecksumGenerator.generateSha256(new File("src/test/resources/basic.txt"));
        assertEquals("4c23610c2f2a05dd8c7b6c8acb06a7f7009461266a169e457d20844bd747f611", output);
    }
}

		
	

Run it and then that should now work and pass. Congratulations you now have your very own checksum hashing program.

I would recommend looking at my github project, linked in the TL;DR to see better code and how I would actually recommend implementing things. Plus there are javadocs that might help clear things up as well.