头图

One article to understand one-way hash encryption: MD5, SHA-1, SHA-2, SHA-3

码农StayUp
中文
WeChat search: Code Farm StayUp
Homepage address: https://gozhuyinglong.github.io
Source code sharing: https://github.com/gozhuyinglong/blog-demos

1. Definition

One-way hash function (one-way hash function) refers to the calculation of different input values through a one-way hash function to obtain a fixed-length output value. This input value is called message (message), and the output value is called hash value (hash value).

单向散列函数

The one-way hash function is also called message digest function (message digest function), hash function or hash function . The input message is also called (pre-image). The output hash value is also called message digest (message digest) or fingerprint (fingerprint), which is equivalent to the ID of the message.

There are many implementation algorithms for one-way hash functions, the common ones are: MD5 , SHA-1 , SHA-2 and SHA-3 .

2. Features

Through the above definition, our understanding of the one-way hash function is still vague. The following describes the characteristics of the one-way hash function to deepen the impression.

2.1 The length of the hash value is fixed

Regardless of the length of the message, the length of the hash value calculated using the same algorithm is always fixed. For example, MD5 algorithm, no matter how much input, the length of the generated hash value is always 128 bits (16 bytes).

However, a bit is a unit that a computer can recognize, and we humans are more accustomed to using a hexadecimal string to represent it (a byte occupies two hexadecimal characters).

散列值长度固定

2.2 Different messages have different hash values

Using the same message, the generated hash value must be the same.

Use different messages, the hash value generated is not the same. Even if there is only one bit difference, the obtained hash value will be very different.

This feature is also called collision resistance , for algorithms with weak collision resistance, we should not use it.

消息不同其散列值也不同

2.3 Have unidirectionality

The hash value can only be calculated from the message, and the message cannot be inversely calculated from the hash value.

具备单向性

2.4 Fast calculation speed

The calculation of the hash value is fast. Although the longer the message, the longer it takes to calculate the hash value, but it will also be completed in a short time.

3. Common Algorithms

The MD5 and SHA-1 algorithms have been compromised and should not be used for new purposes; SHA-2 and SHA-3 are still safe and can be used.

SHA-2 includes: SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256.

SHA-3 includes: SHA3-224, SHA3-256, SHA3-384, SHA3-512.

Algorithm nameHash lengthIs it safe
MD5128Not safe
SHA-1160Not safe
SHA-224224Safety
SHA-256256Safety
SHA-384384Safety
SHA-512512Safety
SHA-512/224224Safety
SHA-512/256256Safety
SHA3-224224Safety
SHA3-256256Safety
SHA3-384384Safety
SHA3-512512Safety

4. Application Scenario

One-way hash function does not ensure the confidentiality of information, it is a cryptographic technique to ensure the integrity of information. Let's look at its application scenarios.

4.1 User password protection

When the user sets the password, the password itself is not recorded, only the hash value of the password is recorded, and only the user knows the plaintext of the password. When verifying the password, as long as the entered password is correct, the hash value obtained must be the same, indicating that the verification is correct.

In order to prevent the rainbow table from cracking, the password can also be salted. As long as the password is verified, the same salt can be used to complete the verification.

用户密码保护

The advantage of using the hash value to store the password is that even if the database is stolen, the ciphertext cannot be deduced from what the plaintext is, which makes the password storage more secure.

4.2 Interface verification

In order to ensure the security of the interface, it can be sent by signing.

The sender and receiver must have a shared secret key . When the sender sends a request to the receiver, a signature is attached to the parameters (the signature is generated by the shared secret key + service parameter , which is encrypted by a one-way hash function). After the receiver receives it, it uses the same method to generate a signature, and then compares it with the received signature. If it is consistent, the signature verification is successful.

In this way, it is possible to verify whether the service parameters have been tampered with, and to verify the identity of the sender.

接口验签

4.3 File integrity check

When a file is mounted on a website, its hash value and algorithm are also attached, such as the official Tomcat website.

Tomcat官网下载页面

After downloading, the user calculates its hash value and compares whether the result is the same, thereby verifying the integrity of the file.

4.4 Cloud Disk Second Transmission

When we put our favorite video on the network disk, we found that it only took a few seconds to upload successfully, and this file is a few gigabytes in size, how do we do it?

In fact, this "second transmission" function can be implemented using a one-way hash function.

When we upload a file, the cloud disk client will first generate a hash value for the file. Use this hash value to match in the database. If it matches, it means that the file already exists on the cloud server. Only by associating the hash value with the user, this "upload" can be completed.

In this way, only one copy of a file is stored on the cloud server, which greatly saves the space of the cloud server.

云盘秒传

5. Code Implementation

The java.security.MessageDigest class of JDK provides us with a message digest algorithm for MD5 and SHA hash value generation. The following code is simply encapsulated for direct use.

public class MDUtil {

    /**
     * MD5 加密
     *
     * @param data 要加密的数据
     * @return 32位十六进制字符串
     */
    public static String MD5(byte[] data) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] bytes = md.digest(data);
            return bytesToHexString(bytes);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * MD5 加密
     *
     * @param data 要加密的数据
     * @return 32位十六进制字符串
     */
    public static String MD5(String data) {
        return MD5(data.getBytes());
    }

    /**
     * SHA-1 加密
     *
     * @param data 要加密的数据
     * @return 40位十六进制字符串
     */
    public static String SHA1(byte[] data) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] bytes = md.digest(data);
            return bytesToHexString(bytes);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * SHA-1 加密
     *
     * @param data 要加密的数据
     * @return 40位十六进制字符串
     */
    public static String SHA1(String data) {
        return SHA1(data.getBytes());
    }

    /**
     * SHA-224 加密
     *
     * @param data 要加密的数据
     * @return 56位十六进制字符串
     */
    public static String SHA224(byte[] data) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-224");
            byte[] bytes = md.digest(data);
            return bytesToHexString(bytes);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * SHA-224 加密
     *
     * @param data 要加密的数据
     * @return 56位十六进制字符串
     */
    public static String SHA224(String data) {
        return SHA224(data.getBytes());
    }

    /**
     * SHA-256 加密
     *
     * @param data 要加密的数据
     * @return 64位十六进制字符串
     */
    public static String SHA256(byte[] data) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] bytes = md.digest(data);
            return bytesToHexString(bytes);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * SHA-256 加密
     *
     * @param data 要加密的数据
     * @return 64位十六进制字符串
     */
    public static String SHA256(String data) {
        return SHA256(data.getBytes());
    }

    /**
     * SHA-384 加密
     *
     * @param data 要加密的数据
     * @return 96位十六进制字符串
     */
    public static String SHA384(byte[] data) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-384");
            byte[] bytes = md.digest(data);
            return bytesToHexString(bytes);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * SHA-384 加密
     *
     * @param data 要加密的数据
     * @return 96位十六进制字符串
     */
    public static String SHA384(String data) {
        return SHA384(data.getBytes());
    }

    /**
     * SHA-512 加密
     *
     * @param data 要加密的数据
     * @return 128位十六进制字符串
     */
    public static String SHA512(byte[] data) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-512");
            byte[] bytes = md.digest(data);
            return bytesToHexString(bytes);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * SHA-512 加密
     *
     * @param data 要加密的数据
     * @return 128位十六进制字符串
     */
    public static String SHA512(String data) {
        return SHA512(data.getBytes());
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param bytes 字节数组
     * @return 十六进制字符串
     */
    private static String bytesToHexString(byte[] bytes) {
        StringBuilder hexValue = new StringBuilder();
        for (byte b : bytes) {
            int val = b & 0xFF;
            if (val < 16) {
                hexValue.append("0");
            }
            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();
    }

}

The following uses these algorithms to calculate the hash value of "123456":

public static void main(String[] args) {
    System.out.println("MD5\t\t" + MDUtil.MD5("123456"));
    System.out.println("SHA-1\t" + MDUtil.SHA1("123456"));
    System.out.println("SHA-224\t" + MDUtil.SHA224("123456"));
    System.out.println("SHA-256\t" + MDUtil.SHA256("123456"));
    System.out.println("SHA-384\t" + MDUtil.SHA384("123456"));
    System.out.println("SHA-512\t" + MDUtil.SHA512("123456"));
}

Output result:

MD5      e10adc3949ba59abbe56e057f20f883e
SHA-1    7c4a8d09ca3762af61e59520943dc26494f8941b
SHA-224  f8cdb04495ded47615258f9dc6a3f4707fd2405434fefc3cbf4ef4e6
SHA-256  8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92
SHA-384  0a989ebc4a77b56a6e2bb7b19d995d185ce44090c13e2984b7ecc6d446d4b61ea9991b76a4c2f04b1b4d244841449454
SHA-512  ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413

I use Java8, which does not support SHA-3, so the above code only encapsulates MD5, SHA-1 and SHA-2.

Java8支持的算法

SHA-3 is supported since Java9

Java9支持的算法

6. Complete code

For the complete code, please visit my Github, if it is helpful to you, welcome to Star, thank you!

https://github.com/gozhuyinglong/blog-demos/blob/main/java-source-analysis/src/main/java/io/github/gozhuyinglong/utils/MDUtil.java

7. Recommended reading

阅读 2.9k

人生就是一个不断学习的过程,通过学习来充实自己的头脑,让自己更有智慧的生活下去,去探索那未知领域...

54 声望
7 粉丝
0 条评论

人生就是一个不断学习的过程,通过学习来充实自己的头脑,让自己更有智慧的生活下去,去探索那未知领域...

54 声望
7 粉丝
文章目录
宣传栏