01-31-2016, 05:49 AM
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
If you're interested interested in knowing the type of drive then use the following snippet:
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.
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:
The above will return the digest of the volume as an array of bytes which we can convert to hex using the following method.
So, Here the complete code (Only class):-
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.
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.