Password generator: Difference between revisions

From Rosetta Code
Content added Content deleted
No edit summary
Line 1,434: Line 1,434:
}
}


function Add-PasswordCharacter ([char[]]$From)
function Select-PasswordCharacter ([char[]]$From)
{
{
$key = Get-Seed
$key = Get-Seed
Line 1,453: Line 1,453:
}
}


$password.Add($key,$From[$index])
$password.Add($key, $From[$index])
}
}
}
}
Process
Process
{
{
1..$Count | ForEach-Object {
for ($i = 1;$i -le $Count; $i++)
{

[hashtable] $password = @{}
[hashtable] $password = @{}


Line 1,466: Line 1,466:
if($password.Count -lt $Length)
if($password.Count -lt $Length)
{
{
Add-PasswordCharacter -From $array # Append to $password
Select-PasswordCharacter -From $array # Append to $password
}
}
}
}
Line 1,472: Line 1,472:
for ($j = $password.Count; $j -lt $Length; $j++)
for ($j = $password.Count; $j -lt $Length; $j++)
{
{
Add-PasswordCharacter -From $allChars # Append to $password
Select-PasswordCharacter -From $allChars # Append to $password
}
}



Revision as of 03:20, 9 February 2017

Task
Password generator
You are encouraged to solve this task according to the task description, using any language you may know.

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

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



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

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

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

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

const std::string UNS = "O0l1I5S2Z";

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

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

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

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

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

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

} </lang>

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


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

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"


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

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]

Lua

<lang Lua>function randPW (length)

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

end

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

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

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

>lua pwgen.lua

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

A Lua script to generate random passwords.

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


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

ooRexx

Translation of: [[#|]] – REXX

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

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

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

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

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

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

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

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

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

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

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

PARI/GP

PARI/GP has a very good 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)

Perl

We use Math::Random, for two reasons: 1) we can use its random_permutation() function; 2) there is a security aspect to this task, so we should avoid using the built-in rand() function as it is presumably less sophisticated. <lang perl>use strict; use English; use Const::Fast; use Getopt::Long; use Math::Random;

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

if (! GetOptions(%opts)) {command_line_help(); exit 1; } $num_pwds >= 1 or die "Number of passwords must be at least 1"; $pwd_length >= 4 or die "Password length must be at least 4"; random_set_seed_from_phrase($seed_phrase);

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

  1. Oh syntax highlighter, please be happy once more "

foreach my $i (1 .. $num_pwds) {

   print gen_password(), "\n";

} exit 0;

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.
   for (my $j = 0; $j < $pwd_length - 4; $j++) {
       my $one_of_four = random_uniform_integer(1, 0, 3);
       push @chars, $generators[$one_of_four]->();
   }
   return join(q{}, random_permutation(@chars));

}

sub random_lc {

   my $idx = random_uniform_integer(1, 0, scalar(@lcs)-1);
   return $lcs[$idx];

}

sub random_uc {

   my $idx = random_uniform_integer(1, 0, scalar(@ucs)-1);
   return $ucs[$idx];

}

sub random_digit {

   my $idx = random_uniform_integer(1, 0, scalar(@digits)-1);
   return $digits[$idx];

}

sub random_other {

   my $idx = random_uniform_integer(1, 0, length($others)-1);
   return substr($others, $idx, 1);

}

sub command_line_help {

   print "Usage: $PROGRAM_NAME ",
         "[--password_length=<l> (default: $pwd_length)] ",
         "[--num_passwords=<n> (default: $num_pwds)] ",
         "[--seed_phrase= (default: $seed_phrase)] ",
         "[--help]\n";
   return;

}</lang> Transcript (with paths redacted):

...>password_generator.pl --help
Usage: ...\password_generator.pl [--password_length=<l> (default: 8)] [--num_passwords=<n> (default: 6)] [--seed_phrase=<s> (default: TOO MANY SECRETS)] [--help]

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

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

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 Select-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)
               {
                   Select-PasswordCharacter -From $array # Append to $password
               }
           }
           for ($j = $password.Count; $j -lt $Length; $j++)
           {
               Select-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#

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

Racket

<lang racket>

  1. lang racket

(require racket/cmdline)

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

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

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

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

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

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

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

(define (is-readable? c)

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

(define (random-selection lst)

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

(define (generate len readable)

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

(define (run len cnt seed readable)

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

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

(command-line #:program "passwdgen"

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


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

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

REXX

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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