Java Random Password Generator with SecureRandom

For passwords never use Math.random() or Random, because their numbers can be predicted. Use SecureRandom, which is made for security. This generator makes sure that the password has at least one character of each type.

Program

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {
    static final String UPPER = "ABCDEFGHJKLMNPQRSTUVWXYZ";      // no I and O: easy to confuse
    static final String LOWER = "abcdefghijkmnopqrstuvwxyz";     // no l
    static final String DIGITS = "23456789";                      // no 0 and 1
    static final String SYMBOLS = "!@#$%^&*-_=+";
    static final SecureRandom RANDOM = new SecureRandom();

    static String generate(int length) {
        if (length < 8) {
            throw new IllegalArgumentException("Use at least 8 characters");
        }
        String all = UPPER + LOWER + DIGITS + SYMBOLS;
        List<Character> chars = new ArrayList<>();

        chars.add(pick(UPPER));            // one of each type
        chars.add(pick(LOWER));
        chars.add(pick(DIGITS));
        chars.add(pick(SYMBOLS));
        while (chars.size() < length) {
            chars.add(pick(all));
        }
        Collections.shuffle(chars, RANDOM);

        StringBuilder sb = new StringBuilder();
        for (char c : chars) sb.append(c);
        return sb.toString();
    }

    static char pick(String set) {
        return set.charAt(RANDOM.nextInt(set.length()));
    }

    public static void main(String[] args) {
        String password = generate(14);
        System.out.println("Length: " + password.length());
        System.out.println("Has upper: " + password.chars().anyMatch(Character::isUpperCase));
        System.out.println("Has lower: " + password.chars().anyMatch(Character::isLowerCase));
        System.out.println("Has digit: " + password.chars().anyMatch(Character::isDigit));
        System.out.println("Has symbol: " + password.chars().anyMatch(c -> SYMBOLS.indexOf(c) >= 0));
        System.out.println("Two passwords are different: " + !generate(14).equals(generate(14)));
    }
}
Output

Length: 14
Has upper: true
Has lower: true
Has digit: true
Has symbol: true
Two passwords are different: true

We print the checks and not the password itself, because a real password is different on every run. When you run it, print password to see it.

Good to know

  • SecureRandom uses the random source of the operating system.
  • Removing the letters which look alike (l, 1, O, 0) makes a password easier to read.
  • Never save a password as plain text. Save a hash made with a slow algorithm like bcrypt, scrypt or Argon2.
  • Never write passwords in logs or in the source code.

Related: Java Math Class and Java Strings.


Learn more about the similar topics:
Tutorials
No Content Found.
Exercises & Assignments
No Content Found.
Interview Questions & Answers
No Content Found.