The H2 HASH function returns bytes, and SELECT HASH('MD5', 'test') AS new_id FROM my_table; displays a text value:
098f6bcd4621d373cade4e832627b4f6
How to retrieve that same text value in Java? Using ResultSet.getBytes("new_id") gives the object's address, something like [B#48f278eb. Feeding that through new String(ResultSet.getBytes("new_id"), StandardCharsets.UTF_8) gives gobbledygook: �Oh�؆nr�Mz��.
The reason you see [B#48f278eb is because the resulting MD5 hash is in bytes in a non-string format.
Here is a complete example of generating the MD5 hash and converting the resulting bytes to a string by using a StringBuilder and formatting it String.format("%02x", b):
String text = "test";
//Generate MD5 hash
byte[] bytesOfMessage = text.getBytes("UTF-8");
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] arr = md.digest(bytesOfMessage);
//Convert the bytes to a string
StringBuilder strBuilder = new StringBuilder();
for(byte b:arr){
strBuilder.append(String.format("%02x", b));
}
//The complete string
String strHash = strBuilder.toString();
//Print or use the string
System.out.println("The MD of " + text + " is " + strHash);
And the output is as expected:
The MD of test is 098f6bcd4621d373cade4e832627b4f6
Related
I have got to make the same function in Java and C#, but the result are not the same.
My code in C# :
string xmlString = System.IO.File.ReadAllText(#"crc.xml");
byte[] bytes = Encoding.ASCII.GetBytes(xmlString);
// step 1, calculate MD5 hash from input
MD5 md5 = System.Security.Cryptography.MD5.Create();
byte[] hash = md5.ComputeHash(bytes);
// step 2, convert byte array to hex string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
sb.Append(hash[i].ToString("X2"));
}
Console.WriteLine(sb.ToString());
And my code in Java :
string xmlstring = Files.readString(Paths.get("crc.xml"));
MessageDigest m = MessageDigest.getInstance("MD5");
byte[] digest = m.digest(xmlstring.getbytes());
String hash = new BigInteger(1, digest).toString(16);
System.out.println(hash);
In C# I have this result :
F5F8B2F361FEA6EA30F24BEBAA5BDE3A
But in Java I have this result :
8fb40aad49fbf796b82a2faa11cda764
What I'm doing wrong?
Codebrane say it. Use
byte[] bytes = Encoding.UFT8.GetBytes(xmlString);
instead of
byte[] bytes = Encoding.ASCII.GetBytes(xmlString);
Basically I have this
if (args.length != 1) {
System.err.println("Usage: java MyMd5 <message>");
System.exit(1);
}
try {
// get message
byte[] message = args[0].getBytes("UTF8");
// create message digest object for MD5
MessageDigest messageDigest = MessageDigest.getInstance("SHA");
// System.out.println("Provider: " +
messageDigest.getProvider().getInfo();
// create message digest
messageDigest.update(message);
byte[] md = messageDigest.digest();
// print result
System.out.println("Message Digest Algorithm: MD5");
System.out.println("Message: " + new String(message));
System.out.println("Message Digest: \"" + new String(md, "UTF8") + "\"");
String HashPassword=new String(md, "UTF8");
System.out.println(HashPassword);
System.out.println(HashPassword.equals("???8p???W?B:??N?~"));
but somehow when I try to compare it is returning false. Is it some problem with my encoding? Thanks!
Message Digest Algorithm: MD5
Message: pass123
Message Digest: "???8p???W?B:??N?~"
???8p???W?B:??N?~
false
The problem is with unnecessary encoding, with md5 we have to encode the String in the correct way instead of using UTF8 encoding
public static void main(String[] args) throws Exception {
String pass = "pass123";
byte[] message = pass.getBytes();
MessageDigest messageDigest = MessageDigest.getInstance("SHA");
messageDigest.update(message);
byte[] md = messageDigest.digest();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < md.length; i++) {
sb.append(Integer.toString((md[i] & 0xff) + 0x100, 16).substring(1));
}
System.out.println("encoded pass:" + sb.toString());
System.out.println(sb.toString().equals("aafdc23870ecbcd3d557b6423a8982134e17927e"));
}
If I understood your question correctly you want to compare newly generated hash string with existing one (stored in a data base or somewhere else). It's possible with provided above code and you will get true if you store generated value (not copy it from console) to the data base for example, and then compare it with newly generated.
But when you generate hash it contains symbols (characters), that doesn't have correct representation in any String encoding. So, nobody don't store hashes as a plain strings. Usually they are stored in hex string representation or Base64 representation.
Implementation with the use of hex strings provided below:
public static void main(String[] args) throws Exception { // args = ["Hello world"]
if (args.length != 1) {
System.err.println("Usage: java MyMd5 <message>");
System.exit(1);
}
// get message
byte[] message = args[0].getBytes("UTF8"); //You may have problems with encoding here. In Windows, for example, with symbols that are out of English alphabet range
// create message digest object for MD5
MessageDigest messageDigest = MessageDigest.getInstance("SHA");
// System.out.println("Provider: " +
messageDigest.getProvider().getInfo();
// create message digest
messageDigest.update(message);
byte[] md = messageDigest.digest();
System.out.println("Digest: " + byteArrayToHexString(md));
System.out.println("Is equals? " + byteArrayToHexString(md).equals("7b502c3a1f48c8609ae212cdfb639dee39673f5e"));
}
private static String byteArrayToHexString(byte[] array) {
StringBuilder result = new StringBuilder(array.length);
IntStream.range(0, array.length)
.forEach(i -> result.append(Integer.toString( (array[i] & 0xff) + 0x100, 16).substring(1)));
return result.toString();
}
Also, in provided example mentioned that you are using MD5, but actually it's SHA. MessageDigest messageDigest = MessageDigest.getInstance("SHA");
I'm using this:
import com.sun.org.apache.xml.internal.security.utils.Base64; to encode/decode Base64 strings and byte arrays to store into a db.
I'm testing out encoding and decoding to see if I can get back the original string:
SecureRandom srand = new SecureRandom();
byte[] randomSalt = new byte[64];
srand.nextBytes(randomSalt);
System.out.println("rand salt bytes: " + randomSalt); // first line
String salt = Base64.encode(randomSalt);
try {
System.out.println(Base64.decode(salt)); // second line
}catch(Base64DecodingException e){
System.out.println(e);
}
However, this prints out:
rand salt bytes: [B#68286c59
[B#44d01f20
Why are these not the same, so that I can get back the original byte array?
What you are doing is actually dealing with the java pointer instead of the actual bytes.
This is the correct way to implement
byte[] bytesEncoded = Base64.encodeBase64(str .getBytes());
System.out.println("ecncoded value is " + new String(bytesEncoded ));
// Decode data on other side, by processing encoded data
byte[] valueDecoded= Base64.decodeBase64(bytesEncoded );
System.out.println("Decoded value is " + new String(valueDecoded));
I have a question about how java prints the HexString and how to print it in the same format that C# using the BitConverter does.
We (both) are generating this Hex as result of hashing a string with SHA-1 :
a94a8fe5ccb19ba61c4c873d391e987982fbbd3 (hash for "test" string)
The problem is when we test the hashing in C# , C# prints with uppercase and separated with "-" , like A9-4A-8F .. and so on.
How can I print the same format with java?
The code for hashing and printing is this:
String password = "test";
byte[] key = password.getBytes();
MessageDigest md = MessageDigest.getInstance("SHA-1",new BouncyCastleProvider());
byte[] hash = md.digest(key);
String result = "";
for (byte b : hash) {
result += Integer.toHexString(b & 255);
}
return result;
String result = "";
for (byte b : hash) {
result += Integer.toHexString(b & 255).toUpperCase() + "-";
}
return result.subString(0, result.length()-1);
I want to hash a password using MD5 and I have given a string named MD5ControlHash
I found that I can hash a password in this way:
public static void main(String[] args)throws Exception
{
String password = "123456";
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(password.getBytes());
byte byteData[] = md.digest();
//convert the byte to hex format method 1
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
}
System.out.println("Digest(in hex format):: " + sb.toString());
}
However I don't know where should I use MD5ContolHash. Can anyone help me?
Does this code work correctly?
Thanks
If MD5ControlHash is a string, where should be stored hash of the password, you need to replace this line of code:
System.out.println("Digest(in hex format):: " + sb.toString());
with
MD5ControlHash = sb.toString();
If this string called MD5ControlHash stores the source data to hash, just use MD5ControlHash instead of password
And if you doubt about correctness of the code, just try it out!