3

Here is the .NET Regular Expression that I am using to create a strong password (which is not correct for my project password requirements):

(?=^.{15,25}$)(\d{2,}[a-z]{2,}[A-Z]{2,}[!@#$%&+~?]{2,})

Password requirements:

  1. Minimum 15 Character (up to 25)
  2. Two Numbers
  3. Two Uppercase Letters
  4. Two Lowercase Letters
  5. Two Special Characters ! @ # $ % & + ~ ?

They are not required to be beside one another & in the specific order as the Regular Expression that I pasted requires.

The above Regular Expression requires a password like this: 12abCD!@QWertyP

It REQUIRES them in the specific order in the RE... which is not what I want!

This should pass a correctly formatted RE with the specifications listed above: Qq1W!w2Ee#3Rr4@Tt5

How can I remove the necessity for them to be beside one another and in order?? Obviously the password should be random if the person so chooses.

Jeff Atwood
  • 63,320
  • 48
  • 150
  • 153
  • 2
    Why the 25 character upper limit? You're not storing it anywhere are you? – Bob Kaufman Sep 28 '09 at 20:32
  • Sorry for chitchat but would not be smarter to choose minimum password length based on "entropy". For instance - lowcase or upcase 40 characters, lower and upper leters 30, upcase+lowcase+numbesr 25, all printable set 15 characters minimum. I personaly always hate when i have to cose from such restrictions. – Luka Rahne Sep 28 '09 at 20:40
  • 1
    I agree with the other upvoted answers, this is not a good fit for a regex – Jeff Atwood Oct 03 '09 at 04:02
  • Yes, we are storing the password in the database. I agree with most everyone that this is not a good use for the REGEX and have moved on to a random password generator to provide the password that will be created for the user, e-mailed to them, and stored in the DB. THANK YOU for your excellent contributions and hard work on this question! –  Oct 13 '09 at 15:34
  • The password minimum was 15 characters, but I just grabbed an arbitrary number (25) as the upper limit. Not many people want to have a 15 character password, let alone a 25 character. –  Oct 13 '09 at 15:36

7 Answers7

10

I think you're looking for more than what a regex was designed to do.

Consider a C#/VB method like this:

bool IsStrongPassword( String password )
{
    int upperCount = 0;
    int lowerCount = 0;
    int digitCount = 0;
    int symbolCount = 0;

    for ( int i = 0; i < password.Length; i++ )
    {
        if ( Char.IsUpper( password[ i ] ) )
            upperCount++;
        else if ( Char.IsLetter( password[ i ] ) )
            lowerCount++;
        else if ( Char.IsDigit( password[ i ] ) )
            digitCount++;
        else if ( Char.IsSymbol( password[ i ] ) )
            symbolCount++;
    }

    return password.Length >= 15 && upperCount >= 2 && lowerCount >= 2 && digitCount >= 2 && symbolCount >= 2;
}
Bob Kaufman
  • 12,864
  • 16
  • 78
  • 107
3

This will be much more readable and maintainable in classic code:

The pseudo-code would be:

int count_alpha = 0, count_digit = 0, count_symbol = 0, ...

for each ch in password:
  if is_alpha(ch):
     count_alpha += 1
  elif is_digit(ch):
     count_digit += 1
  ...

if (count_alpha < 2) or (count_digit < 2) or ...
  rejection_message() 
  ...

It might be that you're implementing the requirements rather than in a position to influence them, but I'd generally recommend estimating the entrophy and using existing code to do that.

Will
  • 73,905
  • 40
  • 169
  • 246
2

As far as I know, you cannot do that reasonably, meaning you'd have to list all possible order combinations in the regex, which would add up to 24 combinations.

I would do 4 separate checks:

  • \d{2,}
  • [a-z]{2,}
  • [A-Z]{2,}
  • [!@#$%&+~?]{2,}

Related question: Variable order regex syntax

As an aside, your rules look too cumbersome to me I would reconsider them, for example, to have 3 chars of two of etters, digits or symbols.

Community
  • 1
  • 1
Vinko Vrsalovic
  • 330,807
  • 53
  • 334
  • 373
1
^(?=.*\d.*\d)(?=.*[a-z].*[a-z])(?=.*[A-Z].*[A-Z])(?=.*[!@#$%&+~?].*[!@#$%&+~?]).{15,25}$

This regex will do what you want. It will be making up to 5 passes through your password string, but considering what you are doing with it, I don't expect that to be a problem.

Edited to fix a typo that ruined the regex.

Paul Williams
  • 617
  • 1
  • 7
  • 17
  • If you expect to be given super-long strings, you could create a variant of this where the check for character count comes first. Since you are matching the entire string anyway, the character count step could be part of a lookahead as well, saving you from having to rewrite any other portion of the expression. – Paul Williams Sep 28 '09 at 21:02
  • The list of symbolic characters can be expanded to [!@#$%&+-/`^)(|\=:;.,}{~?] – Doguhan Uluca Jun 02 '11 at 16:07
0

To require one of each character type, you can use this:

(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%&+~?])^.{15,25}$

I'm not quite sure how to translate that to require two of each character type, though.

Basically, the ?= matches a suffix to .* (i.e. anything), but doesn't capture anything, so you can check that all of the conditions are met specifying order.

bdukes
  • 152,002
  • 23
  • 148
  • 175
0

I think it could be as follow too:

^(?=(.\d){2,})(?=(.[a-z]){2,})(?=(.[A-Z]){2,})(?=(.[!@#$%&+~?]){2,})).{15,25}$

  • This requires the two digits (or others symbols in the same group) to be subsequent, e.g. !%34dfZXaaaaaaaa will work, !%3dfZXaaaaaaaa1 will not. – Kcats Oct 05 '09 at 14:16
0
^((?=(.*\d){2,})(?=(.*[a-z]){2,})(?=(.*[A-Z]){2,})(?=(.*[!@#$%&+~?]){2,})).{15,25}$

I know this is a year old, but from the few responses, I gathered that this would work.

The top answer is correct except, it just needs a * preceding the pattern.

CrazyEnigma
  • 2,824
  • 1
  • 17
  • 17