I suggest using apache commons RandomStringUtils. Use something what is already done.
String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~`!@#$%^&*()-_=+[{]}\\|;:\'\",<.>/?";
String pwd = RandomStringUtils.random( 15, characters );
System.out.println( pwd );
If you are using maven
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
otherwise download jar
UPDATE Version with secure random. So matter of required characters left and can be solved as in comment, generate required parts separately and normal ones. Then join them randomly.
char[] possibleCharacters = (new String("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~`!@#$%^&*()-_=+[{]}\\|;:\'\",<.>/?")).toCharArray();
String randomStr = RandomStringUtils.random( randomStrLength, 0, possibleCharacters.length-1, false, false, possibleCharacters, new SecureRandom() );
System.out.println( randomStr );
Answer from Robert Wadowski on Stack OverflowI suggest using apache commons RandomStringUtils. Use something what is already done.
String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~`!@#$%^&*()-_=+[{]}\\|;:\'\",<.>/?";
String pwd = RandomStringUtils.random( 15, characters );
System.out.println( pwd );
If you are using maven
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
otherwise download jar
UPDATE Version with secure random. So matter of required characters left and can be solved as in comment, generate required parts separately and normal ones. Then join them randomly.
char[] possibleCharacters = (new String("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~`!@#$%^&*()-_=+[{]}\\|;:\'\",<.>/?")).toCharArray();
String randomStr = RandomStringUtils.random( randomStrLength, 0, possibleCharacters.length-1, false, false, possibleCharacters, new SecureRandom() );
System.out.println( randomStr );
I recently learned about Passay. It provides the required functionality needed in its PasswordGenerator class. It randomly generates passwords meeting the requirements similar to what is written below using CharacterRules rather than PasswordCharacterSets as I have done below. Instead of holding a list of unused indexes for random character insertion, it simply shuffles the character buffer after inserting characters that meet the requirements.
Below is left over from before, I recommend using Passay if your licensing allows it, this code should work otherwise and provides details of why the generated passwords are crytographically strong
I ended up writing this code twice. Once to get a random character result, but it turned out the distribution of characters depended on the size of the character set(whoops!). I rewrote it and now you should just copy/paste the code and change the Main.java to the character sets you want. Although it could have been done differently, I think this is a relatively straightforward approach to get the correct result and I encourage reuse, comments, criticisms, and well-thought edits.
The controls of the PasswordGenerator code is as follows:
- Min/Max Length: Set using a random number
- PasswordCharacterSet: It is assumed that all PasswordCharacterSets passed into PasswordGenerator consist of unique character sets, if not, the random characters will have a skew towards the duplicates.
- PasswordCharacterSet Min Characters: The min characters to use for this character set.
The main bits for the actual password generation:
- Randomness of Random: We're using SecureRandom which is backed by a cryptographically strong PRNG, rather than the Random class which is not.
- Random character order for the password: All the indexes of the pw char array are added to the remainingIndexes array. As we call addRandomCharacters, it removes an index randomly and we use the removed index to populate the array.
- Random characters: In addRandomCharacters, a random index from the character index we're using is chosen and added to the pw array.
- Guaranteeing minimum characters of each type are set: We simply carve out the minimum character amount first. We choose the minimum amount of random values from each character set and then move on.
- Random distribution for the remaining characters: After the minimum values have been set, we want to make the rest of the characters random across all character sets. All the characters are added to a single array. The remaining slots are filled using the same strategy for the previous character sets.
Description of password complexity: Password complexity is usually talked about in bits of entropy. Here are the number of possibilities for your keyspace:
There is at least one uppercase alpha character (out of 26), one lowercase alpha character(out of 26), one digit (out of 10), and one special character (out of 32), the way you calculate the number of possibilities is the number of possibilities for each character multiplied by the number of characters since they are randomly placed in the string. So we know the possibilities for four of the characters are:
Required Characters = 26*26*10*32=216,320
All remaining characters have 94 (26+26+10+32) possibilities each
Our calculation is:
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
With this is mind, if you want the most secure passwords, you should always choose the highest amount of characters possible which is 14 in this case.
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;
}
}
}
PasswordGenerator.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 password generator - Stack Overflow
I've made a password generator software in Java, I do have multiple doubts about Crypto and Security, need help with suggestions and improvement...
java - Secure random password generator - Code Review Stack Exchange
java - Hardware components based on which to generate password - Information Security Stack Exchange
Videos
I use this immutable class.
It uses the builder pattern.
It doesn't support extension.
public final class PasswordGenerator {
private static final String LOWER = "abcdefghijklmnopqrstuvwxyz";
private static final String UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String DIGITS = "0123456789";
private static final String PUNCTUATION = "!@#$%&*()_+-=[]|,./?><";
private boolean useLower;
private boolean useUpper;
private boolean useDigits;
private boolean usePunctuation;
private PasswordGenerator() {
throw new UnsupportedOperationException("Empty constructor is not supported.");
}
private PasswordGenerator(PasswordGeneratorBuilder builder) {
this.useLower = builder.useLower;
this.useUpper = builder.useUpper;
this.useDigits = builder.useDigits;
this.usePunctuation = builder.usePunctuation;
}
public static class PasswordGeneratorBuilder {
private boolean useLower;
private boolean useUpper;
private boolean useDigits;
private boolean usePunctuation;
public PasswordGeneratorBuilder() {
this.useLower = false;
this.useUpper = false;
this.useDigits = false;
this.usePunctuation = false;
}
/**
* Set true in case you would like to include lower characters
* (abc...xyz). Default false.
*
* @param useLower true in case you would like to include lower
* characters (abc...xyz). Default false.
* @return the builder for chaining.
*/
public PasswordGeneratorBuilder useLower(boolean useLower) {
this.useLower = useLower;
return this;
}
/**
* Set true in case you would like to include upper characters
* (ABC...XYZ). Default false.
*
* @param useUpper true in case you would like to include upper
* characters (ABC...XYZ). Default false.
* @return the builder for chaining.
*/
public PasswordGeneratorBuilder useUpper(boolean useUpper) {
this.useUpper = useUpper;
return this;
}
/**
* Set true in case you would like to include digit characters (123..).
* Default false.
*
* @param useDigits true in case you would like to include digit
* characters (123..). Default false.
* @return the builder for chaining.
*/
public PasswordGeneratorBuilder useDigits(boolean useDigits) {
this.useDigits = useDigits;
return this;
}
/**
* Set true in case you would like to include punctuation characters
* (!@#..). Default false.
*
* @param usePunctuation true in case you would like to include
* punctuation characters (!@#..). Default false.
* @return the builder for chaining.
*/
public PasswordGeneratorBuilder usePunctuation(boolean usePunctuation) {
this.usePunctuation = usePunctuation;
return this;
}
/**
* Get an object to use.
*
* @return the {@link gr.idrymavmela.business.lib.PasswordGenerator}
* object.
*/
public PasswordGenerator build() {
return new PasswordGenerator(this);
}
}
/**
* This method will generate a password depending the use* properties you
* define. It will use the categories with a probability. It is not sure
* that all of the defined categories will be used.
*
* @param length the length of the password you would like to generate.
* @return a password that uses the categories you define when constructing
* the object with a probability.
*/
public String generate(int length) {
// Argument Validation.
if (length <= 0) {
return "";
}
// Variables.
StringBuilder password = new StringBuilder(length);
Random random = new SecureRandom();
// Collect the categories to use.
List<String> charCategories = new ArrayList<>(4);
if (useLower) {
charCategories.add(LOWER);
}
if (useUpper) {
charCategories.add(UPPER);
}
if (useDigits) {
charCategories.add(DIGITS);
}
if (usePunctuation) {
charCategories.add(PUNCTUATION);
}
// Build the password.
for (int i = 0; i < length; i++) {
String charCategory = charCategories.get(random.nextInt(charCategories.size()));
int position = random.nextInt(charCategory.length());
password.append(charCategory.charAt(position));
}
return new String(password);
}
}
This is a usage example,
PasswordGenerator passwordGenerator = new PasswordGenerator.PasswordGeneratorBuilder()
.useDigits(true)
.useLower(true)
.useUpper(true)
.build();
String password = passwordGenerator.generate(8); // output ex.: lrU12fmM 75iwI90o
Be careful! As mentioned in the comments, this class is not guaranteed to generate a password that fully matches the "builder" settings.
Example: even if you set .useUpper(true) the password may not contain any uppercase character.
You can make use of org.apache.commons.lang.RandomStringUtils to generate random text/passwords. Please refer to this link for example.
I recently started studying cryptography, hashing, and everything else... And for that, I started creating a strong password generator that I'm aiming to make it secure with techniques related to RNG following my learning in cryptography with Java and the java.security.SecureRandom class. I called it Grifforix. As a password generator alone is not very useful in practice, I intend to also make it a secure password manager and a password authenticator in the future. But for now it's only a password generator. And on this journey, many doubts appeared to me and I want help with these main ones and feedback on what I've done so far, please.
Project's Code: https://github.com/GuilhermeIsNotUnix/Grifforix/
I know I'm showing things in the terminal, but it's just because my program doesn't yet have a GUI, I plan to do it in the future with JavaFX. Now, I have some doubts, first I wanted to know if my code currently has any type of vulnerability or something that I could improve in its generational password security. And for suggestions to improve it, what I thought so far:
[1] I am aware that the all types of characters need to have the same probability of being generated, so that no type of character is generated more than another, otherwise the password would be biased and someone who knew this could exploit this vulnerability. So, when I started, I knew that, and the way I generate a character, it comes from a constant formed by combining all the character types together. So, in theory, I'm not "pulling" characters from different alphabets that have different sizes (if that were the case, the probability of each character would be different, since each "alphabet" of a character type doesn't have the same size)... in this case, since every character comes from the same place, the probability of generating a character type must be the same. Right?
[2] Although my program appears to be generating strong and secure passwords with a good combination of character types, sometimes it can happen that the program spits out a password that does not have numbers, for example (or one of the character types). This, as far as I know, is not exactly my fault, I believe, but perhaps a consequence of uncontrolled randomness. So I was thinking about creating a certain type of "filter" that would analyze the generated password kinda of statistically, before actually giving it to the user. And in this "filter", the program would analyze the generated password to check possible problems and check its quality, (such as what I mentioned about sometimes generating a password, although strong, but with a type of character missing or with less quantity than others). If the password isn't that good, it would discard and generate another one until finding a pretty good one. I haven't technically thought about it yet, I just have some ideas in my head, and the issue of trying to balance the number of characters of all types equally is just one of the things that would dictate the quality of the password, but maybe there are more things that I'm not aware of to take into account in the quality of a password, suggest me if you think of more things about this please.
Furthermore, the way I thought about balancing the number of all types of characters equally could cause some problems from what I thought in my head. Because there are 4 types of characters (alpha, ALPHA, Nums and Symbs), but depending on the password length that the user requests (for example, a length that is not a multiple of 4) in theory it would mean that the password would never actually have the same number of character types, so, as a rule, some type of character would be more than the others in quantity, right? What to do in this case? Leave the password with that extra character type?
[3] Is there some type of process that I have to do besides encryption and hashing to "hide" the data and not leave it exposed? (Maybe against some kind of memory hack or reverse enginer that I'm not aware of). Again, I know I'm currently showing the hashing and data in the terminal by printing, I only did this because the program doesn't have a GUI, just for testing, but this question goes deeper into when the program already has a GUI for example.
[4] What areas of computer science are related to what I'm doing besides Cryptography and Security? Are there other areas with technical names related to this that I'm not aware of? (Maybe subareas)
[5] Taking advantage of the previous question about the areas of computer science... What books would you recommend me to study that are related to all of this?
Top hit on Google looks very similar; in any case no need to reinvent this.
But really, if this is the initial password, the users are going to get it how? Are the being forced to reset it immediately? All that is more a question for https://security.stackexchange.com/ than here.
But sure, looks okay, AFAIK SecureRandom is thread-safe (is that important?) and it's going to produce "random enough" output, the loop is okay too.
Though why specifically 16 characters and not e.g. 32? Do they have to enter them from a sheet of paper? Then there would be a couple of issues with it, like possibly mistaking i, I, l, L and 1, or 0, o and O, ... and so on.
Idea
Quite often it is a better idea to indicate the strength of the password and leave the actual password generation to the user. That way they can generate one using their own scheme, implemented by their password manager or browser.
[EDIT: this doesn't apply to the generation of an initial password as asked for in the question, in which case supplying a password in such a way is fine]
Design
The problem of fully random passwords is that it may be that e.g. no symbols are put into a password by chance. This would seem fine, random is random after all. However, if an attacker simply only uses the ABC + digits then your password may not be that secure. It is in other words a good idea to make sure that at least some symbols are in it. One way to do it is to generate one or two symbols and then shuffle them in.
[EDIT: this is a debatable design decision, some appear to make sure that the password has full entropy. For a targeted attack that makes sense, but e.g. password aggregation by an adversary could make shuffling in a symbol at a random location more secure. Lengthening the password by one character again may "fix" the entropy issue].
Code
public String generatePassword(int length) {
It is not a good idea to use String for passwords since String instances are usually interned and can therefore not be deleted. The idea is to use char[] where each element of the array can be zero'd out after use. Most if not all functions in the Java base classes will use char[] for passwords.
private static final Random RANDOM = new SecureRandom();
Random and SecureRandom instances are mutable. It is not a good idea to use mutable instances as class fields, even if they are thread safe.
SecureRandom is easy to instantiate, so just instantiating it in the method itself is fine. Otherwise split it into two functions, one accepting a Random and one that calls the other one, while creating an instance of SecureRandom:
public char[] generatePassword(int length) {
generatePassword(length, new SecureRandom());
}
public char[] generatePassword(int length, Random random) {
...
}
That way the user can have one instance of SecureRandom and reuse it over several method calls, including other methods.
password.append(POSSIBLE_CHARACTERS.charAt(RANDOM.nextInt(POSSIBLE_CHARACTERS.length())));
Please do not do not put multiple statements on a single line. It's unnecessarily confusing.
On windows, you can use the DPAPI to protect your keystore and ensure that the data can be decrypted only on the machine on which it was encrypted (or if you want, by only the user that encrypted it).
This will be a more straight forward approach than trying to generate a hash out of hardware information, will provide the same (or better) degree of security and will have less chances of making a mistake and would also avoid the problem of hardware changes resulting in data loss.
- If you were on Linux, you could simply query
/dev/urandomto get the random value without carrying about what the source of the randomness exactly is. But yes, the device will use noise generated by the devices to increase the entropy. - On Windows you may use the Windows equivalent: https://stackoverflow.com/questions/191335/windows-equivalent-of-dev-random
- But you may also use everything else that is meant for crypto purposes. You have tagged your question with [java]. In Java you may use the
SecureRandomclass. The output is unpredictable and this should be the most important concern regarding a random number generator.