8

This question is a follow up on the question here:

Why is char[] preferred over String for passwords?

That question is great for understanding why it is good to use a char[] instead of a String; however, it doesn't explain how to perform password validation on a char[] in a secure manner. That is what I would like to know about here.

Put simply, I need to check to see if a password meets the following requirements:

  • Contains at least one uppercase letter
  • Contains at least one lowercase letter
  • Contains at least one digit
  • Contains at least one symbol
  • Is at least n characters, but no more than m

Now I understand how I can use regular expressions to perform the validation... these answers show how to do that:

As far as I know, regular expression checks involve working with strings. It doesn't seem secure to use them because strings are immutable, and thus they cannot be cleared immediately after using them. A char[], on the other hand, can be cleared.

So, how can I perform validation on a password which is stored in a char[], and not a string?

I could iterate through each character, but then I would have to create each set that I want to test. Ideally, it would be useful to be able to take advantage of regular expressions.

In Java, I can do regular expressions check via the following methods.

String.matches(String regex)

Or

Pattern pattern = Pattern.compile(String regex);
pattern.matcher(CharSequence testString).matches();

As you can see, both methods do not support working directly with a char[].

Community
  • 1
  • 1
Nicholas Miller
  • 4,205
  • 2
  • 39
  • 62
  • No experience with doing so, so I don't know the security ramifications, but, you could compile your own `Pattern` and use `matcher(CharSequence)` – MadProgrammer Jul 24 '14 at 02:54

4 Answers4

5

I would try to avoid a complicated regex, I would suggest something like -

boolean validatePassword(char[] password, int n, int m) {
  if (password == null || password.length < n || password.length > m) {
    return false;
  }
  boolean upper = false;
  boolean lower = false;
  boolean digit = false;
  boolean symbol = false;
  for (char ch : password) {
    if (Character.isUpperCase(ch)) {
      upper = true;
    } else if (Character.isLowerCase(ch)) {
      lower = true;
    } else if (Character.isDigit(ch)) {
      digit = true;
    } else { // or some symbol test.
      symbol = true;
    }
    // This short-circuits the rest of the loop when all criteria are true.
    if (upper && lower && digit && symbol) {
      return true;
    }
  }
  return upper && lower && digit && symbol;
}
Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
  • Thanks! Although this doesn't use regex, it still does the validation. I was unaware of `Character.isLower/Upper/Digit()` fucntions. If the goal is to erase the password, shouldn't the local char[] be zeroed-out? – Nicholas Miller Jul 24 '14 at 03:56
  • @NickMiller Generally, I'd prefer to let the caller dispose of it. Once this method completes you know the password is valid only as a password (not a correct password per se), you haven't actually done anything with it yet (as far as this method knows anyway). – Elliott Frisch Jul 24 '14 at 03:57
  • Please correct me if I am wrong, but isn't the char[] inside the method a copy? And if it is a copy, it should be cleared out because we do not want to wait until the GC activates. – Nicholas Miller Jul 24 '14 at 04:04
  • 1
    @NickMiller *Good news*! You're incorrect. It is not a copy. Java is pass by value, but the value of Object(s), **including** Array(s), is the reference. – Elliott Frisch Jul 24 '14 at 04:06
  • Ah! I get it, the reference is copied, but both references point to the same memory! :) – Nicholas Miller Jul 24 '14 at 04:28
4

Just iterate through char[] to do basic password acceptance validation

jmj
  • 237,923
  • 42
  • 401
  • 438
3

You can use CharBuffer.wrap(char[]) to access the char array as a CharSequence.

Pattern.matches(regex, CharBuffer.wrap(myCharArray))
holmis83
  • 15,922
  • 5
  • 82
  • 83
2

Java's regex implementation does not require String objects - you are expected to pass a CharSequence. If you would rather not create a String from a char[] array, you could wrap an array in your own implementation of the CharSequence interface.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • I like this since `CharSequence` can contain a mutable `char[]` in the background. I could just restrict access and provide a function to clear the array when I'm finished. My only concern is whether or not the the regex functions store the character data. – Nicholas Miller Jul 24 '14 at 03:51