Generate Secure Password in Java

In this tutorial, we will generate a random alpha-numeric string of characters, which can be used as a user password.

Password Requirements

When generating passwords, it’s important to set requirements that make them strong and difficult to guess. Here are some guidelines to follow when creating password requirements:

Length

The length of a password is one of the most important factors in determining its strength. A longer password is generally more secure than a shorter one. Passwords should be at least 8 characters long, but ideally should be closer to 12-15 characters or more.

Complexity

A strong password should be complex, using a mix of upper and lowercase letters, numbers, and symbols. Avoid using dictionary words or common phrases, as these can be easily guessed. Instead, use a combination of random characters to create a password that is difficult to crack.

Uniqueness

Avoid using the same password for multiple accounts or services. If one password is compromised, it could potentially give an attacker access to all of your accounts. Instead, use a unique password for each account or service.

Regularly Change Passwords

Regularly changing passwords can help prevent unauthorized access to your accounts. It’s a good practice to change passwords at least every 90 days.

By setting strong password requirements, you can help protect your accounts and prevent unauthorized access. Remember to follow these guidelines when generating passwords, and regularly review and update your passwords to stay secure.

Generating Secure Passwords using Java’s SecureRandom Class

The code example below allows you to specify the length of a password. However, it’s important to note that while longer passwords are harder to brute force, they can also be harder to remember. In my opinion, a password length of 8-10 characters is strong enough for most cases. Nevertheless, if needed, you can always make the password longer using the code example below.

package com.appsdeveloperblog.encryption;

import java.security.SecureRandom;
import java.util.Random;
 
public class GenerateSecurePassword {
    // Use SecureRandom to generate random numbers for password characters
    private static final Random RANDOM = new SecureRandom();
    // Define the character set for the password
    private static final String ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

    public static void main(String[] args) {
        // Define desired password length
        int passwordLength = 10;
        
        // Generate Secure Password
        String password = generatePassword(passwordLength);
        
        // Print out password value
        System.out.println("Secure password: " + password);
    }

    // Method to generate a secure password of specified length
    public static String generatePassword(int length) {
        StringBuilder returnValue = new StringBuilder(length);

        // Iterate through password length and append random characters from character set
        for (int i = 0; i < length; i++) {
            returnValue.append(ALPHABET.charAt(RANDOM.nextInt(ALPHABET.length())));
        }

        // Convert StringBuilder to String and return
        return new String(returnValue);
    }
}

Output:

Secure password: IWNFsAF6Dg

This code generates a secure random password with a desired length using Java’s SecureRandom class. The code defines a constant ALPHABET, which contains all the possible characters that can be used in a password (letters and digits).

The generatePassword method creates a StringBuilder object and iterates through the desired password length, randomly selecting a character from the ALPHABET string and appending it to the StringBuilder object. The method then returns the generated password as a String.

The main method sets the desired password length, generates a secure password using the generatePassword method, and prints out the password value to the console.

Password Hashing

Password hashing is an important technique for protecting user passwords from unauthorized access. Instead of storing passwords in plain text, which can be easily read by anyone who gains access to the storage system, passwords are hashed before storage. A hash function takes an input (the password), applies a mathematical algorithm to it, and produces a fixed-size output (the hash).

In Java, you can use the MessageDigest class to compute a hash of a password. The MessageDigest class provides a number of different hash functions, such as SHA-256 and SHA-512, that are appropriate for password hashing. Here’s an example of how to hash a password using SHA-256:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class PasswordHasher {
    public static String hashPassword(String password) throws NoSuchAlgorithmException {
        // Create a new instance of the SHA-256 hash function
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        
        // Compute the hash of the password bytes
        byte[] hash = md.digest(password.getBytes());
        
        // Convert the hash bytes to a string of hexadecimal digits
        StringBuilder sb = new StringBuilder();
        for (byte b : hash) {
            sb.append(String.format("%02x", b));
        }
        
        // Return the hashed password as a string
        return sb.toString();
    }

    public static void main(String[] args) throws NoSuchAlgorithmException {
        // Define a password to hash
        String password = "myPassword123";
        
        // Hash the password using the SHA-256 algorithm
        String hashedPassword = hashPassword(password);
        
        // Print the original password and the hashed password
        System.out.println("Original password: " + password);
        System.out.println("Hashed password: " + hashedPassword);
    }
}

Output:

Original password: myPassword123
Hashed password: 71d4ec024886c1c8e4707fb02b46fd568df44e77dd5055cadc3451747f0f2716

In this example, the MessageDigest.getInstance() method is called with the name of the hash function to use. The digest() method is then called with the password bytes as input to compute the hash. Finally, the hash is converted to a string of hexadecimal digits using the StringBuilder class and returned.

When a user logs in and enters their password, the password is hashed again using the same algorithm and compared to the stored hash. If the two hashes match, the user is authenticated.

It’s important to note that hashing alone is not enough to protect passwords. Attackers can still use techniques such as dictionary attacks and rainbow tables to guess passwords based on their hashes. To make password cracking more difficult, passwords should be salted before hashing.

Salting involves adding a random value (the salt) to the password before hashing. This makes it more difficult for attackers to use precomputed hash tables to guess the password. In the next section, we’ll discuss how to salt passwords in Java.

Password Salting

Password salting is an additional security measure that is used to further protect passwords against attacks. In a salted password, a random sequence of characters, called a salt, is added to the password before it is hashed. This makes it much more difficult for an attacker to crack the password, even if they have obtained the hashed password from a compromised database.

Here’s how password salting works:

  1. Generate a random salt string. This should be a long, random sequence of characters, such as a UUID or a random string of bytes.
  2. Concatenate the salt string to the plaintext password.
  3. Hash the salted password using a secure hash algorithm, such as SHA-256 or bcrypt.
  4. Store the salt string and the hashed password in the database.

When a user logs in, the salt string is retrieved from the database and concatenated to the plaintext password. The resulting salted password is hashed using the same algorithm that was used during registration, and the resulting hash is compared to the hash stored in the database. If the hashes match, the user is authenticated.

By adding a salt to each password before hashing it, an attacker would have to compute the hash for each password + salt combination, which greatly increases the difficulty of cracking the password. Additionally, even if an attacker were to obtain the salted passwords and the salt values from the database, they would not be able to use precomputed rainbow tables to crack the passwords, since each salt value is unique.

Here’s an example of how you could modify the PasswordHasher class from our earlier example to support password salting:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

public class SaltedPasswordHasher {
    private static final int SALT_LENGTH = 16;

    public static void main(String[] args) throws NoSuchAlgorithmException {
        // Define a password to hash and verify
        String password = "myPassword123";

        // Hash the password with a salt
        String saltedHash = SaltedPasswordHasher.hashPassword(password);
        System.out.println("Salted hash of password: " + saltedHash);

        // Verify the password against the salted hash
        boolean isCorrectPassword = SaltedPasswordHasher.verifyPassword(password, saltedHash);
        System.out.println("Is password correct? " + isCorrectPassword);
    }

    // Hashes the given password with a random salt
    public static String hashPassword(String password) throws NoSuchAlgorithmException {
        SecureRandom random = new SecureRandom();

        // Generate a random salt
        byte[] salt = new byte[SALT_LENGTH];
        random.nextBytes(salt);

        // Hash the password with the salt
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(salt);
        byte[] hash = md.digest(password.getBytes());

        // Concatenate the salt and hashed password, and encode as a Base64 string
        String saltedHash = Base64.getEncoder().encodeToString(concatenateArrays(salt, hash));
        return saltedHash;
    }

    // Verifies a password against a salted hash
    public static boolean verifyPassword(String password, String saltedHash) throws NoSuchAlgorithmException {
        // Decode the salted hash back into its constituent salt and hash values
        byte[] saltAndHash = Base64.getDecoder().decode(saltedHash);
        byte[] salt = new byte[SALT_LENGTH];
        byte[] hash = new byte[saltAndHash.length - SALT_LENGTH];
        splitArray(saltAndHash, salt, hash);

        // Hash the password with the retrieved salt
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(salt);
        byte[] testHash = md.digest(password.getBytes());

        // Compare the computed hash with the stored hash
        return MessageDigest.isEqual(hash, testHash);
    }

    // Concatenates two byte arrays into a single array
    private static byte[] concatenateArrays(byte[] a, byte[] b) {
        byte[] result = new byte[a.length + b.length];
        System.arraycopy(a, 0, result, 0, a.length);
        System.arraycopy(b, 0, result, a.length, b.length);
        return result;
    }

    // Splits a byte array into two separate arrays
    private static void splitArray(byte[] source, byte[] dest1, byte[] dest2) {
        System.arraycopy(source, 0, dest1, 0, dest1.length);
        System.arraycopy(source, dest1.length, dest2, 0, dest2.length);
    }
}

Output:

Salted hash of password: 1jEZrq5ntTuFTTX4JoRUZ+0dHX2GvMMfzKJxH+0GtclpDS3tud9r4JE2+bELjLEI
Is password correct? true

In this modified version of the PasswordHasher class, we generate a random salt using a SecureRandom instance, and concatenate it to the plaintext password before hashing it. We then encode the salt and hashed password as a single Base64-encoded string, which we can store in the database.

When verifying a password, we retrieve the salted hash from the database and decode it back into its constituent salt and hash values. We then hash the plaintext password with the same salt value, and compare the resulting hash with the stored hash value.

This is just one example of how you could implement password salting in Java. Note that the exact implementation details may vary depending on your specific use case and requirements.

Overall, password salting is a simple and effective technique that can greatly improve the security of your password storage system.

Conclusion

In conclusion, generating secure passwords is an essential aspect of ensuring the security of user accounts and sensitive data. By utilizing strong password hashing techniques such as salting and stretching, you can significantly enhance the security of your passwords and make it much more difficult for attackers to crack them.

In this tutorial, we have covered several approaches to generating secure passwords in Java. We explored the use of random number generators, password-hashing algorithms, and salting techniques. By combining these approaches, you can create strong and secure passwords that are resistant to brute-force attacks and other common password-cracking techniques.

Remember, the security of your passwords depends not only on the strength of the algorithm you use but also on how well you protect the secrets that you use to generate and store those passwords. So, always make sure to follow best practices for password management and storage to maximize the security of your applications and protect your users’ data.

Leave a Reply

Your email address will not be published. Required fields are marked *