所以,我五年后编辑了自己对这个问题的答案,因为当时我并不知道自己在做什么。答案虽然有效,但并不是最优解。
1. 实际问题:“如何在Java中执行MySQL UNHEX()函数”
1.1 MySQL中UNHEX()函数的作用是什么
这个问题的答案非常简单。它将一个十六进制字符的字符串转换为二进制对象。
请记住:十六进制字符串只是表示字节的文本方式之一。就像这句话一样简单,答案也很简单 - 我们只需要将这个字符串转换为byte[]
。
有了这个知识,我们就有了我们的答案,这个答案早在几年前就在SO上了:如何使用Java将十六进制转储的字符串表示转换为字节数组?
简而言之:
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;
}
或者简单地说:
import javax.xml.bind.DatatypeConverter;
public static byte[] hexStringToByteArray(String s) {
return DatatypeConverter.parseHexBinary(s);
}
Java > 8移除了Java EE类,您可以通过添加以下依赖项来添加DataTypeConverter:
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.3</version>
</dependency>
2. 当我问这个问题时,我实际想要解决的问题的答案: "如何在Java中执行MySQL PASSWORD()函数"
2.1 MySQL中PASSWORD()函数实际上是做什么的
MySQL的Password()函数是输入的sha1哈希值的sha1哈希值,以十六进制表示前缀*
构成的。
2.2 分解
2.2.1 SHA1哈希值
要构建任何输入的SHA1哈希值,我们可以使用Java中的MessageDigest
类。
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 SHA1-Hash的SHA1-Hash
public static byte[] mysqlPasswordHash(byte[] data) throws NoSuchAlgorithmException {
return sha1(sha1(data));
}
2.2.3 构建byte[]
的十六进制表示
这是我之前描述的UNHEX()函数的相反操作,当我提出这个问题时已经有很多答案了。请参见:如何在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);
}
或者,如果您有可用的DataTypeConverter
:
public static String bytesToHex(byte[] bytes) {
return DatatypeConverter.printHexBinary(bytes);
}
2.2.4 MySQL密码函数的等效实现
如果您按照前面步骤所述添加了方法,则Java中的MySQL-Password实现如下:
public static String mysqlPasswordHashString(String password, Charset charset) throws NoSuchAlgorithmException {
return "*" + bytesToHex(mysqlPasswordHash(password.getBytes(charset)));
}
2.3 调用方法
要调用该方法,您需要提供一个java.nio.charset.Charset
。为了获得与在您的MySQL数据库上运行此操作相同的结果,您必须找出您的MySQL的默认字符集是什么。
假设您的MySQL使用UTF-8:
public static void main(String[] args) throws Exception {
final String mysqlPasswordHash = mysqlPasswordHashString("Hello world", StandardCharsets.UTF_8);
System.out.println(mysqlPasswordHash);
}
unhexedHash1
)中!应该使用字节数组。 - JimmyB