How to Secure Passwords with Salt in Java: MD5 Salting Explained

This article explains the concept of password salting, its security benefits, and provides a complete Java implementation using MD5, including salt generation, hashing with and without salt, storing salt within the hash, and verification procedures for registration and login.

21CTO
21CTO
21CTO
How to Secure Passwords with Salt in Java: MD5 Salting Explained

What is Salting?

Many companies store user passwords as hash values (the article uses MD5 as an example, though bcrypt is more common). Because hash functions can collide, if a database is compromised attackers can obtain the hash values and potentially recover passwords using methods such as rainbow‑table attacks.

Example: http://www.cmd5.com/

These hashes can be cracked.

Salting Principle

Simply put, the original hash H(p) becomes H(p+salt). Each hash operation uses a random salt, effectively changing the hash function each time.

If H changes, existing rainbow‑table data becomes useless; new tables must be generated for the specific H, greatly increasing cracking difficulty.

How to Salt?

1. Generate Salt

private static char[] hex = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
/**
 * Custom simple salt generator: a random 16‑character string where each character is a random hexadecimal digit.
 */
public static String salt(){
    Random random = new Random();
    StringBuilder sb = new StringBuilder(16);
    for(int i=0;i<sb.capacity();i++){
        sb.append(hex[random.nextInt(16)]);
    }
    return sb.toString();
}

2. Input with Salt

String inputWithSalt = inputStr + salt; // add salt to the input

Salting is that simple.

3. Output with Salt

The resulting hash can optionally embed the salt. In practice the salt used for the hash is stored together with the hash value so that during login the same salt can be retrieved.

/**
 * @params: [inputStr, type] inputStr is the plaintext; type 0 means registration (store hash), 1 means login verification
 * @Descrption: MD5 with salt. Salt is obtained in two ways; input plaintext with salt; output ciphertext with salt (store salt in the hash).
 */
public static String MD5WithSalt(String inputStr, int type){
    try{
        MessageDigest md = MessageDigest.getInstance("MD5");
        String salt = null;
        if(type == 0){ // registration
            salt = salt();
        }else if(type == 1){ // login verification
            String queriedHash = null; // hash retrieved from DB
            salt = getSaltFromHash(queriedHash);
        }
        String inputWithSalt = inputStr + salt; // add salt
        String hashResult = byte2HexStr(md.digest(inputWithSalt.getBytes()));
        System.out.println("Salted ciphertext:" + hashResult);
        // Store salt in the hash for later verification
        char[] cs = new char[48];
        for(int i=0;i<48;i+=3){
            cs[i] = hashResult.charAt(i/3*2);
            cs[i+1] = salt.charAt(i/3);
            cs[i+2] = hashResult.charAt(i/3*2+1);
        }
        hashResult = new String(cs);
        return hashResult;
    }catch(Exception e){
        e.printStackTrace();
        return e.toString();
    }
}

The operation of inserting the salt into the hash is straightforward: assuming the hash is 32 characters long and the salt is 16 characters, a salt character is inserted after every two hash characters.

Backend Password Storage and Verification Process

1. Store Password on Registration

User registers and sends account and password p1 from the front end to the back end.

The back end randomly generates a salt.

Compute H(p1+salt) and store the resulting salted hash (hash1) in the database.

2. Verify Password on Login

User logs in and sends account and password p2 from the front end.

Retrieve the stored hash (hash2) for the given account from the database.

Extract the salt from hash2.

Compute H(p2+salt) to obtain hash3 and compare hash2 with hash3; if equal, login succeeds, otherwise it fails.

Java Implementation

MD5 is used as the hash function. The JDK does not provide a built‑in salting process, so we implement it ourselves. (Bcrypt salting is simpler; see the author's other blog for that source.)

package EncryptAndDecrypt;
import java.security.MessageDigest;
import java.util.Random;
/**
 * 32‑bit MD5 hash implementation. Note: hashing is one‑way and cannot be decrypted.
 */
public class MyMD5 {
    private static char[] hex = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    public static void main(String[] args) throws Exception {
        String input = "123456";
        System.out.println("MD5 encryption
Plaintext:" + input + "
No‑salt ciphertext:" + MD5WithoutSalt(input));
        System.out.println("Salted ciphertext:" + MD5WithSalt(input,0));
    }
    public static String MD5WithoutSalt(String inputStr){
        try{
            MessageDigest md = MessageDigest.getInstance("MD5");
            return byte2HexStr(md.digest(inputStr.getBytes()));
        }catch(Exception e){
            e.printStackTrace();
            return e.toString();
        }
    }
    // MD5WithSalt method as shown earlier
    // ... (other helper methods: salt(), byte2HexStr(), getSaltFromHash())
    public static String salt(){
        Random random = new Random();
        StringBuilder sb = new StringBuilder(16);
        for(int i=0;i<sb.capacity();i++){
            sb.append(hex[random.nextInt(16)]);
        }
        return sb.toString();
    }
    private static String byte2HexStr(byte[] bytes){
        StringBuffer result = new StringBuffer();
        for(byte b : bytes){
            result.append(hex[(b>>>4) & 0xf]);
            result.append(hex[b & 0xf]);
        }
        return result.toString();
    }
    public static String getSaltFromHash(String hash){
        StringBuilder sb = new StringBuilder();
        char[] h = hash.toCharArray();
        for(int i=0;i<hash.length();i+=3){
            sb.append(h[i+1]);
        }
        return sb.toString();
    }
}

Sample output (first run):

MD5加密
明文:123456
无盐密文:E10ADC3949BA59ABBE56E057F20F883E
加盐密文:80D05C08F8879B2C84BA0C40143D224F
带盐密文:8D0D8053C0F8F6887791B2BC804B7A0EC4901543DD2B241F

Sample output (second run):

MD5加密
明文:123456
无盐密文:E10ADC3949BA59ABBE56E057F20F883E
加盐密文:2CFFE57B054378D926A6FF14A1985F22
带盐密文:21CF7FE957CB0354C37B8DC9256AD6F0F174A719785AF222

Because the same plaintext produces identical unsalted hashes but different salted hashes, salting significantly improves password security.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javainformation securityHashingMD5password salting
21CTO
Written by

21CTO

21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.