I'd like to sum up what has been discussed on my question about basic checks on password; What follows could be further discussed and improved and then, if you like, go to code snippets or categorized q/a.

The question

First of all, the question was:

What I need is to do just a minimal check, in particular:

  • password is at least 5 characters long;
  • password contains alphabetic characters and digits
  • password isn't a repetition of a few characters or patterns (e.g.: "pippo12": too many p's; "cacca11": only c's and a's, and widely repeated; "32ratatata": the pattern "ta" appears 3 times and covers 60% of the password...)

While the first two points are really easy to code:

. . .

I'm not sure how to manage the third point in a clear and efficient manner . . .

What's basic, anyway?

An old ugly programming language, one could say :-)

After reading monks' comments I went back to my Essential System Administration book (2nd edition, unfortunately :-). At page 210, speaking about Password Triviality Checks, it broadly says that the passwd command (she's speaking about UNIX passwords) may reject passwords that are:

Speaking about the SCO(TM) UNIX'goodpw program, she then shows some examples of passwords that would be rejected for the user chavez:

There have been interesting considerations about repeated characters or sequences. I share the opinion expressed by an Anonymous Monk, even if agree that 'ppppp' isn't more difficult to crack than 'abcde' or 'qwerty'.

What do you mean for basic, then?

Now, the requirement in the original question was to have something clear and efficient; in particular, waiting for more that a second to have the password check is not acceptable.

I ran john the ripper against my password, with a dictionary of nearly 187000 words it took 44 seconds: too much; we have to drop some requirements to have a real basic check:

Therefore, here is what we'll consider "a minimal check for passwords":

Ok. I would you code that?

Personally? This is my first attempt:

#!/usr/bin/perl # # call this file passcheck.pl in order to test it with the # test script use strict ; use warnings ; sub passcheck { my ($username,$password,$name,$surname,$city) = @_ ; my ($minlen,$maxlen,$maxfreq) = (5,8,.5) ; my $plen = length $password ; my $pclean = lc $password ; $pclean =~ s/[^a-z]//g ; my %prots = map {$_,qr/$_/} ($pclean,leftrotations($pclean)) ; # Check length { return "password is too short" if $plen < $minlen ; return "password is too long" if $plen > $maxlen ; } # Check repetitions { my @chars = split //,$password ; my %unique ; foreach my $char (@chars) { $unique{$char}++ } ; while (my ($char,$count) = each %unique) { return "Too many repetions of char $char" if $count/$plen > $maxfreq ; } } # Check password against username, name, surname and city # All but username could be composed, like "Alan Louis", or "Di Cioc +cio" # or "Los Angeles", so we have to treat each chunk separately. { my %chunks = map { ($_,qr/$_/) } split(/\s+/,lc(join(" ",$name,$surname,$city))) ; # Add username to %chunks # You can compact the code below in one line, but why? :-) { my $lcuser = lc $username ; $chunks{$lcuser} = qr/$lcuser/ ; } foreach my $chunk (keys %chunks) { foreach my $rot (keys %prots) { return "password matches personal data after some left rotatio +n" if $rot =~ $chunks{$chunk} or $chunk =~ $prots{$rot} ; } } } # Left rotations of the password don't match it { foreach my $rot (leftrotations($password)) { return "Password matches itself after some left rotation" if $rot eq $password ; } } # Password contains alphas, digits and non-alpha-digits { local $_ = $password ; return "Password must contain alphanumeric characters, digits and +symbols" unless /[a-z]/i and /\d/ and /[^a-z0-9]/i ; } return "password ok" ; } sub leftrotations { my $string = shift ; my $n = length $string ; my @result ; # note: $i < $n, since the n-th permutation is the password again for (my $i = 1 ; $i < $n ; $i++) { $string =~ s/^(.)(.*)$/$2$1/ ; push @result,$string ; } return @result ; } 1 ;

I tested it with this small test script:

#!/usr/bin/perl use Test::More qw(no_plan) ; my ($username,@userinfo) = qw(bronto Marco Marongiu Capoterra) ; my $good = 'c0m&c@z%' ; my @passwords = qw(shrt waytoolong manyyyyy nto12bro% comar1$ marmaron poterr@1 t1c&t1c& pitbull) ; my $ok = "password ok" ; require './passcheck.pl' ; is($ok,passcheck($username,$good,@userinfo),"$good is good") ; isnt($ok,passcheck($username,$_,@userinfo),"$_ is bad") foreach @passw +ords ;

Would you like to improve those subs with me?

Ciao!
--bronto


The very nature of Perl to be like natural language--inconsistant and full of dwim and special cases--makes it impossible to know it all without simply memorizing the documentation (which is not complete or totally correct anyway).
--John M. Dlugosz

edited: Tue Jul 29 14:01:03 2003 by jeffa - readmore tag


In reply to Minimal password checking: a summary by bronto

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.