[Tutorial] Calculating Checksums for Logical Volumes in Java
#1
Hello GS,

In this post I will discuss how to get checksums/hash of a logical volume in an OS. There are several tools available which provides similar features but most of them are coded in C++/C# (maybe I am not sure). Some flavors of Linux comes packed with CLI tools like dc3dd/dcfldd which provides on the fly hash generation. I wanted to achieve this volume hash generation using java and after googling quite a bit I didn't quite find any good tutorials or references but I found something interesting  here.

Thereafter I tried to access this drive as a file in Java and once I have a file object, its easier to get the checksum using java's builtin MessageDigest class. The only catch being that you have to execute the code using admin privileges. The code I will be sharing now has been tested on windows and the resulting hash obtained has been verified by calculating the hash for a particular drive using a hex editor (Winhex).

1. Task One: Get list of all Logical Drives

Code:
File[] drives = File.listRoots(); //Returns the system drive letters.

If you're interested interested in knowing the type of drive then use the following snippet:

Code:
FileSystemView fsv = FileSystemView.getFileSystemView();
        for (File f : drives){
            System.out.println(fsv.getSystemTypeDescription(f));            
        }

The above outputs something like the following where Local Disk means a logical volume (namely C:\, D:\ etc.) To get the display name for each drive use the function getSystemDisplayName from FileSystemView class.

Code:
Local Disk
Local Disk
Local Disk
CD Drive

1. Task Two: Understanding how to access the drives as file objects.

According to the link I gave earlier to get raw access to logical drives we should map the path as \\.\[Drive Letter]. Say if we have a function getVolumeHash(File file, String hashAlgo) where the first parameter is the complete path to the logical volume then we will pass the arguments as follows:

Code:
File compLoc = new File("\\\\.\\" + drives[0].toString());
byte[] mdbytes = getVolumeHash(compLoc, "SHA1"); //Let's take SHA1 for now.

The above will return the digest of the volume as an array of bytes which we can convert to hex using the following method.

Code:
/**
     * Converts array of bytes to hex string.
     *
     * @param bytes Byte Array to be converted to Hex String.
     * @return Returns the hex string for {@code bytes} array.
     */
    public static String byteArrayToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).
                    substring(1));
        }
        return sb.toString();
    }

So, Here the complete code (Only class):-

Code:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 *
 * @author Psycho_Coder
 */
public class DigestDiskVolume {

    /**
     * Converts array of bytes to hex string.
     *
     * @param bytes Byte Array to be converted to Hex String.
     * @return Returns the hex string for {@code bytes} array.
     */
    public static String byteArrayToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).
                    substring(1));
        }
        return sb.toString();
    }

    /**
     * Array of Logical Volumes
     *
     * @return returns File array of Logical Volumes
     */
    public static File[] getSystemLogicalVolumes() {
        return File.listRoots();
    }

    /**
     * <p>
     * Returns the hash of the file whose path and the type of Hashing Algo
     * scheme is passed as arguments to the method.</p>
     *
     * @param file Logical Volume which is to be hashed.
     * @param hashAlgo Hashing algorithm to be used.
     * @return returns Hex encoded hash of the file
     */
    public static String getVolumeHash(File file, String hashAlgo) {
        byte[] mdbytes = null;
        try (RandomAccessFile raf = new RandomAccessFile(file, "r");
                FileChannel fc = raf.getChannel();) {

            ByteBuffer buffer = ByteBuffer.allocate(4096);
            MessageDigest md = MessageDigest.getInstance(hashAlgo);

            while (fc.read(buffer) != -1) {
                buffer.flip();
                md.update(buffer);
                buffer.clear();
            }

            mdbytes = md.digest();
        } catch (NoSuchAlgorithmException | FileNotFoundException ex) {
            System.err.println(ex.getMessage());
        } catch (IOException ex) {
            System.err.println(ex.getMessage());
        }
        return byteArrayToHex(mdbytes);
    }
}

I believe the code performance can be increased if we use MappedByteBuffer. Well you can have a go. I hope you like this short tutorial and learned something new today. If you have some doubts please comment. I will try my best to answer your query.

Thanking you,
Sincerely,
Psycho_Coder.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Java sockets 0xRar 3 17,896 12-24-2020, 12:36 PM
Last Post: 0xRar
  Useful resources to become a better Java programmer LOSTINSAUCE 2 20,351 12-21-2020, 09:41 AM
Last Post: 0xRar
  Java won't work properly QMark 2 17,651 02-12-2019, 12:25 AM
Last Post: QMark
  Words with friends(Cheat) Java ImArtisan 0 14,130 03-15-2018, 10:35 AM
Last Post: ImArtisan