How can I create a password?

2019-01-22 09:29发布

问题:

I want to give maybe a million password to some users that should be like:

  1. It must have at least 6 characters
  2. It must have digits and also letters

Should I use Random here? How?

回答1:

RandomStringUtils from Apache Commons Lang provide some methods to generate a randomized String, that can be used as password.


Here are some examples of 8-characters passwords creation:

// Passwords with only alphabetic characters.
for (int i = 0; i < 8; i++) {
    System.out.println(RandomStringUtils.randomAlphabetic(8));
}
System.out.println("--------");
// Passwords with alphabetic and numeric characters.
for (int i = 0; i < 8; i++) {
    System.out.println(RandomStringUtils.randomAlphanumeric(8));
}

which creates the following result:

zXHzaLdG
oDtlFDdf
bqPbXVfq
tzQUWuxU
qBHBRKQP
uBLwSvnt
gzBcTnIm
yTUgXlCc
--------
khDzEFD2
cHz1p6yJ
3loXcBau
F6NJAQr7
PyfN079I
8tJye7bu
phfwpY6y
62q27YRt

Of course, you have also methods that may restrict the set of characters allowed for the password generation:

for (int i = 0; i < 8; i++) {
    System.out.println(RandomStringUtils.random(8, "abcDEF123"));
}

will create only passwords with the characters a, b, c, D, E, F, 1, 2 or 3:

D13DD1Eb
cac1Dac2
FE1bD2DE
2ab3Fb3D
213cFEFD
3c2FEDDF
FDbFcc1E
b2cD1c11


回答2:

When using Apache's RandomStringUtils for security reasons (i.e. passwords), it's very important to combine the use of a SecureRandom source:

RandomStringUtils.random(6, 0, 0, true, true, null, new SecureRandom());


回答3:

Use SecureRandom, it provides a more random passwords.

You can create a single password using something like this (note: untested code).

// put here all characters that are allowed in password
char[] allowedCharacters = {'a','b','c','1','2','3','4'};

SecureRandom random = new SecureRandom();
StringBuffer password = new StringBuffer();

for(int i = 0; i < PASSWORD_LENGTH; i++) {
    password.append(allowedCharacters[ random.nextInt(allowedCharacters.length) ]);
}

Note that this does not guarantee that the every password will have both digits and characters.



回答4:

Here's one that I wrote a while back:

package com.stackoverflow.does.my.code.for.me;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;

public class PasswordUtil {

    /** Minimum password length = 6 */
    public static final int MIN_PASSWORD_LENGTH = 6;
    /** Maximum password length = 8 */
    public static final int MAX_PASSWORD_LENGTH = 8;

    /** Uppercase characters A-Z */
    public static final char[] UPPERS = new char[26];
    /** Lowercase characters a-z */
    public static final char[] LOWERS = new char[26];
    /**
     * Printable non-alphanumeric characters, excluding space.
     */
    public static final char[] SPECIALS = new char[32];
    public static final char[] DIGITS = new char[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    static {
        // Static initializer block for populating arrays
        int U = 'A';
        int l = 'a';
        int d = '0';
        for (int i = 0; i < 26; i++) {
            UPPERS[i] = (char) (U + i);
            LOWERS[i] = (char) (l + i);
            if (i < 10) {
                DIGITS[i] = (char) (d + i);
            }
        }
        int p = 0;
        for (int s = 33; s < 127; s++) {
            char specialChar = (char) 32;

            if (s >= 'a' && s <= 'z')
                s = 'z' + 1; // jump over 'a' to 'z'
            else if (s >= 'A' && s <= 'Z')
                s = 'Z' + 1; // jump over 'A' to 'Z'
            else if (s >= '0' && s <= '9')
                s = '9' + 1; // jump over '0' to '9'

            specialChar = (char) s;
            SPECIALS[p] = specialChar;
            p++;
        }
    }

    public String generatePassword() {
        List<char[]> activeSets = new ArrayList<char[]>(4);
        List<char[]> inactiveSets = new ArrayList<char[]>(4);

        activeSets.add(UPPERS);
        activeSets.add(LOWERS);
        activeSets.add(SPECIALS);
        activeSets.add(DIGITS);

        SecureRandom random = new SecureRandom();

        int passwordLength = 5 + random.nextInt(3);
        StringBuffer password = new StringBuffer(passwordLength + 1);

        for (int p = 0; p <= passwordLength; p++) {
            char[] randomSet = null;
            if (activeSets.size() > 1) {
                int rSet = random.nextInt(activeSets.size());
                randomSet = activeSets.get(rSet);
                inactiveSets.add(randomSet);
                activeSets.remove(rSet);
            } else {
                randomSet = activeSets.get(0);
                inactiveSets.add(randomSet);
                activeSets.clear();
                activeSets.addAll(inactiveSets);
                inactiveSets.clear();
            }
            int rChar = random.nextInt(randomSet.length);
            char randomChar = randomSet[rChar];
            password.append(randomChar);
        }

        return password.toString();
    }
}


回答5:

This is also a nice one:

String password = Integer.toString((int) (Math.random() * Integer.MAX_VALUE), 36);

It however does not guarantee that the password always contains both digits and letters, but most of the aforementioned suggestions also doesn't do that.



回答6:

What I would do is something like this:

  1. Create two arrays, one with the allowed letters and other with the allowed digits.
  2. Use Random to decide the length of the password.
  3. Use Random to decide whether the next character is a letter or a digit.
  4. Use Random once more to generate an index for the array of letters or digits (depending on wht you obtained in step 3). Append the obtained character to the password.
  5. Repeat from 3 until you have the amount of characters obtained in 2.


回答7:

This will be the easiest one :)

String char_group = "abcdefghijklmnopqrstuvwxyz";
String digit_group = "123456789";

// first choose a len of pwd
Random ran = new Random();
int pwd_len = ran.nextInt(50); //50 is the max length of password,say
// check that pwd_len is not less than 6
// do the check here

// finally create the password..
StringBuffer pwd = new StringBuffer();
Random RNG = new Random();
for (int i = 0; i < pwd_len ; i++) {
    int randomNum = RNG.nextInt(100);
    char c = '';
    // Here 25% is the ratio of mixing digits
    // in the password, you can change 4 to any
    // other value to change the depth of mix
    // or you can even make it random. 
    if (randomNum % 4 == 0) {
        c = digit_group[randomNum  % digit_group.length];
    } else {
        c = char_group[randomNum  % char_group.length];
    }
    pwd.append(c);
}
return pwd.toString();


回答8:

A bit late, but I usually use the following code:

private static final int PASSWORD_SIZE = 16;
private static final String VALID_SPECIAL_CHARACTERS = "!@#$%&*()_-+=[]{}\\|:/?.,><"; // Note the double \ as escape

private static String createPassword() {
    SecureRandom random = new SecureRandom();
    StringBuilder password = new StringBuilder();
    while (password.length() < PASSWORD_SIZE) {
        char character = (char) random.nextInt(Character.MAX_VALUE);
        if ((character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z') || (character >= '0' && character <= '9') || VALID_SPECIAL_CHARACTERS.contains(String.valueOf(character))) {
            password.append(character);
        }
    }
    return password.toString();
}

There is no guarantee that there will always be a number, special character, lower-case and upper-case character in the password. This could be enforced by first adding a character and a digit, however this would create passwords that are a bit more predictable.



回答9:

Here is how you can make sure your generated password meets your password criteria, e.g: in your case, i would use this regex:

<code>String regex = "^(?=[a-zA-Z0-9ñÑ]*\d)(?=[a-zA-Z0-9ñÑ]*[a-z])(?=[a-zA-Z0-9ñÑ]*[A-Z])[a-zA-Z0-9ñÑ]{6,}$"</code>

This regex meets the following criteria:

1.- at least 1 lowerCase letter

2.- at least 1 upperCase letter

3.- at least 1 digit(number)

4.- at least 6 characters (note that adding a number greater than 6 after the comma at the end of the regex, will now meet a criteria that at least 6 characters and a max of whatever you put in there)

<code>char[] char = {'a','b','c','d','e','f','g','h',...};

SecureRandom random = new SecureRandom();
StringBuffer password = new StringBuffer();</code>

while(!password.toString().matches("your regex")){
    for(int i = 0; i < 8; i++) {
    password.append(char [ random.nextInt(char .length) ]);
    }
}
System.out.println(password.toString());

What this code does is that whileyour generated password doesn't meet your criteria, it will loop the for loop over and over.



回答10:

Implemented a PasswordBuilder. Supports passwrod limit, must have characters and how much of them, char ranges and a list of them.

Usage Example:

System.out.println(new PasswordBuilder().addCharsOption("!@#$%&*()_-+=[]{}\\|:/?.,><", 1).addRangeOption('A', 'Z', 1).addRangeOption('a', 'z', 0).addRangeOption('0', '9', 1).build());

Example result: QU1GY7p+j+-PUW+_

System.out.println(new PasswordBuilder().addCharsOption("!@#$%&*()_-+=[]{}\\|:/?.,><", 1).addRangeOption('A', 'Z', 1).addRangeOption('a', 'z', 0).addRangeOption('0', '9', 1).setSize(5).build());

Example result: %,4NX

Implementation:

//Version=1.0
//Source=https://www.dropbox.com/s/3a4uyrd2kcqdo28/PasswordBuilder.java?dl=0
//Dependencies=java:7 com.google.guava:guava:18.0 commons-lang:commons-lang:2.6

import com.google.common.primitives.Chars;
import org.apache.commons.lang.ArrayUtils;

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

/**
 * Created by alik on 5/26/16.
 */
public class PasswordBuilder {
    private int size = 16;
    private List<Character> options = new ArrayList<>();
    private Map<List<Character>, Integer> musts = new java.util.LinkedHashMap<>();
    private SecureRandom secureRandom = new SecureRandom();

    public PasswordBuilder() {
    }

    public PasswordBuilder setSize(int size) {
        this.size = size;
        return this;
    }

    public PasswordBuilder addRangeOption(char from, char to, int mustCount) {
        List<Character> option = new ArrayList<>(to - from + 1);
        for (char i = from; i < to; ++i) {
            option.add(i);
        }
        return addOption(option, mustCount);
    }

    public PasswordBuilder addCharsOption(String chars, int mustCount) {
            return addOption(Chars.asList(chars.toCharArray()), mustCount);
    }

    public PasswordBuilder addOption(List<Character> option, int mustCount) {
        this.options.addAll(option);
        musts.put(option, mustCount);
        return this;

    }

    public String build() {
        validateMustsNotOverflowsSize();
        Character[] password = new Character[size];

        // Generate random from musts
        for (Map.Entry<List<Character>, Integer> entry : musts.entrySet()) {
            for (int i = 0; i < entry.getValue(); i++) {
                int charIndex = secureRandom.nextInt(entry.getKey().size());
                char c = entry.getKey().get(charIndex);
                addChar(password, c);
            }
        }

        // Generate from overall
        for (int i = 0; i < password.length; i++) {
            if (password[i] != null) continue;
            password[i] = options.get(secureRandom.nextInt(options.size()));
        }
        return new String(ArrayUtils.toPrimitive(password));
    }

    private void addChar(Character[] password, char c) {
        int i;
        for (i = secureRandom.nextInt(password.length); password[i] != null; i = secureRandom.nextInt(password.length)) {
        }
        password[i] = c;
    }

    private void validateMustsNotOverflowsSize() {
        int overallMusts = 0;
        for (Integer mustCount : musts.values()) {
            overallMusts += mustCount;
        }
        if (overallMusts > size) {
            throw new RuntimeException("Overall musts exceeds the requested size of the password.");
        }
    }

    public static void main(String[] args) {
        System.out.println(new PasswordBuilder().addCharsOption("!@#$%&*()_-+=[]{}\\|:/?.,><", 1).addRangeOption('A', 'Z', 1).addRangeOption('a', 'z', 0).addRangeOption('0', '9', 1).build());
        System.out.println(new PasswordBuilder().addCharsOption("!@#$%&*()_-+=[]{}\\|:/?.,><", 1).addRangeOption('A', 'Z', 1).addRangeOption('a', 'z', 0).addRangeOption('0', '9', 1).setSize(5).build());
    }
}