Password generator

From Rosetta Code
Task
Password generator
You are encouraged to solve this task according to the task description, using any language you may know.
File:Passwords.jpg

Create a password generation program which will generate passwords containing random ASCII characters from the following groups:

  • lower-case letters: a-z
  • upper-case letters: A-Z
  • digits: 0-9
  • other printable characters excluding white-space, backslash and grave:  !"#$%&'()*+,-./:;<=>?@[]^_{|}~


The generated password(s) must include at least one lower-case letter, one upper-case letter and one character from digits and 'other'.

The user must be able to specify the password length and the number of passwords to generate.

The passwords should be displayed or written to a file, one per line.

The randomness should be from a system source or library.

The program should implement a help option or button which should describe the program and options when invoked.

You may also allow the user to specify a seed value, and give the option of excluding visually similar characters.

For example:           Il1     O0     5S     2Z           where the characters are:

  •   capital eye, lowercase ell, the digit one
  •   capital oh, the digit zero
  •   the digit five, capital ess
  •   the digit two, capital zee



C++

<lang cpp>

  1. include <iostream>
  2. include <string>
  3. include <algorithm>
  4. include <ctime>

const std::string CHR[] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz",

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

const std::string UNS = "O0l1I5S2Z";

std::string createPW( int len, bool safe ) {

   std::string pw;
   char t;
   for( int x = 0; x < len; x += 4 ) {
       for( int y = x; y < x + 4 && y < len; y++ ) {
           do {
               t = CHR[y % 4].at( rand() % CHR[y % 4].size() );
           } while( safe && UNS.find( t ) != UNS.npos );
           pw.append( 1, t );
       }
   }
   std::random_shuffle( pw.begin(), pw.end() );
   return pw;

} void generate( int len, int count, bool safe ) {

   for( int c = 0; c < count; c++ ) {
       std::cout << createPW( len, safe ) << "\n";
   }
   std::cout << "\n\n";

} int main( int argc, char* argv[] ){

   if( argv[1][1] == '?' || argc < 5 ) {
       std::cout << "Syntax: PWGEN length count safe seed /?\n"
                    "length:\tthe length of the password(min 4)\n"
                    "count:\thow many passwords should be generated\n"
                    "safe:\t1 will exclud visually similar characters, 0 won't\n"
                    "seed:\tnumber to seed the random generator or 0\n"
                    "/?\tthis text\n\n";
   } else {
       int l = atoi( argv[1] ),
           c = atoi( argv[2] ),
           s = atoi( argv[4] );
       if( s == 0 ) s = int( std::time( 0 ) );
       if( l < 4 ) {
           std::cout << "Passwords must be at least 4 characters long.\n\n";
       } else {
           std::srand( unsigned( s ) );
           generate( l, c, argv[3][0] == '1' );
       }
   }
   return 0;

} </lang>

Output:
PWGEN 6 6 1 8
Rd3&Mm
$X6ttJ
fx7D,K
9sHh$L
d~U3Nn
9AE?ab

Elixir

<lang elixir>defmodule Password do

 @lower Enum.map(?a..?z, &to_string([&1]))
 @upper Enum.map(?A..?Z, &to_string([&1]))
 @digit Enum.map(?0..?9, &to_string([&1]))
 @other ~S"""

!"#$%&'()*+,-./:;<=>?@[]^_{|}~ """ |> String.codepoints |> List.delete_at(-1)

 @all @lower ++ @upper ++ @digit ++ @other
 
 def generator do
   {len, num} = get_argv
   Enum.each(1..num, fn _ ->
     pswd = [Enum.random(@lower), Enum.random(@upper), Enum.random(@digit), Enum.random(@other)]
     IO.puts generator(len-4, pswd)
   end)
 end
 
 def generator(0, pswd), do: Enum.shuffle(pswd) |> Enum.join
 def generator(len, pswd), do: generator(len-1, [Enum.random(@all) | pswd])
 
 def get_argv do
   {len,num} = case System.argv do
     ["?"]     -> usage
     []        -> {8,1}
     [len]     -> {String.to_integer(len), 1}
     [len,num] -> {String.to_integer(len), String.to_integer(num)}
     _         -> usage
   end
   if len<4 or num<1, do: usage, else: {len,num}
 end
 
 defp usage do
   IO.puts ["Password generator\n",
            "Usage: [password length(=8)] [number of passwords to generate(=1)]"]
   exit(:normal)
 end

end

Password.generator</lang>

Output:
Elixir> elixir pswdgen.exs
Yu4*CSi|

Elixir> elixir pswdgen.exs 20 5
TWRfdAVYf_jl"Y~8gzx]
-)-D8Xz_fq5}c[STq("9
)xc30V06lEW&>k{9L_ON
GU$t*{887i5Ef@y(%VN'
}(b!m:DT%A7tLy[|qz{C

J

Implementation:

<lang J>thru=: <. + i.@(+*)@-~ chr=: a.&i.

lower=: 'a' thru&.chr 'z' upper=: 'A' thru&.chr 'Z' digit=: '0' thru&.chr '9' other=: ('!' thru&.chr '~')-.lower,upper,digit,'`\' all=: lower,upper,digit,other

pwgen =:verb define"0 :: pwhelp

 NB. pick one of each, remainder from all, then shuffle
 (?~y) { (?@# { ])every lower;upper;digit;other;(y-4)#<all
 pwgen x#y

)

pwhelp =:echo bind (noun define)

 [x] pwgen y - generates passwords of length y
 optional x says how many to generate (if you want more than 1)
 y must be at least 4 because 
 passwords must contain four different kinds of characters.

)</lang>

Example use (from J command line):

<lang J> pwgen'help'

 [x] pwgen y - generates passwords of length y
 optional x says how many to generate (if you want more than 1)
 y must be at least 4 because 
 passwords must contain four different kinds of characters.
  pwgen 10

S%"x8X0}:K

  5 pwgen 10

+u.9(XDM.O ]a@Yb6j~DI Oo?|2oc4yi 9V9[EJ:Txs $vYd(>4L:m</lang>

Java

Works with: Java version 7

<lang java>import java.util.*;

public class PasswordGenerator {

   final static Random rand = new Random();
   public static void main(String[] args) {
       int num, len;
       try {
           if (args.length != 2)
               throw new IllegalArgumentException();
           len = Integer.parseInt(args[0]);
           if (len < 4 || len > 16)
               throw new IllegalArgumentException();
           num = Integer.parseInt(args[1]);
           if (num < 1 || num > 10)
               throw new IllegalArgumentException();
           for (String pw : generatePasswords(num, len))
               System.out.println(pw);
       } catch (IllegalArgumentException e) {
           String s = "Provide the length of the passwords (min 4, max 16) you "
                   + "want to generate,\nand how many (min 1, max 10)";
           System.out.println(s);
       }
   }
   private static List<String> generatePasswords(int num, int len) {
       final String s = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~";
       List<String> result = new ArrayList<>();
       for (int i = 0; i < num; i++) {
           StringBuilder sb = new StringBuilder();
           sb.append(s.charAt(rand.nextInt(s.length())));
           sb.append((char) (rand.nextInt(10) + '0'));
           sb.append((char) (rand.nextInt(26) + 'a'));
           sb.append((char) (rand.nextInt(26) + 'A'));
           for (int j = 4; j < len; j++) {
               int r = rand.nextInt(93) + '!';
               if (r == 92 || r == 96) {
                   j--;
               } else {
                   sb.append((char) r);
               }
           }
           result.add(shuffle(sb));
       }
       return result;
   }
   public static String shuffle(StringBuilder sb) {
       int len = sb.length();
       for (int i = len - 1; i > 0; i--) {
           int r = rand.nextInt(i);
           char tmp = sb.charAt(i);
           sb.setCharAt(i, sb.charAt(r));
           sb.setCharAt(r, tmp);
       }
       return sb.toString();
   }

}</lang>

7V;m
4u>I
J2$s
I8~h

2Q4,dD.Y'z>8
<|U)qS7S9d_M
c4*hLisq^e26
'H$1e)BpYh*8
*'R8yEmvh9v]

Lua

<lang Lua>function randPW (length)

   local index, pw, rnd = 0, ""
   local chars = {
       "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
       "abcdefghijklmnopqrstuvwxyz",
       "0123456789",
       "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~"
   }
   repeat
       index = index + 1
       rnd = math.random(chars[index]:len())
       if math.random(2) == 1 then
           pw = pw .. chars[index]:sub(rnd, rnd)
       else
           pw = chars[index]:sub(rnd, rnd) .. pw
       end
       index = index % #chars
   until pw:len() >= length
   return pw

end

math.randomseed(os.time()) if #arg ~= 2 then

   print("\npwgen.lua")
   print("=========\n")
   print("A Lua script to generate random passwords.\n")
   print("Usage:    lua pwgen.lua [password length] [number of passwords to generate]\n")
   os.exit()

end for i = 1, arg[2] do print(randPW(tonumber(arg[1]))) end</lang> Command line session:

>lua pwgen.lua

pwgen.lua
=========

A Lua script to generate random passwords.

Usage:  lua pwgen.lua [password length] [number of passwords to generate]


>lua pwgen.lua 8 4
!A%1Ghs5
)cU?2eT5
9wHh1'V/
6lN9*Nx<

ooRexx

Translation of: [[#|]] – REXX

<lang oorexx>/*REXX program generates a random password according to the Rosetta Code task's rules.*/ parse arg L N seed xxx dbg /*obtain optional arguments from the CL*/ casl= 'abcdefghijklmnopqrstuvwxyz' /*define lowercase alphabet. */ casu= translate(casle) /*define uppercase alphabet. */ digs= '0123456789' /*define digits. */ /* avoiding the ambiguous characters Il1 o0 5S */ casl= 'abcdefghijkmnpqrtuvwxy' /*define lowercase alphabet. */ casu= translate(casl) /*define uppercase alphabet. */ digs= '0123456789' /*define digits. */ spec= !"#$%&()+,-./:;<=>?@[]^{|}~' /*define a bunch of special characters.*/ if L='?' then call help /*does user want documentation shown? */ if L= | L="," then L=8 /*Not specified? Then use the default.*/ If N= | N="," then N=1 /* " " " " " " */ If xxx=| xxx="," then xxx='1lI0O2Z5S' /* " " " " " " */ if seed> &,

  seed<>','            then Do
 if \datatype(seed,'W')then call ser "seed is not an integer:" seed
 Call random ,,seed                             /*the seed for repeatable RANDOM BIF #s*/
 End

casl=remove(xxx,casl) casu=remove(xxx,casu) digs=remove(xxx,digs) Say 'casl='casl Say 'casu='casu Say 'digs='digs Say 'spec='spec if \datatype(L, 'W') then call ser "password length, it isn't an integer: " L if L<4 then call ser "password length, it's too small: " L if L>80 then call ser "password length, it's too large: " L if \datatype(N, 'W') then call ser "number of passwords, it isn't an integer: " N if N<0 then call ser "number of passwords, it's too small: " N

   do g=1  for N                                /*generate  N  passwords (default is 1)*/
   pw=letterL()||letterU()||numeral()||special()/*generate  4  random  PW constituents.*/
           do k=5  to  L;       z=random(1, 4)  /* [?]  flush out PW with more parts.  */
           if z==1  then pw=pw || letterL()     /*maybe append random lowercase letter.*/
           if z==2  then pw=pw || letterU()     /*  "      "      "   uppercase    "   */
           if z==3  then pw=pw || numeral()     /*  "      "      "       numeral      */
           if z==4  then pw=pw || special()     /*  "      "      "   special character*/
           end   /*k*/                          /* [?]  code below randomizes PW chars.*/
   t=length(pw)                                 /*the length of the password (in bytes)*/
           do L+L                               /*perform a random number of char swaps*/
           a=random(1,t);     x=substr(pw,a,1)  /*A: 1st char location;  X is the char.*/
           b=random(1,t);     y=substr(pw,b,1)  /*B: 2nd   "      "      Y  "  "    "  */
           pw=overlay(x,pw,b);  pw=overlay(y,pw,a)  /* swap the two chars.             */
           end  /*swaps*/                       /* [?]  perform extra swap to be sure. */
   say right(g,length(N))  'password is: ' pw counts() /*display the  Nth  password    */
   end       /*g*/

exit /*stick a fork in it, we're all done. */ /*--------------------------------------------------------------------------------------*/ ser: say; say '***error*** invalid' arg(1); exit 13 /*display an error message*/ letterL: return substr(casl, random(1, length(casl)), 1) /*return random lowercase.*/ letterU: return substr(casu, random(1, length(casu)), 1) /* " " uppercase.*/ numeral: return substr(digs, random(1, length(digs)), 1) /* " " numeral. */ special: return substr(spec, random(1, length(spec)), 1) /* " " special char*/ remove: Procedure

 Parse arg nono,s
 Return space(translate(s,,nono),0)

/*--------------------------------------------------------------------------------------*/ counts:

 If dbg> Then Do
   cnt.=0
   str.=
   Do j=1 To length(pw)
     c=substr(pw,j,1)
     If pos(c,casL)>0 Then Do; cnt.0casL=cnt.0casL+1; str.0casL=str.0casL||c; End
     If pos(c,casU)>0 Then Do; cnt.0casU=cnt.0casU+1; str.0casU=str.0casU||c; End
     If pos(c,digs)>0 Then Do; cnt.0digs=cnt.0digs+1; str.0digs=str.0digs||c; End
     If pos(c,spec)>0 Then Do; cnt.0spec=cnt.0spec+1; str.0spec=str.0spec||c; End
     End
   txt=cnt.0casL cnt.0casU cnt.0digs cnt.0spec
   If pos(' 0 ',txt)>0 Then
     txt=txt 'error'
   Return txt str.0casL str.0casU str.0digs str.0spec
   End
 Else
   txt=
 Return txt

help: signal .; .: do j=sigL+2 to sourceline()-1; say sourceline(j); end; exit 0 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~ documentation begins on next line.~~~~~~~~~~~~~~~~~~~~~~~~~ +-----------------------------------------------------------------------------+ ¦ Documentation for the GENPW program: ¦ ¦ ¦ ¦ Rexx genpwd <length|,> <howmany|,> <seed|,> <xxx|,> <dbg> ¦ ¦ 8 1 n '1lI0O2Z5S' none Defaults ¦ ¦ ¦ ¦--- where: ¦ ¦ length is the length of the passwords to be generated. ¦ ¦ The default is 8. ¦ ¦ If a comma (,) is specified, the default is used. ¦ ¦ The minimum is 4, the maximum is 80. ¦ ¦ ¦ ¦ howMany is the number of passwords to be generated. ¦ ¦ The default is 1. ¦ ¦ xxx Characters NOT to be used in generated passwords ¦ ¦ dbg Schow count of characters in the 4 groups ¦ +-----------------------------------------------------------------------------+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~documentation ends on the previous line.~~~~~~~~~~~~~~~~~~~*/</lang>

Output:
D:\>rexx genpwd 12 4 33 , x
casl=abcdefghijkmnpqrtuvwxy
casu=ABCDEFGHJKMNPQRTUVWXY
digs=346789
spec='!"#$%&()+,-./:;<=>?@[]^{|}~
1 password is:  B78<3(3Et(U8 1 3 5 3 t BEU 78338 <((
2 password is:  v+k6X6AV^;[7 2 3 3 4 vk XAV 667 +^;[
3 password is:  x3MV:7?CcH{D 2 5 2 3 xc MVCHD 37 :?{
4 password is:  C49PHCj[~D9/ 1 5 3 3 j CPHCD 499 [~/

D:\>regina genpwd 12 4 33 , x
casl=abcdefghijkmnpqrtuvwxy
casu=ABCDEFGHJKMNPQRTUVWXY
digs=346789
spec='!"#$%&()+,-./:;<=>?@[]^{|}~
1 password is:  e4)XnD4jq"xb 6 2 2 2 enjqxb XD 44 )"
2 password is:  9r3H:a97HyW8 3 3 5 1 ray HHW 93978 :
3 password is:  y76-^r^M{8JQ 2 3 3 4 yr MJQ 768 -^^{
4 password is:  C$W@aMHBjc8g 4 5 1 2 ajcg CWMHB 8 $@ 

PARI/GP

PARI/GP has a very good buildin random generator. <lang parigp>passwd(len=8, count=1, seed=0) = {

 if (len <= 4, print("password too short, minimum len=4"); return());
 if (seed, setrand(seed));
 my (C=["abcdefghijklmnopqrstuvwxyz","ABCDEFGHIJKLMNOPQRSTUVWXYZ","0123456789","!\"#$%&'()*+,-./:;<=>?@[]^_{|}~"], P, j);
 for (i=1, count,
   K = vector(#C); P = "";
   for (l=1, len,
     K[j = random(#C)+1]++;
     P = concat(P, Strchr(Vecsmall(C[j])[random(#C[j])+1]))
   );
   if (prod(z=1, #K, K[z]), print(P), i--)    \\ if password contains all char classes print else redo  
 );

}

addhelp(passwd, "passwd({len},{count},{seed}): Password generator, optional: len (min=4, default=8), count (default=1), seed (default=0: no seed)");</lang>

Output: passwd()

34K76+mB

Output of 10 passwords of length 8 with seed enabled: passwd(8,10,1)

6,89DhJa
xO<XsR8b
R&UagR5h
*21e((D%
pR5Ss&rW
7o7]Fuj+
:N6C6y2L
$L?1s4x)
1R5q'5pw
#4vmVHy5

Show help: ?passwd

passwd({len},{count},{seed}): Password generator, optional: len (min=4, default=8), count (default=1), seed (default=0: no seed)

Perl 6

Works with: Rakudo version 2016.05

<lang perl6>my @chars =

 set('a' .. 'z'),
 set('A' .. 'Z'),
 set('0' .. '9'),
 set(<!"#$%&'()*+,-./:;<=>?@[]^_{|}~>.comb);
  1. bleh. unconfuse syntax highlighter. '"

sub MAIN ( Int :$l = 8, Int :$c = 1, Str :$x = ) {

   note 'Password length must be >= 4' and exit if $l < 4;
   note 'Can not generate fewer than 0 passwords' and exit if $c < 0;
   my $chars = [∪] @chars».=&filter;
   note 'Can not exclude an entire required character group' and exit
     if any(@chars».elems) == 0;
   for ^$c {
       my @pswd;
       @pswd.push( @chars[$_].roll ) for ^4;
       @pswd.push( $chars    .roll ) for 4 ..^ $l;
       say [~] @pswd.pick(*);
   }
   sub filter (Set $set) { $set ∖ set($x.comb) }

}

sub USAGE() {

   say qq:to/END/;
   Specify a length:              --l=8 (default 8),
   Specify a count:               --c=1 (default 1),
   Specify characters to exclude: --x=
   (must escape characters significant to the shell)
   E.G.
   {$*PROGRAM-NAME} --l=14 --c=5 --x=0O\\\"\\\'1l\\\|I
   END

}</lang> Sample output: Using defaults:

c?6!xU+u

With passed parameters: --l=14 --c=5 --x=0O\'\"1l\|I

6H~jC+5(+&H44x
+Rr}2>htHMa.Y9
t~#&N]sp_zGK2#
TcP73CJ@euFMjj
9%-tYX]z?8-xA5

Racket

<lang racket>

  1. lang racket

(require racket/cmdline)

(define valid-uppercase '(#\A #\B #\C #\D #\E #\F #\G #\H #\I #\J

                         #\K #\L #\M #\N #\O #\P #\Q #\R #\S #\T
                         #\U #\V #\W #\X #\Y #\Z))

(define valid-lowercase '(#\a #\b #\c #\d #\e #\f #\g #\h #\i #\j

                         #\k #\l #\m #\n #\o #\p #\q #\r #\s #\t
                         #\u #\v #\w #\x #\y #\z))

(define valid-numbers '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)) (define valid-symbols '(#\! #\\ #\" #\# #\$ #\% #\& #\' #\( #\)

                       #\* #\+ #\, #\- #\. #\/ #\: #\; #\< #\=
                       #\> #\? #\@ #\[ #\] #\^ #\_ #\{ #\| #\}
                       #\~))

(define visual-invalid '(#\0 #\O #\1 #\I #\l #\| #\5 #\S #\2 #\Z))

(define (is-readable? c)

 (empty? (filter (lambda (x) (eq? x c)) visual-invalid)))

(define (random-selection lst)

 (list-ref lst (random (length lst))))

(define (generate len readable)

 (let ([upper (if readable (filter is-readable? valid-uppercase) valid-uppercase)]
       [lower (if readable (filter is-readable? valid-lowercase) valid-lowercase)]
       [numbers (if readable (filter is-readable? valid-numbers) valid-numbers)]
       [symbols (if readable (filter is-readable? valid-symbols) valid-symbols)])
   (let loop ([lst (map random-selection (list upper lower numbers symbols))])
     (cond
       [(<= len (length lst)) (shuffle lst)]
       [else (match (random 4)
               [0 (loop (cons (random-selection upper) lst))]
               [1 (loop (cons (random-selection lower) lst))]
               [2 (loop (cons (random-selection numbers) lst))]
               [3 (loop (cons (random-selection symbols) lst))])]))))

(define (run len cnt seed readable)

 (random-seed seed)
 (let loop ([x cnt])
   (unless (zero? x)
     (display (list->string (generate len readable)))
     (newline)
     (loop (- x 1)))))

(define len (make-parameter 10)) (define cnt (make-parameter 1)) (define seed (make-parameter (random 1 1000000))) (define readable? (make-parameter #f))

(command-line #:program "passwdgen"

             #:once-each
             [("-l" "--length") integer "password length"  (len (string->number integer))]
             [("-c" "--count") integer "number of password" (cnt (string->number integer))]
             [("-s" "--seed") integer "random generator seed" (seed (string->number integer))]
             [("-r" "--readable") "safe characters" (readable? #t)])


(run (len) (cnt) (seed) (readable?)) </lang> Sample output:

$ racket ./passwdgen.rkt
4K{3EU30nP
$ racket ./passwdgen.rkt -l 15 -c 3 -s 1 -r
3_7tY~krwNz8MBP
966xU!&KT6mpW,M
Wh,(o*c_/Bf99K4

REXX

This REXX code was written as generically and idiomatically as possible so that the   special characters   and  
the lowercase and uppercase alphabets may be extended with letters from other alphabets.

This REXX version supports specifying a seed for the   random   BIF,   as well as specification of characters
to   not   to be used for the password.

This version isn't restricted to ASCII characters,   it also supports EBCDIC as well.

It has a REXX statement   (as a comment)   to support the writing of the generated passwords to a file.

The documentation (help) could be expanded greatly, but only an abridged version is included here to keep
this REXX example relatively small for this Rosetta Code task.

Also, much more error checking should be added;   not the least of it would be:

  •   if too many arguments specified   (on the command line)
  •   checking if the (random) seed is valid
  •   better (informative) error messages   (more verbose)
  •   don't let the user generate a gazillion passwords
  •   checking if the hexadecimal literal   (yyy)   is valid
  •   checking (for instance) if all digits were excluded via the   xxx   and/or   yyy   option

<lang rexx>/*REXX program generates a random password according to the Rosetta Code task's rules.*/ @L='abcdefghijklmnopqrstuvwxyz'; @U=@L; upper @U /*define lower-, uppercase Latin chars.*/ @#= 0123456789 /* " " string of base ten numerals.*/ @@= '!"#$%&()+,-./:;<=>?@[]^{|}~' || "'" /*define a bunch of special characters.*/ parse arg L N seed xxx yyy . /*obtain optional arguments from the CL*/ if L=='?' then signal help /*does user want documentation shown? */ if L== | L=="," then L=8 /*Not specified? Then use the default.*/ if N== | N=="," then N=1 /* " " " " " " */ if xxx\== then call weed xxx /*Any chars to be ignored? Scrub lists*/ if yyy\== then call weed x2c(yyy) /*Hex " " " " " " */ if datatype(seed,'W') then call random ,,seed /*the seed for repeatable RANDOM BIF #s*/ if \datatype(L, 'W') then call serr "password length, it isn't an integer: " L if L<4 then call serr "password length, it's too small (< 4): " L if L>80 then call serr "password length, it's too large (> 80): " L if \datatype(N, 'W') then call serr "number of passwords, it isn't an integer: " N

   do g=1  to N;       $=                       /*generate N passwords (default is one)*/
       do k=1  for L;       z=k;   if z>4  then z=random(1,4) /*1st four parts │ random*/
       if z==1  then $=$ || substr(@L,random(1,length(@L)),1) /*append lowercase letter*/
       if z==2  then $=$ || substr(@U,random(1,length(@U)),1) /*   "   uppercase    "  */
       if z==3  then $=$ || substr(@#,random(1,length(@#)),1) /*   "    numeral        */
       if z==4  then $=$ || substr(@@,random(1,length(@@)),1) /*   "  special character*/
       end   /*k*/
                                                /* [↓]  scrambles PW, hides gen order. */
       do a=1  for L;          b=random(1, L)   /*swap every character with another.   */
       parse var $ =(a) x +1 =(b)  y  +1        /*≡  x=substr($,a,1);  y=substr($,b,1) */
       $=overlay(x,$,b);       $=overlay(y,$,a) /*(both statements) swap two characters*/
       end  /*L+L*/                             /* [↑]  more swaps obfuscates gen order*/
   say right(g, length(N))  'password is: '  $  /*display the  Nth  password to console*/
   /*      call lineout 'GENPW.PW', $  */       /*and also write the password to a file*/     /*or not.*/
   end      /*g*/                               /* [↑]  {a comment}   fileID= GENPW.PW */

exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ weed: parse arg ig; @L=dont(@L); @U=dont(@U); @#=dont(@#); @@=dont(@@); return dont: return space( translate(arg(1), , ig), 0) /*remove chars from a list*/ serr: say; say '***error*** invalid' arg(1); exit 13 /*display an error message*/ help: signal .; .: do j=sigL+1 to sourceline(); say strip(left(sourceline(j),79)); end /* ╔═════════════════════════════════════════════════════════════════════════════╗ ║ GENPW  ? ◄─── shows this documentation. ║ ║ GENPW ◄─── generates 1 password (with length 8). ║ ║ GENPW len ◄─── generates (all) passwords with this length║ ║ GENPW , n ◄─── generates N number of passwords. ║ ║ GENPW , , seed ◄─── generates passwords using a random seed. ║ ║ GENPW , , , xxx ◄─── generates passwords that don't contain xxx║ ║ GENPW , , , , yyy ◄─── generates passwords that don't contain yyy║ ║ ║ ╟──────────── where [if a comma (,) is specified, the default is used]: ║ ║ len is the length of the passwords to be generated. The default is 8.║ ║ The minimum is 4, the maximum is 80. ║ ║ n is the number of passwords to be generated. The default is 1.║ ║ seed is an integer seed used for the RANDOM BIF. (Default is random.)║ ║ xxx are characters to NOT be used for generating passwords. ║ ║ The default is to use all the (normal) available characters. ║ ║ yyy (same as XXX, except the chars are expressed as hexadecimal pairs).║ ╚═════════════════════════════════════════════════════════════════════════════╝ */</lang> output   when using the inputs of:   10   20

 1 password is:  EQG@~?~a[6
 2 password is:  2J:"Cm|ol<
 3 password is:  Io32~fa[?L
 4 password is:  r)@;2;PsZE
 5 password is:  }#H"7Rk?4{
 6 password is:  cHB8Q!%@PI
 7 password is:  a7m75132.S
 8 password is:  Qcg4>FeNb7
 9 password is:  52vHl'+HIP
10 password is:  139Vk]aIL-
11 password is:  f1g;}b/W1W
12 password is:  lC74rIv5s<
13 password is:  O9$8g1}er4
14 password is:  c|E?Uh4c8~
15 password is:  :39OK2E8u#
16 password is:  vw=+uI-X+3
17 password is:  8YhJ)BS>>~
18 password is:  Vd]ZCUw%<0
19 password is:  6([b4Qk;O7
20 password is:  5ST.}:1t@O

Run BASIC

<lang Runbasic> a$(1) = "0123456789" a$(2) = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" a$(3) = "abcdefghijklmnopqrstuvwxyz" a$(4) = "!""#$%&'()*+,-./:;<=>?@[]^_{|}~" a$(0) = a$(1) + a$(2) + a$(3) + a$(4)

[main]

html "

" html "" html "" html "" html "
Password Generator
Number of Characters"

html "<INPUT TYPE=number id='howBig' NAME='howBig' value=7 min=4 max=16>"

html "
4 to 16
How many to generate"

html "<INPUT TYPE=number id='howMany' NAME='howMany' value=10 min=1 max=100>"

html "
1 to 100
"

button #gen, "Gemerate", [gen] button #ext, "Exit", [exit]

html "

"

wait

' ----------------------------- ' Generate Password ' ----------------------------- [gen] howBig = val(#request get$("howBig")) howMany = val(#request get$("howMany")) cls print "Generate ";howMany;" passwords with ";howBig;" characters" i = 0 while i < howMany pw$ = "" ok$ = "...." pw$ = ""

for j = 1 to howBig
	w$ = mid$(a$(0),int(rnd(0) * len(a$(0))) + 1,1)

for k = 1 to 4 if instr(a$(k),w$) then ok$ = left$(ok$,k-1) + "*" + mid$(ok$,k+1)

	next k
	pw$ = pw$ + w$

next j if ok$ = "****" then ' Do we pass with the requirements i = i + 1 print "#";i;" ";pw$ end if WEND goto [main] [exit] ' get outta here end </lang>Output:

Generate 10 passwords with 7 characters
#1 69+;Jj8
#2 80+T_e9
#3 1NEy[7e
#4 vj4~EvD
#5 3E(852y
#6 Cxjo]5R
#7 Hm5'tF+
#8 %i^<N7>
#9 9P8Qx_P
#10 f0Qho:5

Scala

Using SBT to run rather than a shell script or executable jar: <lang scala>object makepwd extends App {

 def newPassword( salt:String = "", length:Int = 13, strong:Boolean = true ) = {
   val saltHash = salt.hashCode & ~(1 << 31)
   
   import java.util.Calendar._
   val cal = java.util.Calendar.getInstance()
   val rand = new scala.util.Random((cal.getTimeInMillis+saltHash).toLong)
   val lower = ('a' to 'z').mkString
   val upper = ('A' to 'Z').mkString
   val nums = ('0' to '9').mkString
   val strongs = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~"
   val unwanted = if( strong ) "" else "0Ol"
   
   val pool = (lower + upper + nums + (if( strong ) strongs else "")).
              filterNot( c => unwanted.contains(c) )
   
   val pwdStream = Stream.continually( (for( n <- 1 to length; c = pool(rand.nextInt(pool.length) ) ) yield c).mkString )
   // Drop passwords that don't have at least one of each required character
   pwdStream.filter( pwd => 
     pwd.exists(_.isUpper) &&
     pwd.exists(_.isLower) &&
     pwd.exists(_.isDigit) &&
     (if(strong) pwd.exists(! _.isLetterOrDigit) else true)
   ).head
 }
 val pwdLength = """^(\d{1,4})$""".r
 val howMany = """^\-n(\d{0,3})$""".r
 val help = """^\-\-(help)$""".r
 val pwdSalt = """^\-s(.*)""".r
 val strongOption = """(?i)(strong)""".r
 
 
 var (salt,length,strong,helpWanted,count,unknown) = ("",13,false,false,1,false)
 
 args.foreach{ 
   case pwdLength(l) =>    length = math.min(math.max(l.toInt,6),4000)
   case strongOption(s) => strong = true
   case pwdSalt(s) =>      salt = s
   case howMany(c) =>      count = math.min(c.toInt,100)
   case help(h) =>         helpWanted = true
   case _ =>               unknown = true
 }
 if( count > 1 ) println
 
 if( helpWanted || unknown ) {
   println( """
 makepwd <length> "strong" -s<salt> -n<how-many> --help
   <length>     = how long should the password be
   "strong"     = strong password, omit if special characters not wanted
   -s<salt>     = "-s" followed by any non-blank characters 
                    (increases password randomness)
   -n<how-many> = "-n" followed by the number of passwords wanted
   --help       = displays this
   
 For example: makepwd 13 strong -n20 -sABCDEFG

""".stripMargin )

 }
 else for( i <- 1 to count ) println( newPassword( i + salt, length, strong ) )
 if( count > 1 ) println  

}</lang>

Output:

> sbt "run --help"

...

  makepwd <length> "strong" -s<salt> -n<how-many> --help

    <length>     = how long should the password be
    "strong"     = strong password, omit if special characters not wanted
    -s<salt>     = "-s" followed by any non-blank characters
                     (increases password randomness)
    -n<how-many> = "-n" followed by the number of passwords wanted
    --help       = displays this

  For example: makepwd 13 strong -n20 -sABCDEFG

> sbt "run 13 strong -sMySecret -n3"

...

}mR46_*cOq&v0
Ab~A!ddH8%JPd
z{A.m+$cqy#9I

zkl

Put the following code into a file (such as pwdg.zkl): <lang zkl>var pwdLen=10, pwds=1, xclude="";

argh:=Utils.Argh( L("+xclude","","Don't use these characters",fcn(arg){ xclude=arg }), L("+len","","Number of characters in password", fcn(arg){ pwdLen=arg.toInt() } ), L("+num","","Number of passwords to generate", fcn(arg){ pwds=arg.toInt() } ), ); try{ argh.parse(vm.arglist) }catch{ System.exit(1) }

isl:='wrap(w){ (w.sink(String).walk() - xclude).split("") }; // iterator to string to list g1,g2,g3:=isl(["a".."z"]), isl(["A".."Z"]), isl(["0".."9"]); g4:=("!\"#$%&'()*+,-./:;<=>?@[]^_{|}~" - xclude).split(""); all:=List().extend(g1,g2,g3,g4); // I can shuffle lists, not strings

   // generate random characters of filler needed to complete password

fill:='wrap(){ (pwdLen-4).pump(List,'wrap(){ all[(0).random(all.len())] }) };

do(pwds){

  pwd:=T(g1,g2,g3,g4).pump(List(),"shuffle",T("get",0)); // 1 from each of these
  pwd.extend(fill()).shuffle().concat().println();

}</lang> This is a command line program so output can be redirected.

Output:
$ zkl pwdg.zkl -?
Unknown option: ?
Options:
  --len <arg>: Number of characters in password
  --num <arg>: Number of passwords to generate
  --xclude <arg>: Don't use these characters

$ zkl pwdg.zkl --len 10 --xclude "Il1 O0 5S 2Z" --num 5
xyo9p$T]L8
D6}KeDYVq6
4<?BCWpRLj
4~x_46-Tqi
*:XE3G@myQ