6
\$\begingroup\$

While I do know that there are many questions regarding "password generators," I have a different approach and would like to know if it is effective.

1) The below password generator takes on a different approach that other basic password generators, creating an empty string of x length, x being the desired length of the final password, and inserting characters and sub-stringing. I would like to know if this fashion is more effective than adding random characters one-by-one

2) Have I ensured the most random-ness of the characters in the password by using this character set? Or should I rearrange the characters differently?

public static final String CHARACTER_SET = ("aA1bB2cC3dD4eE5fF6gG8hH9iI0jJkKlLmMnNoOpP&qQrRsStT_uUvV-wWxX+yYzZ");

3) I also seek general reminders on java conventions that I do not know.

Here is my full class for reference.

public class PasswordGenerator {

  public static final String VERSION = ("1.0");

  public static final String CHARACTER_SET = ("aA1bB2cC3dD4eE5fF6gG8hH9iI0jJkKlLmMnNoOpP&qQrRsStT_uUvV-wWxX+yYzZ");

  public static void main(String[] args) {
    System.out.println("Welcome to password generator, version: " + VERSION);
    System.out.println(generatePassword(20));
  }

  private static String generatePassword(int passwordLength) {
    String password = "";
    for (int i = 0; i < passwordLength; i++) {
      password = password + " ";
    }
    Random random = new Random();
    for (int i = 0; i < password.length(); i++) {
      if (i == 0) {
        password = String.valueOf(CHARACTER_SET.charAt(random.nextInt(65))) + password.substring(1, password.length());
      } else {
        password = password.substring(0, i) + String.valueOf(CHARACTER_SET.charAt(random.nextInt(65))) + password.substring(i + 1, password.length());
      }
    }
    return password.toString();
  }
}

Note: The 65 comes from the CHARACTER_SET length, which I have found out before.

\$\endgroup\$
  • 3
    \$\begingroup\$ Your assumption that the order of the characters in your character set has influence on the randomness of the password is flawed. \$\endgroup\$ – Mast Dec 23 '15 at 8:28
  • \$\begingroup\$ @Mast Why would it be? Any random number generator is not completely random, it just follows a very complicated sequence that makes it seem random, so maximizing the results of that very complicated sequence (in a simple way of course, if anybody knows) is what I'm requesting, it can be a very small difference. \$\endgroup\$ – Mar Dev Dec 23 '15 at 8:35
  • 3
    \$\begingroup\$ @MarDev Changing the order of the character set does not make the generated password more or less random. It has no effect on randomness. \$\endgroup\$ – assylias Dec 23 '15 at 8:37
  • \$\begingroup\$ In some contexts it is a hassle to enter upper case letters, digits, and special characters. You can avoid all of that hassle by sticking with only lower case letters. In order to compensate for the security lost due to a smaller set of possible characters, you have to increase password length by 40%. It is still easier for the user to type in a password in all lower case letters, even if they have to type a few more. \$\endgroup\$ – kasperd Dec 23 '15 at 11:49
  • \$\begingroup\$ Unrelated, however something similar is also done in JavaScript here [bit.ly/2jSilhl] may be easy to replicate in java also. \$\endgroup\$ – Kzvi Feb 1 '17 at 0:29
3
\$\begingroup\$

Utility class convention

The convention for utility class (i.e. those that only have public static methods) is to final-ize them and mark their constructor private, so that they cannot be instantiated:

public final class PasswordGenerator {

    private PasswordGenerator() {
        // empty
    }

    // public static methods to follow
}

Other conventions

Placing () around your literal Strings is quite unconventional, the conventional form is easier to understand (and likely raises less questions from another Java developer):

public static final String VERSION = "1.0";
public static final String CHARACTER_SET = "aA1...";

Hard-coding

As mentioned in the other answers, you should not have to hard-code 65. Instead, relying on CHARACTER_SET.length() is good enough, and recommended so that the range of numbers returned by Random.next() follows any future modifications to your CHARACTER_SET's size.

Approach

The below password generator takes on a different approach that other basic password generators, creating an empty string of x length, x being the desired length of the final password, and inserting characters and sub-stringing. I would like to know if this fashion is more effective than adding random characters one-by-one

Why do you think this can end up being more effective? Strings in Java are immutable, meaning every concatenation of String values will create new instances of Strings.

To step through your generation literally:

// assuming length = 5
// start with 5 spaces
"     "
"a" + "    "
"a" + "b" + "   "
"ab" + "c" + "  "
"abc" + "d" + " "
"abcd" + "e"
"abcde"

That seems like an extremely roundabout way of concatenating five characters...

Understanding 'randomness'

Have I ensured the most random-ness of the characters in the password by using this character set?


Any random number generator is not completely random, it just follows a very complicated sequence that makes it seem random, so maximizing the results of that very complicated sequence (in a simple way of course, if anybody knows) is what I'm requesting, it can be a very small difference. - Yourself

I think your understanding of pseudo-random number generation (or 'sequence' as you refer to) is half-complete. Theoretically, 'jumbling' your character set may influence the 'randomness' if and only if it's used as an input to said generation. This theoretical generation can then appear to give 'random' values simply by iterating through the set character-by-character, or if the set's ordering is used to influence the derivation in some other manner.

However, since you are already relying on Random.nextInt(), which generation is independent of your character set, you do not have to worry about the ordering of said set.

\$\endgroup\$
3
\$\begingroup\$

Note: The 65 comes from the CHARACTER_SET length, which I have found out before.

It's 65 at the moment. But what if you want to support more or less characters? A different character set? You'd have to change those hard-coded values every time.

CHARACTER_SET.charAt(random.nextInt(65)

Can be replaced by:

CHARACTER_SET.charAt(random.nextInt(CHARACTER_SET.length())

There is one more hard-coded value in your code.

System.out.println(generatePassword(20));

Extract the 20 to it's own variable. This allows you to extend your program to, for example, ask for user input and use that value instead. Perhaps the user prefers 16 or 28.

\$\endgroup\$
3
\$\begingroup\$

SecureRandom.getInstanceStrong() returns a more secure Random implementation than Random itself, because Random uses the system time.

\$\endgroup\$
  • \$\begingroup\$ Just looked into it, it's compatible with what I'm doing, I will definitely do more research. Thanks! \$\endgroup\$ – Mar Dev Dec 23 '15 at 8:51
2
\$\begingroup\$

1) I would like to know if this fashion is more effective than adding random characters one-by-one

Your method is not very efficient because you create a lot of objects. Everytime you write password = ... + ... you create a new String.

The proper way to concatenate characters into a String is to either use a StringBuilder or create a char[65], populate each char and create a String from the char[] with new String(array).

2) Have I ensured the most random-ness of the characters in the password by using this character set?

You are picking the characters randomly - so whatever the order should not have any impact on the randomness of the password.

3) I also seek general reminders on java conventions that I do not know.

The brackets are redundant in public static final String VERSION = ("1.0");, and also in CHARACTER_SET.

You say "The 65 comes from the CHARACTER_SET length, which I have found out before". Well then make it clear! Ideally your code should be self explanatory. So instead of using 65, use CHARACTER_SET.length.

password.toString() is redundant: password is already a String...

Strings in Java are immutable, so prepopulating the string with spaces is a waste of time because that string will be discarded anyway.

\$\endgroup\$
  • \$\begingroup\$ Definitely accepted, one more question just came to mind. Should main() declaration follow declaration of generatePassword(...)? I know Java doesn't use forward declarations unlike C++, but is there any opinion on that? \$\endgroup\$ – Mar Dev Dec 23 '15 at 8:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.