All,
I recently encountered a situation where strong passwords that were changed regularly weren't very strong at all for anyone who knew the "standard format". Before I show the code, I will demonstrate the math.

If you use upper/lower case letters, numbers, and just 10 special characters, each position in a password can have 72 possible values. If you require an 8 character password, this is 722_204_136_308_736 possible passwords. If you use a standard format for passwords to make them easier to remembering, you may be dramatically reducing that keyspace.

In this hypothetical example, 'a5X11y%B' may be one of the passwords generated but you only need to know 'a5X1' to know the whole password. Let me explain:

• The 1st character is always lowercase a-z
• The 2nd character is always a number 0-9
• The 3rd character is always uppercase A-Z
• The 4th character is always a number 0-9
• The 5th character is always the 4th character
• The 6th character is always the next lowercase letter after the 3rd character
• The 7th character is always the special character associated with the number of the 2nd character
• The 8th character is always the next uppercase letter after the 1st character
This has a key space of 26 * 10 * 26 * 10 = 67_600 and can easily be cracked using brute force.

```#!/usr/bin/perl
use strict;
use warnings;
use Algorithm::Loops 'NestedLoops';
use Win32::OLE;

my \$file = \$ARGV[0] or die "Usage: \$0 <file>";   # Important to use fu
+ll path

# Win32::OLE Example Program
my \$word;
eval {\$word = Win32::OLE->GetActiveObject('Word.Application')};
die "MSWord not installed" if \$@;
\$word = Win32::OLE->new('Word.Application') or die "Can't start Word"
+if ! defined \$word;
\$word->{Visible} = 1;

my @key = (['a' .. 'z'], [0 .. 9], ['A' .. 'Z'], [0 .. 9]);
my \$next = NestedLoops(\@key);

while (my @half = \$next->()) {
my \$pass = Gen_Pass(@half);
my \$doc = \$word->{Documents}->open({
'FileName'         => \$file,
});
next if ! defined \$doc;
print "\$pass\n", last;
}

sub Gen_Pass {
my @pass = @_;
my %conv = (
1 => '!', 2 => '@', 3 => '#', 4 => '\$', 5 => '%',
6 => '^', 7 => '&', 8 => '\$', 9 => '(', 0 => ')',
);
my (\$third, \$first) = @pass[2, 0];
push @pass, \$pass[-1];                   # Duplicate the 4th numbe
+r
push @pass, lc substr(++\$third, 0, 1);   # Increment 3rd char and
+lc it
push @pass, \$conv{\$pass[1]};             # Convert 2nd num to a sp
+ec char
push @pass, uc substr(++\$first, 0, 1);   # Increment 1st char and
+uc it
return join '', @pass;
}
I do not endorse this type of activity for any other purpose then to help educate and institute change in policy. This is a contrived example and does not represent the "format" I actually saw. I was able to whip up less than 15 lines of code using Win32::OLE and Algorithm::Loops and found the password in approximately 10 minutes. The policy on passwords is changing as a result.

Cheers - L~R

Replies are listed 'Best First'.
Re: Demonstrate Weakness of "Standard Format" Passwords
by CountZero (Bishop) on Nov 11, 2005 at 19:21 UTC
It is indeed very silly to put such artificial constraints on passwords. As a matter of fact any constraint on the composition of passwords will dramatically reduce the keyspace and is therefore a bad idea.

On the other hand you cannot entrust users to choose their own passwords or you get names of pets, birthdates and abc123 all over the place.

Only fully random passwords offer any real level of security but nobody will be able to remember them and then start writing them on scraps of paper which are "hidden" under the keyboard.

I did have some success with the Crypt::GeneratePassword module which generates "pronounceable" random passwords. The keyspace is of course not as large as a truly random password generator but for all but the most critical application it seems OK.

CountZero

"If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

As a matter of fact any constraint on the composition of passwords will dramatically reduce the keyspace and is therefore a bad idea.

I strongly disagree with this assertion for one particular constraint... Disallow "words". I.e. dictionary words, names, pop culture words, jargon, etc. That one's a must and crack (or your favorite replacement) with a good set of dictionaries should be run regularly to make sure it is enforced. There are some other good restraints: disallowing dates, phone numbers, and bible verse references for instance.

```-sauoq
"My two cents aren't worth a dime.";
```
Re: Demonstrate Weakness of "Standard Format" Passwords
by Anonymous Monk on Nov 11, 2005 at 18:14 UTC
I'd also endorse this activity for when a person forgets their password or someone at work is maliciously hiding data, etc.
diotalevi,
That is your perogative, but not mine. There are much more effective ways of password recovery than brute force attacks. Password cracking without authorization is a precarious activity to engage in. This is all I am going to say on the matter. Legal matters aside, everyone has their own conscience to listen to.

Cheers - L~R

I figured it would go without saying that you'd only be doing this stuff if you were supposed to be. You know, if its your job to do this or something like that.