Random Password Generator

40

7

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.

Hand-E-Food

Posted 2014-01-05T22:03:41.630

Reputation: 7 912

10You 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) – Martin Thoma – 2014-01-05T22:36:34.107

@moose, agreed. I've added a new rule. – Hand-E-Food – 2014-01-05T22:53:03.070

22The 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. – MvG – 2014-01-06T05:15:53.640

Password Generator (mkpasswd) (Python recipe) – Grijesh Chauhan – 2014-01-06T05:45:02.503

10

@MvG Indeed: correcthorsebatterystaple

– Jonathon Reinhart – 2014-01-06T05:46:22.987

Well, technically those passwords are safe, but you can be 150% sure that they will be written down by everyone. This reminds me of https://codegolf.stackexchange.com/questions/6203/security-by-post-it, but it isn't a duplicate (because that one was about verifying).

– Konrad Borowski – 2014-01-06T08:21:08.387

"It must be able to generate all permutations of all allowable characters." If you enforce that rule strictly, most answers will be invalid since the underlying PRNG is too bad. In many languages it's seeded by a 32 bit value which is obviously not enough to generate all possible values of such a complex password. – CodesInChaos – 2014-01-06T08:51:35.853

Just give everyone "Passw@rd1234" . They'll never suspect anyone else has the same password! – Carl Witthoft – 2014-01-06T13:08:53.143

@CodesInChaos for simplification we can probably assume true rng? – Cruncher – 2014-01-06T14:15:17.787

1You haven't really answered @moose by requiring that all passwords be generatable. They should appear with equal probability. – Ethan Bolker – 2014-01-06T14:53:57.290

@EthanBolker: Well, I guess that is now ok. It would be quite difficult to check if it really is with equal probability. And probably the only solutions that would come out of this would be "generate and test" ones. – Martin Thoma – 2014-01-06T14:59:29.283

@xfix I wouldn't even dare put the word "safe" near to such a broken password system. Firing the security guys should not be enough for such a mistake, you should also fire the guy who hired them. – o0'. – 2014-01-06T15:05:26.577

@CodesInChaos I don't see why a true RNG is required to create all possible passwords. To generate all possible passwords with equal probability, yes. But (unless I'm misunderstanding something) the PRNG limitation you describe does not preclude one from meeting the requirements specified above. Certainly, you could not generate all possible passwords from a single output of the PRNG. But if every character was individually generated according to separate PRNG outputs, as is done in my answer (and I'm sure some others), you need a very small fraction of that 32-bit PRNG space. – Iszi – 2014-12-07T09:56:35.930

Answers

29

Mathematica (18)

Let me a little cheat

= 15char ASCII pwd
&(^F7yP8k:*1P<t

P.S. not safety :)

ybeltukov

Posted 2014-01-05T22:03:41.630

Reputation: 1 841

6Where's the code? – DavidC – 2014-01-05T23:38:56.997

11Is that guaranteed to satisfy the at least one of each character class requirement? – Hand-E-Food – 2014-01-05T23:42:25.497

@DavidCarraher when you print "=" then the following will be converted to WolframAlpha expression. It is roughly the same as WolframAlpha["ASCII password 15 char"]. – ybeltukov – 2014-01-05T23:51:59.577

3@Hand-E-Food Yes, it is! If you look at the interpretation you will see: password length 15, lower-case letters required, upper-case letters required, numbers required, special characters required. – ybeltukov – 2014-01-05T23:53:40.930

6+1 Clever, but sneaky. – DavidC – 2014-01-05T23:54:17.243

That's great! :-D – Hand-E-Food – 2014-01-05T23:58:37.403

10I knew that Mathematica has a function for everything, but this? – Konrad Borowski – 2014-01-06T08:23:42.850

1Wolfram Alpha states that there are about 10³⁴ passwords with the given properties, corresponding to 113 bit of entropy. The question statement allows only for 315853215942003667374440448000<10³⁰ passwords or 98 bit, so it seems Wolfram Alpha should generate huge amounts of passwords that don't satisfy the criteria. It is therefore very surprising that we haven't noticed a single one non-conforming password. The most plausible reason is that they give a wrong number. They also don't specify a list of the special characters they use, so I doubt whether that agrees with the question. – MvG – 2014-01-06T09:14:27.687

3@MvG From 200-char password with special symbols only I've got !@#%^&*()_-+=~`{[}]|\<>.,;"?'/:$ after deleting duplicates. It looks like the list in the question. – ybeltukov – 2014-01-06T13:11:09.837

13

Ruby, 74 69 bytes

Just randomly sample from the ascii range 33 - 126 until all classes of characters are present:

$_=[*?!..?~].sample(15)*''until~/\d/&&~/[a-z]/&&~/[A-Z]/&&~/\W|_/
p$_

Ruby, 39 bytes

Using moose's clever discovery:

p"0123abcdABCD-+/<".chars.sample(15)*''

Edit to satisfy the mob:

Note that the rules changed after I first posted this. At the time both the previous entries applied to the rules. I would also like to point out that the rules are still not too well defined:

(..) all permutations of all allowable characters

"Permutations". There are no permutations of the allowable characters that complies with the rest of the rules, because any permutation of the set of allowable characters is as long as the set of allowable characters itself (while the password is supposed to be 15 characters long). And there are no repetitions in a permutation. However my first entry is still more "random" than many of the other well upvoted answers here.

Nevertheless, here you have it. Allows repetitions of characters and underscore:

Ruby, 77 bytes

$_=([*?!..?~]*15).sample(15)*''until~/\d/&&~/[a-z]/&&~/[A-Z]/&&~/\W|_/
puts$_

I also used puts instead of p in this one because p prints out the string enclosed in "quotation marks" and some characters escaped with a backslash.

Ruby, 70 bytes

As Ventero points out, ~ can be skipped in front of the regexes, and print can replace puts$_. But with the ugly output this causes you might as well print all the rejected passwords too, squeezing it into a one-liner:

puts$_=([*?!..?~]*15).sample(15)*''until/\d/&&/[a-z]/&&/[A-Z]/&&/\W|_/

Explanation

As requested. $_ is a semi-magical variable that contains the last line read from input - so you don't always need to store it, like this. Here however we use it because of another property, namely that the ~ operator applies a regex directly to it, a trick I first learned by chron. I replaced the usage of all, but it should be quite easy to understand if you get the rest (see the docs).

daniero

Posted 2014-01-05T22:03:41.630

Reputation: 17 193

+1 This is the way I would have done it, but not in Ruby. – Tim Seguine – 2014-01-05T22:55:16.357

2Could you please explain your code a bit? What does .all?{|r|~r} do? What does $_= do? – Martin Thoma – 2014-01-05T23:41:59.757

You can make it a little shorter without the call to #all?, something like: until~/\d/&&~/[a-z]/&&~/[A-Z]/&&~/\W/ – Paul Prestidge – 2014-01-06T03:23:32.537

3The sample line is clever and all, but I think it violates "It must be able to generate all permutations of all allowable characters." Nowhere does it says that the password may only contain a-d as far as letters are concerned. If z is an allowed character, there should be a chance >0 that z is in the password. – nitro2k01 – 2014-01-06T05:07:44.240

1Does \W in Ruby include the underscore _? In most regex dialects I know it does not. And if your code could not generate passwords where a single _ was the only non-alphanumeric symbol, then it would violate one requirement. The second approach very obviously violates that requirement, but I guess it wasn't phrased correctly at that time. – MvG – 2014-01-06T05:09:12.443

1

@MvG: You're correct. \W does not contain an underscore in Perl-compatible RegEx (source).

– Martin Thoma – 2014-01-06T08:42:16.287

1

Furthermore, your solution is affected by the same problem @moose and I had with Python: sample does not repeat elements, so passwords with repeated elements cannot be generated by your code.Can you fix these two issues to make your answer conform to the question? Seeing how yours is the leading solution, excepting Wolfram Alpha, it would be nice to see whether you can conform and still keep the lead. I guess it shouldn't be too hard.

– MvG – 2014-01-06T10:26:29.480

1@moose @Mvg @nitro2k01 see edit. @chron thanks! the usage of all? saved some spaced at first because I assigned the string to another variable and had to use s=~r. Then I remembered your (!) assign-to-$_ trick but forgot to replace all?. – daniero – 2014-01-06T16:55:19.453

1print (with an implicit $_) is shorter than puts$_ (and I don't see a requirement for a trailing newline in the output). If you don't mind generating some warnings you can drop all the unary ~ operators. – Ventero – 2014-01-06T17:19:39.897

12

Java 8 - 354 329 319 275 267 characters

Just for fun, using lambdas with Java 8 - each possible output has the same probability of being found.

It uses the fact that the allowed characters have consecutive ascii codes, from 33 to 126.

class A {
    //flags for, respectively, small caps, large caps, digits, punctuation
    static int a, A, d, p;

    public static void main(String[] x) {
        String s;
        do {
            //Using special String constructor that takes an int[]
            s = new String(new java.util.Random().ints(15, 33, 127)
                                .toArray(),
                           0, 15);
            a = A = d = p = 0;
            s.chars()
                .map(c ->
                      c > 96 & c < 123 ? a = 1
                    : c > 64 & c < 90  ? A = 1
                    : c > 47 & c < 58  ? d = 1
                    : (p = 1))
                .min();
        } while (a + A + d + p < 4);
        System.out.println(s);
    }
}

Sample output:

.*;Tm?svthiEK`3  
o.dzMgtW5|Q?ATo  
FUmVsu<4JF4eB]1

Compressed program:

class A{static int a,A,d,p;public static void main(String[]x){String s;do{s=new String(new java.util.Random().ints(15,33,127).toArray(),0,15);a=A=d=p=0;s.chars().map(c->c>96&c<123?a=1:c>64&c<90?A=1:c>47&c<58?d=1:(p=1)).min();}while(a+A+d+p<4);System.out.println(s);}}

assylias

Posted 2014-01-05T22:03:41.630

Reputation: 223

How about while(a+A+d+p<4) together with a|=1 instead of a++? Or use bitmasks, i.e. stuff like a|=1 through a|=8, with a<15 as loop condition. This saves another 13 chars if I counted correctly. – MvG – 2014-01-06T05:04:52.427

@MvG good point - did something similar, saving a couple extra chars I believe. – assylias – 2014-01-06T09:33:06.810

@MvG And using new String(int[],int,int) saves another 40-odd chars! – assylias – 2014-01-06T09:41:03.067

8

Python 2.X + 3.X (229 characters): Generate and replace

Idea

  1. First make a list with 15 allowed symbols
  2. Replace a random position r by a random digit
  3. Replace a random position s, with s != r, by an upper case letter
  4. The same for lower case letter and symbol as in 2 and 3.

Code

from random import randint as r, shuffle as s
a=list(range(15))
p=a[:]
for i in range(15):
    a[i]=chr(r(32,126))
s(p)
a[p.pop()]=chr(r(48,57))
a[p.pop()]=chr(r(65,90))
a[p.pop()]=chr(r(97,122))
a[p.pop()]=chr(r(33,47))
print(a)

Python 2.X + 3.X (194 characters): Generate and check

import random
from re import search as s
p=''
while not all([s("\d",p),s("[a-z]",p),s("[A-Z]",p),s("[\W_]",p)]):
 p=str(map(chr,[random.choice(list(range(33,127))) for i in range(15)]))
print(p)
  • Thanks to MvG who told me that \u and \l does not exist in Python regex.
  • Thanks to grc who told me that random.sample is without replacement, be to get every possible allowed password we need sampling with replacement.

Using flaw in the problem description

Currently, the problem description does not demand that every symbol / digit appears with the same probability. With the following solution, you cannot make any assumption about a single symbol and/or position. But you can do it with multiple ones.

Python 2.X+ 3.X (62 characters)

from random import sample
print(sample("0123abcdABCD-+/<",15))

Thanks to daniero for the idea to use sample.

Martin Thoma

Posted 2014-01-05T22:03:41.630

Reputation: 669

Very smooth finding the flaw! I've plugged that one, but bonus points for identifying it. :-) – Hand-E-Food – 2014-01-05T22:59:27.423

Your gen&check is similar to my approach. Out of curiosity:where is this \l and so on for python regexes documented? Don't see it in the reference. My Python 3.3.3 won't even accept "\u". The str(…) does not join the letters in either 3.3.3 or 2.7.6. One suggestion for optmization: all(s("\\"+i,p)for i in "dluW").

– MvG – 2014-01-06T04:09:43.167

random.sample chooses elements without replacement, so not all passwords are possible. – grc – 2014-01-06T07:15:22.730

@MvG: Thank you. I've just seen that \u and \l is vim-only. – Martin Thoma – 2014-01-06T08:36:39.167

7

Bash on *nix (109)

while ! grep -Pq [A-Z].*[a-z].*[0-9].*[\\W_]<<<$a$a$a$a
do a=`tr -dc !-~</dev/urandom|head -c15`
done
echo $a

To work correctly, $a must not be set to a valid but non-random password up front. If you want to include a= and a line break up front, that's three more characters but it allows you to run the thing repeatedly. You can obviously also replace all newlines with ; so you have a one-liner which you can execute as often as you whish.

Furthermore, you should have set LC_ALL=C or not set any locale-specific environment variables (LANG and LC_CTYPE in particular), since the character ranges depend on collation order being equal to ascii order.

/dev/urandom is the a source of random bytes. !-~ is the range of all permissible characters, as specified in the question. tr -dc removes all characters not listed in its next argument. head takes 15 of the remaining characters. grep checks whether each of the required kinds does occur at least once. Its input consists of four copies of the candidate, so order of the symbols does not matter, hence all possible passwords stand a chance of getting selected. The -q to grep suppresses output.

For reasons unknown, /dev/random instead of /dev/urandom takes ages. It seems like entropy got exhausted pretty quickly. If you cd into /dev, you can avoid some more bytes, but that feels a bit like cheating.

Python 2 (138)

import re,random
a=''
while not re.search('[A-Z].*[a-z].*[0-9].*[\W_]',a*4):
 a=''.join(random.sample(map(chr,range(33,127))*15,15))
print a

To make the code readable I added a newline and indentation after the loop which is not neccessary and which I did not count.

This is essentially the same idea as in the bash version. The random source here is random.sample, which will not repeat elements. To counter this fact, we use 15 copies of the list of permissible letters. That way, every combination can still occur, although those with repeated letters will occur less often. But I decide to consider this a feature, not a bug, since the question did not require equal probability for all permutations, only the possibility.

Python 3 (145)

import re,random
a=''
while not re.search('[A-Z].*[a-z].*[0-9].*[\W_]',a*4):
 a=''.join(random.sample(list(map(chr,range(33,127)))*15,15))
print(a)

One newline and one indent again not counted. Apart from some Python-3-specific syntax overhead this is the same solution as for Python 2.

JavaScript (161)

a=[];for(i=33;i<127;)a.push(s=String.fromCharCode(i++));
while(!/[A-Z].*[a-z].*[0-9].*[\W_]/.test(s+s+s+s))
for(i=0,s="";i<15;++i)s+=a[Math.random()*94|0];alert(s)

I added the newlines for readability, but did not count them.

R (114)

s<-""
while(!grepl("[A-Z].*[a-z].*[0-9].*(\\W|_)",paste(rep(s,4),collapse="")))
 s<-intToUtf8(sample(33:126,15,T))
s

Linebreak and indentation inside loop added but not counted. If you feel like it, you can again move this to a single ;-separated line.

MvG

Posted 2014-01-05T22:03:41.630

Reputation: 726

Ha! I was just about to point out that you could have used grepl in your R code. If only I'd thought of repeating the test password four times so you could do all the checks in one. And you know, if only I'd thought about sample and intToUtf8. However, you need to add replace=TRUE (or more concisely, you just need to add ,T) to your sample method to make sure you're getting all possible passwords. – AmeliaBR – 2014-01-06T06:26:07.957

@AmeliaBR: You are right, fixed that replace=T mistake, thanks for pointing this out. Finding intToUtf8 by guessing likely names with tab completion took me quite a while; I knew such a function has to exist, but the more common names like chr and so on were not used. – MvG – 2014-01-06T06:33:12.610

@MvG: I don't understand why your Python code terminates at all. Why do you need that *4? I thought your regex would match any string, that ad first one uppercase letter, then anything, then one lowercase letter, than anything ... what did I get wrong? – Martin Thoma – 2014-01-06T08:49:44.060

@moose: As you already noticed, my regex checks for the required categories in a specific order. But by taking the concatenation of four copies of the current candidate, I can ensure that the order no longer matters: Even if my password is symbols followed by digits followed by lowercase followed by uppercase, then there would still be a match. The only way a match can fail is if a category is missing altogether. Also note that I do re.search not re.match, so the regex might match anywhere in the candidate password. Does this explain why it will terminate eventually? – MvG – 2014-01-06T08:55:51.753

Ah, I did not notice that you use re.search instead of re.match. That explains it. But I still think you don't need the *4. Thank you for the explanation (+1) – Martin Thoma – 2014-01-06T09:09:28.190

@MvG: I think you can remove the inner join. This way, you have 9 characters less. – Martin Thoma – 2014-01-06T09:11:50.233

That is some clever regex! I was going to point out that it matches false positives, but after some thinking, I see it really will succeed. – IQAndreas – 2014-01-06T09:23:19.523

@moose: Here is how 'aaa0aaaaAaa.aaa'*4 matches against my regex: aaa0aaaa[A][a]a.aaa|aaa[0]aaaaAaa[.]aaa|aaa0aaaaAaa.aaa|aaa0aaaaAaa.aaa. | denote the concatenation seams, [.] the characters matched by each of the character classes. Thanks for the hint about the inner join! – MvG – 2014-01-06T09:25:07.947

@moose: Now I know what sample problem you are talking about. Hadn't read the comment by grc, and hadn't thought that the R issue AmeliaBR mentioned might affect other languages as well. Will need to fix that. – MvG – 2014-01-06T09:39:26.703

@moose: Fixed now. I decided to stay with random.sample since the overhead of random.choice is considerable. It's a bit sad, though, because I had such a sneaky idea there: I saved the first 15 bytes of my regexp into a string variable, and used that also in place of your range(15). The result was indeed shorter ­– by one byte, but no matter this small difference, I'm still immensely proud of this idea. So sad that sample is so much shorter… – MvG – 2014-01-06T10:03:49.143

Nice fix :-) (Although the solution is terrible in terms of runtime ... but that's not a matter for this codegolf :-)) – Martin Thoma – 2014-01-06T10:14:45.877

JavaScript version could be shorten using for(i=15,s="";i--;) – Florent – 2014-01-07T14:19:54.263

7

C# (123 - 139 103 - 127 characters compacted):

Using a perfectly adequate framework method in System.Web.dll:

class P
{
    static void Main()
    {
        Console.WriteLine(System.Web.Security.Membership.GeneratePassword(15, 1));
    }
}

Compacted:

class P{static void Main()
{Console.WriteLine(System.Web.Security.Membership.GeneratePassword(15,1));}}

Example:

b+m2ae0K:{dz7:A

Alternatively, take the value of the second parameter (int numberOfNonAlphanumericCharacters) from the command line:

class P
{
    static void Main(string[] a)
    {
        Console.WriteLine(System.Web.Security.Membership.GeneratePassword(15, int.Parse(a[0])));
    }
}

Rik

Posted 2014-01-05T22:03:41.630

Reputation: 781

3GeneratePassword does not support the full set of symbols specified in the question. Neither did I find any guarantees about the minimum number of occurrences of each character category. – MvG – 2014-01-06T08:39:17.347

2You could compact further by using class P and string[] a. – d3dave – 2014-01-06T14:45:24.587

@MvG, that's interesting. It looks like it excludes any symbol that's commonly used to write accented characters in languages such as French. Probably a smart move. Changing the keyboard language would be enough to stuff up your password. – Hand-E-Food – 2014-01-06T21:19:59.777

5

R (301 322 characters)

Correction forgot to check for digits.

a='abcdefghijklmnopqrstuvwxyz';
f=as.factor(strsplit(paste(a,toupper(a),
    sep="0123456789`~!@#$%^&*()_+-={}|[]\\:\";'<>?,./"),"")[[1]]);
g=gsub("(.):","\\1",levels(q:q:q:q:q:q:q:q:q:q:q:q:q:q:q));
repeat{p=g[runif(1)*length(g)]; 
    if(grepl("[A-Z]",p)&&grepl("[a-z]",p)&&grepl("[0-9]",p)&&grepl("[^A-Za-z0-9]",p))break;};
print(p);

(whitespace added for clarity only).

Generates all possible 15-character permutations of the 94 characters. Then randomly selects one until it matches the criteria.

The magic is in the q:q operation, which generates a new factor data type that is the interaction of all the factors in the first q list with all the factors in the second list, with every possible combination of those two lists being included in the list of "levels" of that factor. Interact 15 copies of the list of allowed characters, and you get (94^15) possible levels.

Please do not try this at home. The code takes a couple seconds to figure out all the three-character permutations, I really can't imagine how long it would take to figure out all the 15-character permutations, if your computer didn't just run out of memory in the meantime. When I ran the finished (three-character password) script to check it, the first password it spit out was "oO=", which I think about sums up the reaction you should have to this code.

AmeliaBR

Posted 2014-01-05T22:03:41.630

Reputation: 1 031

@MvG has an R script that is both much more practical and much shorter, if much less awesome: http://codegolf.stackexchange.com/a/17700/12413

– AmeliaBR – 2014-01-06T06:28:25.500

Nevertheless, I like your idea. Many code-golf snippets I saw let specific features of the language do the hard work. And your code certainly does that for R, with those interactions. – MvG – 2014-01-07T13:13:55.890

4

Python 2.7 (182)

import random as r,string as s
z=r.sample
j=list(z(s.ascii_lowercase,12)+z(s.ascii_uppercase,1)+z(s.digits,1)+z('`~!@#$%^&*()_+-={}|[]\\:";\'<>?,./',1))
r.shuffle(j)
print ''.join(j)

Jonathon Reinhart

Posted 2014-01-05T22:03:41.630

Reputation: 143

You can get 9 digits less by removing the join as it is not required by the problem descript. Another 2 less by removing spaces. – Martin Thoma – 2014-01-05T22:47:26.777

@moose I took out the spaces right before you commented :-) I feel like the join kinda has to be there: Would users be expected to understand python list syntax from the output: ['q', 'u', ...]? – Jonathon Reinhart – 2014-01-05T22:50:10.777

1

I thought about removing print at all. When size in bytes is important, they might live in the punch card time. That way, they might be able to read the memory ... just by looking at it. Or they are "real programmers": http://xkcd.com/378/

– Martin Thoma – 2014-01-05T22:53:47.290

This is my first swing(?) at code golf... I guess we have to be pedantic, huh :-) – Jonathon Reinhart – 2014-01-05T22:54:42.013

1If I'm reading the code correctly, this does not fulfill the all permutations requirement, it will always have 12 lowercase characters, making passwords with more than one of the other groups (like aA$bc1111111111) impossible. – IQAndreas – 2014-01-05T23:31:48.320

1In Johnathon's defence, I think the permutations rule was added 5 minutes after his post. – Hand-E-Food – 2014-01-05T23:36:57.630

@Hand-E-Food There was still some sort of "cannot be predictable" requirement. (Though, I am still impressed by how "slim" this answer is) – IQAndreas – 2014-01-05T23:46:37.060

One tiny problem, you need to escape the backslash (right now, it's just escaping the :) – IQAndreas – 2014-01-06T00:00:34.813

@IQAndreas Thanks for pointing that out. But it was still working, as '\:' == '\\:'. – Jonathon Reinhart – 2014-01-06T01:04:07.680

4

Mathematica 170

r=RandomSample;f[i_]:=(FromCharacterCode/@Range@@i);
{t,A,a,n}=f/@{{33,126},{65,90},{97,122},{48,57}};
s=Complement[t,A,a,n];
""<>r[Join[RandomChoice/@{A,a,n,s},r[t,11]],15]

Examples

"<]}Pg3/e?3+Z~Oz"
"X/8jWe@f(_x5P:="
"2wz2VQhtJC?*R7^"

DavidC

Posted 2014-01-05T22:03:41.630

Reputation: 24 524

4

Golfscript (60)

Since the obl. golfscript is missing and as a noob I need the practice anyway :)

[48 10{rand}:r~+65 26r+97 26r+33 15r+11,{;32 96r+}%~]{r}$''+

It just builds an array with the 4 required + 11 random characters and sorts in random order.

Joachim Isaksson

Posted 2014-01-05T22:03:41.630

Reputation: 1 161

+1 for {r}$. That's a pretty dirty way to shuffle a list — I like it! ;-) – Ilmari Karonen – 2014-01-07T02:47:45.363

...however, I don't think this can ever output e.g. 0Aa~~~~~~~~~~~~. :-( – Ilmari Karonen – 2014-01-07T13:43:15.327

3

JavaScript 258 240 233 225

R=Math.random;a=b=>b[b.length*R()|0];for(x=[a(l="abcdefghijklmnopqrstuvwxyz"),a(u=l.toUpperCase()),a(n="0123456789"),a(s="`~!@#$%^&*()_+-={}|[]\\:\";'<>?,./")];15>x.length;x.push(a(l+u+n+s)));alert(x.sort(y=>.5-R()).join(""))

Using a rule where:

function(x){return x*x} can be re-written as function(x)x*x. Only seems to work for functions returning a value.

Next iteration, reduced x.sort(function().5-R()) to x.sort(y=>.5-R())

Next iteration, reduced further with fat arrow notation, which sadly only works for Firefox 22 and above.

WallyWest

Posted 2014-01-05T22:03:41.630

Reputation: 6 949

Nice compacting! :D – IQAndreas – 2014-01-06T09:01:32.350

2

JavaScript (269 characters compacted)

For clarity, this is the code before I compacted it down JS-Fiddle of it:

var lowerLetters = "abcdefghijklmnopqrstuvwxyz";
var upperLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var numbers = "0123456789";
var symbols = "`~!@#$%^&*()_+-={}|[]\\:\";'<>?,./";
var allCharacters = lowerLetters + upperLetters + numbers + symbols;

String.prototype.randomChar = function() {
    return this[Math.floor(this.length * Math.random())];
}

var minLength = 15;
var result = [];

// Start off by picking one random character from each group
result.push(lowerLetters.randomChar());
result.push(upperLetters.randomChar());
result.push(numbers.randomChar());
result.push(symbols.randomChar());
// Next, pick a random character from all groups until the desired length is met
while(result.length < minLength) {
    result.push(allCharacters.randomChar());
}
result.shuffle(); // Finally, shuffle the items (custom function; doesn't actually exist in JavaScript, but is very easy to add) -> http://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
result.join("");

Here it is compacted down to 269 characters (JS-Fiddle of it):

l="abcdefghijklmnopqrstuvwxyz";
u=l.toUpperCase();
n="0123456789";
s="`~!@#$%^&*()_+-={}|[]\\:\";'<>?,./";
R=Math.random;

function r(t){
    return t[~~(t.length*R())]
}

for(x=[r(l),r(u),r(n),r(s)];x.length<15;x.push(r(l+u+n+s)));
x.sort(function(){return .5-R()});
alert(x.join(""));

IQAndreas

Posted 2014-01-05T22:03:41.630

Reputation: 1 180

Since I'm ending lines with semi-colons, all removable whitespace was ignored for character counting, but left in for clarity. – IQAndreas – 2014-01-05T23:57:37.110

What do you mean by shuffle() being a "custom function". Is it part of JavaScript or code you would have to write it yourself? – Hand-E-Food – 2014-01-06T01:51:43.557

@Hand-E-Food I meant it is not built into JavaScript, and since any developers here should know how to shuffle an array, I felt including the function in the code was unnecessary. It is available in the JS-Fiddle though (line 16).

– IQAndreas – 2014-01-06T01:58:45.253

1My point is, it counts towards your byte-count. But I see now you have implemented it in the compacted version, so please ignore me. :-) – Hand-E-Food – 2014-01-06T04:39:53.767

2

Clojure (63):

(->> (map char (range 33 127)) (shuffle) (take 15) (apply str))

But need to be improved to ensure that containing at least 1 character of each category (Upper, Lower, Digit, Symbol).

ntalbs

Posted 2014-01-05T22:03:41.630

Reputation: 131

2

In sql-server

declare @a nvarchar(28)
set @a='abcdefghijklmnopqrstuvwxyz'
declare @b nvarchar(max)
set @b='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
declare @c nvarchar(max)
set @c='0123456789'
declare @d nvarchar(max)
set @d='~!@#$%^&*()_+-={}|[]\:";<>?,./'

select left(substring(@a,cast(rand()*10 as int),3)+substring(@b,cast(rand()*10 as int),6)+substring(@c,cast(rand()*10 as int),3)+substring(@d,cast(rand()*10 as int),5),15)

See it in action--1

see it in Action--2

vhadalgi

Posted 2014-01-05T22:03:41.630

Reputation: 189

1I'm having trouble following the last line, but the code does not seem to fulfill the all permutations requirement. – IQAndreas – 2014-01-06T09:15:42.777

Your code will never generate any password starting with ~0Aa, nor any password where b is followed by a. – Heinzi – 2014-01-06T09:39:30.450

@Heinzi:yes i agree all permutations required r not taken into account it just displays a 15 length..characters randomly choosen from a...z,A..Z,0..9,!...+ :(... – vhadalgi – 2014-01-06T09:47:43.720

2

SAS (191)

%macro c(p);compress(p,,"&p")ne''%mend;data x;length p$15;do x=1by 1;do t=1to 15;substr(p,t,1)=byte(ranuni(7)*94+33);end;if %c(kd)and %c(kl)and %c(ku)and %c(ad)then do;put p;stop;end;end;run;

*TQP,(f=h10*)S=

Commented/indented:

%macro c(p); /*compress removes or keeps certain classes of characters*/
  compress(p,,"&p")ne''
%mend;
data x;
length p$15;
do x=1by 1;
    do t=1to 15;
        substr(p,t,1)=byte(ranuni(7)*94+33); /*give it a 33-126, byte discards the noninteger portion rounding down*/
    end;
    if %c(kd)and %c(kl)and %c(ku)and %c(ad)then do; /*k=keep d=digit l/u=lower/upper ad=remove digits and alphas*/
        put p;
        stop;  /*met our requirement, head home*/
    end;
end;
run;

Joe

Posted 2014-01-05T22:03:41.630

Reputation: 283

2

PowerShell: 119

Gofled Code

for(;!($x-cmatch'.*(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!-/:-@[-`{-~]).*')){$x='';1..15|%{$x+=[char](33..126|random)}}$x

Un-golfed and Commented

# Start for loop definition.
for(
    # Skip variable initialization, start definition of run condition.
    ;
    # Loop runs if $x does not meet complexity requirements.
    # Length requirement is not tested here because it is enforced by the generator later.
    # Much thanks to @VasiliSyrakis for the RegEx help.
    !($x-cmatch'.*(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!-/:-@[-`{-~]).*')
)
{
    # Reset $x in case the script block has already run.
    $x='';
    # Use ForEach-Object, via the % alias, to run a loop 15 times.
    1..15|%{
        # Append a random ASCII character from 33-126 to $x.
        # Note: Use get-random instead of random for faster performance.
        $x+=[char](33..126|random)
    }
}
# Display $x.
$x
# Variable cleanup - not included in golfed code.
rv x

Iszi

Posted 2014-01-05T22:03:41.630

Reputation: 2 369

I think this regex may make it ever so slightly shorter: ^.*(?=.{15,})(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!#$%&? "]).*$, you can do one match with this, which will only match when there is one Upper,Lower,Digit,Symbol. – Vasili Syrakis – 2014-01-09T06:01:27.747

@VasiliSyrakis Ok, You might have to walk me through that a bit. Feel free to start up a chat room if you think it will take awhile. A couple things I'm confused on: 1.) I see the number 15 included there. Is that to make sure the string is exactly 15 characters? If so, this can be omitted, since the script naturally only generates 15-character strings. 2.) What do you mean "will only match when there is one Upper, Lower, Digit, Symbol"? Does that mean it will only match when there is exactly one of each, or at least one of each? The former will break things. – Iszi – 2014-01-09T06:07:08.150

Also, does your RegEx ignore ordering of characters? For example, if tuned down to match 4-character strings, would both 1aZ% and (p3R match? I had some difficulty finding ways to do that online. – Iszi – 2014-01-09T06:08:30.157

Tested the new RegEx against output from my current script. It doesn't seem quite reliable. Code: $x-cmatch'^.*(?=.{15,})(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!#$%&? "]).*$' Good matches: C>suD1?hTwbDx(z j%4O]HyeG|u[U$5 O/rGeD0$hJk=GO/ Failed matches: 3evthX3_X^nBrR\ .nA~uYzrR4YV-r. u-IjZE48ntQ;HxV – Iszi – 2014-01-09T06:17:28.927

How do I open a chat room? – Vasili Syrakis – 2014-01-09T06:17:29.823

@VasiliSyrakis Let's just repurpose this one. I think we're done discussing the original topic there.

– Iszi – 2014-01-09T06:20:01.673

1

PHP, 235 225

This script shuffles characters around and then is checked via RegEx to make sure the password is strong (or it is regenerated).

<?php
while(!preg_match('/^(?=.*[A-Z])(?=.*[^A-Za-z])(?=.*[0-9])(?=.*[a-z]).{15}$/',$p)){ $p = substr(str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`~!@#$%^&*()_+-={}|[]\:";\'<>?,./'),0,15); }
echo $p;

ub3rst4r

Posted 2014-01-05T22:03:41.630

Reputation: 282

1Clever, but doesn't allow duplicate characters. – Hand-E-Food – 2014-01-06T01:44:53.907

1Instead of while(true) ... if (condition) break you can use while (!condition) – exussum – 2014-01-06T08:12:13.150

1

Powershell


One Liner version (143 bytes)

sal g random;1..11|%{$P+=[char](33..126|g)};(65..90|g),(97..122|g),(48..57|g),(33..47+58..64+123..126|g)|%{$P=$P.insert((1..11|g),[char]$_)};$P

Mini version (146 bytes)

sal g random
1..11|%{$P+=[char](33..126|g)}
(65..90|g),(97..122|g),(48..57|g),(33..47+58..64+123..126|g)|%{$P=$P.insert((1..11|g),[char]$_)}
$P

Readable version (860 bytes)

function pwgen {

    # Fulfill Upper,Lower,Digit,Symbol requirement by predefining ASCII ranges for each
    # These will be added into the string beginning at line 24

    [array[]]$symbolrange = (33..47),(58..64),(123..126)

    [char]$upper = (get-random (65..90))
    [char]$lower = (get-random (97..122))
    [char]$digit = (get-random (48..57))
    [char]$symbol = $symbolrange | get-random

    [char[]]$requirement = $upper + $lower + $digit + $symbol

    # Create the first 11 characters using any ASCII character between 32 - 126

    foreach ($number in (1..11)) {
        [string]$pass += [char](get-random (33..126))
    }

    # Insert each requirement character at a random position in the string

    foreach ($char in $requirement) {
        [string]$pass = $pass.insert((Get-Random (1..11)),$char)
    }

    return $pass
}

Credit to Iszi for various tips to shorten the code.

Vasili Syrakis

Posted 2014-01-05T22:03:41.630

Reputation: 181

1This doesn't cover all permutations. As an example, abcd1234ABCD{|}~ will never come up because $symbol forces at least one of the symbols to be between ASCII 33 and 47. – Hand-E-Food – 2014-01-06T04:43:53.657

Dangit! Must you point out my laziness!? Just kidding... I've edited it now. I also made each "requirement" character go to a separate index within the string, instead of clumping the four in together at the same index. Now if only I could shorten this... – Vasili Syrakis – 2014-01-06T06:23:22.447

Is there any reason you can't shave a couple more characters by shortening $SR to, perhaps $Q? – Iszi – 2014-01-08T23:54:43.233

You should also be able to cut stuff like (g(65..90)) down to 65..90|g'. And change theforeachstatements toforeach-objectloops using the%alias. Example:foreach($N in (1..11)){...}should be doable as1..11|%{...}`. I'm pretty sure there's other optimizations which are possible, but I've actually got a completely different implementation in mind that I'm planning to try later. – Iszi – 2014-01-09T00:03:47.693

Nice tips :) I shortened it to 213 bytes if I take out the carriage returns and replace with semicolons. – Vasili Syrakis – 2014-01-09T00:20:05.250

More tips: Get-Random can be truncated to just Random. This may bloat the running time a bit, but it still works. Replace (33..47),(58..64),(123..126) with 33..47+58..64+123..126. You also don't need to force the type of $symbolrange to an array - it will auto-type based on the data you've given it. In the shorter version you don't need += to define $Q either - just =. – Iszi – 2014-01-09T04:10:01.423

For that matter, you probably don't even need $Q,$U,$L,$D, or $S at all. If you have a variable that effectively only ever gets used once, then it's probably a variable you don't need. – Iszi – 2014-01-09T04:15:07.193

Damn, awesome tips man, I have to add a credit into the post for all your help :) We're down to 143 bytes now. I never imagined that Powershell could get so short! – Vasili Syrakis – 2014-01-09T04:44:00.420

@VasiliSyrakis Just wait until you see what I'm working on. Pretty sure it's going to still beat 143. Also, check out a thread somewhere around here called something like "Golfing tips for PowerShell". – Iszi – 2014-01-09T04:44:54.087

Okay, so apparently this can be done as per the F# example... like this: [Web.Security.Membership]::GeneratePassword(15,1)... Kinda ruins it :P – Vasili Syrakis – 2014-01-09T05:20:47.823

@VasiliSyrakis Unable to find type [Web.Security.Membership]. – Iszi – 2014-01-09T05:24:49.253

You know what's weird? I get the same error, unless I type [web.security.membership]:: and then do a tab completion on gen or similar. Not sure how to manually load the assembly. – Vasili Syrakis – 2014-01-09T05:28:37.633

Well, ignoring the fact that the OP omitted a requirement to avoid built-in password generation functions, I went ahead and banged it out in 135 characters here.

– Iszi – 2014-01-09T05:42:13.810

One little bug in the code (which I've now got to fix in mine, too) that doesn't affect length: Spaces (ASCII character 32) are not valid characters per the spec of "Keyboard-typeable characters only (as shown in code-type ...)." – Iszi – 2014-01-09T05:54:14.360

1

Python 2.7 (149)

from random import*
''.join(map(lambda x:chr(randint(*(x[1]or(32,126)))),sorted(map(None,sample(range(15),15),((48,57),(65,90),(97,122),(33,47))))))

Written out in a more readable (and not executable) way;

from random import *
''.join(                                          # Concatenate characters to string
  map(                                            # Map all characters using below lambda
    lambda x:chr(randint(*(x[1] or (32, 126)))),  # Map a single range to a random character
                                                  # within a specific range if supplied,
                                                  # otherwise the default "all" range.
    sorted(                                       # After distributing ranges, sort
      map(None,                                   # zip_longest alternative, distributes the
                                                  # required ranges over 4 random positions
        sample(range(15), 15),                    # 0-14 in random order
        ((48, 57), (65, 90), (97, 122), (33, 47)) # The 4 required ranges
      )
    )
  )
)

Fairly straight forward and surprisingly not much longer than a "generate, retry on match fail" version.

Joachim Isaksson

Posted 2014-01-05T22:03:41.630

Reputation: 1 161

Are you sure this can really generate all eligible passwords, including e.g. 0Aa~~~~~~~~~~~~? (Note that '~' == chr(126).) – Ilmari Karonen – 2014-01-07T13:39:45.950

1

PSQL (189)

Feels like PSQL is a bit verbose... :)

SELECT ARRAY_TO_STRING(ARRAY_AGG(CHR((TRUNC((b-a)*RANDOM()+a))::int)ORDER BY RANDOM()),'')FROM(SELECT 32 a,127 b FROM generate_series(1,11)UNION ALL VALUES(48,58),(65,91),(97,123),(33,48))a

SQLfiddle demo.

Joachim Isaksson

Posted 2014-01-05T22:03:41.630

Reputation: 1 161

1

Perl, 92

Not as concise as the Ruby answer, but I'm sure a Perl wizard could make this even shorter... I'm not too happy with all the m//s at the end, but seems to work and should satisfy the conditions to eventually generate all permutations.

do{$_=join"",map{(map{chr}33..127)[rand 94]}0..14}while!(/[A-Z]/&/[a-z]/&/\d/&/[\W_]/);print

Sample usage:

perl -e 'do{$_=join"",map{(map{chr}33..127)[rand 94]}0..14}while!(/[A-Z]/&/[a-z]/&/\d/&/[\W_]/);print'

Edited to fix validation and change [[:punct:]] to [\W_] after MvGs comments.

Dom Hastings

Posted 2014-01-05T22:03:41.630

Reputation: 16 415

1Your generation part is nice, but your selection criterion in the loop condition is plain wrong: e.g. a password of aaaaaaaaaaaaaa would cause the loop to terminate. You should test criteria with non-random passwords to make sure they do what you want them to. – MvG – 2014-01-07T13:10:58.520

Indeed, you are correct, I've fixed this and saved some bytes! Thanks! – Dom Hastings – 2014-01-07T13:50:22.100

1Are you sure about this [[:punct:]]? I guess I'd prefer '[\W_], which is shorter and of which I'm even more sure that it is correct, at least combined with your33..127` range. – MvG – 2014-01-07T15:04:55.447

A good point, I think I was concerned that \W didn't include _, however you're absolutely right, it's not needed: https://gist.github.com/anonymous/8301237. Thank you!

– Dom Hastings – 2014-01-07T15:41:59.063

1

Javascript (209)

r=Math.random;function t(x,y){return String.fromCharCode(Math.floor(y*r()+x))};x=[t(33,14),t(48,10),t(65,26),t(97,26)];for(i=0;i<11;i++)x.push(t(32,95));console.log(x.sort(function(){return r()-0.5}).join(''))

Semi-ungolfed;

// Return a character in the range [x,x+y)
function t(x,y) { return String.fromCharCode(Math.floor(y*Math.random()+x)) }
// Prefill required ranges
x=[ t(33,14), t(48,10), t(65,26), t(97,26)]
// Push 11 totally random (valid) characters
for(i=0; i<11; i++)
  x.push(t(32,95))
// Shuffle and output as string
console.log(x.sort(function(){return Math.random()-0.5})
             .join(''))

Joachim Isaksson

Posted 2014-01-05T22:03:41.630

Reputation: 1 161

1

Java 7 (270 234 characters)

The premise is the same used by @assylias with java 8 (generate random passwords until valid password). However, instead of using lambdas, the password is generated by iterating a char array and validated by matching a regex.

class A {
  public static void main(String [] a) {
    byte[] b = new byte[15];
    String s;
    do {
      new java.util.Random().nextBytes(b);
      s = new String(b);
    } while(!s.matches("(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\\d)(?=.*?[!-/:-@\\[-`]).*"));
    System.out.println(s);
  }
}

Minified Code:

class A {public static void main(String[] a){byte[] b=new byte[15];String s;do{new java.util.Random().nextBytes(b);s=new String(b);}while(!s.matches("(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\\d)(?=.*?[!-/:-@\\[-`]).*"));System.out.println(s);}}

madoke

Posted 2014-01-05T22:03:41.630

Reputation: 111

1

Factor, 196 characters

Same algorithm as MvG and moose's. It is not the shortest but should satisfy all the (current) criteria in the question:

USING: io kernel math pcre random sequences sequences.repeating ;
[ 15 94 random-integers [ 33 + ] "" map-as dup 60 cycle
"[A-Z].*[a-z].*[0-9].*[\\W_]" findall { } = not ] [ drop ] until print

Björn Lindqvist

Posted 2014-01-05T22:03:41.630

Reputation: 590

I might be misinterpreting the regex, but I think something like ~{}|1234abcdABCD will fail the regex. – Hand-E-Food – 2014-01-08T23:41:29.730

1No it will work: "~{}|1234abcdABCD" 60 cycle "[A-Z].*[a-z].*[0-9].*[\\W_]" findall empty? not => t – Björn Lindqvist – 2014-01-09T08:41:37.040

I'll take your word for it. :-) – Hand-E-Food – 2014-01-09T22:51:21.733

1

C - 154 characters

char p[16],c,f,w;main(){srand(time());while(f^15){c=p[15]=f=0;while(c^15){w=33+rand()%94;f|=w
>96&&w<123?1:w>47&&w<59?2:w>64&&w<91?4:8;p[c++]=w;}}puts(p);}

How do I hate srand()? Let me count the ways.

Oberon

Posted 2014-01-05T22:03:41.630

Reputation: 2 881

1

Haskell, 192

import System.Random
main=getStdGen>>= \g->(print.(take 15))$until((\x->all(any(`elem`x))[['a'..'z'],['A'..'Z'],['0'..'9'],['!'..'/']++":;<=>?@[\\]^_`{|}~"]).(take 15))tail$randomRs('"','~')g

The printed string has quotes around it and escapes the backslash and quote characters; if that's unacceptable, print can be replaced with putStrLn for 3 more bytes. Here's a more readable version:

import System.Random

main = do
    g <- getStdGen
    let chars = randomRs ('"', '~') g
    let password = take 15 $ until (hasChars.(take 15)) tail chars
    print password

hasChars :: String -> Bool
hasChars x = all (any (`elem` x)) $
    [ ['a'..'z']
    , ['A'..'Z']
    , ['0'..'9']
    , "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
    ]

It's quite straightforward, it just creates an infinite/lazy list of random ASCII characters in the range '!' to '~', then tosses out the first element until the first 15 characters have at least one character from each string of required characters.

user3175123

Posted 2014-01-05T22:03:41.630

Reputation: 81

1

Excel VBA, 209 bytes

For i = 1 To 15
x = x + Chr(Int(90 * Rnd + 33))
Next
p = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*(_|[^\w])).+$"
With New RegExp
.Pattern = p
Set m = .Execute(x)
If m.Count = 0 Then
MsgBox "redo"
Else
MsgBox x
End If
End With

Randomly generates 15 ASCII characters so all possible combinations are possible. Then uses a regular expression pattern to check if it contains at least one of each criteria.

If it does then the password is displayed, if not "redo" is displayed.

Credit to Bart Kiers for the Regular Expression pattern: https://stackoverflow.com/questions/1559751/regex-to-make-sure-that-the-string-contains-at-least-one-lower-case-char-upper

Wightboy

Posted 2014-01-05T22:03:41.630

Reputation: 339

0

AutoHotkey 352

global o:={}
loop 4
o[c()]:=o(A_index-1)
loop 11
o[c()]:=o(m(r(),4))
loop 15
s.=o[A_index-1]
msgbox % s
r(){
Random,z
return z
}
m(z,r){
return mod(z,r)
}
c(){
while o[t:=m(r(),15)]!=""
j++
return t
}
o(f){
r0:=48,l0:=10,r1:=97,l1:=l2:=26,r2:=65
r := chr(r%f%+m(r(),l%f%))
if f=3
r:=Substr("``~!@#$%^&*()_+-={}|[]\:"";'<>?,./",m(r(),32)+1,1)
return r
}

Using - Just run the script

Avi

Posted 2014-01-05T22:03:41.630

Reputation: 261

0

Python (121 characters)

Makes use of the fact that you can multiply lists in Python [1,2,3] * 2 gives [1,2,3,1,2,3]. Imports random. Numbers in a list multiplied by three are borders between ranges in ascii table for needed characters, e.g. [65, 90] maps to uppercase letters.

print "".join([random.choice([chr(i) for i in range(z[0],z[1])]) for z in [[33,48],[48,58],[58,65],[65,90],[90,123]]* 3])

Pawelmhm

Posted 2014-01-05T22:03:41.630

Reputation: 101

This needs to actually include import random in the code. – Mego – 2016-05-21T11:06:35.460

1"It must be able to generate all permutations of all allowable characters.". I don't think it does that since the ranges are always applied in the same order...? – Joachim Isaksson – 2014-01-06T13:01:26.690

You are right, thank you. Indeed I didn't notice that ranges should be applied in random order, they should be shuffled, I'll edit that in a moment. – Pawelmhm – 2014-01-06T13:57:53.700

0

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($_);}'

Neha Sangore

Posted 2014-01-05T22:03:41.630

Reputation: 49

It is a small sample but the punctuation signs seem to appear a lot more than numbers or letters... – assylias – 2014-01-06T18:53:26.797

This approach uses the categories in a fixed order, so it doesn't allow all possible passwords. – MvG – 2014-01-07T12:56:55.877

@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. – Neha Sangore – 2014-01-08T05:10:40.040

@MvG: Thanks for pointing it out, I fixed it. Please see for the Update. – Neha Sangore – 2014-01-08T05:13:54.433

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. – MvG – 2014-01-08T06:37:08.057

0

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)

Cezar Moise

Posted 2014-01-05T22:03:41.630

Reputation: 31

1Since this is code-golf, you should add character (or byte, in this case) count to your post. – Vereos – 2014-01-07T10:26:33.007

0

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)));

MichaelRushton

Posted 2014-01-05T22:03:41.630

Reputation: 244

0

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.

Rik

Posted 2014-01-05T22:03:41.630

Reputation: 781

0

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

craesh

Posted 2014-01-05T22:03:41.630

Reputation: 121

That's kind of the point; to reduce the code size to as small as possible. – Timtech – 2014-01-09T15:25:17.990

0

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~

Gx1sptDTDa

Posted 2014-01-05T22:03:41.630

Reputation: 101

-1

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..

Zach Leighton

Posted 2014-01-05T22:03:41.630

Reputation: 194

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. – MvG – 2014-01-06T08:48:26.007