I am using this function to generate a random password of length 11, as seen in this post:
import java.util.Random;
public class RandomPassword {
public static void main(String[] args){
RandomPassword r = new RandomPassword(11);
System.out.print(r.nextString());
}
private static final char[] symbols;
static {
StringBuilder tmp = new StringBuilder();
for (char ch = '0'; ch <= '9'; ++ch)
tmp.append(ch);
for (char ch = 'a'; ch <= 'z'; ++ch)
tmp.append(ch);
for (char ch = 'A'; ch <= 'Z'; ++ch)
tmp.append(ch);
symbols = tmp.toString().toCharArray();
}
private final Random random = new Random();
private final char[] buf;
public RandomPassword(int length) {
if (length < 1)
throw new IllegalArgumentException("length < 1: " + length);
buf = new char[length];
}
public String nextString() {
for (int idx = 0; idx < buf.length; ++idx)
buf[idx] = symbols[random.nextInt(symbols.length)];
return new String(buf);
}
}
However I need to modify it so that I can guarantee at least one capital letter, one number and one lowercase letter. Right now there is the possibility that the password could contain all caps/lowercase/numbers and we need at least one of each to be accepted by AD. Any help is appreciated, thanks.
***I am told that it would be best to loop through in nextString()
like this:
public String nextString() {
for (int idx = 0; idx < buf.length; ++idx)
if(buf[buf.length%3].equals(num/lower/cap)){
buf[idx] = symbols[random.nextInt(symbols.length)];
}
.
.
.
return new String(buf);
}
What do you think?
This would prevent loops and would also have the benefit of being truly random.
Or, if you're ok with losing some entropy you could:
Loop over the characters in the array to ensure that each character class is contained within. Then, if it fails, just generate a new random string. This ensures that all are contained and will not fail to validate very often.
I would recommend a regular expresion searching for a set of predifined characters/numbers uppercase/lowercase and a error message
public String getPassword(){
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "SUN");
byte[] salt = new byte[16];
sr.nextBytes(salt);
return wellformedPassword(salt.toString()) ? salt.toString() : secured(salt.toString());
}
public String secured(String pass){
return string1.replaceFirst(Pattern.quote("[a-z]", "Z");
}
public boolean wellformedPassword(String pass){
return checkRegExp(pass, "\\d")
&& checkRegExp(pass, "[A-Z]")
&& checkRegExp(pass, "[a-z]");
}
public boolean checkRegExp(String str, String pattern){
Pattern p = Pattern.compile(pattern);
Matcher n = p.matcher(str);
return n.find();
}
SHA assure you lowercase letters and numbers, then you just need to turn, one (in my case) or more to upper.
this is a dummy approach wich can be improved. Share your code so i cant edit later my answer for anyone else.
You could get that char and turn it to upper instead of Z but i guess with this you can get started.
This "cheats" (is weaker than it could be), but it meets the usual requirements (or can be modified to meet them):
import java.util.Random;
public class Password {
private static final String UPPER = "ABCDEFGHIJKLMNPQRSTUVWXYZ";
private static final String LOWER = "abcdefghijklmnpqrstuvwxyz";
private static final String NUMBER = "123456789";
private static final String SPECIAL = "!@#$%&*+?";
private Random randGen = new Random();
public static void main(String[] argv) {
Password me = new Password();
for (int i = 0; i <= 10; i++) {
me.printPassword();
}
}
private void printPassword() {
StringBuffer buf = new StringBuffer();
buf.append(LOWER.charAt(Math.abs(randGen.nextInt()) % LOWER.length()));
buf.append(LOWER.charAt(Math.abs(randGen.nextInt()) % LOWER.length()));
buf.append(NUMBER.charAt(Math.abs(randGen.nextInt()) % NUMBER.length()));
for (int i = 0; i <= 4; i++) {
buf.append(LOWER.charAt(Math.abs(randGen.nextInt()) % LOWER.length()));
}
buf.append(UPPER.charAt(Math.abs(randGen.nextInt()) % UPPER.length()));
buf.append(LOWER.charAt(Math.abs(randGen.nextInt()) % LOWER.length()));
System.out.println(buf.toString());
}
}
I had another algorithm that was better, but lost it.
(I like to print out multiple "suggestions" and then pick the one that seems easiest to remember.)
I really don't know how reliable it is but a try
List<Character> listOfUpperCaseLetter = new ArrayList<Character>();
for(int i = 65;i<91;i++){
char ch = (char)i;
listOfUpperCaseLetter.add(ch);
}
List<Character> listOfLowerCaseLetter = new ArrayList<Character>();
for(int i = 97;i<123;i++){
char ch = (char)i;
listOfLowerCaseLetter.add(ch);
}
List<Integer> listOfInt = new ArrayList<Integer>();
for(int i =0;i<10;i++){
listOfInt.add(i);
}
StringBuilder br = new StringBuilder();
Collections.shuffle(listOfLowerCaseLetter);
Collections.shuffle(listOfUpperCaseLetter);
Collections.shuffle(listOfInt);
br.append(listOfUpperCaseLetter.get(0));
br.append(listOfLowerCaseLetter.get(1));
br.append(listOfLowerCaseLetter.get(3));
br.append(listOfInt.get(1));
br.append(listOfInt.get(0));
br.append(listOfLowerCaseLetter.get(2));
br.append(listOfUpperCaseLetter.get(1));
br.append(listOfLowerCaseLetter.get(0));
br.append(listOfUpperCaseLetter.get(2));
br.append(listOfInt.get(2));
System.out.println(br.toString());
I simply added an if/else
statement saying to add certain members of the symbols
array (0-10, 11-35, 36-61). This guarantees what is needed. Sometimes the simplest answer is the best answer. Thanks for the ideas.
if (idx == 0){
buf[idx] = symbols[random.nextInt(10)];
}else if (idx == 1){
buf[idx] = symbols[10 + random.nextInt(35-10+1)];
}else if(idx == 2){
buf[idx] = symbols[36 + random.nextInt(61-36+1)];
}else{
buf[idx] = symbols[random.nextInt(symbols.length)];
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.