Generate CRC32 hash of a file in Golang turorial

17 April, 2016

In previous posts I showed how to make a MD5 hash and a SHA1 hash of a file, generating a CRC checksum on a file is however a bit more complicated since it uses a polynomial table. I'll explain everything in depth.

Polynomial tables

A polynomial table is a table that gets constructed by a specified polynomial, Go does this for you with the function MakeTable in the hash/crc32 package. In simple words the table tells how the CRC hash should be calculated.

There are five used CRC-32 standards.

Name Uses Polynomial representation (reversed)
CRC-32 Layer 2 ethernet network and SATA error detection. Checksums for PNG, MPEG-2, Gzip, Bzip2,...  0xEDB88320
CRC-32C (Castagnoli) Error detection in iSCSI. Checksums for Btrfs, ext4,... 0x82F63B78
CRC-32K (Koopman)   0xEB31D82E
CRC-32K2 (Koopman 2)   0x992C1A4C
CRC-32Q Error detection in aviation communications AIXM 0xD5828281

A Golang function

This function requires two arguments in the parameters, the first one a string to the location of your file and the second one a unsigned 32bit reversed polynomial representation. It returns either the CRC hash if no error has occurred or an error.

The function

import (
	"encoding/hex"
	"fmt"
	"hash/crc32"
	"io"
	"os"
)
func hash_file_crc32(filePath string, polynomial uint32) (string, error) {
	//Initialize an empty return string now in case an error has to be returned
	var returnCRC32String string

	//Open the fhe file located at the given path and check for errors
	file, err := os.Open(filePath)
	if err != nil {
		return returnCRC32String, err
	}

	//Tell the program to close the file when the function returns
	defer file.Close()

	//Create the table with the given polynomial
	tablePolynomial := crc32.MakeTable(polynomial)

	//Open a new hash interface to write the file to
	hash := crc32.New(tablePolynomial)

	//Copy the file in the interface
	if _, err := io.Copy(hash, file); err != nil {
		return returnCRC32String, err
	}
	
	//Generate the hash
	hashInBytes := hash.Sum(nil)[:]

	//Encode the hash to a string
	returnCRC32String = hex.EncodeToString(hashInBytes)

	//Return the output
	return returnCRC32String, nil
}

Example

This example will print out the CRC-32 hash of itself, the running program.

package main

import (
	"encoding/hex"
	"fmt"
	"hash/crc32"
	"io"
	"os"
)

func hash_file_crc32(filePath string, polynomial uint32) (string, error) {
	var returnCRC32String string
	file, err := os.Open(filePath)
	if err != nil {
		return returnCRC32String, err
	}
	defer file.Close()
	tablePolynomial := crc32.MakeTable(polynomial)
	hash := crc32.New(tablePolynomial)
	if _, err := io.Copy(hash, file); err != nil {
		return returnCRC32String, err
	}
	hashInBytes := hash.Sum(nil)[:]
	returnCRC32String = hex.EncodeToString(hashInBytes)
	return returnCRC32String, nil

}

func main() {
	hash, err := hash_file_crc32(os.Args[0], 0xedb88320)
	if err == nil {
		fmt.Println(hash)
	}
}

More about CRC