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.

5
  • 2
    Why the 25 character upper limit? You're not storing it anywhere are you? Commented Sep 28, 2009 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. Commented Sep 28, 2009 at 20:40
  • 1
    I agree with the other upvoted answers, this is not a good fit for a regex Commented Oct 3, 2009 at 4: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! Commented Oct 13, 2009 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. Commented Oct 13, 2009 at 15:36

7 Answers 7

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; } 
Sign up to request clarification or add additional context in comments.

Comments

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.

Comments

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.

Comments

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.

2 Comments

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.
The list of symbolic characters can be expanded to [!@#$%&+-/`^)(|\=:;.,}{~?]
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.

Comments

0

I think it could be as follow too:

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

1 Comment

This requires the two digits (or others symbols in the same group) to be subsequent, e.g. !%34dfZXaaaaaaaa will work, !%3dfZXaaaaaaaa1 will not.
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.

Comments