So, I'm editing my own answer to this question 5 years later, since back then I didn't really know what I was really doing. The answer worked, but wasn't optimal.
1. The actual question: "How do I perform MySQL UNHEX() Function in Java"
1.1 What does the UNHEX() Function in MySQL actually do
The answer to this question is pretty simple. It takes a string of hexadecimal characters and converts it to a binary-object.
Keep in mind: A hexadecimal string is simply one of many ways to represent bytes as text. And as easy as this sentence is, is the answer to this question - we simply have to convert this string to a byte[]
.
And with that knowledge, we have our answer, which has been right here on SO years ago: Convert a string representation of a hex dump to a byte array using Java?
In short:
// this is the Java equivalent to the UNHEX() function in MySQL
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
Or simply:
import javax.xml.bind.DatatypeConverter;
// this is the Java equivalent to the UNHEX() function in MySQL
public static byte[] hexStringToByteArray(String s) {
return DatatypeConverter.parseHexBinary(s);
}
(Java > 8 removed the Java EE Classes, you can add the DataTypeConverter by adding the following dependency):
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.3</version>
</dependency>
2. The answer to the problem I actually wanted to solve when I asked this question: "How do I perform MySQL PASSWORD() Function in Java"
2.1 What does the PASSWORD() Function in MySQL actually do
The MySQL Password() Function is the sha1-Hash of the sha1-Hash of the input, in hexadecimal representation, prefixxed with the literal *
.
2.2 Break it down
2.2.1 The SHA1-Hash
To build the SHA1-Hash of any input, we can use the MessageDigest
class in Java.
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public static byte[] digest(String algorithm, byte[] data) throws NoSuchAlgorithmException {
return MessageDigest.getInstance(algorithm).digest(data);
}
public static byte[] sha1(byte[] data) throws NoSuchAlgorithmException {
return digest("SHA-1", data);
}
2.2.2 The SHA1-Hash of the SHA1-Hash
public static byte[] mysqlPasswordHash(byte[] data) throws NoSuchAlgorithmException {
// using the method explained in 2.2.1 twice
return sha1(sha1(data));
}
This is the reverse of the UNHEX() Function I described before and already had many answers when I asked this question. See: How to convert a byte array to a hex string in Java?
private static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.UTF_8);
public static String bytesToHex(byte[] bytes) {
final byte[] hexChars = new byte[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
return new String(hexChars, StandardCharsets.UTF_8);
}
Or, if you have the DataTypeConverter
available:
public static String bytesToHex(byte[] bytes) {
return DatatypeConverter.printHexBinary(bytes);
}
2.2.4 The equivalent of the MySQL Password Function
If you added the methods described in the previous steps, the MySQL-Password implementation in Java works like this:
public static String mysqlPasswordHashString(String password, Charset charset) throws NoSuchAlgorithmException {
return "*" + bytesToHex(mysqlPasswordHash(password.getBytes(charset)));
}
2.3 Calling the method
To call the method, you have to provide a java.nio.charset.Charset
. To get the same results as you'd run this on your MySQL DB, you have to figure out what the default Charset of your MySQL is.
Let's say your MySQL uses UTF-8:
public static void main(String[] args) throws Exception {
final String mysqlPasswordHash = mysqlPasswordHashString("Hello world", StandardCharsets.UTF_8);
System.out.println(mysqlPasswordHash);
}