Recently, before using Gin to reconstruct the background program written by SpringBoot, the password saved in the database is the MD5 value salted and hashed twice. Before SpringBoot, Shiro was called for two MD5 operations. I found that the MD5 tool library of Golang does not provide the encapsulation of salt and encryption times, and it is not mentioned in the blog, so here is a record of my encapsulation of MD5 function with salt and encryption times

Golang uses the MD5 library

Golang’s own crypto encryption library has the implementation of MD5 function, which is mainly used in two ways. One is to call write and write the byte array to be calculated in advance into the block block, and pass in nil when calling sum. The sum function is passed the byte array directly as follows:

package utils

import (
	"crypto/md5"
	"encoding/hex"
)

// Method 1: Pass parameters through Write
func MD5(str string) string {
	b := []byte(str)
	h := md5.New()
	h.Write(b)
	return hex.EncodeToString(h.Sum(nil))}// Method two uses Sum to send parameters
func MD5_2(str string) string {
	b := []byte(str)
	h := md5.New()
	return hex.EncodeToString(h.Sum(b))
}
Copy the code

To add salt, add the first method to write salt, as shown below:

func MD5_SALT(str string, salt string) string {
	b := []byte(str)
	s := []byte(salt)
	h := md5.New()
	h.Write(s) // Write the salt first
	h.Write(b)
	return hex.EncodeToString(h.Sum(nil))}Copy the code

Incorrect multiple encryption encapsulation

After checking the use of MD5 function to add salt, I took it for granted that multiple encryption should be the process of adding salt in a cycle. After calling the following encapsulation, I found that the calculated salt value was wrong, and there was no article on the Internet for multiple encryption, so I went to the encapsulation in SpringBoot.

// Add salt incorrectly and encrypt multiple times
func MD5_SALT_MULT(str string, salt string, times int) string {
	b := []byte(str)
	s := []byte(salt)
	h := md5.New()
	var res []byte
	for i := 0; i < times; i++ {
		h.Write(s)
		h.Write(b)
		res = h.Sum(nil)
		b = res
	}
	return hex.EncodeToString(res)
}
Copy the code

Java salt and multiple encryption MD5 function

I looked at the previous SpringBoot project and found that MD5 encapsulation of Shiro framework was called at that time. All I needed to do was pass the salt value and encryption times into SimpleHash function, without thinking about the subsequent calculation.

import org.apache.shiro.crypto.RandomNumberGenerator;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;

public class PasswordHelper {
    // Random string generator, used to generate salt values
    private RandomNumberGenerator numberGenerator = new SecureRandomNumberGenerator();

    // Hash algorithm md5
    public static final String ALGORITHM_NAME = "md5";

    // hash number 2
    public static final int HASH_ITERATION = 2;

    /** * Encrypt user *@paramUser User, user name, password, salt encryption factor */
    public String encryptPassword(String password){
        if (password == null || "".equals(password))
            return;
        // Generate encryption factor to save salt.
        String salt = numberGenerator.nextBytes().toHex();
        // Encryption password SimpleHash (algorithm name, password, salt byte, times).tohex ()
        String newPassword = new SimpleHash(ALGORITHM_NAME, password, salt, HASH_ITERATION).toHex();
        // Update the password
        returnnewPassword; }}Copy the code

The core code for SimpleHash is as follows: Salt is used only once, and the rest function is called after each operation to clear the block in the digest. Now that you know how to do this, you simply translate this Java code into Golang code

package org.apache.shiro.crypto.hash;

public class SimpleHash extends AbstractHash {
    protected byte[] hash(byte[] bytes, byte[] salt, int hashIterations) throws UnknownAlgorithmException {
        MessageDigest digest = this.getDigest(this.getAlgorithmName());
        if(salt ! =null) {
            digest.reset();
            digest.update(salt);
        }

        byte[] hashed = digest.digest(bytes);
        int iterations = hashIterations - 1;

        for(int i = 0; i < iterations; ++i) {
            digest.reset();
            hashed = digest.digest(hashed);
        }

        returnhashed; }}Copy the code

With Golang to achieve salt and multiple encryption MD5 function

The Java MessageDigest object and the Golang hash structure can be considered equivalent. They both have rest functions, except that Java calculates the hash by calling digest and Golang calculates the Sum. All you need is a simple translation of the Java code above. The final package is as follows:

package utils

import (
	"crypto/md5"
	"encoding/hex"
)

func MD5V(str string, salt string, iteration int) string {
    b := []byte(str)
    s := []byte(salt)
	h := md5.New()
	h.Write(s) // First pass in the salt value, before because of the wrong order stuck for a long time
	h.Write(b)
        var res []byte
	res = h.Sum(nil)
	for i := 0; i < iteration- 1; i++ {
		h.Reset()
		h.Write(res)
		res = h.Sum(nil)}return hex.EncodeToString(res)
}
Copy the code