40
\$\begingroup\$

The domain server requires that all employees have a strong, random password conforming to the following rules:

  • Exactly 15 characters long.
  • Keyboard-typeable characters only (as shown in code-type below). Teaching the sales to use ALT+NUMPAD codes is not permitted.
  • At least 1 lower case letter: abcdefghijklmnopqrstuvwxyz
  • At least 1 upper case letter: ABCDEFGHIJKLMNOPQRSTUVWXYZ
  • At least 1 numeric digit: 0123456789
  • At least 1 symbol: `~!@#$%^&*()_+-={}|[]\:";'<>?,./

For this purpose IT have commissioned and will be distributing a Random Password Generator to all employees. All employees will be required to use the Random Password Generator. The requirements for the Random Password Generator are, in addition to the password restrictions above:

  • It must be able to generate all permutations of all allowable characters.
  • It must display the generated password on the screen.
  • The code is required to be as small as possible (in bytes).

Please submit your proposed solution within the next week.

\$\endgroup\$
13
  • 10
    \$\begingroup\$ You should also demand that all passwords which are allowed appear with the same probability (otherwise I can simply make a 30 characters long list with allowed characters, shuffle it, and give the first 15 ones) \$\endgroup\$ Commented Jan 5, 2014 at 22:36
  • \$\begingroup\$ @moose, agreed. I've added a new rule. \$\endgroup\$ Commented Jan 5, 2014 at 22:53
  • 22
    \$\begingroup\$ The IT guys should be fired, or at least better educated: If you do generate passwords randomly, then restricting the set of permissible passwords to those which include at least one character of each category in fact weakens the passwords, since it reduces the size of the permissible set. And our programs would be that much easier if we didn't have to check for that… OK, don't modify the contest after so many submissions have arrived; it's fine as a challenge. \$\endgroup\$
    – MvG
    Commented Jan 6, 2014 at 5:15
  • 10
    \$\begingroup\$ @MvG Indeed: correcthorsebatterystaple \$\endgroup\$ Commented Jan 6, 2014 at 5:46
  • 1
    \$\begingroup\$ You haven't really answered @moose by requiring that all passwords be generatable. They should appear with equal probability. \$\endgroup\$ Commented Jan 6, 2014 at 14:53

37 Answers 37

1
2
0
\$\begingroup\$

PHP 5.5 (230 bytes)

echo preg_replace_callback('/./', function ($a)
{
  return chr([rand(33, 126), rand(48, 57), rand(65, 90), rand(97, 122), ord(str_shuffle('`~!@#$%^&*()_+-={}|[]\:";\'<>?,./')[0])][$a[0]]);
}
, str_shuffle(str_pad('1234', 15, 0)));

Or on one line (211 bytes)

echo preg_replace_callback('/./',function($a){return chr([rand(33,126),rand(48,57),rand(65,90),rand(97,122),ord(str_shuffle('`~!@#$%^&*()_+-={}|[]\:";\'<>?,./')[0])][$a[0]]);},str_shuffle(str_pad('1234',15,0)));
\$\endgroup\$
0
\$\begingroup\$

Perl (134 characters)

Perl one-liner::

perl -e 'push @a,map{(33..47,58..64,91..96,123..126)[rand (32)]}1;push @a,map{(65..90)[rand(26)]}1;push @a,map{(97..122)[rand(26)]}1;push @a,map{(48..57)[rand(10)]}1;push @a,map{(33..126)[rand(10)]} 1..11;foreach (@a){print chr($_);}'

The Output:

_Gj2()%%&)$#"%&
$Vn7"#"'#%*&$%(
]Tj2*'%)&"#"#(%

Update:

perl -MList::Util=shuffle -e 'push @a,map{(33..47,58..64,91..96,123..126)[rand (32)]}1;push @a,map{(65..90)[rand(26)]}1;push @a,map{(97..122)[rand(26)]}1;push @a,map{(48..57)[rand(10)]}1;push @a,map{(33..126)[rand(10)]} 1..11; @a=shuffle @a;foreach (@a){print chr($_);}'
\$\endgroup\$
5
  • \$\begingroup\$ It is a small sample but the punctuation signs seem to appear a lot more than numbers or letters... \$\endgroup\$
    – assylias
    Commented Jan 6, 2014 at 18:53
  • \$\begingroup\$ This approach uses the categories in a fixed order, so it doesn't allow all possible passwords. \$\endgroup\$
    – MvG
    Commented Jan 7, 2014 at 12:56
  • \$\begingroup\$ @assylias : It is randomized selection so no-one can predict it, n' in some runs you can get more of alphabets and numbers than the punctuation mark. And for what it matters, it satisfies all the above mentioned criteria for a strong password. Please, do correct me if I am missing something. \$\endgroup\$ Commented Jan 8, 2014 at 5:10
  • \$\begingroup\$ @MvG: Thanks for pointing it out, I fixed it. Please see for the Update. \$\endgroup\$ Commented Jan 8, 2014 at 5:13
  • \$\begingroup\$ Now you are using the characters from the different categories in random order, but still in fixed proportion. Which is why you have so many more symbols in your examples than one would expect, as assylias pointed out. \$\endgroup\$
    – MvG
    Commented Jan 8, 2014 at 6:37
0
\$\begingroup\$

Python 3.3 (360 characters)

First generate a random character from each list, to ensure the first rule.
Them add a random sample from the whole group of allowed characters to complete the rest of the password.
Now we have a random sequence of 15 chars (a seed), with at least one of each, but the first 4 are always, in order, a lower, an upper, a numeric and a symbol. So we shuffle the seed, thus allowing all possible and valid passwords to be generated.

from random import sample

lower = 'abcdefghijklmnopqrstuvwxyz'
upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
numeric = '0123456789'
symbol = '''`~!@#$%^&*()_+-={}|[]\:";'<>?,./'''

seed = sample(lower, 1) + sample(upper, 1) + sample(numeric, 1) + sample(symbol, 1) +\
   sample(lower + upper + numeric + symbol, 11)
pwd = ''.join(sample(seed, 15))
print(pwd)
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Since this is code-golf, you should add character (or byte, in this case) count to your post. \$\endgroup\$
    – Vereos
    Commented Jan 7, 2014 at 10:26
0
\$\begingroup\$

F#, 67 66 59 characters

Using the same framework method as the C# solution, but obviously F# is shorter:

Web.Security.Membership.GeneratePassword(15,1)|>printf "%s"

I don't need to specify System, apparently.

\$\endgroup\$
0
\$\begingroup\$

Bash (111 bytes)

a=`strings /dev/urandom | head -c 512 | iconv -f utf-8 -t us-ascii//TRANSLIT | tr -d '\n' | head -c 15`
echo $a

Example outputs:

bw?<{qqH$lh}VC2
M)2@(nH9IdkOwYh
x;&_IR)NM7bCNd~
\$\endgroup\$
0
\$\begingroup\$

C++11 (489 characters)

#include <algorithm>
#include <iostream>
#include <string>
#include <random>
using namespace std;random_device r;uniform_int_distribution<> d4(0,3),d10(0,9),d26(0,25);
char rc(int t){int i=0;switch(t){case 0:i=48+d10(r);break;case 1:i=32;case 2:i+=65+d26(r);break;case 3:i=33+[](unsigned j){return j<15?j:j<22?j+10:j+68;}(d26(r));}return char(i);}
int main(){string s(15,0);int i=0;for(;i<4;i++){s[i]=rc(i);}for(;i<15;i++){s[i]=rc(d4(r));}random_shuffle(s.begin(),s.end());cout<<s<<endl;}

Update: stripped down from 673 to 489 characters

\$\endgroup\$
1
  • \$\begingroup\$ That's kind of the point; to reduce the code size to as small as possible. \$\endgroup\$
    – Timtech
    Commented Jan 9, 2014 at 15:25
-1
\$\begingroup\$

Perl (73 characters)

sub x{@x=map{chr rand6+6*$_+27%122}1..15;print splice@x,rand@x,1 while@x}

Maybe someone can minify it more..

\$\endgroup\$
1
  • \$\begingroup\$ The requirement “It must be able to generate all permutations of all allowable characters.” is not satisfied. For example, the first generated symbol will be between 33 and 37. Even if you reoder afterwards, the fact that your password must contain one of these six letters remains. Other passwords cannot be the result of your code. \$\endgroup\$
    – MvG
    Commented Jan 6, 2014 at 8:48
1
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.