I would like to create a password generator that create password according to the restriction set by user. The restrictions is:
- Minimum Password Length
- Maximum Password Length
- Minimum Letter And Digit
- Minimum Letter
- Minimum Uppercase Letter
- Minimum Lowercase Letter
- Minimum Digit
- Maximum Repeat Character
I lookout through google and most of the example code doesn't meet the requirement that I need. So I improvise the code like this:
private char[] GeneratePassword(int minLength, int maxLength,
int maxRepeatCharacter, int minLetterAndDigit, int minLetter,
int minLowerCaseLetter, int minUpperCaseLetter, int minDigit) {
final String LETTER = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
final String UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
final String LOWERCASE = "abcdefghijklmnopqrstuvwxyz";
final String DIGIT = "0123456789";
final String[] randomSelector = {LETTER,UPPERCASE,LOWERCASE,DIGIT};
int len = getRandomNumber(minLength, maxLength);
char[] passwordGenerated = new char[len];
char[] characterUsed = new char[len];
int selection;
int letterAndDigitUsed = 0;
int letterUsed = 0;
int lowerCaseLetterUsed = 0;
int upperCaseLetterUsed = 0;
int digitUsed = 0;
int index = 0;
if (minLength > maxLength) {
// throw new IllegalArgumentException("Min.Length > Max.Length!");
}
if (minLetter + minDigit > minLetterAndDigit) {
// throw new IllegalArgumentException("Error!");
}
while (index != len) {
selection = getRandomNumber(0, randomSelector.length);
if (selection == 0) {
passwordGenerated[index] = LETTER.charAt(RandomUtils.nextInt(0,
LETTER.length()));
if (checkRepeatCharacter(passwordGenerated[index],
characterUsed, index, maxRepeatCharacter) == false) {
characterUsed[index] = passwordGenerated[index];
index++;
letterUsed++;
letterAndDigitUsed++;
break;
}
} else if (selection == 1) {
passwordGenerated[index] = UPPERCASE.charAt(RandomUtils
.nextInt(0, UPPERCASE.length()));
if (checkRepeatCharacter(passwordGenerated[index],
characterUsed, index, maxRepeatCharacter) == false) {
characterUsed[index] = passwordGenerated[index];
index++;
upperCaseLetterUsed++;
letterAndDigitUsed++;
break;
}
} else if (selection == 2) {
passwordGenerated[index] = LOWERCASE.charAt(RandomUtils
.nextInt(0, LOWERCASE.length()));
if (checkRepeatCharacter(passwordGenerated[index],
characterUsed, index, maxRepeatCharacter) == false) {
characterUsed[index] = passwordGenerated[index];
index++;
lowerCaseLetterUsed++;
letterAndDigitUsed++;
break;
}
} else if (selection == 3) {
passwordGenerated[index] = DIGIT.charAt(RandomUtils.nextInt(0,
DIGIT.length()));
if (checkRepeatCharacter(passwordGenerated[index],
characterUsed, index, maxRepeatCharacter) == false) {
characterUsed[index] = passwordGenerated[index];
index++;
digitUsed++;
letterAndDigitUsed++;
break;
}
}
}
return passwordGenerated;
}
private boolean checkRepeatCharacter(char passwordGenerated,
char[] passwordUsed, int index, int maxRepeatCharacter) {
int characterRepeated = 0;
for (int i = 0; i < index; i++) {
if (String.valueOf(passwordUsed[i]).equals(
String.valueOf(passwordGenerated))) {
characterRepeated++;
if (characterRepeated == maxRepeatCharacter) {
return true;
}
}
}
return false;
}
private int getRandomNumber(int minLength, int maxLength) {
Random r = new Random();
return r.nextInt(maxLength - minLength) + minLength;
}
The problem that I'm having is how to ensure the minimum condition are met. At the same time, I dont want my password to be generated by repeating at the same type of character.
Example: If I put my maximum password length to 10 and I want a minimum digit of 5. I prefer to have
1jP2k3o4m9
rather than57812aJ9tP
.2nd Example: If I put my maximum password length to 5 and I want a minimum lowercase letter of 3. I prefer to have
Pj9mn
rather thanjkl5V
.
As you can see, the 2nd generated password is trying to fullfill the minimum requirement first, then only do a random selection to other character type. Which will make the password more vulnerable. Is there any way to do this algorithm.
I would take a look at something like vt-password:
https://code.google.com/p/vt-middleware/wiki/vtpassword
In addition to providing flexible mechanisms for working with password validation based on some fairly standard required characteristics, it provides support for generating passwords that meet the conditions defined by a list of "character rules":
https://code.google.com/p/vt-middleware/wiki/vtpassword#Generating_passwords
Worth noting that the project has graduated from incubation and is now known as Passay - http://www.passay.org/.
The current password generator JavaDocs don't reflect the same set of character rules that were available with vt-password. You could either run with vt-password for a time, or provide your own
CharacterRule
implementations to work with the Passay generator (+ validator, if also required).I have fixed my code. So far I've tested, I works perfectly as required. I leave this code just in case someone else need it in the future.