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

Task
Password generator
You are encouraged to solve this task according to the task description, using any language you may know.
         lower-case letters:  a ──► z
         upper-case letters:  A ──► Z
                     digits:  0 ──► 9
 other printable characters:  !"#$%&'()*+,-./:;<=>?@[]^_{|}~ 
 (the above character list excludes white-space, backslash and grave) 


The generated password(s) must include   at least one   (of each of the four groups):

   lower-case letter, 
   upper-case letter,
   digit  (numeral),   and 
   one  "other"  character. 


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



8086 Assembly

This program runs under MS-DOS. The number and length of passwords are given as command line arguments, and there are command line options /E (to exclude Il1 O0 5S 2Z from the passwords), and /S (to set the seed for the RNG, without this option the system time is used). Help is printed when no arguments are given.

<lang asm> cpu 8086 bits 16 ;;; MS-DOS syscalls gettim: equ 2Ch ; Get system time write: equ 40h ; Write to file exit: equ 4Ch ; Exit with return code ;;; MS-DOS process data arg: equ 80h ; Command line argument (length + string) ;;; BIOS calls conout: equ 0Eh ; Write character to console vstate: equ 0Fh ; Get current video state section .text org 100h mov ah,gettim ; Seed the RNG using the system time int 21h ; (in case of no argument) mov [rnddat],cx mov [rnddat+2],dx mov si,arg ; See if we have any arguments lodsb test al,al jnz hasarg jmp usage ; If not, print usage string ;;; Parse the command line arguments hasarg: xor bx,bx ; We do, zero-terminate the string xchg al,bl mov [si+bx],al mov di,count ; Place to start reading arguments doarg: lodsb ; Get argument byte .chr: test al,al ; Zero? jnz .arg ; If not, there are arguments left jmp check ; If so, we're done .arg: cmp al,' ' ; Space? je doarg ; Then get next character cmp al,'/' ; Option? je opt dec byte [nargs] ; Otherwise, it's an argument jnz rdnum ; Read a number if we still need one jmp usage ; Otherwise, incorrect arguments rdnum: xor bp,bp ; Place to keep number .chr: mov bl,al ; Keep the character in case not a digit sub al,'0' ; Make into digit cmp al,9 ; Valid digit? ja .done ; If not, done with number add bp,bp ; Multiply accumulator by 10 mov dx,bp add bp,bp add bp,bp add bp,dx xor ah,ah ; Then add the digit add bp,ax lodsb ; Read next digit jmp .chr .done: mov ax,bp ; Write the number into memory stosw mov al,bl ; Restore the character (next argument) jmp doarg.chr opt: lodsb ; Get option character or al,32 ; Make lowercase cmp al,'e' ; E? je .e cmp al,'s' ; S? je .s jmp usage ; If not, invalid argument .e: inc byte [excl] ; /E: turn on exclusion jmp doarg .s: lodsb ; /S: should be followed by '=' cmp al,'=' je .s_ok jmp usage ; If not, invalid argument .s_ok: xor bp,bp ; DX:BP = RNG state xor dx,dx .hex: lodsb ; Get (potential) hex digit mov ah,al ; Keep it around call hexdgt ; Parse hexadecimal digit jnc .hdone ; If invalid, we're done shl bp,1 ; Make room for it in the state rcl dx,1 ; Because it's a 32-bit value, shl bp,1 ; which is stored in two 16-bit registers, rcl dx,1 ; we have to shift and rotate the bits shl bp,1 ; one by one. rcl dx,1 shl bp,1 rcl dx,1 or dl,al ; Finally, add in the hexadecimal digit jmp .hex .hdone: mov [rnddat],bp ; Store random seed mov [rnddat+2],dx mov al,ah ; Restore the next character jmp doarg.chr ;;; Check the arguments check: dec byte [nargs] ; Were all arguments used? jz .argok jmp usage .argok: mov cx,[count] ; CX = count mov bp,[length] ; BP = length test cx,cx ; Sanity check (count must not be zero) mov si,errmsg.cnt jnz .cntok jmp error .cntok: cmp bp,4 ; Length must be at least four mov si,errmsg.len jae .len2 jmp error .len2: cmp bp,255 ; Length must be no more than 255 mov si,errmsg.lmax jbe mkmask jmp error ;;; Make a bitmask in which BP fits (for generating random ;;; numbers in the right range) mkmask: mov cx,bp mov bx,cx .loop: shr cx,1 or bx,cx test cx,cx jnz .loop stc rcl bx,1 mov [lmask],bl ; Password <= 255 chars ;;; Generate a password genpwd: lea cx,[bp-4] ; Get length minus four mov di,buffer ; Write password into buffer mov dl,[excl] ; Exclusion flag mov bx,lc ; A lowercase letter, mov ah,lc.len call rndchr mov bx,uc ; An uppercase letter call rndchr ; (same length of course) mov bx,dgt ; A digit, mov ah,dgt.len call rndchr mov bx,sym ; And a symbol mov ah,sym.len call rndchr test cx,cx ; If CX=0, we need no extra characters jz .done mov bx,cr ; Otherwise, we need CX extra characters mov ah,cr.len .loop: call rndchr loop .loop .done: mov ax,0A0Dh ; End with a newline stosw ;;; Swap the first four characters with random characters ;;; from the password, so the four necessary characters won't ;;; necessarily be at the beginning. swap: mov dx,bp ; Get length mov dh,[lmask] ; Load the mask mov si,buffer ; Password buffer xor bh,bh xor ah,ah ; Starting at zero .loc: call rand ; Get random byte and al,dh ; Mask off unused bits cmp al,dl ; Result within password? jae .loc ; If not, get another random number mov bl,ah ; Load first character in CL mov cl,[si+bx] mov bl,al ; Load random character in CH mov ch,[si+bx] mov [si+bx],cl ; Write them back the other way around mov bl,ah mov [si+bx],ch inc ah ; Next character cmp ah,4 ; Are we there yet? jb .loc ; If not, do another character. ;;; Write password to standard output xor bx,bx ; File handle 0 = stdout lea cx,[bp+2] ; Length = password length + 2 (for newline) mov dx,si ; Location of password mov ah,write ; Write the password int 21h jnc .ok ; Carry clear = success mov si,errmsg.wrt ; Otherwise, print error message jmp error .ok: dec word [count] ; Need any more passwords? jz stop ; If not, stop jmp genpwd ; Otherwise, make another password ;;; Quit with return code 0 (success) stop: mov ax,exit<<8 int 21h ;;; Generate a random character. BX=table, AH=length, ;;; DL=exclusion on/off rndchr: call rand ; Random number and al,7Fh ; from 0 to 127 cmp al,ah ; Within valid length? jae rndchr ; If not, get new random number xlatb ; Otherwise, get character from table test dl,dl ; Is exclusion on? jz .out ; If not, just store it push cx ; Otherwise, keep CX around, push di ; and DI, mov cx,ex.len ; See if character is in exclusion table mov di,ex repne scasb pop di ; restore DI pop cx ; Restore CX je rndchr ; And if it was found, get another character .out: stosb ; Store in password buffer ret ;;; Random number generator using XABC algorithm ;;; Returns random byte in AL rand: push cx push dx mov cx,[rnddat] ; CH=X CL=A mov dx,[rnddat+2] ; DH=B DL=C inc ch ; X++ xor cl,ch ; A ^= X xor cl,dl ; A ^= C add dh,cl ; B += A mov al,dh ; C' = B shr al,1 ; C' >>= 1 xor al,cl ; C' ^= A add al,dl ; C' += C mov dl,al ; C = C' mov [rnddat],cx mov [rnddat+2],dx pop dx pop cx ret ;;; If AL is a hexadecimal digit in ASCII, set AL to be its ;;; value. Carry flag set if digit was valid. hexdgt: or al,32 ; Make letter lowercase (numbers unchanged) sub al,'0' ; Subtract 0 cmp al,10 ; If it is a valid digit now, we're done jc .out sub al,39 ; Otherwise, correct for cmp al,17 .out: ret ;;; Write the help message, and stop with return code 2 usage: mov si,help ;;; Write an error message, directly to the console, bypassing ;;; DOS to ensure it does not end up in the redirected output. ;;; Then, stop with return code 2 (failure) error: mov ah,vstate ; Retrieve current video state int 10h ; (this sets BH = current page) .loop lodsb ; Get string byte test al,al ; Zero? jz .out ; Then we have reached the end mov ah,conout ; Otherwise, write the character int 10h jmp .loop ; And get another one .out: mov ax,exit<<8|2 ; Stop with error code 2 int 21h section .data nargs: db 3 ; We need two non-option arguments excl: db 0 ; Exclusion is off by default cr: ;;; Password characters lc: db 'abcdefghijklmnopqrstuvwxyz' .len: equ $-lc uc: db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' .len: equ $-uc dgt: db '0123456789' .len: equ $-dgt sym: db '!"#$%&()*+,-./:;<=>?@[]^_{|}~',39 ; 39=single quote .len: equ $-sym cr.len: equ $-cr ex: db 'Il1O05S2Z' ; Excluded characters .len: equ $-ex ;;; Help message help: db 'PASSGEN [/S=seed] [/E] count length',13,10 db 9,'generate <count> passwords of length <length>',13,10 db 13,10 db 9,'/S=seed: set RNG seed (hexadecimal number)',13,10 db 9,'/E: exclude visually similar characters',13,10 db 0 errmsg: ;;; Error messages .len: db 'Minimum password length is 4.',0 .lmax: db 'Maximum password length is 255.',0 .cnt: db 'At least one password must be generated.',0 .wrt: db 'Write error.',0 section .bss count: resw 1 ; Amount of passwords to generate length: resw 1 ; Length of passwords lmask: resb 1 ; Mask for random number generation rnddat: resb 4 ; RNG state buffer: resb 257 ; Space to store password</lang>

Ada

<lang Ada>with Ada.Numerics.Discrete_Random; with Ada.Strings.Fixed; with Ada.Command_Line; with Ada.Integer_Text_IO; with Ada.Text_IO;

procedure Mkpw is

  procedure Put_Usage;
  procedure Parse_Command_Line (Success : out Boolean);
  function Create_Password (Length : in Positive;
                            Safe   : in Boolean)
                           return String;
  procedure Put_Usage is
     use Ada.Text_IO;
  begin
     Put_Line ("Usage:                                                     ");
     Put_Line ("   mkpw help   - Show this help text                       ");
     Put_Line ("   mkpw [count <n>] [length <l>] [seed ] [safe]         ");
     Put_Line ("     count <n>  - Number of passwords generated (default 4)");
     Put_Line ("     length <l> - Password length (min 4)       (default 4)");
     Put_Line ("     seed <l>   - Seed for random generator     (default 0)");
     Put_Line ("     safe       - Do not use unsafe characters  (0O1lIS52Z)");
  end Put_Usage;
  Lower_Set  : constant String := "abcdefghijklmnopqrstuvwxyz";
  Upper_Set  : constant String := "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  Digit_Set  : constant String := "0123456789";
  Spec_Set   : constant String := "!""#$%&'()*+,-./:;<=>?@[]^_{|}~";
  Unsafe_Set : constant String := "0O1lI5S2Z";
  Full_Set : constant String := Lower_Set & Upper_Set & Digit_Set & Spec_Set;
  subtype Full_Indices is Positive range Full_Set'Range;
  package Full_Index_Generator is
     new Ada.Numerics.Discrete_Random (Full_Indices);
  Index_Generator : Full_Index_Generator.Generator;
  Config_Safe          : Boolean  := False;
  Config_Count         : Natural  := 4;
  Config_Length        : Positive := 6;
  Config_Seed          : Integer  := 0;
  Config_Show_Help     : Boolean  := False;
  procedure Parse_Command_Line (Success : out Boolean) is
     use Ada.Command_Line;
     Got_Safe,   Got_Count : Boolean  := False;
     Got_Length, Got_Seed  : Boolean  := False;
     Last       : Positive;
     Index      : Positive := 1;
  begin
     Success := False;
     if Argument_Count = 1 and then Argument (1) = "help" then
        Config_Show_Help := True;
        return;
     end if;
     while Index <= Argument_Count loop
        if Ada.Command_Line.Argument (Index) = "safe" then
           if Got_Safe then
              return;
           end if;
           Got_Safe := True;
           Config_Safe     := True;
           Index := Index + 1;
        elsif Argument (Index) = "count" then
           if Got_Count then
              return;
           end if;
           Got_Count := True;
           Ada.Integer_Text_IO.Get (Item => Config_Count,
                                    From => Argument (Index + 1),
                                    Last => Last);
           if Last /= Argument (Index + 1)'Last then
              return;
           end if;
           Index := Index + 2;
        elsif Argument (Index) = "length" then
           if Got_Length then
              return;
           end if;
           Got_Length := True;
           Ada.Integer_Text_IO.Get (Item => Config_Length,
                                    From => Argument (Index + 1),
                                    Last => Last);
           if Last /= Argument (Index + 1)'Last then
              return;
           end if;
           if Config_Length < 4 then
              return;
           end if;
           Index := Index + 2;
        elsif Argument (Index) = "seed" then
           if Got_Seed then
              return;
           end if;
           Got_Seed := True;
           Ada.Integer_Text_IO.Get (Item => Config_Seed,
                                    From => Argument (Index + 1),
                                    Last => Last);
           if Last /= Argument (Index + 1)'Last then
              return;
           end if;
           Index := Index + 2;
        else
           return;
        end if;
     end loop;
     Success := True;
  exception
     when Constraint_Error | Ada.Text_IO.Data_Error =>
        null;
  end Parse_Command_Line;
  function Create_Password (Length : in Positive;
                            Safe   : in Boolean)
                           return String
  is
     function Get_Random (Safe : in Boolean)
                         return Character;
     function Get_Random (Safe : in Boolean)
                         return Character
     is
        use Ada.Strings.Fixed;
        C : Character;
     begin
        loop
           C := Full_Set (Full_Index_Generator.Random (Index_Generator));
           if Safe then
              exit when Index (Source => Unsafe_Set, Pattern => "" & C) = 0;
           else
              exit;
           end if;
        end loop;
        return C;
     end Get_Random;
     function Has_Four (Item : in String)
                       return Boolean;
     function Has_Four (Item : in String)
                       return Boolean
     is
        use Ada.Strings.Fixed;
        Has_Upper, Has_Lower : Boolean := False;
        Has_Digit, Has_Spec  : Boolean := False;
     begin
        for C of Item loop
           if Index (Upper_Set, "" & C) /= 0 then Has_Upper := True; end if;
           if Index (Lower_Set, "" & C) /= 0 then Has_Lower := True; end if;
           if Index (Digit_Set, "" & C) /= 0 then Has_Digit := True; end if;
           if Index (Spec_Set,  "" & C) /= 0 then Has_Spec  := True; end if;
        end loop;
        return Has_Upper and Has_Lower and Has_Digit and Has_Spec;
     end Has_Four;
     Password : String (1 .. Length);
  begin
     loop
        for I in Password'Range loop
           Password (I) := Get_Random (Safe);
        end loop;
        exit when Has_Four (Password);
     end loop;
     return Password;
  end Create_Password;
  Parse_Success : Boolean;

begin

  Parse_Command_Line (Parse_Success);
  if Config_Show_Help or not Parse_Success then
     Put_Usage;  return;
  end if;
  if Config_Seed = 0 then
     Full_Index_Generator.Reset (Index_Generator);
  else
     Full_Index_Generator.Reset (Index_Generator, Config_Seed);
  end if;
  for Count in 1 .. Config_Count loop
     Ada.Text_IO.Put_Line (Create_Password (Length => Config_Length,
                                            Safe   => Config_Safe));
  end loop;

end Mkpw;</lang>

Output:
$ ./mkpw count 8 length 22 safe
">M<P]GMHf77cbT%b8.eX]
W3Q&k~L*R,z)39(a{AvGon
3Xvh=:P9BGGU$=YPD{dFW@
^X)]vV4fFtCXksgv+,usHx
$89*bxyb?@aQEQ8~~vaq9o
FW{F*-]tDJH~]/7CLtRe-k
6%K6(8&fyX=,&TBFvW%kz3
+@pyJ'3YQ'%~9?Tm/BHk?A

Arturo

<lang rebol>lowercase: `a`..`z` uppercase: `A`..`Z` digits: `0`..`9` other: map split "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~" => [to :char]

any: lowercase ++ uppercase ++ digits ++ other

generate: function [length][

   if length < 4 [
       print (color #red "ERROR: ") ++ "password length too short"
       exit
   ]
   chars: new @[sample lowercase sample uppercase sample digits sample other]
   while [length > size chars][
       'chars ++ sample any
   ]
   join shuffle chars

]

if 0 = size arg [

   print {
       ---------------------------------
       Arturo password generator
       (c) 2021 drkameleon
       ---------------------------------
       usage: passgen.art <length>
   }
   exit

]

loop 1..10 'x [

   print generate to :integer first arg

]</lang>

Output:
; executed with ./passgen.art 10

T{6G7:qgyp
s7|iC2S0Tf
D6.Ac}1}oz
9**;81R@h<
H+|0CBN(ca
x!C#0yri]@
OfV7wlg*<G
{0z3MVJUNg
yULk,=B)84
C>o6]&9y<X

AWK

<lang AWK>

  1. syntax: GAWK -f PASSWORD_GENERATOR.AWK [-v mask=x] [-v xt=x]
  2. examples:
  3. REM 4 character passwords using Rosetta Code default of: lower, upper, number, other
  4. GAWK -f PASSWORD_GENERATOR.AWK
  5. REM 8 character passwords; Rosetta Code default plus another four
  6. GAWK -f PASSWORD_GENERATOR.AWK -v mask=LUNPEEEE
  7. REM 8 character passwords ignoring Rosetta Code requirement
  8. GAWK -f PASSWORD_GENERATOR.AWK -v mask=EEEEEEEE
  9. REM help
  10. GAWK -f PASSWORD_GENERATOR.AWK ?
  11. sorting:
  12. PROCINFO["sorted_in"] is used by GAWK
  13. SORTTYPE is used by Thompson Automation's TAWK

BEGIN {

   PROCINFO["sorted_in"] = "@ind_str_asc" ; SORTTYPE = 1
   srand()
  1. setup strings of valid characters used by mask
   arr["L"] = "abcdefghijklmnopqrstuvwxyz"        # Lower case
   arr["U"] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"        # Upper case
   arr["N"] = "0123456789"                        # Numbers
   arr["P"] = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~"   # Punctuation: I.E. other
   arr["A"] = arr["L"] arr["U"]                   # Alphabetic: lower and upper case
   arr["E"] = arr["L"] arr["U"] arr["N"] arr["P"] # Everything: lower, upper, number, punctuation
   arr["B"] = " "                                 # Blank: a space
  1. validate array index and length of assignment
   for (i in arr) {
     if (length(i) != 1) {
       error(sprintf("arr[%s], index is invalid",i))
     }
     if (length(arr[i]) == 0) {
       error(sprintf("arr[%s], is null",i))
     }
     mask_valids = sprintf("%s%s",mask_valids,i)
   }
  1. validate command line variables
   if (mask == "") {
     mask = "LUNP" # satisfy Rosetta Code task requirement
   }
   if (xt == "") {
     xt = 10 # default iterations
   }
   if (xt !~ /^[0-9]+$/) {
     error("xt is not 0-9")
   }
  1. validate each character in mask
   for (i=1; i<=length(mask); i++) {
     c = substr(mask,i,1)
     if (!(c in arr)) {
       error(sprintf("mask position %d is %s, invalid",i,c))
     }
   }
  1. help
   if (ARGV[1] == "?") {
     syntax()
     exit(0)
   }
   if (ARGC-1 != 0) {
     error("no files allowed on command line")
   }
  1. make passwords
   if (errors == 0) {
     for (i=1; i<=xt; i++) {
       make_password()
     }
   }
   exit(errors+0)

} function error(message) {

   printf("error: %s\n",message)
   errors++

} function make_password( c,i,indx,password,valids) {

   for (i=1; i<=length(mask); i++) {  # for each character in mask
     c = substr(mask,i,1)             # extract 1 character from mask
     valids = arr[c]                  # valid characters for this position in mask
     indx = int(rand() * length(valids)) + 1
     c = substr(valids,indx,1)        # extract 1 character from list of valids
     password = password c            # build password
   }
   printf("%s\n",password)

} function syntax( cmd,i) {

   cmd = "GAWK -f PASSWORD_GENERATOR.AWK"
   printf("syntax: %s [-v mask=x] [-v xt=x]\n\n",cmd)
   printf("  mask  1..n bytes determines password format and length; consists of %s\n",mask_valids)
   for (i in arr) {
     printf("%9s - %s\n",i,(arr[i] == " ") ? "<space>" : arr[i])
   }
   printf("  xt    number of passwords to generate\n\n")
   printf("example: %s -v mask=%s -v xt=%s\n",cmd,mask,xt)

} </lang>

Output:
GAWK -f PASSWORD_GENERATOR.AWK -v mask=LUNPEEEE -v xt=5
iX1<-a%p
xH6]rrZ+
eK8*5@P/
cY9'kwG*
qS9=7wtU

C

<lang c>

  1. include <stdio.h>
  2. include <stdlib.h>
  3. include <time.h>
  1. define DEFAULT_LENGTH 4
  2. define DEFAULT_COUNT 1

char* symbols[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz", "0123456789", "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~"}; int length = DEFAULT_LENGTH; int count = DEFAULT_COUNT; unsigned seed; char exSymbols = 0;

void GetPassword () {

   //create an array of values that determine the number of characters from each category 
   int lengths[4] = {1, 1, 1, 1};
   int count = 4;
   while (count < length) {
       lengths[rand()%4]++;
       count++;
   } 
   //loop through the array of lengths and set the characters in password
   char password[length + 1];
   for (int i = 0; i < length; ) { 
       //pick which string to read from
       int str = rand()%4;
       if (!lengths[str])continue;   //if the number of characters for that string have been reached, continue to the next interation
       char c;
       switch (str) {
           case 2:
               c = symbols[str][rand()%10];
               while (exSymbols && (c == 'I' || c == 'l' || c == '1' || c == 'O' || c == '0' || c == '5' || c == 'S' || c == '2' || c == 'Z'))
                   c = symbols[str][rand()%10];
               password[i] = c;
           break;
           case 3:
               c = symbols[str][rand()%30];
               while (exSymbols && (c == 'I' || c == 'l' || c == '1' || c == 'O' || c == '0' || c == '5' || c == 'S' || c == '2' || c == 'Z'))
                   c = symbols[str][rand()%30];
               password[i] = c;
           break;
           default:
               c = symbols[str][rand()%26];
               while (exSymbols && (c == 'I' || c == 'l' || c == '1' || c == 'O' || c == '0' || c == '5' || c == 'S' || c == '2' || c == 'Z'))  
                   c = symbols[str][rand()%26];
               password[i] = c;
           break;
       }
       i++;
       lengths[str]--;
   }
   password [length] = '\0';
   printf ("%s\n", password);

}

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

   seed = (unsigned)time(NULL);
   //handle user input from the command line
   for (int i = 1; i < argc; i++) {
       switch (argv[i][1]) {
           case 'l':
               if (sscanf (argv[i+1], "%d", &length) != 1) {
                   puts ("Unrecognized input. Syntax: -l [integer]");
                   return -1;
               }
               
               if (length < 4) {
                   puts ("Password length must be at least 4 characters.");
                   return -1;
               }
               i++;                
           break;
           case 'c':
               if (sscanf (argv[i+1], "%d", &count) != 1) {
                   puts ("Unrecognized input. Syntax: -c [integer]");
                   return -1;
               }
               if (count <= 0) {
                   puts ("Count must be at least 1.");
                   return -1;
               }
               i++;
           break;
           case 's':
               if (sscanf (argv[i+1], "%d", &seed) != 1) {
                   puts ("Unrecognized input. Syntax: -s [integer]");
                   return -1;
               }
               i++;
           break;
           case 'e':
               exSymbols = 1;
           break;
           default:
               help:
               printf ("Help:\nThis program generates a random password.\n"
               "Commands:"
                  "Set password length: -l [integer]\n"
                  "Set password count: -c [integer]\n"
                  "Set seed: -s [integer]\n"
                  "Exclude similiar characters: -e\n"
                  "Display help: -h");
               return 0;
           break;
       }    
   }
   srand (seed);
   for (int i = 0; i < count; i++)
       GetPassword();
   
   return 0;

} </lang>

Output:
./password
5zK@

./password -c 3 -l 10
L=C17QQn<$
uyC;X5kc76
D8Yw.827$]

C#

<lang csharp>using System; using System.Linq;

class Program {

   const string Lower = "abcdefghijklmnopqrstuvwxyz";
   const string Upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   const string Digits = "0123456789";
   const string Symbols = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~";
   static readonly string[] Full = {Lower, Upper, Digits, Symbols, Lower + Upper + Digits + Symbols};
   const string Similar = "Il1O05S2Z";
   static readonly string[] Excluded = Full.Select(x => new string(x.Except(Similar).ToArray())).ToArray();
   static Random _rng = new Random();
   static string[] _symbolSet = Full;
   static void Main(string[] args)
   {
       int length = 12, count = 1;
       try
       {
           foreach (var x in args.Select(arg => arg.Split(':')))
           {
               switch (x[0])
               {
                   case "-l": length = int.Parse(x[1]); break;
                   case "-c": count = int.Parse(x[1]); break;
                   case "-s": _rng = new Random(x[1].GetHashCode()); break;
                   case "-x": _symbolSet = bool.Parse(x[1]) ? Excluded : Full; break;
                   default: throw new FormatException("Could not parse arguments");
               }
           }
       }
       catch { ShowUsage(); return; }
       try
       {
           for (int i = 0; i < count; i++)
               Console.WriteLine(GeneratePass(length));
       }
       catch (Exception ex) { Console.WriteLine("Error: " + ex.Message); }
   }
   static void ShowUsage()
   {
       Console.WriteLine("Usage: PASSGEN [-l:length] [-c:count] [-s:seed] [-x:(true|false)]");
       Console.WriteLine("\t-l: the length of the generated passwords");
       Console.WriteLine("\t-c: the number of passwords to generate");
       Console.WriteLine("\t-s: seed for the random number generator");
       Console.WriteLine("\t-x: exclude similar characters: " + Similar);
       Console.WriteLine("Example: PASSGEN -l:10 -c:5 -s:\"Sample Seed\" -x:true");
   }
   static string GeneratePass(int length)
   {
       var minLength = _symbolSet.Length - 1;
       if(length < minLength)
           throw new Exception("password length must be " + minLength + " or greater");
       int[] usesRemaining = Enumerable.Repeat(1, _symbolSet.Length).ToArray();
       usesRemaining[minLength] = length - minLength;
       var password = new char[length];
       for (int ii = 0; ii < length; ii++)
       {
           int set = _rng.Next(0, _symbolSet.Length);
           if (usesRemaining[set] > 0)
           {
               usesRemaining[set]--;
               password[ii] = _symbolSet[set][_rng.Next(0, _symbolSet[set].Length)];
           }
           else ii--;
       }
       return new string(password);
   }

}</lang>

Output:
PASSGEN -l:12 -c:6
Bc'9(i(&bw]G
g=9JnTy2tzMn
G8^UtYdx4D9Y
^S4uq?*yXEA=
W{3*hdk&0p?R
"4Ips4;8S3o~

C++

<lang cpp>#include <iostream>

  1. include <string>
  2. include <algorithm>
  3. 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 exclude 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] ),
           e = atoi( argv[3] ), 
           s = atoi( argv[4] );
       if( l < 4 ) {
           std::cout << "Passwords must be at least 4 characters long.\n\n";
       } else {
           if (s == 0) {
              std::srand( time( NULL ) );
           } else {
              std::srand( unsigned( s ) );
           }
           generate( l, c, e != 0 );
       }
   }
   return 0;   

}</lang>

Output:
PWGEN 6 6 1 8
9@NcCe
4jERh!
<zX4Mr
Cob+X7
GU8_jt
rF9t%F

PWGEN 6 6 0 8
cn2ZO~
W:iRm7
0|hyJU
.h3JfL
3oq;FT
u*VT4t

Ceylon

module.ceylon:

<lang ceylon> module rosetta.passwordgenerator "1.0.0" {

   import ceylon.random "1.2.2";

}

</lang>

run.ceylon:

<lang ceylon> import ceylon.random {

   DefaultRandom,
   Random

}

Character[] lowerCaseChars = 'a'..'z'; Character[] upperCaseChars = 'A'..'Z'; Character[] numsAsChars = '0'..'9'; Character[] specialChars = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~".sequence(); Character[] allChars = lowerCaseChars.append(upperCaseChars)

                                    .append(numsAsChars)
                                    .append(specialChars);

shared void run() {

   print("2 passwords of size 8");
   print("------");
   generatePasswords(8,2).each(print);
   print("------");
   print("5 passwords of size 12");
   print("------");
   generatePasswords(12,5).each(print);
   print("------");
   print("7 passwords of size 16");
   print("------");
   generatePasswords(16,7).each(print);
   print("------");
   print("2 passwords of size 16 exclude AiX24!~");
   print("------");
   generatePasswords(16,7,"AiX24!~".sequence()).each(print);

}

String[] generatePasswords(Integer numChars, Integer numPasswords, Character[] excludedChars=[])

   => [for (count in 1..numPasswords) generatePassword(numChars,excludedChars) ];

//The generated password(s) must include at least one lower-case letter, one upper-case letter and one character from digits and 'other'. String generatePassword(Integer numChars, Character[] excludedChars) {

   "Must provide a password length of at least 4"
   assert(numChars >= 4);
   value random = DefaultRandom();
   value fixedPartOfPassword = passwordFragmentForRequirements(random,excludedChars);
   value randomPart =
      randomPartOfPassword{ random = random;
                            index = fixedPartOfPassword.size + 1;
                            randomPart = "";
                            numChars = numChars;
                            candidateChars = filterCharsToExclude(allChars, excludedChars); };
   value unshuffledPassword = fixedPartOfPassword + randomPart;
   assert(unshuffledPassword.string.size == numChars);
   "excluded chars contained"
   assert(! unshuffledPassword.any((char) => excludedChars.contains(char)));
   "Sizes not equal"
   assert(unshuffledPassword.size == numChars);
   value shuffledPassword =
       shuffleCharsRecursive(unshuffledPassword.string,"",unshuffledPassword.indexes().sequence());
   "Sizes not equal"
   assert(shuffledPassword.string.size == numChars);
   "set of characters not equal"
   assert(set(unshuffledPassword) == set(shuffledPassword));
   return shuffledPassword;

}

String passwordFragmentForRequirements(Random random, Character[] excludedChars)

   => String({filterAndUse(random,lowerCaseChars, excludedChars),
              filterAndUse(random,upperCaseChars,excludedChars),
              filterAndUse(random,numsAsChars,excludedChars),
              filterAndUse(random,specialChars,excludedChars)});

String randomPartOfPassword(Random random,

                           Integer index,
                           String randomPart,
                           Integer numChars,
                           Character[] candidateChars) {
   if(index <= numChars) {
       value candidateCharsIndex = random.nextInteger(candidateChars.size);
       assert(exists allChar = candidateChars[candidateCharsIndex]);
       return randomPartOfPassword{ random=random;
                                    index=index+1;
                                    randomPart = randomPart + allChar.string;
                                    numChars =numChars;
                                    candidateChars = candidateChars; };
   }
   return randomPart;

}

String shuffleCharsRecursive(String orig,String shuffledString,Integer[] remainingOrigIndexes) {

   value random = DefaultRandom();
   if (nonempty constRemainingIndexes = remainingOrigIndexes) {
       value randomIndex = random.nextInteger(orig.size);
       assert(exists nextChar = orig[randomIndex]);
       String newShuffledString;
       Integer[] newRemainingIndexes;
       if (constRemainingIndexes.contains(randomIndex)) {
           newShuffledString = shuffledString + nextChar.string;
           newRemainingIndexes = constRemainingIndexes.filter((index) => randomIndex != index).sequence();
       } else {
           newShuffledString = shuffledString;
           newRemainingIndexes = constRemainingIndexes;
       }
       return shuffleCharsRecursive{ orig=orig;
                                     shuffledString=newShuffledString;
                                     remainingOrigIndexes=newRemainingIndexes; };
   }
   return shuffledString;

}

Character filterAndUse(Random random, Character[] chars, Character[] excludedChars) {

   value charsToUse = filterCharsToExclude(chars, excludedChars);
   value charToUseIndex = random.nextInteger(charsToUse.size);
   assert( exists charToUse = charsToUse[charToUseIndex]);
   return charToUse;

}

Character[] filterCharsToExclude(Character[] chars, Character[] charsToExclude)

   => chars.filter((char) => ! charsToExclude.contains(char)).sequence();

</lang>


Output:
2 passwords of size 8
------
o"{#3A]F
7OZ{k-!-
------
5 passwords of size 12
------
>jA%dQ[71RR{
e-(KQgjr!H1B
XF41ALUX&odg
)vpjL6YI=S38
[=e8."8!A*Dn
------
7 passwords of size 16
------
r/|'y0G&5:UA]AF#
75}P4L>^R0'#WkLR
bK2{Tg1del{pM/}n
86mz,.NfUB3b-A4)
4KOh7D5'W<oQ=/(e
s1b8~XA*f'y6mCA8
D^RwIB9-tL:_JTD7
------
2 passwords of size 16 exclude AiX24!~
------
8bx3$y=ZPdcT"Ls3
{M$EeG{x:]"6cZO|
"{?zn{80?g^eGK&w
u{VN#jy{TZpJ}5/F
5;_VaVG?^O:6xCo%
v:xx%Ht*Zc13GekC
Mg0M:BpCbz3O0BDo

Clojure

<lang clojure>(ns pwdgen.core

 (:require [clojure.set :refer [difference]]
           [clojure.tools.cli :refer [parse-opts]])
 (:gen-class))

(def minimum-length 4) (def cli-options

 [["-c" "--count NUMBER" "Number of passwords to generate"
   :default 1
   :parse-fn #(Integer/parseInt %)]
  ["-l" "--length NUMBER" "Length of the generated passwords"
   :default 8
   :parse-fn #(Integer/parseInt %)
   :validate [#(<= minimum-length %) (str "Must be greater than or equal to " minimum-length)]]
  ["-x", "--exclude-similar" "Exclude similar characters"]
  ["-h" "--help"]])

(def lowercase (map char (range (int \a) (inc (int \z))))) (def uppercase (map char (range (int \A) (inc (int \Z))))) (def numbers (map char (range (int \0) (inc (int \9))))) (def specials (remove (set (concat lowercase uppercase numbers [\` \\])) (map char (range (int \!) (inc (int \~)))))) (def similar #{\I \l \1 \| \O \0 \5 \S \2 \Z})

(defn sanitize [coll options]

 (if (:exclude-similar options) (into '() (difference (set coll) similar)) coll))

(defn generate-password [options]

 (let [upper (rand-nth (sanitize uppercase options))
       lower (rand-nth (sanitize lowercase options))
       number (rand-nth (sanitize numbers options))
       special (rand-nth (sanitize specials options))
       combined (shuffle (sanitize (concat lowercase uppercase numbers specials) options))]
   (shuffle (into (list upper lower number special) (take (- (:length options) minimum-length) combined)))))

(defn -main [& args]

 (let [{:keys [options summary]} (parse-opts args cli-options)]
   (if (:help options) (println summary)
     (dotimes [n (:count options)]
       (println (apply str (generate-password options)))))))</lang>
Output:
$ lein run -- -h
  -c, --count NUMBER     1  Number of passwords to generate
  -l, --length NUMBER    8  Length of the generated passwords
  -x, --exclude-similar     Exclude similar characters
  -h, --help

$ lein run -l 20 -c 2
xn~a9UDE,rUm+x2w3o00
vlA|&fI>W57D^U:3g9L!

$ lein run --length 5 --count 3 -x
VT6-u
#kR6Y
Pj+4b

Commodore BASIC

Note that on line 220, the CLR statement is called prior to restarting the program to avoid a ?REDIM'D ARRAY ERROR if line 85 should execute. By default, single dimension arrays do not need to be DIMensioned if kept to 11 elements (0 through 10) or less. Line 85 checks for this.

<lang gwbasic>1 rem password generator 2 rem rosetta code 10 g$(1)="abcdefghijklmnopqrstuvwxyz" 15 g$(2)="ABCDEFGHIJKLMNOPQRSTUVWXYZ" 20 g$(3)="0123456789" 25 g$(4)="<>!@#$%^&*()[];:'.?/" 30 print chr$(147);chr$(14) 35 print "Password Generator":print 40 print "Press H for help, or any":print "other key to begin.":print 45 get k$:if k$="" then 45 50 if k$="h" then gosub 500 60 print chr$(147) 65 input "Enter password length: (6-30)";pl 70 if pl<6 or pl>30 then print "Out of range.":goto 65 75 print:input "How many passwords (1-20)";np 80 if np<1 or np>20 then print "Out of range.":goto 75 85 if np>10 then dim pw$(np) 90 if np*pl > 100 then print:print "Um... Ok, this might take a bit." 100 for pc=1 to np 105 for i=1 to 4:g(i)=0:next 110 tp$="" 112 for i=1 to pl 115 cg=int(rnd(1)*4)+1 120 cc=int(rnd(1)*len(g$(cg)))+1 125 tp$=tp$+mid$(g$(cg),cc,1) 130 g(cg)=g(cg)+1 135 next i 140 for i=1 to 4 145 if g(i)=0 then goto 110 150 next i 155 pw$(pc)=tp$ 160 next pc 200 print chr$(147);"Password list:":print 205 for pc=1 to np:print pc;chr$(157);".";tab(6);pw$(pc):next pc 210 print:print "Again? (y/n)"; 215 get k$:if k$<>"y" and k$<>"n" then 215 220 if k$="y" then clr:goto 10 225 end 500 rem *** help *** 505 print chr$(147);"This program will generate a password" 510 print "made up of each of the following" 515 print "character types:":print 520 print " - Uppercase Letter (A-Z)" 525 print " - Lowercase Letter (a-z)" 530 print " - Number (0-9)" 535 print " - Punctuation and Other Symbols" 540 print " (e.g. # $ ! & [ . ;, etc.)" 545 print 550 print "You may choose how many total characters"; 555 print "(up to 30) should be in the password, " 560 print "and how many passwords (up to 20) should"; 565 print "be generated. The program ensures that " 570 print "there is at least one character from " 575 print "each of the character types in each " 580 print "password." 585 print 590 print "Note: You can edit the character lists" 595 print "on lines 10-25 to customize the" 600 print "selection pool." 605 print 610 print "Press any key to begin." 615 get k$:if k$="" then 615 620 return</lang>

Output:
Password Generator                      
                                        
Press H for help, or any                
other key to begin.                     

This program will generate a password   
made up of each of the following        
character types:                        
                                        
 - Uppercase Letter (A-Z)               
 - Lowercase Letter (a-z)               
 - Number (0-9)                         
 - Punctuation and Other Symbols        
   (e.g. # $ ! & [ . ;, etc.)           
                                        
You may choose how many total characters
(up to 30) should be in the password,   
and how many passwords (up to 20) should
be generated. The program ensures that  
there is at least one character from    
each of the character types in each     
password.                               
                                        
Note: You can edit the character lists  
on lines 10-25 to customize the         
selection pool.                         
                                        
Press any key to begin.
                                        
Enter password length: (6-30)? 12       
                                        
How many passwords (1-20)? 10           
                                        
Um... Ok, this might take a bit.

Password list:                          
                                        
 1.   K6GmO#[%lz7w                      
 2.   L6W(ln<Qldvy                      
 3.   lc48].KX<F$w                      
 4.   3$Z%;8/&70y5                      
 5.   <Ns@!W9#0[s3                      
 6.   )Sr!oZ<1pS1I                      
 7.   mhC4VTy]6a:7                      
 8.   !j4ntp8lJ1JY                      
 9.   ?b?1x48m$D65                      
 10.  Ooi;3W>[gr77                      
                                        
Again? (y/n)                            
ready.
█

Common Lisp

<lang lisp> (defvar *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))

(defvar *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))

(defvar *numbers* '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9))

(defvar *special-characters* '(#\! #\\ #\# #\$ #\% #\& #\' #\( #\) #\*

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

(defvar *similar-characters* '(#\I #\l #\1 #\| #\O #\0 #\5 #\S #\2 #\Z))

(defun make-readable (s)

 (remove-if (lambda (x) (member x *similar-characters*)) s))

(defun shuffle-list (input-list)

 (loop with l = (length input-list)
    for i below l
    do (rotatef (nth i input-list)
        (nth (random l) input-list)))
 input-list)

(defun generate-password (len human-readable)

 (let*
   ((upper (if human-readable (make-readable *uppercase*) *uppercase*))
   (lower (if human-readable (make-readable *lowercase*) *lowercase*))
   (number (if human-readable (make-readable *numbers*) *numbers*))
   (special (if human-readable (make-readable *special-characters*) *special-characters*))
   (character-groups (list upper lower number special))
   (initial-password (reduce (lambda (acc x)
     (cons (nth (random (length x)) x) acc))
     character-groups :initial-value NIL)))
   (coerce (shuffle-list (reduce (lambda (acc x)
     (declare (ignore x))
     (let ((group (nth (random (length character-groups)) character-groups)))
       (cons (nth (random (length group)) group) acc)))
     (make-list (- len 4)) :initial-value initial-password)) 'string)))

(defun main (len count &optional human-readable)

 (if (< len 4)
   (print "Length must be at least 4~%")
   (loop for x from 1 to count do
     (print (generate-password len human-readable)))))

</lang>

Output:
$ (main 10 4 t)
"AV}HU&?8^s"
"y~868Wr3?j"
"4wy:Wy$zR8"
"Lx'6fsU+3t"
"&zXi3s71Jf"
"7ppunc1;G1"

Crystal

<lang Crystal>require "random/secure"

special_chars = true similar = 0 require_groups = true length = 20 count = 1

def show_usage

 puts <<-USAGE
 
      Passwords generator
      Usage: pass2 [count] [-l<length>] [-s{0|1|2}] [-ng] [-ns]
        count: number of passwords to be generated (default: 1)
        -l<length>: length of passwords (default: 20)
        -s{0|1|2}: exclude visually similar characters. 
                     0 - don't exclude (default)
                     1 - exclude 0, O, 1, I, l, |
                     2 - also exclude 2, Z, 5, S
       -ng: dont require password to include character from every group
       -ns: dont include special chars in password
       
       Default value of switches is choosen to match the task in page header, but I suggest to use the "-s1 -ng -ns".
      USAGE

end

count_set = false begin

 ARGV.each do |arg|
   case arg
   when /-l(\d+)/
     length = $1.to_i
     raise "Error: minimal length is 4" if length < 4
   when /-s(\d)/
     similar = $1.to_i
     raise "Error: minimal length is 4" unless {0, 1, 2}.includes? similar
   when /-ng/
     require_groups = false
   when /-ns/
     special_chars = false
   when /(\d+)/
     raise "incorrect arguments" if count_set
     count_set = true
     count = $1.to_i
   else
     raise "incorrect argument"
   end
 end

rescue ex

 puts ex.message
 show_usage
 exit

end

  1. actual program

GROUPS = [('a'..'z').to_a, ('A'..'Z').to_a, ('0'..'9').to_a] GROUPS << "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~".chars if special_chars

letters = GROUPS.flatten letters -= "1l|I0O".chars if similar > 0 letters -= "5S2Z".chars if similar > 1

loop do

 s = Array(Char).new(length) { letters.sample(Random::Secure) }
 # it's better to just discard in order to don't lose enthropy
 next if require_groups && GROUPS.any? { |x| (s & x).size == 0 }
 puts s.join
 count -= 1
 break if count <= 0

end </lang>

Output:
user@laptop:/mnt/d/Projects/crystal$ ./pass2
0X{feScBZ_/b>7)>aL8)
user@laptop:/mnt/d/Projects/crystal$ ./pass2 -?
incorrect argument

Passwords generator
Usage: pass2 [count] [-l<length>] [-s{0|1|2}] [-ng] [-ns]

  count: number of passwords to be generated (default: 1)
  -l<length>: length of passwords (default: 20)
  -s{0|1|2}: exclude visually similar characters.
               0 - don't exclude (default)
               1 - exclude 0, O, 1, I, l, |
               2 - also exclude 2, Z, 5, S
 -ng: don't require password to include character from every group
 -ns: don't include special chars in password

 Default value of switches is choosen to match the task in page header, but I suggest to use the "-s1 -ng -ns".
user@laptop:/mnt/d/Projects/crystal$ ./pass2 10 -l20 -s2
j;K#3znen(j9%Bk6<tXf
k]h&i9[#["Pzr^zd<.9]
Xr%:7RP4%]^EXW?xB$A]
@{Jq/HWC%6.6+>BuGg/%
!99Y}8nEM$*hwRQ<-+Q>
*:"[r$tyf8zsv$%}n*M[
4nxHcMjn*v}j_qYon!qc
W#QqTu3NFF/m;Prs3]qe
i:_AEtzJQ^J]ek:G9[8=
=#_i3t]p}^gJP"z(&QaA
user@laptop:/mnt/d/Projects/crystal$ ./pass2 10 -l10 -s1 -ng -ns
fd5rHMaT6v
GzwccX2jQZ
Lx8rivLSLQ
a9NzxSQMhm
w5rrfpwJt8
RsbtZbgMxM
FcRPVxrxAA
s9fzZMwb8d
pKGyGPT7yN
ABZcXEPNWq
user@laptop:/mnt/d/Projects/crystal$

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

F#

The function

<lang fsharp> // A function to generate passwords of a given length. Nigel Galloway: May 2nd., 2018 let N = (set)"qwertyuiopasdfghjklzxcvbnm" let I = (set)"QWERTYUIOPASDFGHJKLZXCVBNM" let G = (set)"7894561230" let E = (set)"""!"#$%&'()*+,-./:;<=>?@[]^_{|}~[||]""" let L = Array.ofSeq (Set.unionMany [N;I;G;E]) let y = System.Random 23 let pWords n=

 let fN n = not (Set.isEmpty (Set.intersect N n )||Set.isEmpty (Set.intersect I n )||Set.isEmpty (Set.intersect G n )||Set.isEmpty (Set.intersect E n ))
 Seq.initInfinite(fun _->(set)(List.init n (fun _->L.[y.Next()%(Array.length L)])))|>Seq.filter fN|>Seq.map(Set.toArray >> System.String)

</lang>

A possible use

Print 5 password of length 8 <lang fsharp> pWords 8 |> Seq.take 5 |> Seq.iter(printfn "%s") </lang>

Output:
+06:?H^w
$36=?Ofn
37<@TXk
,169GJWl
&6CDelow

Factor

Works with: Factor version 0.99 2020-01-23

<lang factor>USING: arrays assocs combinators command-line continuations io kernel math math.parser multiline namespaces peg.ebnf prettyprint random sequences ; FROM: sets => without ; IN: rosetta-code.password-generator

STRING: usage password-generator generates random passwords.

Commands:
  -l [int>=4]  Set password length (required)
  -c [int>0]   Set password count  (required)
  -s [int]     Set seed for random number generator
  -x           Exclude similar characters
     [empty]   Show this help

! Parse command line arguments into assoc EBNF: parse-args [=[

 int  = "-"? [0-9]+ => [[ concat sift string>number ]]
 l    = "-l" " "~ int ?[ 4 >= ]?
 c    = "-c" " "~ int ?[ 0 >  ]?
 s    = "-s" " "~ int
 x    = "-x" => 0 2array 
 arg  = l | c | s | x
 args = arg ((" "~ arg)+)?
      => [[ first2 [ 1array ] dip append ]]

]=]

CONSTANT: similar {

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

}

dissimilar ( -- seq ) similar [ "Il1O05S2Z" without ] map ;

! Set seed if seed provided; otherwise use system rng.

choose-rng ( args-assoc -- )
   "-s" of [ [ random-generator get ] dip seed-random drop ]
   [ system-random-generator get random-generator set ] if* ;
choose-character-set ( args-assoc -- seq )
   "-x" of dissimilar similar ? ;

! Create a "base" for a password; one character from each ! category.

<base> ( seq -- str ) [ random ] "" map-as ;
password ( seq length -- str )
   4 - over concat [ random ] curry "" replicate-as
   [ <base> ] dip append randomize ;
.passwords ( count seq length -- )
   [ password print ] 2curry times ;
gen-pwds ( args-assoc -- )
   {
       [ choose-rng ]
       [ "-c" of ]
       [ choose-character-set ]
       [ "-l" of ]
   } cleave .passwords ;
main ( -- )
   command-line get " " join
   [ parse-args gen-pwds ] [ 2drop usage print ] recover ;

MAIN: main</lang>

Output:
>password-generator
password-generator generates random passwords.

 Commands:
   -l [int>=4]  Set password length (required)
   -c [int>0]   Set password count  (required)
   -s [int]     Set seed for random number generator
   -x           Exclude similar characters
      [empty]   Show this help

>password-generator -l 10 -c 7 -s 33 -x
][#9vNKg%C
/%H|3mtg{H
-FsN'v,q:3
M"9B:8|z*(
8@Tb;zoF#i
^96AD+um@~
9L6Lqt|yh|


FreeBASIC

Translation of: Run BASIC

<lang freebasic>Dim As String charS(4)

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


Dim As Integer howBig, howMany Do

   Print !"------ Password Generator ------\n"
   Input "Longitud de la contrase¤a (n>=4): ", howBig
   If howBig < 1 Then Sleep: End
   
   Input "Cantidad de contrase¤as (n>=1): ", howMany

Loop While howMany < 1

Print !"\nGeneradas"; howMany; " contrase¤as de"; howBig; " caracteres"

Dim As Integer i = 0 Dim As String password, Ok, w While i < howMany password = ""

   Ok = "...."
   For j As Integer = 1 To howBig
       w = Mid(charS(0), Int(Rnd * Len(charS(0))) + 1, 1)
       For k As Byte = 1 To 4
           If Instr(charS(k), w) Then Ok = Left(Ok, k-1) + "*" + Mid(Ok, k+1)
       Next k
       password += w
   Next j
   If Ok = "****" Then
       i += 1
       Print Using "##. &"; i; password
   End If

Wend Sleep </lang>

Output:
------ Password Generator ------

Longitud de la contraseña (n>=4): 5
Cantidad de contraseñas (n>=1): 2

Generadas 2 contraseñas de 5 caracteres
 1. 1qU+,
 2. v?X7s


Gambas

[https:c/gambas-playground.proko.eu/?gist=0ef1242c761d8a39297fb913fc6a56c0 Click this link to run this code] <lang gambas>' Gambas module file

' INSTRUCTIONS ' I have not used a GUI as you could not run this in the 'Gambas Playground' ' Click on the link above to run this program ' The user can specify the password length and the number of passwords ' to generate by altering the values of the 2 lines below.

Public Sub Main() Dim siPasswordLength As Short = 20 'Password length Dim siPasswordQuantity As Short = 20 'Password quantity Dim sLower As String = "abcdefghijklmnopqrstuvwxyz" 'Lower case characters Dim sUpper As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 'Upper case characters Dim sNumber As String = "1234567890" 'Numbers Dim sOther As String = "'!#$%&'()*+,-./:;<=>?@[]^_{|}~" & Chr(34) 'Other characters + quote Dim sNoGo As String[] = ["I1", "1I", "l1", "1l", "Il",

                       "lI", "O0", "0O", "S5", "5S", "Z2", "2Z"]       'Undesirable string combinations (can be added to if required)

Dim sData As String = sLower & sUpper & sNumber & sOther 'Create 1 string to pick the password characters from Dim sToCheck, sPassword As String 'To hold a possible password for checking, to hold the passwords Dim siCount, siLoop, siCounter As Short 'Various counters Dim bPass As Boolean 'To Pass or not to Pass!

For siCount = 1 To siPasswordQuantity 'Loop the amount of passwords required

 For siLoop = 1 To siPasswordLength                                    'Loop for each charater of the required length
   sToCheck &= Mid(sData, Rand(1, Len(sData)), 1)                      'Get a random character from sData
 Next
 bPass = False                                                         'Set bPass to False
 For siCounter = 1 To Len(sToCheck)                                    'Loop through each character in the generated password
   If InStr(sLower, Mid(sToCheck, siCounter, 1)) Then bPass = True     'If a LOWER CASE letter is included set bPass to True
 Next
 If bPass Then                                                         'If bPass is True then
   bPass = False                                                       'bPass is False
   For siCounter = 1 To Len(sToCheck)                                  'Loop through each character in the generated password
     If InStr(sUpper, Mid(sToCheck, siCounter, 1)) Then bPass = True   'If an UPPER CASE letter is included set bPass to True
   Next
 End If
 
 If bPass Then                                                         'If bPass is True then
   bPass = False                                                       'bPass is False
   For siCounter = 1 To Len(sToCheck)                                  'Loop through each character in the generated password
     If InStr(sNumber, Mid(sToCheck, siCounter, 1)) Then bPass = True  'If a NUMBER is included set bPass to True
   Next
 End If
 If bPass Then                                                         'If bPass is True then
   bPass = False                                                       'bPass is False
   For siCounter = 1 To Len(sToCheck)                                  'Loop through each character in the generated password
     If InStr(sOther, Mid(sToCheck, siCounter, 1)) Then bPass = True   'If an 'OTHER CHARACTER' is included set bPass to True
   Next
 End If
 If bPass Then
   For siCounter = 1 To sNoGo.Max                                      'Loop through each undesirable strings e.g. "0O"
     If InStr(sToCheck, sNoGo[siCounter]) Then bPass = False           'If an undesirable combination is located then set bPass to False
   Next
 Endif
 If bPass = True Then                                                  'If bPass is True (all checks have been passed) then
   sPassword &= sToCheck & gb.NewLine                                  'Add the new password to sPassword with a newline
 Else                                                                  'Else
   Dec siCount                                                         'Decrease the loop counter by one
 Endif
 sToCheck = ""                                                         'Clear sToCheck

Next

Print sPassword 'Print the password list

End</lang> Output:

+j<Zwk,h&0-Bb976hs^B
HCMC2T,rI_&&wBjavysX
/OS6'd-+o|:'[L$1|u56
DP/<$27oa/c)[/t1YI@F
k@fu3yk=vsXsA!3rENN^
7~V?DDZl$W>mwA'tn5~9
:K]LWNxdrUmhwj_2>-85
,/NLH}#r8DeytFkFl.[>
6&mgbo11r)IbI;n@RDal
K$0m^J0r3fk~r56?H+5:
;"AT-D9m^*VKVM"0Gx|}
8k}IT{DAV|P!'wl}64g$
jq3G$h^D&19>?+_9q^:Z
+O$0z;1zN5y'*(79H$Q,

Go

<lang Go> package main

import ( "crypto/rand" "math/big" "strings" "flag" "math"

       "fmt" 

)

var lowercase = "abcdefghijklmnopqrstuvwxyz" var uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" var numbers = "0123456789" var signs = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~" var similar = "Il1O05S2Z"

func check(e error){ if e != nil { panic(e) } }

func randstr(length int, alphastr string) string{ alphabet := []byte(alphastr) pass := make([]byte,length) for i := 0; i < length; i++ { bign, err := rand.Int(rand.Reader, big.NewInt(int64(len(alphabet)))) check(err) n := bign.Int64() pass[i] = alphabet[n] } return string(pass) }

func verify(pass string,checkUpper bool,checkLower bool, checkNumber bool, checkSign bool) bool{ isValid := true if(checkUpper){ isValid = isValid && strings.ContainsAny(pass,uppercase) } if(checkLower){ isValid = isValid && strings.ContainsAny(pass,lowercase) } if(checkNumber){ isValid = isValid && strings.ContainsAny(pass,numbers) } if(checkSign){ isValid = isValid && strings.ContainsAny(pass,signs) } return isValid }


func main() { passCount := flag.Int("pc", 6, "Number of passwords") passLength := flag.Int("pl", 10, "Passwordlength") useUpper := flag.Bool("upper", true, "Enables or disables uppercase letters") useLower := flag.Bool("lower", true, "Enables or disables lowercase letters") useSign := flag.Bool("sign", true, "Enables or disables signs") useNumbers := flag.Bool("number", true, "Enables or disables numbers") useSimilar := flag.Bool("similar", true,"Enables or disables visually similar characters") flag.Parse()

passAlphabet := "" if *useUpper { passAlphabet += uppercase } if *useLower { passAlphabet += lowercase } if *useSign { passAlphabet += signs } if *useNumbers { passAlphabet += numbers } if !*useSimilar { for _, r := range similar{ passAlphabet = strings.Replace(passAlphabet,string(r),"", 1) } } fmt.Printf("Generating passwords with an average entropy of %.1f bits \n", math.Log2(float64(len(passAlphabet))) * float64(*passLength)) for i := 0; i < *passCount;i++{ passFound := false pass := "" for(!passFound){ pass = randstr(*passLength,passAlphabet) passFound = verify(pass,*useUpper,*useLower,*useNumbers,*useSign) } fmt.Println(pass) } } </lang>

Output:
Generating passwords with an average entropy of 65.2 bits 
.JJ%z({4,x
.[n9d7,f8U
1Y:)pL7&R6
:~+I5xCh1#
%6|_gJ!"}m
jOU8z^f_1J

Haskell

The password generation process.

The function password for given length and a list of char sets which should be included, generates random password.

<lang Haskell>import Control.Monad import Control.Monad.Random import Data.List

password :: MonadRandom m => [String] -> Int -> m String password charSets n = do

 parts <- getPartition n
 chars <- zipWithM replicateM parts (uniform <$> charSets)
 shuffle (concat chars)
 where
   getPartition n = adjust <$> replicateM (k-1) (getRandomR (1, n `div` k))
   k = length charSets
   adjust p = (n - sum p) : p

shuffle :: (Eq a, MonadRandom m) => [a] -> m [a] shuffle [] = pure [] shuffle lst = do

 x <- uniform lst
 xs <- shuffle (delete x lst)
 return (x : xs)</lang>

For example:

λ> password ["abcxyz","123"] 10
"x3b1y2ac3z"

λ> replicateM 5 (password ["abcxyz","123","#!"] 8)
["y!b#zyx2","xzcx!1xb","3zcax#aa","!ca1a2c#","#21a#zyc"]

User interface (uses a powerful and easy-to-use command-line option parser).

<lang Haskell>import Options

data Opts = Opts { optLength :: Int

                , optCount :: Int
                , optReadable :: Bool }

instance Options Opts where

   defineOptions = Opts <$>
     simpleOption "length" 8 "password length" <*>
     simpleOption "count" 1 "number of passwords to be generated" <*>
     simpleOption "readable" False "Whether to use only readable characters"

main = runCommand $ \opts args -> do

 let n = optCount opts
     l = optLength opts
     s = if (optReadable opts)
         then zipWith (\\) charSets visualySimilar
         else charSets
 res <- replicateM n (password s (max 4 l))
 mapM_ putStrLn res
 where
   charSets = [ ['a'..'z'] 
              , ['A'..'Z'] 
              , ['0'..'9'] 
              , "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~" ]
   visualySimilar = ["l","IOSZ","012","!|.,"]</lang>
Output:
$ ./password -h
Help Options:
  -h, --help
    Show option summary.
  --help-all
    Show all help options.

Application Options:
  --length :: int
    password length
    default: 8
  --count :: int
    number of passwords to be generated
    default: 1
  --readable :: bool
    whether to avoid visually similar characters
    default: false

$ ./password
PBpx#9hj

$ ./password --length 10 --count 10
2gso<zJtn@
sv:W7inoWk
fovo0mUO:q
[4bC4liy,k
s?cwr2JbTm
z2mrZpav!x
2#bq0rwoOI
W*pv19wrjb
Yx2j)f6is"
j6YM0_qd&v

$ ./password --readable --length 10 --count 10
bsx<xL8aA"
c&~E6ja5oY
Ri7tg7h$hz
oekF}9ab6v
jmmK5_cii7
P@xcqspY8d
kdnkgJ*Ak8
ue~uAuN7g+
gzbkK9$6ye
m#jdQan94z

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]

JavaScript

<lang JavaScript>String.prototype.shuffle = function() {

 return this.split().sort(() => Math.random() - .5).join();

}

function createPwd(opts = {}) {

 let len    = opts.len || 5,                       // password length
     num    = opts.num || 1,                       // number of outputs
     noSims = opts.noSims == false ? false : true, // exclude similar?
     out = [],
     cur, i;
 let chars = [
   'abcdefghijkmnopqrstuvwxyz'.split(),
   'ABCDEFGHJKLMNPQRTUVWXY'.split(),
   '346789'.split(),
   '!"#$%&()*+,-./:;<=>?@[]^_{|}'.split()
 ];
 if (!noSims) {
   chars[0].push('l');
   chars[1] = chars[1].concat('IOSZ'.split());
   chars[2] = chars[2].concat('1250'.split());
 }
 if (len < 4) {
   console.log('Password length changed to 4 (minimum)');
   len = 4;
 }
 while (out.length < num) {
   cur = ;
   // basic requirement
   for (i = 0; i < 4; i++)
     cur += chars[i][Math.floor(Math.random() * chars[i].length)];
   while (cur.length < len) {
     let rnd = Math.floor(Math.random() * chars.length);
     cur += chars[rnd][Math.floor(Math.random() * chars[rnd].length)];
   }
   out.push(cur);
 }
 for (i = 0; i < out.length; i++) out[i] = out[i].shuffle();
 if (out.length == 1) return out[0];
 return out;

}

// testing console.log( createPwd() ); console.log( createPwd( {len: 20}) ); console.log( createPwd( {len: 20, num: 2}) ); console.log( createPwd( {len: 20, num: 2, noSims: false}) ); </lang>

Output:

> Q^g"7 > NP3*fb3L!9++Yf)sx/m# > Array [ "]7Qs9/7En9d,!!j.U6pT", "9LDc-is6tCa6L88dKy6H" ] > Array [ "yI7<)d5a5#4R>v4aLG8.", "s<GJ59||J]vS%_gUf4Xs" ]

Julia

Works with: Julia version 0.6

<lang julia>function passgen(len::Integer; simchars::Bool=true)::String

   if len < 4; error("length must be at least 4") end
   # Definitions
   DIGIT = collect('0':'9')
   UPPER = collect('A':'Z')
   LOWER = collect('a':'z')
   OTHER = collect("!\"#\$%&'()*+,-./:;<=>?@[]^_{|}~")
   if !simchars
       setdiff!(DIGIT, ['0', '1', '2', '5'])
       setdiff!(UPPER, ['O', 'I', 'Z', 'S'])
       setdiff!(LOWER, [     'l'])
   end
   ALL = union(DIGIT, UPPER, LOWER, OTHER)
   chars = collect(rand(set) for set in (DIGIT, UPPER, LOWER, OTHER))
   len -= 4
   append!(chars, rand(ALL, len))
   return join(shuffle!(chars))

end

function passgen(io::IO, len::Int=8, npass::Int=1; seed::Int=-1, simchars::Bool=true)::Vector{String}

   if seed > -1; srand(seed) end
   passwords = collect(passgen(len; simchars=simchars) for i in 1:npass)
   writedlm(io, passwords, '\n')
   return passwords

end

passgen(stdout, 10, 12; seed = 1)</lang>

Output:
p-7w^hK~8r
fDU~f^b5)J
j5.phuRNgB
[/0'0AUUFx
8h;BPr$#[[
R*8h<xAetD
ZelB^Y8lT0
"c4S""j/2QoZ"
~C-o18d6eH
TdrmQ(7?1~
^UH&Iu1*l9
sg8SAF;<4y

Kotlin

<lang Groovy>// version 1.1.4-3

import java.util.Random import java.io.File

val r = Random() val rr = Random() // use a separate generator for shuffles val ls = System.getProperty("line.separator")

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

val exclChars = arrayOf(

   "'I', 'l' and '1'", 
   "'O' and '0'     ",
   "'5' and 'S'     ",
   "'2' and 'Z'     "

)

fun String.shuffle(): String {

   val sb = StringBuilder(this)
   var n = sb.length
   while (n > 1) {
       val k = rr.nextInt(n--)
       val t = sb[n]
       sb[n] = sb[k]
       sb[k] = t
   }
   return sb.toString()

}

fun generatePasswords(pwdLen: Int, pwdNum: Int, toConsole: Boolean, toFile: Boolean) {

   val sb = StringBuilder()
   val ll = lower.length
   val ul = upper.length
   val dl = digit.length
   val ol = other.length
   val tl = ll + ul + dl + ol 
   var fw = if (toFile) File("pwds.txt").writer() else null
 
   if (toConsole) println("\nThe generated passwords are:")
   for (i in 0 until pwdNum) {
       sb.setLength(0)
       sb.append(lower[r.nextInt(ll)])
       sb.append(upper[r.nextInt(ul)])
       sb.append(digit[r.nextInt(dl)])
       sb.append(other[r.nextInt(ol)])
      
       for (j in 0 until pwdLen - 4) {
           val k = r.nextInt(tl)
           sb.append(when (k) {
               in 0 until ll -> lower[k]
               in ll until ll + ul -> upper[k - ll]
               in ll + ul until tl - ol -> digit[k - ll - ul]
               else -> other[tl - 1 - k]
           })
       }
       var pwd = sb.toString()
       repeat(5) { pwd = pwd.shuffle() } // shuffle 5 times say
       if (toConsole) println("  ${"%2d".format(i + 1)}:  $pwd")
       if (toFile) {
           fw!!.write(pwd)
           if (i < pwdNum - 1) fw.write(ls)
       }
   }
   if (toFile) {
      println("\nThe generated passwords have been written to the file pwds.txt") 
      fw!!.close()
   } 

}

fun printHelp() {

   println(""" 
       |This program generates up to 99 passwords of between 5 and 20 characters in 
       |length.
       |
       |You will be prompted for the values of all parameters when the program is run 
       |- there are no command line options to memorize.
       |
       |The passwords can either be written to the console or to a file (pwds.txt), 
       |or both.
       |
       |The passwords must contain at least one each of the following character types:
       |   lower-case letters :  a -> z
       |   upper-case letters :  A -> Z
       |   digits             :  0 -> 9
       |   other characters   :  !"#$%&'()*+,-./:;<=>?@[]^_{|}~
       |
       |Optionally, a seed can be set for the random generator 
       |(any non-zero Long integer) otherwise the default seed will be used. 
       |Even if the same seed is set, the passwords won't necessarily be exactly
       |the same on each run as additional random shuffles are always performed.
       |
       |You can also specify that various sets of visually similar characters
       |will be excluded (or not) from the passwords, namely: Il1  O0  5S  2Z
       | 
       |Finally, the only command line options permitted are -h and -help which
       |will display this page and then exit.
       |
       |Any other command line parameters will simply be ignored and the program
       |will be run normally.
       |
   """.trimMargin())

}

fun main(args: Array<String>) {

   if (args.size == 1 && (args[0] == "-h" || args[0] == "-help")) {
      printHelp()
      return
   }
       
   println("Please enter the following and press return after each one")
  
   var pwdLen: Int?
   do {
      print("  Password length (5 to 20)     : ")
      pwdLen = readLine()!!.toIntOrNull() ?: 0       
   }
   while (pwdLen !in 5..20)
   var pwdNum: Int?
   do {
      print("  Number to generate (1 to 99)  : ")
      pwdNum = readLine()!!.toIntOrNull() ?: 0       
   }
   while (pwdNum !in 1..99)
   
   var seed: Long?
   do {
      print("  Seed value (0 to use default) : ")
      seed = readLine()!!.toLongOrNull()       
   }
   while (seed == null)
   if (seed != 0L) r.setSeed(seed)
   println("  Exclude the following visually similar characters")
   for (i in 0..3) {
       var yn: String
       do {
           print("    ${exclChars[i]} y/n : ")
           yn = readLine()!!.toLowerCase()
       }
       while (yn != "y" && yn != "n")
       if (yn == "y") {
           when (i) {
               0 -> {
                   upper = upper.replace("I", "")
                   lower = lower.replace("l", "")
                   digit = digit.replace("1", "")
               }
               1 -> {
                   upper = upper.replace("O", "")
                   digit = digit.replace("0", "")
               }
               2 -> {
                   upper = upper.replace("S", "")
                   digit = digit.replace("5", "")
               }
               3 -> {
                   upper = upper.replace("Z", "")
                   digit = digit.replace("2", "")
               }
           }
       }
   }
  
   var toConsole: Boolean?
   do {
       print("  Write to console   y/n : ")
       val t = readLine()!!
       toConsole = if (t == "y") true else if (t == "n") false else null
   }
   while (toConsole == null)
   var toFile: Boolean? = true
   if (toConsole) {
       do {
           print("  Write to file      y/n : ")
           val t = readLine()!!
           toFile = if (t == "y") true else if (t == "n") false else null
       }
       while (toFile == null)
   }

   generatePasswords(pwdLen!!, pwdNum!!, toConsole, toFile!!)

}</lang>

Sample input and output:

Please enter the following and press return after each one
  Password length (5 to 20)     : 8
  Number to generate (1 to 99)  : 10
  Seed value (0 to use default) : 0
  Exclude the following visually similar characters
    'I', 'l' and '1' y/n : n
    'O' and '0'      y/n : n
    '5' and 'S'      y/n : n
    '2' and 'Z'      y/n : n
  Write to console   y/n : y
  Write to file      y/n : y

The generated passwords are:
   1:  n09&VswT
   2:  b/:7XL'r
   3:  k1<M2T[/
   4:  1uWCkx6*
   5:  Rr?/4)'d
   6:  _i5,%jAy
   7:  1(Jn]ZD+
   8:  qa1lGNo)
   9:  cfr9{}{K
  10:  OPO3b{tY

The generated passwords have been written to the file pwds.txt

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<

Mathematica/Wolfram Language

<lang Mathematica>(* Length is the Length of the password, num is the number you want, \ and similar=1 if you want similar characters, 0 if not. True and \ False, should work in place of 1/0 *) pwgen[length_Integer: 5, num_Integer: 1, similars_Boolean: 1] :=

pwgenerator[length, num, similars] = 
 Module[{list, valid, validchars, similar, k, j, password, pwlist, 
   lcase, ucase, digits, spec, s}, lcase = Alphabet[];
  ucase = Capitalize[lcase];
  digits = Range[0, 9];
  spec = StringPartition["!:#$%\'()*+,-./:;>=<?@{}[]^_|~", 1];
  validchars = Flatten[Union[lcase, ucase, digits, spec]];
  similar = StringPartition["Il10O5S2Z", 1];
  list = {};
  
  Table[valid = 0;
   While[valid == 0,
    For[j = 0; k = {};, j < length, j++, 
     AppendTo[k, RandomInteger[{1, Length[validchars]}]]];
    k = Flatten[k];
    password = validcharsk;
    Which[(Intersection[password, similar] >= 1 && similars == 0 ), 
     valid = 0;, (Intersection[password, similar] == 0 && 
       similars == 1), 
     valid = 0;, (Intersection[password, similar] == 0 && 
       similars == 0 ), valid = 1; 
     Return[password], (Intersection[password, similar] >= 1 && 
       similars == 1), valid = 1; Return[password]];
    ], {num}];
  
  
  ]</lang>

Nim

<lang Nim>import os, parseopt, random, sequtils, strformat, strutils

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


proc passGen(passLength = 10,

            count = 1,
            seed = 0,
            excludeSimilars = false): seq[string] =
 ## Generate a sequence of passwords.
 # Initialize the random number generator.
 if seed == 0: randomize()
 else: randomize(seed)
 # Prepare list of chars per category.
 var
   lowerLetters = toSeq('a'..'z')
   upperLetters = toSeq('A'..'Z')
   digits = toSeq('0'..'9')
 if excludeSimilars:
   lowerLetters.delete(lowerLetters.find('l'))
   for c in "IOSZ": upperLetters.delete(upperLetters.find(c))
   for c in "012": digits.delete(digits.find(c))
 let all = lowerLetters & upperLetters & digits & Symbols
 # Generate the passwords.
 for _ in 1..count:
   var password = newString(passLength)
   password[0] = lowerLetters.sample
   password[1] = upperLetters.sample
   password[2] = digits.sample
   password[3] = Symbols.sample
   for i in 4..<passLength:
     password[i] = all.sample
   password.shuffle()
   result.add password


proc printHelp() =

 ## Print the help message.
 echo &"Usage: {getAppFileName().lastPathPart} " &
       "[-h] [-l:length] [-c:count] [-s:seed] [-x:(true|false)]"
 echo "  -h: display this help"
 echo "  -l: length of generated passwords"
 echo "  -c: number of passwords to generate"
 echo "  -s: seed for the random number generator"
 echo "  -x: exclude similar characters"


proc getIntValue(key, val: string): int =

 ## Get a positive integer value from a string.
 try:
   result = val.parseInt()
   if result <= 0:
     raise newException(ValueError, "")
 except ValueError:
   quit &"Wrong value for option -{key}: {val}", QuitFailure


var

 passLength = 10
 count = 1
 seed = 0
 excludeSimilars = false
  1. Process options.

var parser = initOptParser()

for kind, key, val in parser.getopt():

 if kind != cmdShortOption:
   printHelp()
   quit(QuitFailure)
 case key
 of "h":
   printHelp()
   quit(QuitSuccess)
 of "l":
   passLength = getIntValue(key, val)
 of "c":
   count = getIntValue(key, val)
 of "s":
   seed = getIntValue(key, val)
 of "x":
   if val.toLowerAscii == "true":
     excludeSimilars = true
   elif val.toLowerAscii == "false":
     excludeSimilars = false
   else:
     quit &"Wrong value for option -x: {val}", QuitFailure
 else:
   quit &"Wrong option: -{key}"
  1. Display the passwords.

for pw in passGen(passLength, count, seed, excludeSimilars):

 echo pw</lang>
Output:
$ ./passgen -c:6
hG']0ipc7P
1|"AjJDYxe
VwU'!7<+!<
=Do]49_vd5
4lqrr>B*X1
8J1_J#>hi7

OCaml

<lang ocaml>let lower = "abcdefghijklmnopqrstuvwxyz" let upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" let digit = "0123456789" let other = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~" (* unconfuse syntax highlighter: " *)

let visually_similar = "Il1O05S2Z"


let mk_pwd len readable =

 let get_char i =
   match i mod 4 with
   | 0 -> lower.[Random.int (String.length lower)]
   | 1 -> upper.[Random.int (String.length upper)]
   | 2 -> digit.[Random.int (String.length digit)]
   | 3 -> other.[Random.int (String.length other)]
   | _ -> raise Exit
 in
 let f =
   if readable then
     (fun i ->
       let rec aux () =
         let c = get_char i in
         if String.contains visually_similar c
         then aux ()
         else (String.make 1 c)
       in
       aux ()
     )
   else
     (fun i ->
       let c = get_char i in
       (String.make 1 c)
     )
 in
 let r = Array.init len f in
 Array.sort (fun _ _ -> (Random.int 3) - 1) r;
 (String.concat "" (Array.to_list r))


let () =

 Random.self_init ();
 let num = ref 1 in
 let len = ref 8 in
 let readable = ref false in
 let speclist = [
   "-n", Arg.Set_int num, "number of passwords";
   "-c", Arg.Set_int len, "number of characters";
   "--readable", Arg.Set readable, "readable";
   "--rand-init", Arg.String (fun s ->
       Random.full_init 
         (Array.map int_of_char (Array.of_seq (String.to_seq s)))
     ), "initialise the random generator with a string";
 ] in
 Arg.parse speclist (fun s -> invalid_arg s) "Password generator";
 for i = 1 to !num do
   print_endline (mk_pwd !len !readable)
 done</lang>
Output:
$ ocaml mkpwd.ml --help
Password generator
  -n number of passwords
  -c number of characters
  --readable readable
  --rand-init initialise the random generator with a string
  --help  Display this list of options

$ ocaml mkpwd.ml 
Zz&tJ[40

$ ocaml mkpwd.ml -n 3 -c 16 --readable --rand-init rosettacode.org
_6yAXM(o4+Gw~73p
]]Pf}84"bwKUH84b
.TijWj7~743Q<K;q

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 builtin random generator. <lang parigp>passwd(len=8, count=1, seed=0) = {

 if (len <= 4, print("password too short, minimum len=4"); return(), 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)

Pascal

<lang PASCAL> program passwords (input,output);

{$mode objfpc} {$H+} { We will need ansi strings instead of short strings

       to hold passwords longer than 255 characters.
       We need to assemble a string to check that each
       password contains an upper, lower, numeral and symbol }

{ This is a random password generater in PASCAL

 Copyright Englebert Finklestien on this day which is
 Setting Orange day 48 of The Aftermath YOLD 3184.
 It is distributed under the terms of the GNU GPL (v3)
 As published by the free software foundation.
 Usage :-
 Without any command line arguments this program
 will display 8 8-character long completely random passwords using
 all 96 available character glyphs from the basic ascii set.
 With a single integer numerical argument it will
 produce eight passwords of the chosen length.
 With a second integer numerical argument between 1 and 65536 it
 will produce that number of passwords.
 With two integer arguments the first is taken as the length of password
 and the second as the number of passwords to produce.
 The length of passwords can also be specified using -l or --length options
 The number of passwords can also be specified using -n or --number options
 It is also possible to exclude those glyphs which are simmilar enough to be
 confused (e.g. O and 0) using the -e or --exclude option
 There are also the standard -a --about and -h --help options
 Other options will produce an error message and the program will halt without
 producing any passwords at all.
}

uses sysutils, getopts;


var c : char;

   optionindex : Longint;
   theopts : array[1..5] of TOption;
   numpass, lenpass, count,j : integer;
   i : longint; { used to get a random number }
   strength : byte; {  check inclusion of different character groups }
   password : string; { To hold a password as we generate it }
   exc : boolean;
   ex : set of char;

procedure about; begin

    writeln('Engleberts random password generator');
    writeln('Writen in FreePascal on Linux');
    writeln('This is free software distributed under the GNU GPL v3');
    writeln;

end;

procedure help; begin

   writeln('Useage:-');
   writeln('passwords   produce 8 passwords each 8 characters long.');
   writeln('Use one or more of the following switches to control the output.');
   writeln('passwords --number=xx -nxx --length=xx -lxx --exclude -e --about -a --help -h');
   writeln('passwords ll nn produce nn passwords of length ll');
   writeln('The exclude option excludes easily confused characters such as `0` and `O` from');
   writeln('the generated passwords.');
   writeln;

end;


begin

 numpass := 8;
 lenpass := 8;
 exc := False;
 ex := ['1','!','l','|','i','I','J','0','O','S','$','5',';',':',',','.','\']; { Set of ambiguous characters }
 OptErr := True;
 Randomize;  {initialise the random number generator}
 {set up to handle the command line options}
 with theopts[1] do
  begin
   name:='length';
   has_arg:=1;
   flag:=nil;
   value:=#0;
  end;
 with theopts[2] do
  begin
   name:='number';
   has_arg:=1;
   flag:=nil;
   value:=#0;
  end;
 with theopts[3] do
  begin
   name:='help';
   has_arg:=0;
   flag:=nil;
   value:=#0;
  end;
 with theopts[4] do
  begin
   name:='about';
   has_arg:=0;
   flag:=nil;
   value:=#0;
  end;
 with theopts[5] do
  begin
   name:='exclude';
   has_arg:=0;
   flag:=nil;
   value:=#0;
  end;

{ Get and process long and short versions of command line args. }

 c:=#0;
 repeat
   c:=getlongopts('ahel:n:t:',@theopts[1],optionindex);
   case c of
     #0 : begin
              if (theopts[optionindex].name = 'exclude') then exc := True;
              if (theopts[optionindex].name = 'length') then lenpass := StrtoInt(optarg);
              if (theopts[optionindex].name = 'number') then numpass := StrtoInt(optarg);

if (theopts[optionindex].name = 'about') then about; if (theopts[optionindex].name = 'help') then help;

          end;
     'a' : about;
     'h' : help;
     'e' : exc := True;
     'l' : lenpass := StrtoInt(optarg);
     'n' : numpass := StrtoInt(optarg);
     '?',':' : writeln ('Error with opt : ',optopt);
   end; { case }
 until c=endofoptions;
 { deal with any remaining command line parameters (two integers)}
 if optind<=paramcount then
   begin
      count:=1;
      while optind<=paramcount do
        begin

if (count=1) then lenpass := StrtoInt(paramstr(optind)) else numpass := StrtoInt(paramstr(optind));

           inc(optind);

inc(count);

        end;
   end;

if not (exc) then ex :=['\']; { if we are not going to exclude characters set the exclusion set to almost empty } { This generates and displays the actual passwords }

   for count := 1 to numpass do begin
      strength := $00;
      repeat
         password :=;
         for j:= 1 to lenpass do begin
            repeat
               i:=Random(130);
            until (i>32) and (i<127) and (not(chr(i) in ex)) ;
            AppendStr(password,chr(i));
            if (CHR(i) in ['0'..'9']) then strength := strength or $01;
            if (chr(i) in ['a'..'z']) then strength := strength or $02;
            if (chr(i) in ['A'..'Z']) then strength := strength or $04;
            if (chr(i) in ['!'..'/']) then strength := strength or $08;
            if (chr(i) in [':'..'@']) then strength := strength or $08;
            if (chr(i) in ['['..'`']) then strength := strength or $08;
            if (chr(i) in ['{'..'~']) then strength := strength or $08;
        end;	 
      until strength = $0f;
   writeln(password);
   end;

end.

</lang> Useage for the output example: passwords --about -h --length=12 --number 12 --exclude

Output:

Engleberts random password generator
Writen in FreePascal on Linux
This is free software distributed under the GNU GPL v3

Useage:-
passwords   produce 8 passwords each 8 characters long.
Use one or more of the following switches to control the output.
passwords --number=xx -nxx --length=xx -lxx --exclude -e --about -a --help -h
passwords ll nn produce nn passwords of length ll
The exclude option excludes easily confused characters such as `0` and `O` from
the generated passwords.

G6ZnfCMoR8)8
]V-Y"L8tFPYM
gveA]%2onN)g
j?4Rz)C(x?RY
mQ]2c)RP~dvU
8<GT{w)]>w^t
Fw"^~73zY8`"
d4KGQmTB4#Nn
PwqYLMEpegv3
mbe^NCTF'a~t
g@vc"B{X+9kg
4tD3w?Vgo_R@

Perl

Use the module Math::Random for marginally better random-ness than the built-in function, but no warranty is expressed or implied, caveat emptor. <lang perl>use strict; use warnings; use feature 'say';

use English; use Const::Fast; use Getopt::Long; use Math::Random;

const my @lcs => 'a' .. 'z'; const my @ucs => 'A' .. 'Z'; const my @digits => 0 .. 9; const my $others => q{!"#$%&'()*+,-./:;<=>?@[]^_{|}~}; # "

my $pwd_length = 8; my $num_pwds = 6; my $seed_phrase = 'TOO MANY SECRETS';

my %opts = ( 'password_length=i' => \$pwd_length, 'num_passwords=i' => \$num_pwds, 'seed_phrase=s' => \$seed_phrase, 'help!' => sub {command_line_help(); exit 0} ); command_line_help() and exit 1 unless $num_pwds >= 1 and $pwd_length >= 4 and GetOptions(%opts);

random_set_seed_from_phrase($seed_phrase); say gen_password() for 1 .. $num_pwds;

sub gen_password {

   my @generators = (\&random_lc, \&random_uc, \&random_digit, \&random_other);
   my @chars = map {$ARG->()} @generators;  # At least one char of each type.
   push @chars, $generators[random_uniform_integer(1, 0, 3)]->() for 1 .. $pwd_length - 4;
   join , random_permutation(@chars);

}

sub random_lc { $lcs[ random_uniform_integer(1, 0, $#lcs) ] } sub random_uc { $ucs[ random_uniform_integer(1, 0, $#ucs) ] } sub random_digit { $digits[ random_uniform_integer(1, 0, $#digits) ] } sub random_other { substr($others, random_uniform_integer(1, 0, length($others)-1), 1) }

sub command_line_help {

   say <<~END
      Usage: $PROGRAM_NAME
      [--password_length=<l> default: 8, minimum: 4]
      [--num_passwords=<n>   default: 6, minimum: 1]
      [--seed_phrase=     default: TOO MANY SECRETS (optional)]
      [--help]
      END

}</lang>

Output:
sc3O~3e0
pE{uh7)%
3J:'L)x8
I{A:h454
tCTH}8(h
b0&S$ZtI

Phix

<lang Phix>constant az = "abcdefghijklmnopqrstuvwxyz",

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

function password(integer len, integer n, sequence exclude="Il1O05S2Z")

   sequence res = {},
            S4 = apply(true,filter,{{az,AZ,O9,OT},{"out"},{exclude}})
   string pw = repeat(' ',len)
   for i=1 to n do
       sequence sel = shuffle({1,2,3,4}&sq_rand(repeat(4,len-4)))
       for c=1 to len do
           string S4c = S4[sel[c]]
           pw[c] = S4c[rand(length(S4c))]
       end for
       res = append(res,pw)
   end for
   return res

end function

integer l = prompt_number("Password length(4..99):",{4,99}),

       n = prompt_number("Passwords required(1..99):",{1,99})

printf(1,"%s\n",join(password(l,n),"\n"))</lang>

Output:
Password length(4..99):12
Passwords required(1..99):6
:EtF77s~%bok
C^Pb&NH8@?u6
RBy%Ep*N9W!t
K%6hxc?C_4_3
vpRBJP)A9@,7
V_3dDf7RhY7N

PicoLisp

<lang PicoLisp>#!/usr/bin/pil

  1. Default seed

(seed (in "/dev/urandom" (rd 8)))

  1. Global defaults

(setq

  *PwCount 1
  *PwLength 12
  *UppChars (mapcar char (range (char "A") (char "Z")))
  *LowChars (mapcar lowc *UppChars)
  *Digits (mapcar format (range 0 9))
  *Others (chop "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~") )
  1. Command line options

(de -count ()

  (setq *PwCount (format (opt))) )

(de -length ()

  (setq *PwLength (format (opt))) )

(de -seed ()

  (seed (opt)) )

(de -exclude ()

  (for C (chop (opt))
     (del C '*UppChars)
     (del C '*LowChars)
     (del C '*Digits)
     (del C '*Others) ) )

(de -help ()

  (prinl "Generate password(s)")
  (prinl "Options:")
  (prinl "   --help")
  (prinl "   --count <num>")
  (prinl "   --length <num>")
  (prinl "   --seed <chars>")
  (prinl "   --exclude <chars>")
  (bye) )

(load T)

  1. Return random character from list

(de randChar (Lst)

  (get Lst (rand 1 (length Lst))) )
  1. Generate password(s)

(do *PwCount

  (prinl
     (by '(NIL (rand)) sort
        (make
           (link
              (randChar *UppChars)  # At least one from each group
              (randChar *LowChars)
              (randChar *Digits)
              (randChar *Others) )
           (do (- *PwLength 4)
              (link
                 (randChar
                    (caar
                       (rot '(*UppChars *Others *Digits *LowChars))) ) ) ) ) ) ) )

(bye)</lang> Test:

$ genpw --help
Generate password(s)
Options:
   --help
   --count <num>
   --length <num>
   --seed <chars>
   --exclude <chars>

$ genpw
[Rg"ia27B?M1

$ genpw  --count 4  --length 20
3O-c23;TbZ~5qAor|!6Q
+H$.bH(aqS19N85a&7aA
?|{(v1EavtB83TTl85W
U%GoEbG%p006l)|+Y1i0

PowerShell

<lang PowerShell> function New-RandomPassword {

 <#
   .SYNOPSIS
       Generates one or more passwords.
   .DESCRIPTION
       Generates one or more passwords.
   .PARAMETER Length
       The password length (default = 8).
   .PARAMETER Count
       The number of passwords to generate.
   .PARAMETER Source
       An array of strings containing characters from which the password will be generated.  The default is good for most uses.
   .PARAMETER ExcludeSimilar
       A switch which indicates that visually similar characters should be ignored.
   .EXAMPLE
       New-RandomPassword
       Generates one password of the default length (8 characters).
   .EXAMPLE
       New-RandomPassword -Count 4
       Generates four passwords each of the default length (8 characters).
   .EXAMPLE
       New-RandomPassword -Length 12 -Source abcdefghijklmnopqrstuvwxyz, ABCDEFGHIJKLMNOPQRSTUVWXYZ, 0123456789
       Generates a password with a length of 12 containing at least one char from each string in Source
   .EXAMPLE
       New-RandomPassword -Count 4 -ExcludeSimilar
       Generates four passwords each of the default length (8 characters) while excluding similar characters "Il1O05S2Z".
 #>
   [CmdletBinding()]
   [OutputType([string])]
   Param
   (
       [Parameter(Mandatory=$false)]
       [ValidateRange(1,[Int]::MaxValue)]
       [Alias("l")] 
       [int]
       $Length = 8,
       [Parameter(Mandatory=$false)]
       [ValidateRange(1,[Int]::MaxValue)]
       [Alias("n","c")] 
       [int]
       $Count = 1,
       
       [Parameter(Mandatory=$false)]
       [Alias("s")] 
       [string[]]
       $Source = @("abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "0123456789", "!\`"#$%&'()*+,-./:;<=>?@[]^_{|}~"),
       [Parameter(Mandatory=$false)]
       [Alias("x")] 
       [switch]
       $ExcludeSimilar
   )
   Begin
   {
       [char[][]] $charArrays = $Source
       [char[]]   $allChars   = $charArrays | ForEach-Object {$_}
       [char[]]   $similar    = "Il1O05S2Z".ToCharArray()
       $random = New-Object -TypeName System.Security.Cryptography.RNGCryptoServiceProvider
       function Get-Seed
       {
           $bytes = New-Object -TypeName System.Byte[] -Argument 4
           $random.GetBytes($bytes)
           [BitConverter]::ToUInt32($bytes, 0)
       }
       function Add-PasswordCharacter ([char[]]$From)
       {
           $key = Get-Seed
           while ($password.ContainsKey($key))
           {
               $key = Get-Seed                        
           }
           $index = (Get-Seed) % $From.Count
           if ($ExcludeSimilar)
           {
               while ($From[$index] -in $similar)
               {
                   $index = (Get-Seed) % $From.Count
               }
           }
           $password.Add($key, $From[$index])
       }
   }
   Process
   {
       for ($i = 1;$i -le $Count; $i++)
       {
           [hashtable] $password = @{}
           foreach ($array in $charArrays)
           {
               if($password.Count -lt $Length)
               {
                   Add-PasswordCharacter -From $array # Append to $password
               }
           }
           for ($j = $password.Count; $j -lt $Length; $j++)
           {
               Add-PasswordCharacter -From $allChars  # Append to $password
           }
           ($password.GetEnumerator() | Select-Object -ExpandProperty Value) -join "" 
       }
   }

} </lang> <lang PowerShell> New-RandomPassword -Length 12 -Count 4 -ExcludeSimilar </lang>

Output:
}[:=~f$9<Q{'
;EB$JX3/)-qq
u;DD.9t3-3]_
/4#YwjRB4-W-

Make it Unix-like: <lang PowerShell> Set-Alias -Name nrp -Value New-RandomPassword -Description "Generates one or more passwords"

nrp -l 12 -n 4 -x </lang>

Output:
]?Vwrj377tAV
g%\QEx)$3|7"
U*89)9TCKw$j
bvG7UQ3%/4F#

Prolog

Works with: SWI-Prolog version 7.6.4 or higher

<lang Prolog>:- set_prolog_flag(double_quotes, chars).

- initialization(main, main).

main( Argv ) :-

   opt_spec( Spec ),
   opt_parse( Spec, Argv, Opts, _ ),    
   (
       member( help(true), Opts ) -> show_help
       ; 
       member( length( Len ), Opts ),
       member( number( Num ), Opts ),
       print_set_of_passwords( Len, Num )
   ).
   

show_help :-

   opt_spec( Spec ),   
   opt_help( Spec, HelpText ),
   write( 'Usage: swipl pgen.pl <options>\n\n' ),
   write( HelpText ),
   nl.    
   

opt_spec([

   [opt(help),   type(boolean), default(false), shortflags([h]), longflags([help]),   
       help('Show Help')],
   [opt(length), type(integer), default(10),    shortflags([l]), longflags([length]), 
       help('Specify the length of each password.')], 
   [opt(number), type(integer), default(1),     shortflags([n]), longflags([number]), 
       help('Specify the number of passwords to create.')]    

]).

print_set_of_passwords( Length, Number ) :-

   forall(
        between( 1, Number, _ ), 
       (
           random_pword( Length, P ), 
           maplist( format('~w'), P ), 
           nl
       )
   ).

random_pword( Length, Pword ) :-

   length( GenPword, Length ),
   findall( C, pword_char( _, C), PwordChars ),
   repeat, 
   maplist(populate_pword( PwordChars ), GenPword ),
   maplist( pword_char_rule( GenPword ), [lower, upper, digits, special] ),
   random_permutation( GenPword, Pword ).
   

populate_pword( PwordChars, C ) :- random_member( C, PwordChars ).

pword_char_rule( Pword, Type ) :-

   pword_char( Type, C ),
   member( C, Pword).
   

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

Output:

Showing help

> swipl .\pgen.pl -h
Usage: swipl pgen.pl <options>

--help    -h  boolean=false  Show Help
--length  -l  integer=10     Specify the length of each password.
--number  -n  integer=1      Specify the number of passwords to create.

>

Default mode, one password, length of 10 characters

> swipl .\pgen.pl
Fv8sfWz-gz
> 

Specify length and number of passwords.

> swipl .\pgen.pl -l 20 -n 10
;t&qeMlw6>{rq4'0p$io
z(i0vc/h7mdszdyXo}mC
:4%Xd[8WK4Y(jg}7?X%M
f6?mpxT9blOA_=0A<b[3
5ABR=KDs&:9O;"3pi2RA
k9eXn_7G4E[_@v;;d<>J
*CX[Nr_B$jD6ZbfUCVbV
E?".8gX.!=ysIfbHW+-H
mS:!$f;-g3,8+LpF'TTH
)L:j,?Uzik:b844C@Yh!
>

PureBasic

<lang PureBasic>EnableExplicit

Procedure.b CheckPW(pw.s)

 Define flag.b=#True,
        tmp.b=#False,
        c.c,
        s.s,
        i.i  
 For c='a' To 'z'
   tmp=Bool(FindString(pw,Chr(c)))
   If tmp : Break : EndIf
 Next  
 flag & tmp
 tmp=#False  
 For c='A' To 'Z'
   tmp=Bool(FindString(pw,Chr(c)))
   If tmp : Break : EndIf
 Next  
 flag & tmp
 tmp=#False  
 For c='0' To '9'
   tmp=Bool(FindString(pw,Chr(c)))
   If tmp : Break : EndIf
 Next  
 flag & tmp
 tmp=#False  
 For c='!' To '/'
   s+Chr(c)
 Next  
 For c=':' To '@'
   s+Chr(c)
 Next  
 s+"[]^_{|}~"  
 For i=1 To Len(pw)
   tmp=Bool(FindString(s,Mid(pw,i,1)))
   If tmp : Break : EndIf
 Next    
 flag & tmp  
 ProcedureReturn flag

EndProcedure

Procedure.s InputHdl(prompt.s="")

 Define txt.s,
        s.s,
        r.i,
        hlp.s  
 Restore Help_01
 Read.s hlp  
 Print(prompt)       
 Repeat
   s=Inkey()    
   If s<>""
     If FindString("0123456789",s)
       txt+s
       Print(s)
     EndIf
     If s=Chr(27)
       txt="0"
       Break
     EndIf            
   ElseIf RawKey()
     r=RawKey()      
     If r=112
       PrintN("")
       PrintN(hlp)  
       Print(~"\n"+prompt)
     EndIf
   EndIf
   Delay(20)
 Until s=Chr(13)
 PrintN("")  
 ProcedureReturn txt

EndProcedure

NewList PasswordChar.c() Define c.c,

      pwlen.i,
      n_of_pw.i, 
      pwstr.s,
      i.i

For c='!' To '~'

 If c<>'\' And c<>'`'
   AddElement(PasswordChar()) : PasswordChar()=c
 EndIf  

Next OpenConsole("Password generator: F1=Help; Esc=End") Repeat

 pwlen=Abs(Val(InputHdl("Length of the password (n>=4): ")))
 If pwlen=0 : Break : EndIf
 If pwlen<4 : Continue : EndIf
 n_of_pw=Abs(Val(InputHdl("Number of passwords (n>=1): ")))
 If n_of_pw=0 : Break : EndIf  
 For i=1 To n_of_pw    
   Repeat      
     pwstr=Mid(pwstr,2)
     RandomizeList(PasswordChar())
     ResetList(PasswordChar())      
     While NextElement(PasswordChar())
       pwstr+Chr(PasswordChar())      
       If Len(pwstr)>=pwlen : Break : EndIf
     Wend
   Until CheckPW(pwstr)
   PrintN(RSet(Str(i),Len(Str(n_of_pw))," ")+") "+pwstr)
   pwstr=""
 Next
 PrintN("")

ForEver End

DataSection

 Help_01:
 Data.s ~"Help: Password generator\n"+
        ~"------------------------\n"+
        ~"Blabla bla blabla bla blablabla.\n"+
        ~"Blabla bla  blablabla.\n"+
        ~"Bla blabla bla blablabla bla.\n"+
        ~"Blabla bla blabla bla.\n"+
        ~"Bla blabla bla blablabla blablabla.\n"+
        ~"Blabla bla blabla bla blablabla.\n"+
        ~"Blabla blabla bla blablabla."
 EndOfHelp:

EndDataSection</lang>

Output:
Length of the password (n>=4): 10
Number of passwords (n>=1): 12
 1) UteCZm/!9V
 2) R1B*C'gw&<
 3) uPDw.:FhY2
 4) v&0HD6tA);
 5) Ldspz:XcT4
 6) ^a9>Viv"R2
 7) k*x=6VCqMd
 8) y6Jz)p|^=h
 9) UO|sFD^Ry2
10) 1g5*e/:kZf
11) y;mJ{g7QX#
12) _Nh=:'V|a2

Length of the password (n>=4):

Python

<lang python>import random

lowercase = 'abcdefghijklmnopqrstuvwxyz' # same as string.ascii_lowercase uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' # same as string.ascii_uppercase digits = '0123456789' # same as string.digits punctuation = '!"#$%&\'()*+,-./:;<=>?@[]^_{|}~' # like string.punctuation but without backslash \ nor grave `

allowed = lowercase + uppercase + digits + punctuation

visually_similar = 'Il1O05S2Z'


def new_password(length:int, readable=True) -> str:

   if length < 4:
       print("password length={} is too short,".format(length),
           "minimum length=4")
       return 
   choice = random.SystemRandom().choice
   while True:
       password_chars = [
           choice(lowercase),
           choice(uppercase),
           choice(digits),
           choice(punctuation)
           ] + random.sample(allowed, length-4)
       if (not readable or 
               all(c not in visually_similar for c in password_chars)):
           random.SystemRandom().shuffle(password_chars)
           return .join(password_chars)


def password_generator(length, qty=1, readable=True):

   for i in range(qty):
       print(new_password(length, readable))

</lang>

Output:
>>> password_generator(14, 4)
i&H.j9F$)'V}!o
w&.U6vaf/HD;sA
i8Hfyq@&M?g:L6
j#%JxdbG9@fvX*
>>> password_generator(8, 4, readable=False)
A#f5c;(E
z@C9iIa1
R{s320IH
$4FLjCL0

R

<lang r> passwords <- function(nl = 8, npw = 1, help = FALSE) {

 if (help) return("gives npw passwords with nl characters each")
 if (nl < 4) nl <- 4
 spch <- c("!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "@", "[", "]", "^", "_", "{", "|", "}", "~")
 for(i in 1:npw) {
   pw <- c(sample(letters, 1), sample(LETTERS, 1), sample(0:9, 1), sample(spch, 1))
   pw <- c(pw, sample(c(letters, LETTERS, 0:9, spch), nl-4, replace = TRUE))
   cat(sample(pw), "\n", sep = "")
 }

}

set.seed(123) passwords(help = TRUE)

    1. [1] "gives npw passwords with nl characters each"

passwords(8)

    1. S2XnQoy*

passwords(14, 5)

    1. :.iJ=Q7_gP?Cio
    2. !yUu7OL|eH;}1p
    3. y2{DNvV^Zl^IFe
    4. Tj@T19L.q1;I*]
    5. 6M+{)xV?i|1UJ/

</lang>

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

Raku

(formerly 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

functional

<lang perl6>my @char-groups =

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

subset MinimumPasswordLength of Int where * >= 4; subset NumberOfPasswords of UInt where * != 0;

sub MAIN( NumberOfPasswords :c(:$count) = 1, MinimumPasswordLength :l(:$length) = 8, Str :x(:$exclude) = ) {

   &USAGE() if 1 == (.comb ∖ $exclude.comb).elems for @char-groups; 
   .say for password-characters($length, $exclude )
       .map( *.split(' ') )
       .map( *.pick: Inf ) # shuffle, so we don't get a predictable pattern
       .map( *.join )
       .head( $count );

}

sub password-characters( $len, $exclude ) {

   ( (( char-groups($exclude)       xx Inf ).map: *.pick).batch(     4)
    Z~
     (( char-groups($exclude, $len) xx Inf ).map: *.pick).batch($len-4) )

}

multi char-groups( $exclude ) { | @char-groups.map( * (-) $exclude.comb ) } multi char-groups( $exclude, $max-weight ) { flat (char-groups($exclude)>>.keys.map: {$_ xx ^$max-weight .roll}) }

sub USAGE() {

   say qq:to/END/;
   Specify a length:              -l=10    (minimum 4)
   Specify a count:               -c=5     (minimum 1)
   Specify characters to exclude: -x=xkcd  (optional)
   Password must have at least one of each: lowercase letter, uppercase letter, digit, punctuation.
  END

}</lang> Sample output:

Without parameters:

d[G2r4;i

With passed parameters: -c=5 -l=12 -x=aeiou

x7)YbEZQ2xp2
CEpZ>#4'rO7d
pn(5B;wb66DM
KA;3T7=s+I5{
LL<tB~L1~Y*q

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

Ring

<lang ring>

  1. Project : Password generator

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

init() plen = number(strp[1])

for n = 1 to strp[2]

    passwords(chars)
    see "password = " + password + nl

next

func passwords(chars)

      index = 0
      password = ""
      while index < plen
                index = index + 1
                charsind1 = index % len(chars) + 1
                charsind2 = random(len(chars[charsind1])-1) + 1
                password = password + chars[charsind1][charsind2]
      end

func init()

      fp = fopen("C:\Ring\calmosoft\pwgen.ring","r")
      r = ""
      str = ""
      nr = 0
      while isstring(r)
              r = fgetc(fp)
              if r != char(10) and not feof(fp)
                 str = str + r
                 nr = nr + 1
                 strp[nr] = str
              else
                 str = ""
              ok
      end
      fclose(fp)

</lang> Output:

password = w6+Am5]N
password = e9(Ca9,I
password = u8/Ah8%H
password = c4\Nc2_J

Ruby

<lang Ruby>ARRS = [("a".."z").to_a,

       ("A".."Z").to_a, 
       ("0".."9").to_a,
       %q(!"#$%&'()*+,-./:;<=>?@[]^_{|}~).chars] # " quote to reset clumsy code colorizer

ALL = ARRS.flatten

def generate_pwd(size, num)

 raise ArgumentError, "Desired size too small" unless size >= ARRS.size
 num.times.map do
   arr = ARRS.map(&:sample)
   (size - ARRS.size).times{ arr << ALL.sample}
   arr.shuffle.join
 end

end

puts generate_pwd(8,3) </lang>

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] print "----------- Password Generator -----------" input "Number of Characters:";howBig if howBig < 1 then goto [exit]

input "How many to generate:";howMany if howMany < 1 then goto [main]

' ----------------------------- ' Generate Password ' ----------------------------- [gen] 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

Rust

<lang rust> use rand::distributions::Alphanumeric; use rand::prelude::IteratorRandom; use rand::{thread_rng, Rng}; use std::iter; use std::process; use structopt::StructOpt; const OTHER_VALUES: &str = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~";

// the core logic that creates our password fn generate_password(length: u8) -> String {

   // cache thread_rng for better performance
   let mut rng = thread_rng();
   // the Alphanumeric struct provides 3/4
   // of the characters for passwords
   // so we can sample from it
   let mut base_password: Vec<char> = iter::repeat(())
       .map(|()| rng.sample(Alphanumeric))
       .take(length as usize)
       .collect();
   let mut end_range = 10;
   // if the user supplies a password length less than 10
   // we need to adjust the random sample range
   if length < end_range {
       end_range = length;
   }
   // create a random count of how many other characters to add
   let mut to_add = rng.gen_range(1, end_range as usize);
   loop {
       // create an iterator of required other characters
       let special = OTHER_VALUES.chars().choose(&mut rng).unwrap();
       to_add -= 1;
       base_password[to_add] = special;
       if to_add == 0 {
           break;
       }
   }
   base_password.iter().collect()

}

  1. [derive(StructOpt, Debug)]
  2. [structopt(name = "password-generator", about = "A simple password generator.")]

struct Opt {

   // make it SECURE by default
   // https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html
   /// The password length
   #[structopt(default_value = "160")]
   length: u8,
   /// How many passwords to generate
   #[structopt(default_value = "1")]
   count: u8,

}

fn main() {

   // instantiate the options and use them as
   // arguments to our password generator
   let opt = Opt::from_args();
   const MINIMUM_LENGTH: u8 = 30;
   if opt.length < MINIMUM_LENGTH {
       eprintln!(
           "Please provide a password length greater than or equal to {}",
           MINIMUM_LENGTH
       );
       process::exit(1);
   }
   for index in 0..opt.count {
       let password = generate_password(opt.length);
       // do not print a newline after the last password
       match index + 1 == opt.count {
           true => print!("{}", password),
           _ => println!("{}", password),
       };
   }

} </lang>

Output:
password-generator 30 5

%"/[:*|}zYNaC2C7IRsAXK8zDZR8JC
)fJGVcMqBLQkU5x2YOpo6Oyw0ezWHh
%/@&@2BBOQBLnH74lsqtj92eWZRQzc
|:%!r77MTosArmxe9J3LvKurcdOX3P
(=>#[!%|z84tH5edhGY48hoylopnIA

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

Seed7

<lang seed7>$ include "seed7_05.s7i";

const func string: generate (in integer: length) is func

 result
   var string: password is "";
 local
   const set of char: allowed is {'!' .. '~'} - {'\\', '`'};
   const set of char: special is allowed - {'A' .. 'Z'} | {'a' .. 'z'} | {'0' .. '9'};
   var integer: index is 0;
   var char: ch is ' ';
   var boolean: ucPresent is FALSE;
   var boolean: lcPresent is FALSE;
   var boolean: digitPresent is FALSE;
   var boolean: specialPresent is FALSE;
 begin
   repeat
     password := "";
     ucPresent := FALSE;
     lcPresent := FALSE;
     digitPresent := FALSE;
     specialPresent := FALSE;
     for index range 1 to length do
       ch := rand(allowed);
       ucPresent := ucPresent or ch in {'A' .. 'Z'};
       lcPresent := lcPresent or ch in {'a' .. 'z'};
       digitPresent := digitPresent or ch in {'0' .. '9'};
       specialPresent := specialPresent or ch in special;
       password &:= ch;
     end for;
   until ucPresent and lcPresent and digitPresent and specialPresent;
 end func;

const proc: main is func

 local
   var integer: length is 0;
   var integer: count is 0;
 begin
   if length(argv(PROGRAM)) <> 2 or not isDigitString(argv(PROGRAM)[1]) or
      not isDigitString(argv(PROGRAM)[2]) then 
     writeln("Usage: pwgen length count");
     writeln("       pwgen -?");
     writeln("length: The length of the password (min 4)");
     writeln("count:  How many passwords should be generated");
     writeln("-?  Write this text");
   else
     length := integer(argv(PROGRAM)[1]);
     count := integer(argv(PROGRAM)[2]);
     if length < 4 then
       writeln("Passwords must be at least 4 characters long.");
     else
       for count do
         writeln(generate(length));
       end for;
     end if;
   end if;
 end func;</lang>
Output:
$ pwgen -?
Usage: pwgen length count
       pwgen -?
length: The length of the password (min 4)
count:  How many passwords should be generated
-?  Write this text
$ pwgen 8 3
S1uqOqU~
@m'-.D,9
>tl1fvEU
$

Swift

Swift uses arc4random() to generate fast and high quality random numbers. However the usage of a user defined seed is not possible within arc4random(). To fulfill the requirements this code uses the C functions srand() and rand() that are integrated into the Swift file via an Bridging-Header.

C file to generate random numbers <lang C>#include <stdlib.h>

  1. include <time.h>

void initRandom(const unsigned int seed){

   if(seed==0){
       srand((unsigned) time(NULL));
   }
   else{
       srand(seed);
   }

}

int getRand(const int upperBound){

   return rand() % upperBound;

}</lang>

Bridging-Header to include C file into Swift <lang C>int getRand(const int upperBound); void initRandom(const unsigned int seed);</lang>

Swift file <lang swift>import Foundation import GameplayKit // for use of inbuilt Fisher-Yates-Shuffle

/* Prints the usage of this code */ func printHelp() -> Void {

   print("Usage: PasswordGenerator [-l:length] [-c:count] [-s:seed] [-x:exclude] [-h:help]")
   print("\t-l: length of the passwords (at leas 4 characters)")
   print("\t-c: number of passwords to generate")
   print("\t-s: seed of the random number generator")
   print("\t-x: exclude of visually similar characters \"Il1O05S2Z\"")
   print("\t-h: print this help")
   exit(0)

}

/* Set characters for generating passwords */ let _lower:String = "abcdefghijklmnopqrstuvwxyz" let _lowerWithoutSimilar:String = "abcdefghijkmnopqrstuvwxyz" let _upper:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" let _upperWithoutSimilar = "ABCDEFGHJKLMNPQRTUVWXY" let _number:String = "0123456789" let _numerWithoutSimilar:String = "1346789" let _other:String = "!\"#$%&'()*+,-./:;<=>?@[]^_{|}~"

/* Generate character arrays out of strings */ let upper = Array(_upper.characters) let upperWithoutSimilar = Array(_upperWithoutSimilar.characters) let lower = Array(_lower.characters) let lowerWithoutSimilar = Array(_lowerWithoutSimilar.characters) let other = Array(_other.characters) let number = Array(_number.characters) let numberWithoutSimilar = Array(_numerWithoutSimilar.characters)

var length:Int=0, count:Int=0, seed:Int=0, xclude:Bool=false

/* Parse CLI arguments */ for i in 1..<CommandLine.arguments.count{

   var arg = CommandLine.arguments[i]
   var argument = arg.components(separatedBy: ":")
   switch(argument[0]){
   case "-l":
       length=Int(argument[1])!
       if length < 4 {
           print("A password must contain of at least 4 characters.")
           exit(-1)
       }
       break
   case "-c":
       count=Int(argument[1])!
       break
   case "-s":
       seed=Int(argument[1])!
       break
   case "-x":
       xclude=true
       break
   case "-h":
       printHelp()
   default:
       print("Could not parse CLI arguments. Use -h for help.")
       exit(0)
   }

}

/* Generate password of given length */ func generatePassword(length len:Int, exclude xcl:Bool) -> String{

   var ret:String = "", loopCount:Int = 0
   
   while(loopCount < len){
       if ret.characters.count < len {
           if xcl {
               ret += String(upperWithoutSimilar[Int(getRand(Int32(upperWithoutSimilar.count-1)))])
           }
           else {
               ret += String(upper[Int(getRand(Int32(upper.count)))])
           }
       }
       
       if ret.characters.count < len {
           if xcl {
               ret += String(lowerWithoutSimilar[Int(getRand(Int32(lowerWithoutSimilar.count-1)))])
           }
           else {
               ret += String(lower[Int(getRand(Int32(lower.count-1)))])
           }
       }
       
       if ret.characters.count < len {
           if xcl {
               ret += String(numberWithoutSimilar[Int(getRand(Int32(numberWithoutSimilar.count-1)))])
           }
           else {
               ret += String(number[Int(getRand(Int32(number.count-1)))])
           }
       }
       
       if ret.characters.count < len {
           ret += String(other[Int(getRand(Int32(other.count-1)))])
       }
       loopCount += 4
   }
   
   // Shuffle the array with an internal shuffle function
   let shuffled = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: Array(ret.characters))
   ret = ""
   for element in shuffled {
       ret += String(describing: element)
   }
   return ret

}

if xclude {

   print("Generating \(count) passwords with length \(length) excluding visually similar characters...")

} else {

   print("Generating \(count) passwords with length \(length) not excluding visually similar characters...")

}

initRandom(UInt32(0)) // initialize with C func srand()

// generate the passwords for i in 1...count {

   print("\(i).\t\(generatePassword(length:length,exclude:xclude))")

}</lang>

Output:
$ PasswordGenerator -h
Usage: PasswordGenerator [-l:length] [-c:count] [-s:seed] [-x:exclude] [-h:help]
	-l: length of the passwords (at leas 4 characters)
	-c: number of passwords to generate
	-s: seed of the random number generator
	-x: exclude of visually similar characters "Il1O05S2Z"
	-h: print this help

$ PasswordGenerator -l:10 -c:5 -x
Generating 5 passwords with length 10 excluding visually similar characters...
1.	Fs7]r)N4Ap
2.	(o6GgXE=6a
3.	A!A7k|N3mi
4.	6]XDKo!nx8
5.	Gi6b>6Mv&C

VBA

<lang vb> Option Explicit Sub Main() Dim s() As String, i As Long

       Debug.Print "list of 10 passwords : "

'do a list of 10 passwords with password's lenght = 21 and visually similar = False

   s = Gp(10, 21, False)
       'return
       Debug.Print "1- with password's lenght = 21 and visually similar = False :"
       For i = 1 To UBound(s): Debug.Print s(i): Next

'do a list of 10 passwords with pattern = "A/9-a/1-9/4-!/5" and visually similar = True

   s = Gp(10, "A/9-a/1-9/4-!/5", True)
       'return
       Debug.Print "2- with pattern = ""A/9-a/1-9/4-!/5"" and visually similar = True :"
       For i = 1 To UBound(s): Debug.Print s(i): Next

End Sub Sub HelpMe() Dim s As String

   s = "Help :" & vbCrLf
   s = s & "----------------------------------" & vbCrLf
   s = s & "The function (named : Gp) needs 3 required parameters :" & vbCrLf & vbCrLf
   s = s & "1- Nb_Passwords (Long) : the number of passwords to generate." & vbCrLf & vbCrLf
   s = s & "2- NbChar_Or_Pattern (Variant) : either a number or a pattern" & vbCrLf
   s = s & "      If number : NbChar_Or_Pattern specify the password length. All the digits are random ASCII characters" & vbCrLf
   s = s & "      If pattern : NbChar_Or_Pattern specify the password length and the layout of passwords." & vbCrLf
   s = s & "             The pattern is built like this :" & vbCrLf
   s = s & "                 ""A"" means Upper case, ""a"" means lower case, 9 means numerics and ! means others characters." & vbCrLf
   s = s & "                 ""-"" is the separator between these values." & vbCrLf
   s = s & "                 the number of characters is specified after the sign (required): ""/""" & vbCrLf
   s = s & "                 example of pattern available : ""A/3-a/2-9/1-!/1""" & vbCrLf & vbCrLf
   s = s & "3- Excl_Similar_Chars (Boolean) : True if you want the option of excluding visually similar characters."
   Debug.Print s

End Sub Private Function Gp(Nb_Passwords As Long, NbChar_Or_Pattern As Variant, Excl_Similar_Chars As Boolean) As String() 'generate a list of passwords Dim l As Long, s() As String

   ReDim s(1 To Nb_Passwords)
   If IsNumeric(NbChar_Or_Pattern) Then
       For l = 1 To Nb_Passwords
           s(l) = p(CLng(NbChar_Or_Pattern), Excl_Similar_Chars)
       Next l
   Else
       For l = 1 To Nb_Passwords
           s(l) = ttt(CStr(NbChar_Or_Pattern), Excl_Similar_Chars)
       Next l
   End If
   Gp = s

End Function Public Function p(n As Long, e As Boolean) As String 'create 1 password without pattern (just with the password's lenght) Dim t As String, i As Long, a As Boolean, b As Boolean, c As Boolean, d As Boolean

   Randomize Timer
   If n < 4 Then
       p = "Error. Numbers of characters is too small. Min : 4"
   ElseIf n >= 4 And n < 7 Then
       T = u(122, 97) & u(90, 65) & u(57, 48) & v
       For j = 5 To n
           i = Int((4 * Rnd) + 1)
           Select Case i
               Case 1: T = T & u(122, 97)
               Case 2: T = T & u(90, 65)
               Case 3: T = T & u(57, 48)
               Case 4: T = T & v
           End Select
       Next j
       'Debug.Print T
       p = y(T)
   Else
       Do
           i = Int((4 * Rnd) + 1)
           Select Case i
               Case 1: t = t & u(122, 97): a = True
               Case 2: t = t & u(90, 65): b = True
               Case 3: t = t & u(57, 48): c = True
               Case 4: t = t & v: d = True
           End Select
           If Len(t) >= 2 And e Then
               If x(t) Then t = Left(t, Len(t) - 1)
           End If
           If Len(t) = n Then
               If a And b And c And d Then
                   Exit Do
               Else
                   w t, a, b, c, d
                   p = p(n, e)
               End If
           ElseIf Len(t) > n Then
               w t, a, b, c, d
               p = p(n, e)
           End If
       Loop
       p = t
   End If

End Function Public Function ttt(s As String, e As Boolean) As String 'create 1 password with pattern Dim a, i As Long, j As Long, st As String, Nb As Long

   a = Split(s, "-")
   For i = 0 To UBound(a)
       Select Case Left(a(i), 1)
           Case "A"
               Nb = CLng(Split(a(i), "/")(1)): j = 0
               Do
                   j = j + 1
                   st = st & u(90, 65)
                   If Len(st) >= 2 And e Then
                       If x(st) Then st = Left(st, Len(st) - 1): j = j - 1
                   End If
               Loop While j < Nb
           Case "a"
               Nb = CLng(Split(a(i), "/")(1)): j = 0
               Do
                   j = j + 1
                   st = st & u(122, 97)
                   If Len(st) >= 2 And e Then
                       If x(st) Then st = Left(st, Len(st) - 1): j = j - 1
                   End If
               Loop While j < Nb
           Case "9"
               Nb = CLng(Split(a(i), "/")(1)): j = 0
               Do
                   j = j + 1
                   st = st & u(57, 48)
                   If Len(st) >= 2 And e Then
                       If x(st) Then st = Left(st, Len(st) - 1): j = j - 1
                   End If
               Loop While j < Nb
           Case "!"
               Nb = CLng(Split(a(i), "/")(1)): j = 0
               Do
                   j = j + 1
                   st = st & v
                   If Len(st) >= 2 And e Then
                       If x(st) Then st = Left(st, Len(st) - 1): j = j - 1
                   End If
               Loop While j < Nb
       End Select
   Next i
   ttt = y(st)

End Function Private Function u(m As Long, l As Long) As String 'random 1 character in lower/upper case or numeric

   Randomize Timer
   u = Chr(Int(((m - l + 1) * Rnd) + l))

End Function Private Function v() As String 'random 1 character "special"

   Randomize Timer
   v = Mid("!""#$%&'()*+,-./:;<=>?@[]^_{|}~", Int((30 * Rnd) + 1), 1)

End Function Private Sub w(t As String, a As Boolean, b As Boolean, c As Boolean, d As Boolean)

   t = vbNullString: a = False: b = False: c = False: d = False

End Sub Private Function x(s As String) As Boolean 'option of excluding visually similar characters Dim t, i As Long Const d As String = "Il I1 l1 lI 1l 1I 0O O0 5S S5 2Z 2? Z? Z2 ?2 ?Z DO OD"

   t = Split(d, " ")
   For i = 0 To UBound(t)
       If Right(s, 2) = t(i) Then
           x = True: Exit Function
       End If
   Next

End Function Private Function y(s As String) As String 'shuffle the password's letters only if pattern Dim i&, t, r As String, d() As Long

   t = Split(StrConv(s, vbUnicode), Chr(0))
   d = z(UBound(t))
   For i = 0 To UBound(t)
       r = r & t(d(i))
   Next i
   y = Left(r, Len(r) - 1)

End Function Private Function z(l As Long) As Long() 'http://rosettacode.org/wiki/Best_shuffle#VBA Dim i As Long, ou As Long, temp() As Long Dim c As New Collection

   ReDim temp(l)
   If l = 1 Then
       temp(0) = 0
   ElseIf l = 2 Then
       temp(0) = 1: temp(1) = 0
   Else
       Randomize
       Do
           ou = Int(Rnd * l)
           On Error Resume Next
           c.Add CStr(ou), CStr(ou)
           If Err <> 0 Then
               On Error GoTo 0
           Else
               temp(ou) = i
               i = i + 1
           End If
       Loop While c.Count <> l
   End If
   z = temp

End Function</lang>

Output:

Function Gp :

list of 10 passwords : 
1- with password's lenght = 21 and visually similar = False :
;OK6^D26"S1^ih77<pR~v
EH9csF8+hC"pw70dL5},A
F1qIC#xXZ!%mQ2kb5&>q1
c|e0*emQ2-bN1}QL-fFB3
/U9)@J54zY44(gI,/vZ5t
3W:!y44(n36nc2<"KW5)Z
7[oOK6^D26"S1^ih77<pR
zveH9csF8+hC"pw70dL5}
,A21qIC#xXZ!%mQ2kb5&>
=11|e0*emQ2-bN1}QL-fF
2- with pattern = "A/9-a/1-9/4-!/5" and visually similar = True :
)C4N#<>r@NDUX094LKF
EJL~!:JKS39U3<AW5"s
H$0t?1'V7+DHV#WFQQ8
71!t0T)BSGZ|V=>KI9V
I50GN^"+T8Vs>E"NKI1
|JAOrWY"WW97_7[Y[2K
EBoB/3)C#Z$F6U3V1,O
ANOBPZ*X2I-3@H]58e:
7D1$7V+BHQH'FV0#w{Q
&%72&LFL6iS~C(HAPQ8

Sub HelpMe :

Help :
----------------------------------
The function (named : Gp) needs 3 required parameters :

1- Nb_Passwords (Long) : the number of passwords to generate.

2- NbChar_Or_Pattern (Variant) : either a number or a pattern
      If number : NbChar_Or_Pattern specify the password length. All the digits are random ASCII characters
      If pattern : NbChar_Or_Pattern specify the password length and the layout of passwords.
             The pattern is built like this :
                 "A" means Upper case, "a" means lower case, 9 means numerics and ! means others characters.
                 "-" is the separator between these values.
                 the number of characters is specified after the sign (required): "/"
                 example of pattern available : "A/3-a/2-9/1-!/1"

3- Excl_Similar_Chars (Boolean) : True if you want the option of excluding visually similar characters.

Wren

Translation of: Kotlin
Library: Wren-ioutil
Library: Wren-fmt

<lang python>import "random" for Random import "/ioutil" for FileUtil, File, Input import "/fmt" for Fmt import "os" for Process

var r = Random.new() var rr = Random.new() // use a separate generator for shuffles var lb = FileUtil.lineBreak

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

var exclChars = [

   "'I', 'l' and '1'",
   "'O' and '0'     ",
   "'5' and 'S'     ",
   "'2' and 'Z'     "

]

var shuffle = Fn.new { |s|

   var sl = s.toList
   rr.shuffle(sl)
   return sl.join()

}

var generatePasswords = Fn.new { |pwdLen, pwdNum, toConsole, toFile|

   var ll = lower.count
   var ul = upper.count
   var dl = digit.count
   var ol = other.count
   var tl = ll + ul + dl + ol
   var fw = toFile ? File.create("pwds.txt") : null

   if (toConsole) System.print("\nThe generated passwords are:")
   for (i in 0...pwdNum) {
       var pwd = lower[r.int(ll)] + upper[r.int(ul)] + digit[r.int(dl)] + other[r.int(ol)]
       for (j in 0...pwdLen - 4) {
           var k = r.int(tl)
           pwd = pwd + ((k < ll)      ? lower[k] :
                        (k < ll + ul) ? upper[k - ll] :
                        (k < tl - ol) ? digit[k - ll - ul] : other[tl - 1 - k])
       }
       for (i in 1..5) pwd = shuffle.call(pwd) // shuffle 5 times say
       if (toConsole) Fmt.print("  $2d: $s", i + 1, pwd)
       if (toFile) {
           fw.writeBytes(pwd)
           if (i < pwdNum - 1) fw.writeBytes(lb)
       }
   }
   if (toFile) {
      System.print("\nThe generated passwords have been written to the file pwds.txt")
      fw.close()
   }

}

var printHelp = Fn.new {

   System.print("""

This program generates up to 99 passwords of between 5 and 20 characters in length.

You will be prompted for the values of all parameters when the program is run - there are no command line options to memorize.

The passwords can either be written to the console or to a file (pwds.txt), or both.

The passwords must contain at least one each of the following character types:

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

Optionally, a seed can be set for the random generator (any non-zero number) otherwise the default seed will be used. Even if the same seed is set, the passwords won't necessarily be exactly the same on each run as additional random shuffles are always performed.

You can also specify that various sets of visually similar characters will be excluded (or not) from the passwords, namely: Il1 O0 5S 2Z

Finally, the only command line options permitted are -h and -help which will display this page and then exit.

Any other command line parameters will simply be ignored and the program will be run normally.

""") }

var args = Process.arguments if (args.count == 1 && (args[0] == "-h" || args[0] == "-help")) {

  printHelp.call()
  return

}

System.print("Please enter the following and press return after each one")

var pwdLen = Input.integer(" Password length (5 to 20)  : ", 5, 20) var pwdNum = Input.integer(" Number to generate (1 to 99)  : ", 1, 99)

var seed = Input.number (" Seed value (0 to use default) : ") if (seed != 0) r = Random.new(seed)

System.print(" Exclude the following visually similar characters") for (i in 0..3) {

   var yn = Input.option("    %(exclChars[i]) y/n : ", "ynYN")
   if (yn == "y" || yn == "Y") {
       if (i == 0) {
           upper = upper.replace("I", "")
           lower = lower.replace("l", "")
           digit = digit.replace("1", "")
       } else if (i == 1) {
           upper = upper.replace("O", "")
           digit = digit.replace("0", "")
       } else if (i == 2) {
           upper = upper.replace("S", "")
           digit = digit.replace("5", "")
       } else if (i == 3) {
           upper = upper.replace("Z", "")
           digit = digit.replace("2", "")
       }
   }

}

var toConsole = Input.option(" Write to console y/n : ", "ynYN") toConsole = toConsole == "y" || toConsole == "Y" var toFile = true if (toConsole) {

   toFile = Input.option("  Write to file      y/n : ", "ynYN")
   toFile = toFile == "y" || toFile == "Y"

}

generatePasswords.call(pwdLen, pwdNum, toConsole, toFile)</lang>

Output:

Sample run:

Please enter the following and press return after each one
  Password length (5 to 20)     : 8
  Number to generate (1 to 99)  : 10
  Seed value (0 to use default) : 0
  Exclude the following visually similar characters
    'I', 'l' and '1' y/n : n
    'O' and '0'      y/n : n
    '5' and 'S'      y/n : n
    '2' and 'Z'      y/n : n
  Write to console   y/n : y
  Write to file      y/n : y

The generated passwords are:
   1: 53oR=Y|#
   2: LdT,[7x=
   3: puQwj#0N
   4: kY0:zL~m
   5: 01BN!fqZ
   6: +3Si33[}
   7: !MV:9/wC
   8: gcAY0m#_
   9: h45R)A|c
  10: SGrpk:86

The generated passwords have been written to the file pwds.txt

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

isd:='wrap(w){ w.pump(String) - xclude }; // iterator to String g1,g2,g3 := isd(["a".."z"]), isd(["A".."Z"]), isd(["0".."9"]); g4:="!\"#$%&'()*+,-./:;<=>?@[]^_{|}~" - xclude; all:=String(g1,g2,g3,g4); fcn rnd(s){ s[(0).random(s.len())] } // pick a random character from s

   // generate random characters of filler needed to complete password

fill:=(pwdLen-4).pump.fp(String,rnd.fp(all)); // a deferred/pending calculation

do(numPwds){

  // Data is byte bucket (and editor). I can shuffle a Data but not a String.
  pwd:=T(g1,g2,g3,g4).pump(Data,rnd); // 1 from each of these into a Data
  pwd.extend(fill()).shuffle().text.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