XerX
XerX

Reputation: 91

Linux - Generate random password based on requirements

\Hello, I've been searching for a day but cannot find a way to specify concrete password requirements when generating one with Bash:
-at least 12 char length:
-at least 4 different letters:
-at least 3 digits:
-at least 3 special chars -_+=#^*

I use the urandom: tr -dc A-Za-z0-9_ < /dev/urandom | head -c 16 | xargs which generates, in this case, 16 char string with letters, numbers and underscore. But I cannot specify the critera above.

Upvotes: 1

Views: 3537

Answers (2)

Kaz
Kaz

Reputation: 58588

Solution in TXR Lisp:

$ txr pwgen.tl
ix8K+6I6^#hp
$ txr pwgen.tl
s#J_&Eo348wl
$ txr pwgen.tl
dKt7V4#g&c9+

Code:

(let* ((abc (join "a".."z"))
       (ABC (upcase-str abc))
       (dig (join "0".."9"))
       (chr "-_+=#^&"))
  (labels ((relem (str) [str (rand (len str))])
           (dr (str n) [(shuffle str) 0..n])
           (r (str n) (str-seq (take n (gun (relem str))))))
    (flow `@(dr abc 4)@(r dig 3)@(r chr 3)@(r ABC 2)`
      shuffle
      put-line)))

We must call (make-random-state) to make a new, randomized state for the pseudo-random-number generator (PRNG), and store that in *random-state*. Otherwise we will get the same password every time.

The rules about which chararacters must be present give us ten characters. So we need two more. Let us meet that requirement by choosing two random upper case letters.

The program prepares some strings: abc contains the alphabet, dig the digits 0 through 9 and so on.

There are some local functions: (relem str) chooses a random character from the string str; (dr str n) chooses n different random ("dr") characters from str and returns them as a string; (r str n) chooses n random characters from str, not necessarily different.

We then use these functions inside a quasistring: a back-quoted string template with interpolation. That gives us a string in which the required items are in order: four different letters, three digits, three characters from the set, and then two random upper case letters.

We inject this string into a pipeline using flow which passes it thorugh shuffle, and hands it off to put-line.

(gun (relem str)) means repeatedly evaluate the expression (relem str) and use the values to generate an lazy sequence, until that expression returns nil: ("gun" means "generate until nil"). Since relem doesn't return nil, we get an infinite sequence of random choices of letters from str. We use (take n (gun ...)) to just take the first n, and then str-seq (string from sequence) to turn those letters into a string.

Upvotes: 0

Roman Pavelka
Roman Pavelka

Reputation: 4181

For example this would fulfill criteria:

echo $(tr -dc A-Za-z < /dev/urandom | head -c 16)abcd123+-=

First criterium is easy and you already achieved that, others are fulfilled by fixed suffix appended to end.

You can make it bit better by random permutation of the result:

echo $(echo $(tr -dc A-Za-z < /dev/urandom | head -c 16)abcd123+-= | fold -w 1 | shuf | tr -d "\n")

(I helped myself with this answer)

Upvotes: 2

Related Questions