如何创建一个满足的Java系统的长度和字符集需求的随机密码?
我要创建一个随机密码是10-14个字符,并且至少有一个大写字母,一个小写,和一个特殊字符。不幸的是,一些特殊的字符是太特殊了,不能用,所以我不能只使用打印的ASCII。
许多本网站上的例子,而不产生的字符或没有在业务设置像上面给出的那些现实要求足够的熵的随机密码或会话密钥,所以我要求更尖锐的问题,以得到更好的答案。
我的字符集,标准美式键盘除了空间上的每个特殊字符:
A-Z
a-z
0-9
~`!@#$%^&*()-_=+[{]}\|;:'",<.>/?
我建议使用Apache的百科全书RandomStringUtils。使用什么东西都已经完成。
String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~`!@#$%^&*()-_=+[{]}\\|;:\'\",<.>/?";
String pwd = RandomStringUtils.random( 15, characters );
System.out.println( pwd );
如果您在使用maven
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
否则下载JAR
更新版本与安全随机。所以物质所需的字符左右是可以解决的,如评论,分别生成所需的零件和正常的。然后随机加入他们的行列。
char[] possibleCharacters = (new String("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~`!@#$%^&*()-_=+[{]}\\|;:\'\",<.>/?")).toCharArray();
String randomStr = RandomStringUtils.random( randomStrLength, 0, possibleCharacters.length-1, false, false, possibleCharacters, new SecureRandom() );
System.out.println( randomStr );
我最近了解到Passay。它提供了其所需PasswordGenerator class所需要的功能。它随机生成满足类似于以下使用CharacterRules而不是PasswordCharacterSets因为我已经做了如下书面要求的密码。相反,持有未使用的索引列表随机字符插入,它只是洗牌将符合要求的字符后的字符缓冲区。
下面是之前遗留下来的,我建议使用Passay如果您的许可允许,此代码应工作,否则,提供的为什么生成的密码是crytographically强大的细节
我结束了两次编写这些代码。一旦得到一个随机字符的结果,但事实证明,文字的分布取决于字符集的大小(哎呦!)。我重写了它,现在你应该只是复制/粘贴代码和改变Main.java的字符集你想要的。虽然它本来可以做不同的,我觉得这是一个比较简单的方法来得到正确的结果,我鼓励重用,意见,批评和深思熟虑的编辑。
所述PasswordGenerator代码的控制如下:
对于实际的密码生成的主要位:
密码复杂性说明:密码的复杂性通常谈到的熵位。以下是为您的密钥空间可能性的数量:
有至少一个大写字母字符(总共26),一个小写字母字符(总共26),一个数字(满分10分),和一个特殊字符(总共32),用这种方法计算的可能性的数量是为每个字符乘以字符数可能性的数目,因为它们是随机放置的的字符串中。因此,我们知道的人物的四种可能性:
Required Characters = 26*26*10*32=216,320
所有剩余的字符具有94(26 + 26 + 10 + 32)的每个的可能性
我们的计算公式为:
Characters Possibilities Bits of Entropy
10 chars 216,320*94^6 = 149,232,631,038,033,920 ~2^57
11 chars 216,320*94^7 = 14,027,867,317,575,188,480 ~2^63
12 chars 216,320*94^8 = 1,318,619,527,852,067,717,120 ~2^70
13 chars 216,320*94^9 = 123,950,235,618,094,365,409,280 ~2^76
14 chars 216,320*94^10 = 11,651,322,148,100,870,348,472,320 ~2^83
随着这是头脑,如果你想要最安全的密码,你应该始终选择可能的字符,这是在这种情况下14的最高金额。
main.Java
package org.redtown.pw;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import org.redtown.pw.PasswordGenerator.PasswordCharacterSet;
public class Main {
public static void main(String[] args) {
Set<PasswordCharacterSet> values = new HashSet<PasswordCharacterSet>(EnumSet.allOf(SummerCharacterSets.class));
PasswordGenerator pwGenerator = new PasswordGenerator(values, 10, 14);
for(int i=0; i < 10; ++i) {
System.out.println(pwGenerator.generatePassword());
}
}
private static final char[] ALPHA_UPPER_CHARACTERS = { 'A', 'B', 'C', 'D',
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
private static final char[] ALPHA_LOWER_CHARACTERS = { 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
private static final char[] NUMERIC_CHARACTERS = { '0', '1', '2', '3', '4',
'5', '6', '7', '8', '9' };
private static final char[] SPECIAL_CHARACTERS = { '~', '`', '!', '@', '#',
'$', '%', '^', '&', '*', '(', ')', '-', '_', '=', '+', '[', '{',
']', '}', '\\', '|', ';', ':', '\'', '"', ',', '<', '.', '>', '/',
'?' };
private enum SummerCharacterSets implements PasswordCharacterSet {
ALPHA_UPPER(ALPHA_UPPER_CHARACTERS, 1),
ALPHA_LOWER(ALPHA_LOWER_CHARACTERS, 1),
NUMERIC(NUMERIC_CHARACTERS, 1),
SPECIAL(SPECIAL_CHARACTERS, 1);
private final char[] chars;
private final int minUsage;
private SummerCharacterSets(char[] chars, int minUsage) {
this.chars = chars;
this.minUsage = minUsage;
}
@Override
public char[] getCharacters() {
return chars;
}
@Override
public int getMinCharacters() {
return minUsage;
}
}
}
password generator.Java
package org.redtown.pw;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class PasswordGenerator {
private final List<PasswordCharacterSet> pwSets;
private final char[] allCharacters;
private final int minLength;
private final int maxLength;
private final int presetCharacterCount;
public PasswordGenerator(Collection<PasswordCharacterSet> origPwSets, int minLength, int maxLength) {
this.minLength = minLength;
this.maxLength = maxLength;
// Make a copy of the character arrays and min-values so they cannot be changed after initialization
int pwCharacters = 0;
int preallocatedCharacters = 0;
List<PasswordCharacterSet> pwSets = new ArrayList<PasswordCharacterSet>(origPwSets.size());
for(PasswordCharacterSet origpwSet : origPwSets) {
PasswordCharacterSet newPwSet = new PwSet(origpwSet);
pwSets.add(newPwSet);
pwCharacters += newPwSet.getCharacters().length;
preallocatedCharacters += newPwSet.getMinCharacters();
}
this.presetCharacterCount = preallocatedCharacters;
this.pwSets = Collections.unmodifiableList(pwSets);
if (minLength < presetCharacterCount) {
throw new IllegalArgumentException("Combined minimum lengths "
+ presetCharacterCount
+ " are greater than the minLength of " + minLength);
}
// Copy all characters into single array so we can evenly access all members when accessing this array
char[] allChars = new char[pwCharacters];
int currentIndex = 0;
for(PasswordCharacterSet pwSet : pwSets) {
char[] chars = pwSet.getCharacters();
System.arraycopy(chars, 0, allChars, currentIndex, chars.length);
currentIndex += chars.length;
}
this.allCharacters = allChars;
}
public char[] generatePassword() {
SecureRandom rand = new SecureRandom();
// Set pw length to minLength <= pwLength <= maxLength
int pwLength = minLength + rand.nextInt(maxLength - minLength + 1);
int randomCharacterCount = pwLength - presetCharacterCount;
// Place each index in an array then remove them randomly to assign positions in the pw array
List<Integer> remainingIndexes = new ArrayList<Integer>(pwLength);
for(int i=0; i < pwLength; ++i) {
remainingIndexes.add(i);
}
// Fill pw array
char[] pw = new char[pwLength];
for(PasswordCharacterSet pwSet : pwSets) {
addRandomCharacters(pw, pwSet.getCharacters(), pwSet.getMinCharacters(), remainingIndexes, rand);
}
addRandomCharacters(pw, allCharacters, randomCharacterCount, remainingIndexes, rand);
return pw;
}
private static void addRandomCharacters(char[] pw, char[] characterSet,
int numCharacters, List<Integer> remainingIndexes, Random rand) {
for(int i=0; i < numCharacters; ++i) {
// Get and remove random index from the remaining indexes
int pwIndex = remainingIndexes.remove(rand.nextInt(remainingIndexes.size()));
// Set random character from character index to pwIndex
int randCharIndex = rand.nextInt(characterSet.length);
pw[pwIndex] = characterSet[randCharIndex];
}
}
public static interface PasswordCharacterSet {
char[] getCharacters();
int getMinCharacters();
}
/**
* Defensive copy of a passed-in PasswordCharacterSet
*/
private static final class PwSet implements PasswordCharacterSet {
private final char[] chars;
private final int minChars;
public PwSet(PasswordCharacterSet pwSet) {
this.minChars = pwSet.getMinCharacters();
char[] pwSetChars = pwSet.getCharacters();
// Defensive copy
this.chars = Arrays.copyOf(pwSetChars, pwSetChars.length);
}
@Override
public char[] getCharacters() {
return chars;
}
@Override
public int getMinCharacters() {
return minChars;
}
}
}
下面是一个使用刚刚香草Java和实现要求的工具。它基本上得到所需的每一个字符集之一。然后填充与整个组随机字符休息。然后洗牌这一切。
public class PasswordUtils {
static char[] SYMBOLS = (new String("^$*.[]{}()?-\"!@#%&/\\,><':;|_~`")).toCharArray();
static char[] LOWERCASE = (new String("abcdefghijklmnopqrstuvwxyz")).toCharArray();
static char[] UPPERCASE = (new String("ABCDEFGHIJKLMNOPQRSTUVWXYZ")).toCharArray();
static char[] NUMBERS = (new String("0123456789")).toCharArray();
static char[] ALL_CHARS = (new String("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789^$*.[]{}()?-\"!@#%&/\\,><':;|_~`")).toCharArray();
static Random rand = new SecureRandom();
public static String getPassword(int length) {
assert length >= 4;
char[] password = new char[length];
//get the requirements out of the way
password[0] = LOWERCASE[rand.nextInt(LOWERCASE.length)];
password[1] = UPPERCASE[rand.nextInt(UPPERCASE.length)];
password[2] = NUMBERS[rand.nextInt(NUMBERS.length)];
password[3] = SYMBOLS[rand.nextInt(SYMBOLS.length)];
//populate rest of the password with random chars
for (int i = 4; i < length; i++) {
password[i] = ALL_CHARS[rand.nextInt(ALL_CHARS.length)];
}
//shuffle it up
for (int i = 0; i < password.length; i++) {
int randomPosition = rand.nextInt(password.length);
char temp = password[i];
password[i] = password[randomPosition];
password[randomPosition] = temp;
}
return new String(password);
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(getPassword(8));
}
}
}
使用的rt.jar的java.util包中的随机功能,我们可以创建任意长度的随机密码。下面是相同的代码段。
public class GeneratePassword {
public static void main(String[] args)
{
int length = 10;
String symbol = "-/.^&*_!@%=+>)";
String cap_letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
String small_letter = "abcdefghijklmnopqrstuvwxyz";
String numbers = "0123456789";
String finalString = cap_letter + small_letter +
numbers + symbol;
Random random = new Random();
char[] password = new char[length];
for (int i = 0; i < length; i++)
{
password[i] =
finalString.charAt(random.nextInt(finalString.length()));
}
System.out.println(password);
}
}