java - 如何在 Java 中执行 MySQL UNHEX() 函数

标签 java mysql hash passwords

我试图从字符串中获取 Java 中的 MySQL 密码哈希,所以我用谷歌搜索了一下,发现了 MySQL 中的 PASSWORD() 是如何工作的:

SELECT SHA1(UNHEX(SHA1('test')));

给出与

相同的结果
SELECT PASSWORD('test');

有了这个我继续。

我编写了一个将字符串转换为 SHA1 哈希的方法,该方法非常有效(测试了几个不同的字符串,得到与 MySQL 中的 SHA1(str) 相同的结果)

接下来要做的是 UNHEX() 方法。我现在卡住了。

我目前的方法:

public static String toMySQLPasswordHash(String str)
{
    String hash1 = toSHA1Hash(str);
    String unhexedHash1 = new String(DatatypeConverter.parseHexBinary(hash1));
    String hash2 = toSHA1Hash(unhexedHash1);

    String passwordHash = "*" + hash2.toUpperCase();


    return passwordHash;
}

我的“toSHA1Hash”方法:

public static String toSHA1Hash(String str)
{
    MessageDigest md = null;

    try
    {
        md = MessageDigest.getInstance("SHA-1");
    }
    catch (NoSuchAlgorithmException e)
    {
        Logger.WriteLog(e.toString());
    }

    if (md == null)
        return null;


    md.reset();
    md.update(str.getBytes());

    byte[] byteData = md.digest();
    StringBuilder sb = new StringBuilder();

    for (byte currByte : byteData)
        sb.append(Integer.toString((currByte & 0xff) + 0x100, 16).substring(1));

    return sb.toString();
}

我不喜欢使用任何外部包,所以请帮我只用 JDK 1.8.0_40 来做这件事。

最佳答案

所以,5 年后我正在编辑我自己对这个问题的回答,因为那时我真的不知道我到底在做什么。答案有效,但不是最佳答案。

1。实际问题:“如何在 Java 中执行 MySQL UNHEX() 函数”

1.1 MySQL中的UNHEX()函数到底做了什么

这个问题的答案很简单。它需要一个 string of hexadecimal characters 并将其转换为二进制对象。

请记住:十六进制字符串只是将字节表示为文本的多种方式之一。就像这句话一样简单,就是这个问题的答案 - 我们只需要将这个字符串转换为 byte[]

有了这些知识,我们就有了答案,多年前就在这里:Convert a string representation of a hex dump to a byte array using Java?

简而言之:

    // 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;
    }

或者简单地说:

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 删除了 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-Hash 的 sha1-Hash,在 hexadecimal representation 中,前缀为文字 *

2.2 分解

2.2.1 SHA1-哈希

要构建任何输入的 SHA1-Hash,我们可以使用 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 {
        // using the method explained in 2.2.1 twice
        return sha1(sha1(data));
    }

2.2.3 构建byte[]

hexadecimal representation

这与我之前描述的 UNHEX() 函数相反,当我问这个问题时已经有很多答案。参见: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);
    }

或者,如果您有可用的 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);
    }

关于java - 如何在 Java 中执行 MySQL UNHEX() 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32180069/

相关文章:

php - cakephp 的密码哈希值不一样

c - C 中字符串的 FNV 哈希

java - 处理大数组的多线程计算

Java 长任务 - 它停止写入文件了吗?

mysql - 在数据库中创建新主键的最佳选择是什么?

mysql - SQL 查询组随机播放

php - mysql无法插入8列的表

Ruby 将特定的散列键映射到新的散列键

java - 查找二维数组相对于任意位置的对角线边缘 - Java

java - 是否可以在@Component类中的3个或更多bean之间进行优先级排序?