MD5 hash not changed after the file has been altered - java

i'm creating the md5 hash generator. i first test it with an original file, then i altered the file to see whether the md5 hash codes is changed or not. the hash code did not change even after i altered the same file. what is the problem?
public class MD5CheckSum {
public byte [] createChecksum (String filename) throws Exception {
InputStream fis = new FileInputStream(filename);
byte[] buffer = new byte[1024];
MessageDigest complete = MessageDigest.getInstance("MD5");
int numRead;
do {
numRead = fis.read(buffer);
if (numRead > 0){
complete.update(buffer,0,numRead);
}
}while (numRead !=1);
fis.close();
return complete.digest();
}
public String getMD5Checksum(String filename) throws Exception {
/*byte[] b = createChecksum(filename);
String result = "";
for (int i=0; i < b.length; i++){
result += Integer.toString(( b[i] & 0xff) + 0x100, 16).substring( 1 );
}
return result;*/
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] messageDigest = md.digest(filename.getBytes());
BigInteger number = new BigInteger(1, messageDigest);
String hashtext = number.toString(16);
// Now we need to zero pad it if you actually want the full 32 chars.
while (hashtext.length() < 32) {
hashtext = "0" + hashtext;
}
return hashtext;
}
public MD5CheckSum() throws Exception{
String path = "C:/Users/user/Downloads/Documents/ECOMM SUMMER BLOSSOM.docx";
System.out.println("MD5 Hash Succeed");
System.out.println(getMD5Checksum(path));
}
EDITED: I changed some code
public static String getMD5Checksum(String filename) throws Exception {
byte[] b = createChecksum(filename);
String result = "";
for (int i=0; i < b.length; i++) {
result += Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 );
}
return result;
}
public static void main(String args[]) {
try {
System.out.println("Start hashing....");
System.out.println(getMD5Checksum("C:/Users/user/Downloads/Documents/21.pdf"));
System.out.println("Done hashing....");
}
catch (Exception e) {
e.printStackTrace();
}
}
But it takes too long to generate the hash and currently the hash still not generated till now.

filename.getBytes() gets bytes of the filename, not the file contents.
I could tell you how to load the entire file into a byte array, but that would be bad, because it could take up huge amounts of memory when it just isn't necessary to keep the entire file in memory while the hash is calculated.
Instead you should open a stream and get the hash of that. See this answer for that: https://stackoverflow.com/a/304350/360211

You're seem to calculate the MD5-sum of the filename not the content of the file. What you should have done to avoid this is to use a file with a known MD5-sum (by for example run md5sum on it) and check if your code yields the same result.
Also I can't help noting that your createCheckSum seem to be a better candidate to be working as it seem to actually work on the content of the file.
Just verifying that you get different value for different input may show that you've got a candidate for check summing, but it's a poor check that it's actually the correct algorithm used.

Related

SHA Hashing behaving unexpectedly in Java - Code Provided

Reading in a file and then hashing it using SHA-256 I found a tutorial which showed two separate ways to do it.
When comparing the file that I hashed (Which was a PDF) against both methods, they did not match up. I am following the code properly, not understanding why it isn't matching up.
Here is my result:
Hex format: b050692edb134da209adf76347f6c5e49db8734edeaa44876606ec8e5559ab4e
Hex format: b050692edb134da29adf76347f6c5e49db8734edeaa4487666ec8e5559ab4e
It looks like it is lopping off the two zeros in the middle, I just don't understand why
Java Code
import java.io.FileInputStream;
import java.security.MessageDigest;
public class SHAHash{
public static void main(String[] args)throws Exception{
MessageDigest md = MessageDigest.getInstance("SHA-256");
FileInputStream fis = new FileInputStream("myfile");
byte[] dataBytes = new byte[1024];
int nread = 0;
while((nread = fis.read(dataBytes))!= -1){
md.update(dataBytes, 0, nread);
};
byte[] mdbytes = md.digest();
StringBuffer sb1 = new StringBuffer();
for(int i = 0; i < mdbytes.length; i++){
sb1.append(Integer.toString((mdbytes[i] & 0xFF) + 0x100, 16).substring(1));
}
System.out.println("Hex format: " + sb1.toString());
StringBuffer sb2 = new StringBuffer();
for(int i = 0; i < mdbytes.length; i++){
sb2.append(Integer.toHexString(0xFF & mdbytes[i]));
}
System.out.println("Hex format: " + sb2.toString());
}
}
Instead of StringBuffer you should be using StringBuilder (the methods aren't synchronized and you aren't using multiple threads, it's like the difference between a Vector and an ArrayList). Also, you need to preserve leading 0(s). You could correct your second loop with something like String.format(String, Object...). Putting that together like,
StringBuilder sb2 = new StringBuilder();
for (int i = 0; i < mdbytes.length; i++) {
sb2.append(String.format("%02x", 0xFF & mdbytes[i]));
}
System.out.println("Hex format: " + sb2.toString());
The difference between both is that the first adds 0x100 and then only takes a substring.
That way the toString call in the first loop always returns a string with a leading 1 followed by the actual value. That way the zero is preserved.
The second loop produces wrong output because the zero digit gets lost.

Convert Hex to Byte with big string

I tried the different ways to convert hex to byte, there are four methods in the code, three of them I comment it out, only one there is no error when I run it, but I confused that when I repeated to run the code, it gave me the different result (should be generate "byte").
There is a question is when I use "method1", it gave me the result (byte), but once I changed to "method2", it will not generate the result, I don't know why. I thought it should generate same result, when I have same string.
public class Convert {
/**
* #param args
* #throws IOException
*/
// String everything;
public static void main(String[] args) throws IOException {
//String everything;
// TODO Auto-generated method stub
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("C:\\TEMP1\\Doctor.txt"));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
StringBuilder sb = new StringBuilder();
String line = null;
try {
line = br.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while (line != null) {
sb.append(line);
sb.append('\n');
line = br.readLine();
}
//*********Method 1****************
//String r="1ee079746828d7c6f9af46f93c1ef2555ff4b14b2378ad53a258d18dc6a8363fb57f3448783833722bd9ef291ba53153afca31a96de404755e78f68b76fd5a77e4be3b984ea25244842e92a8ed40da1f1a588fb3da26b8bc21d74cd8476534f26ee454df086567c4d7cf3334f794cede41a9b051a5c393a35584afcf";
//byte[] b = new BigInteger(r,16).toByteArray();
//System.out.println("Byte for public key: "+b);
//*********Method 2****************
//String r2 = sb.toString();
//System.out.println("Doctor contect file: "+r2);
//byte[] b = new BigInteger(r2,16).toByteArray();
//System.out.println("Byte for public key: "+b);
//********Method 3*****************
String r="1ee079746828d7c6f9af46f93c1ef2555ff4b14b2378ad53a258d18dc6a8363fb57f3448783833722bd9ef291ba53153afca31a96de404755e78f68b76fd5a77e4be3b984ea25244842e92a8ed40da1f1a588fb3da26b8bc21d74cd8476534f26ee454df086567c4d7cf3334f794cede41a9b051a5c393a35584afcf";
int len = r.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(r.charAt(i), 16) << 4)
+ Character.digit(r.charAt(i+1), 16));
System.out.println(data);
}
//********Method4******************
/*
String r2 = sb.toString();
int len = r2.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(r2.charAt(i), 16) << 4)
+ Character.digit(r2.charAt(i+1), 16));
System.out.println(data);
}
*/
//String r=everything;
// String r="1ee079746828d7c6f9af46f93c1ef2555ff4b14b2378ad53a258d18dc6a8363fb57f3448783833722bd9ef291ba53153afca31a96de404755e78f68b76fd5a77e4be3b984ea25244842e92a8ed40da1f1a588fb3da26b8bc21d74cd8476534f26ee454df086567c4d7cf3334f794cede41a9b051a5c393a35584afcf";
// double convert=Double.parseDouble(r);
// long convert=(long)(Integer.parseInt(r,32)&0xFF);
// byte convert=Byte.parseByte(r,32);
// byte convert=Integer.parseInt(everything,16);
// System.out.println("Byte for public key: "+convert);
} finally {
br.close();
}
}
}
You're printing the result of calling toString on a byte[]. That's not going to give you what you want.
For diagnostic purposes, use System.out.println(Arrays.toString(data)). And do that at the end of the loop rather than within it:
for (int i = 0; i < len; i += 2) {
...
}
System.out.println(Arrays.toString(data));
There are plenty of alternative approaches to parsing a hex string, mind you. I don't personally like the idea of using an XML-focused API (as recommended in the question comments) when you're not dealing with XML, but it would certainly work - and any number of third party APIs have hex conversion routines.
EDIT: As noted in comments, I believe your hex conversion code is also broken at the moment - but that should probably be fixed by using a prebuilt one from elsewhere. The main purpose of this answer was to explain why you're getting results such as "[B#40a0dcd9". Once you can see the data, you can verify it.
I'm unsure on why you do that, so this answer may not reflect your intend.
I tried to comprehend your stuff and came to the conclusion that you want to split that string into two character blocks, treat them as a hex number and convert them to a byte.
That wont work, as the second block e0 is larger that Byte.MAX_VALUE. So, heres my latest guess on what could be the code that you are looking for (using Integer).
public static void main(String[] args) {
String r = "1ee079746828d7c6f9af46f93c1ef2555ff4b14b2378ad53a258d18dc6a8363fb57f3448783833722bd9ef291ba53153afca31a96de404755e78f68b76fd5a77e4be3b984ea25244842e92a8ed40da1f1a588fb3da26b8bc21d74cd8476534f26ee454df086567c4d7cf3334f794cede41a9b051a5c393a35584afcf";
char[] rA = r.toCharArray();
int len = r.length();
int[] data = new int[len / 2];
for (int i = 0; i < len; i += 2) {
String base = "#" + rA[i] + rA[i+1];
System.out.println("base: " + base);
data[i / 2] = Integer.decode(base);
System.out.println(data[i/2]);
}
}
After reading your question again, it seems that you describe that when you use the String directly (method1) it works, but if you read if from a file (method2) it does not.
The reason is simple: You add a \n at the end of the String you read from file. You do not do so in your method1.

Hmac Sha256 incorrect result value AWS-Java

public static void main(String[] args) throws SignatureException {
String data = "GET"+"\n"+"webservices.amazon.com"+"\n"+"/onca/xml"+"\n"+"AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&ItemId=0679722769&Operation=ItemLookup&ResponeGroup=ItemAttributes%2COffers%2CImages%2CReviews&Service=AWSECommerceService&Timestamp=2009-01-01T12%3A00%3A00Z&Version=2009-01-06";
String key = "1234567890";
String result = calculateRFC2104HMAC(data, key);
System.out.println(result);
}
private static final String HMAC_SHA_ALGORITHM = "HmacSHA256";
public static String calculateRFC2104HMAC(String data, String key)throws java.security.SignatureException{
String result;
try {
// get an hmac_sha256 key from the raw key bytes
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes("UTF-8"), HMAC_SHA_ALGORITHM);
// get an hmac_sha256 Mac instance and initialize with the signing key
Mac mac = Mac.getInstance(HMAC_SHA_ALGORITHM);
mac.init(signingKey);
// compute the hmac256 on input data bytes
byte[] rawHmac = mac.doFinal(data.getBytes("UTF-8"));
// base64-encode the hmac256
result = Base64.encodeBase64String(rawHmac);
} catch (Exception e) {
throw new SignatureException("Failed to generate HMAC : " + e.getMessage());
}
return result;
}
So I am trying to calculate this hmac with sha256 for AWS, but I do not get the excpected result, even though this example is taken from official AWS docs: http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/AuthJavaSampleHMACSignature.html And the only thing changed is the algorithm, which did not break the program, so it should work, but it does not.
The result I get: k1T/qvVoXgEvmdFhTEh71vLDznqEVCyKcslA5RRSB6s=
The result I expect: M/y0+EAFFGaUAp4bWv/WEuXYah99pVsxvqtAuC8YN7I=
Does anyone have any idea what is wrong?
It may have to do with how the newline character is interpreted. \n can be a cr, lf, or cr-lf depending on your OS.
AWS uses to two different HMAC functions, the first returns the string representation, the other returns the binary representation. This is from my C++ implementation using OpenSSL, hope it helps:
string hmacHex(string key, string msg)
{
unsigned char hash[32];
HMAC_CTX hmac;
HMAC_CTX_init(&hmac);
HMAC_Init_ex(&hmac, &key[0], key.length(), EVP_sha256(), NULL);
HMAC_Update(&hmac, (unsigned char*)&msg[0], msg.length());
unsigned int len = 32;
HMAC_Final(&hmac, hash, &len);
HMAC_CTX_cleanup(&hmac);
std::stringstream ss;
ss << std::hex << std::setfill('0');
for (int i = 0; i < len; i++)
{
ss << std::hex << std::setw(2) << (unsigned int)hash[i];
}
return (ss.str());
}
the string implementation
string hmac(string key, string msg)
{
unsigned char hash[32];
HMAC_CTX hmac;
HMAC_CTX_init(&hmac);
HMAC_Init_ex(&hmac, &key[0], key.length(), EVP_sha256(), NULL);
HMAC_Update(&hmac, ( unsigned char* )&msg[0], msg.length());
unsigned int len = 32;
HMAC_Final(&hmac, hash, &len);
HMAC_CTX_cleanup(&hmac);
std::stringstream ss;
ss << std::setfill('0');
for (int i = 0; i < len; i++)
{
ss << hash[i];
}
return (ss.str());
}
If you are using Java, I'd recommend using the corresponding SDK. I my experience the API's tend to change rather quickly.

Getting MD5 Hash of File from URL

The result I'm getting is that files of the same type are returning the same md5 hash value. For example two different jpgs are giving me the same result. However, a jpg vs a apk are giving different results.
Here is my code...
public static String checkHashURL(String input) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
InputStream is = new URL(input).openStream();
try {
is = new DigestInputStream(is, md);
int b;
while ((b = is.read()) > 0) {
;
}
} finally {
is.close();
}
byte[] digest = md.digest();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < digest.length; i++) {
sb.append(
Integer.toString((digest[i] & 0xff) + 0x100, 16).substring(
1));
}
return sb.toString();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
This is broken:
while ((b = is.read()) > 0)
Your code will stop at the first byte of the stream which is 0. If the two files have the same values before the first 0 byte, you'll fail. If you really want to call the byte-at-a-time version of read, you want:
while (is.read() != -1) {}
The parameterless InputStream.read() method returns -1 when it reaches the end of the stream.
(There's no need to assign a value to b, as you're not using it.)
Better would be to read a buffer at a time:
byte[] ignoredBuffer = new byte[8 * 1024]; // Up to 8K per read
while (is.read(ignoredBuffer) > 0) {}
This time the condition is valid, because InputStream.read(byte[]) would only ever return 0 if you pass in an empty buffer. Otherwise, it will try to read at least one byte, returning the length of data read or -1 if the end of the stream has been reached.

Get MD5 String from Message Digest

I understand how it works but if I want to print out the MD5 as String how would I do that?
public static void getMD5(String fileName) throws Exception{
InputStream input = new FileInputStream(fileName);
byte[] buffer = new byte[1024];
MessageDigest hash = MessageDigest.getInstance("MD5");
int read;
do {
read = input.read(buffer);
if (read > 0) {
hash.update(buffer, 0, read);
}
} while (read != -1);
input.close();
}
You can get it writing less:
String hex = (new HexBinaryAdapter()).marshal(md5.digest(YOUR_STRING.getBytes()))
String input = "168";
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] md5sum = md.digest(input.getBytes());
String output = String.format("%032X", new BigInteger(1, md5sum));
or
DatatypeConverter.printHexBinary( MessageDigest.getInstance("MD5").digest("a".getBytes("UTF-8")))
Try this
StringBuffer hexString = new StringBuffer();
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] hash = md.digest();
for (int i = 0; i < hash.length; i++) {
if ((0xff & hash[i]) < 0x10) {
hexString.append("0"
+ Integer.toHexString((0xFF & hash[i])));
} else {
hexString.append(Integer.toHexString(0xFF & hash[i]));
}
}
You can also use Apache Commons Codec library.
This library includes methods public static String md5Hex(InputStream data) and public static String md5Hex(byte[] data) in the DigestUtils class.
No need to invent this yourself ;)
First you need to get the byte[] output of the MessageDigest:
byte[] bytes = hash.digest();
You can't easily print this though (with e.g. new String(bytes)) because it's going to contain binary that won't have good output representations. You can convert it to hex for display like this however:
StringBuilder sb = new StringBuilder(2 * bytes.length);
for (byte b : bytes) {
sb.append("0123456789ABCDEF".charAt((b & 0xF0) >> 4));
sb.append("0123456789ABCDEF".charAt((b & 0x0F)));
}
String hex = sb.toString();
Shortest way:
String toMD5(String input) {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] raw = md.digest(input.getBytes());
return DatatypeConverter.printHexBinary(raw);
}
Just remember to handle the exception.
With the byte array, result from message digest:
...
byte hashgerado[] = md.digest(entrada);
...
for(byte b : hashgerado)
System.out.printf("%02x", Byte.toUnsignedInt(b));
Result (for example):
89e8a9f68ad3c4bba9b9d3581cf5201d
/**
* hashes:
* e7cfa2be5969e235138356a54bad7fc4
* 3c9ec110aa171b57bb41fc761130822c
*
* compiled with java 8 - 12 Dec 2015
*/
public static String generateHash() {
long r = new java.util.Random().nextLong();
String input = String.valueOf(r);
String md5 = null;
try {
java.security.MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
//Update input string in message digest
digest.update(input.getBytes(), 0, input.length());
//Converts message digest value in base 16 (hex)
md5 = new java.math.BigInteger(1, digest.digest()).toString(16);
}
catch (java.security.NoSuchAlgorithmException e) {
e.printStackTrace();
}
return md5;
}
FYI...
In certain situations this did not work for me
md5 = new java.math.BigInteger(1, digest.digest()).toString(16);
but this did
StringBuilder sb = new StringBuilder();
for (int i = 0; i < digest.length; i++) {
if ((0xff & digest[i]) < 0x10) {
sb.append("0").append(Integer.toHexString((0xFF & digest[i])));
} else {
sb.append(Integer.toHexString(0xFF & digest[i]));
}
}
String result = sb.toString();
Call hash.digest() to finish the process. It will return an array of bytes.
You can create a String from a byte[] using a String constructor, however if you want a hex string you'll have to loop through the byte array manually and work out the characters.
This is another version of #anything answer:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < digest.length; i++) {
if ((0xff & digest[i]) < 0x10) {
sb.append("0").append(Integer.toHexString((0xFF & digest[i])));
} else {
sb.append(Integer.toHexString(0xFF & digest[i]));
}
}
String result = sb.toString();

Categories

Resources