608

I would like to generate a random string (e.g. passwords, user names, etc.). It should be possible to specify the needed length (e.g. 13 chars).

What tools can I use?

(For security and privacy reasons, it is preferable that strings are generated off-line, as opposed to online on a website.)

landroni
  • 10,906
  • 2
    There are already good answers are at AskUbuntu. (I use apg personally.) – Sparhawk Sep 20 '15 at 13:07
  • 3
    @Sparhawk The AskUbuntu question/answers are more about listing tools. Please consider adding an answer here exhibiting how to use apg to generate a random string. – landroni Sep 20 '15 at 15:51
  • 3
    Be cautious about using random number generation on computers. Some are much less random than they appear, but telling the difference between 'good' and 'bad' random number generation is quite hard. – Sobrique Sep 21 '15 at 11:15
  • @Sobrique Excellent point about pseudo-random number generators (e.g. /dev/urandom). Would be nice to have some answers using true random number generators, based on e.g. random.org. – landroni Sep 21 '15 at 11:23
  • 98
    Joke answer: To generate a truly random string, place a new user in front of Emacs (or Vim) and ask them to exit. ;) – Wildcard Oct 30 '16 at 04:51

26 Answers26

576

My favorite way to do it is by using /dev/urandom together with tr to delete unwanted characters. For instance, to get only digits and letters:

tr -dc A-Za-z0-9 </dev/urandom | head -c 13; echo

Alternatively, to include more characters from the OWASP password special characters list:

tr -dc 'A-Za-z0-9!"#$%&'\''()*+,-./:;<=>?@[\]^_`{|}~' </dev/urandom | head -c 13; echo

If you have some problems with tr complaining about the input, try adding LC_ALL=C like this:

LC_ALL=C tr -dc 'A-Za-z0-9!"#$%&'\''()*+,-./:;<=>?@[\]^_`{|}~' </dev/urandom | head -c 13; echo

tr also has a character class for graphical characters that is a bit more readable. Limiting it to the C locale should produce the same kind of output as the above explicit list of characters:

LC_ALL=C tr -dc '[:graph:]' </dev/urandom | head -c 13; echo
Toby Speight
  • 8,678
herbert
  • 6,222
  • Interesting. How do you control length with this approach? – landroni Sep 19 '15 at 08:21
  • @landroni You can use the -c parameter to head. E.g. head -c10 /dev/urandom | tr -dc A-Za-z0-9 – Brandin Sep 19 '15 at 08:46
  • @landroni, you could use dd bs=100 count=1 if=/dev/urandom to get 100 bytes. – dubiousjim Sep 19 '15 at 08:46
  • 51
    Or do this: head /dev/urandom | tr -dc A-Za-z0-9 | head -c10 - This way is more accurate. You get 10 characters that are capitals, lowers, or digits – Brandin Sep 19 '15 at 08:47
  • @Brandin, yes the last you suggested is the best approach since you cannot control directly what /dev/urandom will generate. – herbert Sep 19 '15 at 08:51
  • @Brandin Looks good. My last gripe with this approach is that what I actually get looks like this: aXPaX9zdzcgeek@liv-inspiron:~$. Some line break seems to be lacking... – landroni Sep 19 '15 at 09:02
  • 1
    @landroni To add the \n in the output you'll probably have to add it yourself. Here's a simple bash syntax shell function - make it a shell script if you want: function genPass() { N=${1:-8}; head /dev/urandom | tr -dc A-Za-z0-9 | head -c$N; echo ""; } – Brandin Sep 19 '15 at 09:09
  • 1
    @landroni Or if you want an easier one-liner, use echo with backticks to generate the \n for you: echo "$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c10)" – Brandin Sep 19 '15 at 09:16
  • 19
    The first head command might be problematic. It will output the first 10 lines from /dev/urandom, which means it will stop once it has seen the 10th newline. So the length of the output send to the tr command is random. It is possible that there will be less than 13 characters in the output from tr. I haven't computed the probability of this happening, the calculations are a bit tricky. – kasperd Sep 19 '15 at 22:40
  • 9
    Better do it like this: <dev/urandom tr -dc "$charset" | head -c "$length" – Petr Skocik Sep 20 '15 at 13:06
  • 1
    @PSkocik Yes, only that you omitted /. It should be </dev/urandom tr -dc "$charset" | head -c "$length". And for Bradins solution: why not </dev/urandom tr -dc A-Za-z0-9 | head -c 10 ; echo? Is 'echo "" more portable? – BartekChom Sep 21 '15 at 10:08
  • 3
    +1 Here's a quick attempt to include the other characters from the OWASP password special characters page, escaped for bash command line: tr -dc A-Za-z0-9\!\"#$\&\'\(\)\*+,-./\:\\\\\;\<=\>\?@[]^_\{|}~` – Rup Jul 28 '16 at 10:26
  • 2
    @Rup I'm not sure what's not working with your tr .. command but just quoting everything (except for the single quote) works – tr -dc 'A-Za-z0-9!"#$%&'\''()*+,-./:;<=>?@[\]^_\{|}~'`. – Kenny Evitt Aug 18 '16 at 19:33
  • Someone pointed out that this could possibly fail to output a random string of any desired length. I figure that's very unlikely. I asked for more details here. – Kenny Evitt Nov 12 '16 at 22:35
  • 3
    Doesn't work on OSX's version of tr but does with GNU tr (which you can get via brew install coreutils.) – scorpiodawg Mar 07 '17 at 20:13
  • 15
    +1 for the LC_ALL=C workaround. In my case head /dev/urandom | LC_ALL=C tr -dc A-Za-z0-9 | head -c 13) fixed the OSX tr problem just in place. – Camilo Sampedro Sep 28 '18 at 10:14
  • Built this from the foundation of the answer and comments: https://unix.stackexchange.com/a/476125/9583 – Iiridayn Oct 19 '18 at 07:53
  • 23
    macOS tr by default expects UTF-8 input, but /dev/urandom is not UTF-8 encoded characters but just random bytes, so you will get a tr: Illegal byte sequence error. You can fix this problem by setting the LC_ALL env var to C for the tr command in the pipe. This causes tr to expect arbitrary bytes. – weibeld Oct 23 '18 at 09:11
  • 1
    You can make that longer OWASP command shorter by using this equivalent: </dev/urandom tr -dc '!-~' | head -c 13; echo And with LC_ALL: LC_ALL=C tr -dc '!-~' </dev/urandom | head -c 13; echo – Tynach Dec 07 '19 at 21:01
  • 1
    Actually, now that I looked at the OWASP page, it also includes spaces. So change '!-~' to ' -~' to include that. – Tynach Dec 07 '19 at 21:32
  • tr -dc A-Za-z0-9 </dev/urandom | head -c 32 | wl-copy copies the output to clipboard (Wayland). – user598527 Apr 18 '23 at 11:46
  • The cat /dev/urandom and </dev/ramdom options break when using set -euo pipefail in a script. So I use head -c 8192 /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9_' | head -c 13. Given enough bytes to the first head is rare not to get enough characters for the last. – Francisco Puga Nov 10 '23 at 17:13
  • Isn't tr completely the wrong tool to use here? It's much easier to get a predictable string length with dd if=/dev/urandom bs=16 count=1 | base64. – Tom Feb 09 '24 at 09:50
501

I am using the openssl command, the swiss army knife of cryptography.

openssl rand -base64 12

or

openssl rand -hex 12
Martin Vegter
  • 358
  • 75
  • 236
  • 411
  • 29
    rand -hex will limit the output to just 16 characters, rather than the 90+ on my keyboard. base64 is better because it's 64 characters, but it's not random (e.g. there are predictable padding patterns, and perhaps some characters appear more often than others). – Martin Tournoij Aug 27 '16 at 17:37
  • 4
    @Carpetsmoker: Note that the example openssl rand -base64 12 produces 16 characters of output (because 256 values are mapped to 64). And the hex example produces 24 characters. There's no loss in the case of the hex since it's a simple 1:2 mapping, but there might be a little in the base64 case since padding is used. The radix does not affect the randomness, it's the way one is mapped to another that does. (and the total bit count is much more important). – Dennis Williamson May 19 '17 at 20:29
  • 2
    The question was "How to generate a random string of a specific length" @DennisWilliamson, so while your comment is correct as such, it's not correct in the context of this question. – Martin Tournoij May 19 '17 at 20:31
  • @Carpetsmoker: In that case, neither is this answer. – Dennis Williamson May 19 '17 at 20:58
  • 20
    This answer deserves more upvotes.

    urandom, pwgen, gpw, etc may or may not be available on your system; also in different environments, a policy that works on one may not work on another. It would be a pretty dysfunctional setup to not have openssl.

    Even better:

    openssl rand -base64 32 | tr -d /=+ | cut -c -16

    That'll give you 32 char minus non-alphanum's and trimmed to 16 char length. Makes it easy to deal with as an admin. Users only have alphanums (which they tend to appreciate). The length is long enough that the removal of special chars don't overly impact the entropy. Golden.

    – zentechinc Sep 05 '17 at 16:34
  • 1
    This worked also straight forward on a mac – otmezger Jun 15 '18 at 09:05
  • I am here to initialize IV, and this is what i was missing – Suhayb Apr 14 '19 at 16:12
  • 1
    This should be the top answer. – xxfelixxx Apr 29 '19 at 08:35
  • 5
    Note that according to its manual, the openssl rand command is still a pseudo-random generator, therefore not cryptographically secure. This suited my needs, but may not suit the need of all applications, e.g. initializing IV as mentioned in another comment. – spikyjt Feb 25 '20 at 15:09
  • 19
    Note that the manual says openssl rand is a cryptographically secure pseudo random number generator (CSPRNG). – ZoFreX Mar 22 '21 at 09:51
  • 1
    You probably want to use openssl rand 64 | openssl enc -A -base64 for longer strings, otherwise it will cut of at 80 characters because of backward compatibility with old terminals. – asynts Mar 16 '22 at 09:11
  • Beware this can generate not valid symbols for passwords like \n – tuxErrante Mar 15 '24 at 14:42
212

To generate a random password you can use pwgen:

pwgen generates random, meaningless but pronounceable passwords. These passwords contain either only lowercase letters, or upper and lower case mixed, or digits thrown in. Uppercase letters and digits are placed in a way that eases remembering their position when memorizing only the word.

Generate 7 passwords of length 13:

geek@liv-inspiron:~$ pwgen 13 7
Eu7Teadiphaec giepahl3Oyaiy iecoo9Aetaib4 phaiChae6Eivi athoo3igee8Co
Iphu4ufeDeelo aesoYi2lie9he 

As mentioned in the comments, you can avoid reducing entropy by using the -s argument (i.e. generate more secure, completely random but hard to remember passwords):

geek@liv-inspiron:~$ pwgen -s 13 7
eAfycrPlM4cYv 4MRXmZmyIVNBp D8y71iqjG7Zq7 FQRHcserl4R8O yRCUtPtV3dsqV
0vJpp2h0OrgF1 QTp7MKtJyTrjz 

For brew users, see here.


To generate random user names you can use gpw:

This package generates pronounceable passwords. It uses the statistics of three-letter combinations (trigraphs) taken from whatever dictionaries you feed it.

Generate 7 passwords (user names) of length 13:

geek@liv-inspiron:~$ gpw 7 13
sreepoidahsas
risadiestinge
ntodynesssine
deodstestress
natinglumperm
riasigentspir
enderiferback
AdminBee
  • 22,803
landroni
  • 10,906
48

Inspired by Pablo Repetto I ended up with this easy to remember solution:

shuf -er -n20  {A..Z} {a..z} {0..9} | tr -d '\n'

-e echoes the result

-r allows any character to appear multiple times

-n20 requests a random string with a length of 20 characters

{A..Z} {a..z} {0..9} defines the allowed char classes

shuf is part of coreutils and widely available or at least been ported.

Stephen Kitt
  • 434,908
45

Here is how, I do it. It generates 10 characters random string. You can optimize it by replacing the "fold", with other string processing tools.

cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 10 | head -n 1
  • 1
    Note that you also add a newline at the end. To fix that, and optimize by replacing fold -w 10 | head -n 1 with head -c10 – elomage Apr 07 '21 at 07:17
  • 1
    I've been using this for years however in macOS Big Sur it breaks with "Input error" – hyperknot Apr 23 '21 at 00:19
  • 1
    add LC_ALL as suggested in another answer: cat /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | fold -w 10 | head -n 1 – Ludovic Kuty Aug 18 '23 at 08:19
30

To generate password with the highest entropy possible with standard Linux tools that are built into every distribution I use:

< /dev/urandom tr -cd "[:print:]" | head -c 32; echo

This outputs all of the ASCII printable characters - from 32 (space) to 126 (tilde, ~). The password length can be controlled with the head's -c flag. There are also other possible character sets in tr (to not include the space, just characters 33-126, use [:graph:]).

drws
  • 411
  • 2
    In what way is this different from the existing answers? Specifically, herbert's comes to mind. – Fox Apr 27 '17 at 22:40
  • 7
    @Fox His solution uses hardcoded list of characters, which is not an encouraged programming practice because of code readability, compactness and cleanliness. Also some of the special printable ASCII characters could be interpreted by bash, not to mention the most obvious drawback of his one liner - if maximum entropy is desired, can one be sure that all of the available characters are included in the list? And that there are no duplicates which could possibly alter the tr's behaviour? His answer should be replaced by mine since you asked :) – drws Apr 29 '17 at 13:37
  • 4
    Many if not most web sites have restrictions on the characters that can be in a password, so hard-coding '[:print:]' doesn't feel any better to me than hard-coding the OWASP password special character list. I feel that almost every answer here could be improved by using a variable, but that is such a minor change that I'd only suggest an edit – Fox Apr 29 '17 at 13:54
  • 3
    < /dev/urandom tr -cd '[:graph:]'| tr -d '\\' | head -c 32; echo if you dont want \ characters in generated string. \ because is an escape character in many languages causes problems – mzzzzb Mar 08 '18 at 14:36
  • < /dev/urandom tr -cd "[:print:]" | tr -d ' \\/\`\|' | head -c 32; echo to exclude | \ / ` and space – Ryan Krage Aug 15 '19 at 12:19
  • 2
    @RyanKrage :graph: already excludes space, so a better solution than :print:. – Dani_l Feb 16 '20 at 10:14
25

Use the xxd command to specify length (via -l), which works both in Linux and macOS.  See the xxd(1) man page or the Linux xxd Command Tutorial for Beginners (with Examples).

xxd -l16 -ps /dev/urandom
northtree
  • 351
17

Depending on the level of randomness you want, you could simply go with bash's (also zsh and ksh, possibly others) builtin $RANDOM variable:

$ echo $RANDOM | tr '[0-9]' '[a-z]'
bfeci
$ echo $RANDOM | tr '[0-9]' '[a-z]'
cijjj

The methods reading directly from /dev/urandom are far simpler, but for the sake of completion, you could also use $RANDOM:

echo $(for((i=1;i<=13;i++)); do printf '%s' "${RANDOM:0:1}"; done) | tr '[0-9]' '[a-z]'

Important: this solution will only produce random strings using the first 10 letters of the alphabet. Whether or not that is enough for you depends on what you need this for.

terdon
  • 242,166
  • How do you control the length of the generated string? – landroni Sep 19 '15 at 13:33
  • 2
    @landroni I don't think you can short of using a loop until you get the right length. $RANDOM will print a number between 0 and 32767. – terdon Sep 19 '15 at 13:36
  • I've tried running the command some 20 times, and I can never get anything longer than 4-5 chars... – landroni Sep 19 '15 at 13:38
  • @landroni yes, that's what I said, it generates numbers between 0 and 32767, so 5 digits will be the max. If you need longer ones or need to be able to specify the length, please edit your question and make that clear. – terdon Sep 19 '15 at 14:20
  • I've now clarified the question to include length requirement. – landroni Sep 19 '15 at 15:51
  • 2
    @landroni thanks, I've added a way to specify length but it's not very good. I'd just use something like rand=$(head -c 100 /dev/urandom | tr -dc A-Za-z0-9 | head -c13) instead. – terdon Sep 19 '15 at 16:12
  • Thanks. The loop only generates strings with small characters. Is it possible to have capitals and/or numbers in the resulting string? – landroni Sep 19 '15 at 16:59
  • @landroni probably, but it's not worth the effort. Just use /dev/urandom as the other answers (and my previous comment) suggest instead. – terdon Sep 19 '15 at 17:01
  • @landroni echo $RANDOM$RANDOM$RANDOM|head -c13. – Skippy le Grand Gourou Jun 10 '16 at 10:34
  • Beware that this solution is limited to the 10 first characters of the alphabet. – Skippy le Grand Gourou May 08 '19 at 11:22
  • 1
    @SkippyleGrandGourou very good point. I added this to the answer, thanks. – terdon May 08 '19 at 11:30
12

APG is included by default on some Linux distributions.

To generate passwords from size 5 to 10 in subsets Special, Numeric, Capital and Lower, the command is:

apg -MSNCL -m 5 -x 10

And returns

@OpVeyhym9
3:Glul
3DroomIc?
hed&Os0
NefIj%Ob3
35Quok}

As said by @landroni in comment.

Sandburg
  • 367
10

I use:

base64 < /dev/urandom | tr -d 'O0Il1+/' | head -c 44; printf '\n'

This gives me 57 possible characters. The string can be copy-pasted (removed + and /) or printed and retyped as the difficult to distinguish characters (I1lO0) have been removed.

  • 44 characters gives me: log2(5744) > 256.64 bits of entropy
  • 22 characters gives me: log2(5722) > 128.32 bits of entropy

I like this because:

  • the command is simple to type and memorable
  • it uses standard system tools - no extra binaries
  • doesn't "waste" much randomness (uses 89% of the random bits it receives vs ~24% for solutions directly piping to tr)
  • 22 and 44 characters pair quite nicely (just above even) common power of two breakpoints
  • the output can be easily selected and pasted or printed and retyped with minimal human error rates
  • shorter than hex encoded (32 and 64 instead of 22 and 44) solutions such as md5sum/sha1sum, etc.

Credit to https://unix.stackexchange.com/a/230676/9583 and especially the comments for my initial inspiration.

Iiridayn
  • 310
  • If you need numbers/special characters - typically there will be a number, if not you can safely append 1 without reducing entropy (while generating a new one to get one w/a number does reduce entropy). You can also safely append a ! without reducing entropy. Neither scheme increases entropy worth anything either, but could bring the generated string into compliance with older password requirements. – Iiridayn Oct 17 '18 at 21:28
  • 1
    And it works on macOS! – Micah Henning May 02 '20 at 02:56
6

@Brandin explained in a comment to another answer how to get at most 100 bytes from /dev/urandom using head -c 100. Another way to do this is with dd:

tr -dc A-Za-z0-9 < /dev/urandom | dd bs=100 count=1 2>/dev/null

The 2>/dev/null at the end of the dd command is to suppress the "... records in / ... records out" output.

I'm not aware of any substantial advantages/disadvantages between these two methods.

I had an issue with both methods of tr complaining about the input. I thought this was because it didn't like receiving binary input, and hence suggested first filtering /dev/random with iconv -c -t US. However, Gilles suggested a different diagnosis and solution, which works for me:

LC_ALL=C tr -dc A-Za-z0-9 </dev/urandom | dd bs=100 count=1 2>/dev/null
dubiousjim
  • 2,698
  • For some reason the iconv solution maxes one CPU core and doesn't yield an output (I waited some 10s before killing it)... – landroni Sep 19 '15 at 09:38
  • On my Ubuntu 14.04 system iconv is provided by libc-bin 2.19. I'm not sure if it's the same iconv... – landroni Sep 19 '15 at 13:36
  • tr supports binary input. However a range like A-Z may be influenced by locale settings. Try LC_ALL=C tr … – Gilles 'SO- stop being evil' Sep 19 '15 at 20:27
  • 1
    @Gilles According to the POSIX spec it doesn't "support binary input". Only GNU tr does because it doesn't support multibyte at all (e.g. last time I checked it changing case was implemented by simply setting the sixth bit of every byte). Other systems (e.g. BSD) do support multibyte and this will fail there since the chance that a random input stream is also a valid multibyte stream is very small in most encodings. GNU may add multibyte support at any given moment, at which point this will fail. Of course, setting LC_ALL=C will fix that. – Martin Tournoij Aug 27 '16 at 17:33
  • @Carpetsmoker POSIX does require tr to process binary input (in the C locale). (Well, ok, it only says explicitly that null bytes are to be supported, it doesn't say that non-empty files not ending with a newline character are to be supported, but in practice that's always the case as well.) – Gilles 'SO- stop being evil' Aug 27 '16 at 17:57
  • @Gilles In the C locale any byte is a character with the exception of the NUL byte; but not so in multibyte encodings; how is it supposed to handle invalid UTF-8 sequences (which are almost guaranteed to occur with a random input)? The sane thing to do is to show an error and exit (which is what BSD tr will do). It seems to me that in 2016 we should assume multibyte by default, rather than as an afterthought, and reasoning from that, tr doesn't really support binary input (with the exception of the NUL byte). – Martin Tournoij Aug 27 '16 at 18:08
6

You can use one of md5 tools that has precisely this purpose. In the case of creating a completely random password you can use the md5pass. It is a very simple tool to use and very helpful, since you can use "normal text" together with a "salt" to jump-bit construction of the same password that you can recover afterwards, or alternatively you may want to get a completely random password all the time. The general usage is:

md5pass [password] [salt]

where password is a chosen word that will be used for the construction of the random string and salt is the jump in bytes to be used. Like this:

md5pass word

$1$.MUittVW$j.XDTF1QRnxqFdXRUiSLs0

This will create a "a random sequence" password for you to use. If you use no salt, then you may not be able to recreate this same string afterwards.

However if you use a salt like this:

md5pass word 512

$1$512$.0jcLPQ83jgszaPT8xzds0

then you can create a sequence which you can recover if you use the word in conjunction with the same salt (or jump) if it was originally defined.

landroni
  • 10,906
Joke Sr. OK
  • 903
  • 1
  • 8
  • 11
  • When a salt is being used, this sounds similar to the PasswordMaker approach... – landroni Sep 26 '15 at 08:20
  • -Yes May sound similar to one maker password, but the difference is that it is not a commercial program or anything, because the set of md5 tools, "md5pass, md5sum, md5sum.textutils" dealt with here are concerned and are available the system at no cost some !!! – Joke Sr. OK Sep 26 '15 at 13:17
  • I actually had in mind PasswordMaker, which is also open-source and non-commercial. – landroni Sep 26 '15 at 16:43
  • If you don't have (or like) md5pass, a very similar idea also works with openssl: openssl passwd <BLABLA>, where <BLABLA> is an arbitrary string. This command just generates a hash of that string using the crypt algorithm by default. Old-fashioned, no high security, but for quick-and-dirty applications (like temporary accounts) may be acceptable. – András Aszódi Jan 29 '21 at 16:24
6

These two commands generate random passwords and passphrases, respectively.

shuf --random-source=/dev/urandom --repeat --head-count=20 file_with_characters | tr --delete '\n'

shuf --random-source=/dev/urandom --repeat --head-count=7 file_with_words | tr '\n' ' '

The password generator requires a file_with_characters containing all the characters you want the password to use, one character per line, and exactly one time each. The file must not contain blank lines, and lines must be newline-terminated.

The passphrase generator requires a file_with_words containing all the words you want the passphrase to use, one word per line, and exactly one time each. The file must not contain blank lines, and lines must be newline-terminated.

The --head-count option specifies the length of the password--in characters--or passphrase--in words.

Pablo Repetto
  • 61
  • 1
  • 1
5

I've found that piping /dev/urandom to tr on macOS didn't work. Here's another way:

set="abcdefghijklmonpqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
n=6
rand=""
for i in `seq 1 $n`; do
    char=${set:$RANDOM % ${#set}:1}
    rand+=$char
done
echo $rand
Jake
  • 231
  • Check the last example of my answer. It does not use tr. https://unix.stackexchange.com/a/494931/203075 – Zibri Jan 17 '19 at 11:18
4

I would like to contribute my usual command to generate a password

$ cat /dev/urandom | base64 | head -n 1 |tr -dc '[:alnum:]' |cut -c -13
b0R55751vWW9V

To configure the length of the password, change the number in the cut command to the length that you require, for example, 24 character

$ cat /dev/urandom | base64 | head -n 1 |tr -dc '[:alnum:]' |cut -c -24
WFBhVHuKbrnRhd5kdWXPzmZG

Don't want confusing 0 or O, 1 or l? Filter it out with another tr

$ cat /dev/urandom | base64 | head -n 1 |tr -dc '[:alnum:]' | tr -d '0O1l'|cut -c -24
JuCphwvhrhppD9wVqfpP2beG

I personally never prefer special character in password, that is why I only choose [:alnum:] for my password generator

  • urandombase64 has already been given as an answer. And, in fact, that previous answer also included removing ‘O’, ‘0’, ‘I’, ‘l’ and ‘1’. And why do you need both head and cut? – G-Man Says 'Reinstate Monica' Sep 06 '22 at 20:43
3

pwgen, as everyone else has said, for passwords.

Lowercase only, secure, at least 1 number, 8 characters, 1 result

$ pwgen -snA 8 1
d14o5wgh

Same, but at least 1 uppercase

$ pwgen -csn 8 1
bMxDxcr4

A diceware cli for usernames, and passwords if you want, for something a little more recollection friendly; I use the pip package diceware, which is fine for my needs.

3 words and 2 symbols

$ diceware -n3 -s2
DemandingWhimsical*a1iar

I am sure there are at least 100 more, of which 74% are written in nodejs, because, uh.. well that's what they do. Whichever you do decide upon, I would prioritize built-in upcase/downcase, because you will have those contraints at some point, and performing either of those is annoyingly long in posix shell.

cheers

2

The Unix philosophy of "many small tools that do one thing well" serves you very well in this case.

  • /dev/urandom is a stream of random "bytes" (which include non-printable characters)
  • base64 encodes byte data into [A-Za-z0-9/+] (which is entirely printable)
  • dd copies input to output applying modifiers given as arguments (which can include block size and block count)

OSX

base64     < /dev/urandom | dd bs=1k count=1

Linux

base64 -w0 < /dev/urandom | dd bs=1k count=1

Notes:

  • If you need a subset of the characters, you can insert a modifier in the pipe.
    • Ex: tr -d '[A-Z/+]' to get rid of capital letters and + and /
  • You can set the bs (block size) to whatever length you need.
  • On Linux, base64 wraps to 76 columns by default and must be reset with -w0 unless you want that.
2

I got my way with grep:

grep -ao '[!-~]' < /dev/urandom | head -32 | tr -d '\n' ; echo ""

Without special characters:

grep -ao '[A-Za-z0-9]' < /dev/urandom | head -32 | tr -d '\n' ; echo ""

head defines the length of the string.

1

I maintain secpwgen in Alpine Linux & keep the sources on my Github.

It can produce random strings or diceware phrases:

musl64 [~]$ secpwgen
USAGE: secpwgen <-p[e] | -A[adhsy] | -r | -s[e]> N

PASSPHRASE of N words from Diceware dictionary
  -p    generate passphrase
  -pe   generate enhanced (with symbols) passphrase

SKEY PASSWORD of N words from S/Key dictionary
  -s    generate passphrase
  -se   generate enhanced (with symbols) passphrase

ASCII RANDOM of N elements (at least one option MUST be present)
  -A    Each letter adds the following random elements in output:
    a    alphanumeric characters
    d    decimal digits
    h    hexadecimal digits
    s    special characters
    y    3-4 letter syllables

RAW RANDOM
  -r    output BASE64 encoded string of N random BITS
  -k    output koremutake encoding of N random BITS

To generate a 13 character random string you would use:

musl64 [~]$ secpwgen -Aas 13
----------------
WK5#*V<]M3<CU ;ENTROPY=67.21 bits
----------------
INFO: destroying random number generator.
INFO: zeroing memory.

musl64 [~]$ secpwgen -Aa 13
----------------
GP0FIEBM9Y3BT ;ENTROPY=67.21 bits
----------------
INFO: destroying random number generator.
INFO: zeroing memory.

For users to remember a password use the diceware phrases:

musl64 [~]$ secpwgen -p 5
----------------
wq seen list n8 kerr  ;ENTROPY=65.00 bits
----------------
INFO: destroying random number generator.
INFO: zeroing memory.

I personally like:

musl64 [~]$ secpwgen -r 512
----------------
h62lL7G4gwh3/j9c7YteQvVXoqJrQKKPWVR3Lt7az36DcfWZWtUgBT19iwmJBwP4UahNzPe7qYD7OcklUFpCzQ== ;ENTROPY=512.00 bits
----------------
INFO: destroying random number generator.
INFO: zeroing memory.
1

Only using head y md5sum to generate hex passwords of length 22:

 head -c 2048 /dev/urandom | md5sum | head -c 22 ; echo

Ultra secure? Maybe not. Easy? Yes.

Fjor
  • 187
1

With a short script:

len=20
arr=( {33..126} ) arrcount=${#arr[@]}
for ((i=0; i<len; i++)); do
    printf \\$(printf '%03o' ${arr[RANDOM%arrcount]})
done; echo

If you prefer without specials characters, use:

arr=( {48..57} {65..90} {97..122} )

This is ascii decimal codes ranges, see man ascii

0

My way for a very secure password (where 16 is the pw length):

cat /dev/urandom | tr -cd [:graph:]|head -c 16

Example result:

jT@s_Nx]gH<wL~W}

Or alternatively, to generate multiple passwords:

cat /dev/urandom | tr -cd [:graph:]|fold -w 16|head -6

Example result:

7ck%G7'|f&}_8(]s
<?*]E.CG[NB'gK#A
:tF-WPTOa3!i7S(h
2xy(>=%3=Kb1B$`6
*98Lf{d?Jzb}6q1\
E7uCEAN2Hz]]y|5*

Little less secure (smaller character set):

cat /dev/urandom |base64 -w 0|fold -w 16|head -6

Example result:

rJqYxYZLOTV+A45w
PUKQ+BoBf6yfZw5m
+LRfpsN9CsLRiN8V
yMS6zDpL6NHmG17s
yTUWPG7Rum97schi
cognvjVwaKaAyPRK
Zibri
  • 573
  • 5
  • 9
0

None of the answers so far are truly cross-OS.

The main flaws are represented by the locale definition (MacOS case) and tr being unable to recognize intervals of characters (Solaris case).

You should try shlibs. It's fresh and truly cross-OS. The code to get a random string is shlibs str005 (./shlibs str005).

Get a random string of 50 chars, include puntuation, exclude numbers:

shlibs str005 50 -p -xd
0

This answer is similar to the /dev/urandom method but using openssl rand.

Generate random bytes large enough such that after filtering down to the desired characters, you still meet the required length.

Here, I generate 1000 random bytes for 10 alphanumeric characters a-zA-Z0-9:

LC_ALL=C tr -dc a-zA-Z0-9 < <(openssl rand 1000) | head -c10

Note that the above uses process substitution <(...). If your shell doesn't support it, you can create a temporary file:

openssl rand 1000 > random.tmp
LC_ALL=C tr -dc a-zA-Z0-9 < random.tmp | head -c10
remykarem
  • 101
  • 2
0

A simple Bash script based on answer by @Gilles Quénot.

Example:


chmod +x './rand_string.sh';

Generate 1 string of length 64.

./rand_string.sh;

Generate 1 string of length 32.

./rand_string.sh 32;

Generate 4 strings of length 25.

./rand_string.sh 25 4;

Script ("rand_string.sh")


#! /usr/bin/env bash

set -eu;

Constants

----------------------------------------------------------------

declare -r _chars=( {48..57} # 0-9 {65..90} # A-Z {97..122} # a-z

{33..47} # !"#$%&'()*+,-./

{58..64} # :;<=>?@

{91..96} # []^_`

{123..126} # {|}~

);

declare -r _lengthDefault=64; declare -r _countDefault=1;

Functions

----------------------------------------------------------------

Main_generateString() { # Options

declare length=&quot;$1&quot;;
shift || true;

# Main

declare charCount=&quot;${#_chars[@]}&quot;;
declare i;

for (( i=0; i &lt; length; i++ ));
do
    declare charHex; charHex=&quot;$( printf -- '%x' &quot;${_chars[RANDOM%charCount]}&quot;; )&quot;;
    printf -- &quot;\\x${charHex}&quot;;
done;

}

Main

----------------------------------------------------------------

main() { # Options

declare length=&quot;${1:-$_lengthDefault}&quot;;
shift || true;
declare count=&quot;${1:-$_countDefault}&quot;;
shift || true;

# Main

declare i;

for (( i=0; i &lt; count; i++ ));
do
    Main_generateString &quot;$length&quot;;
    printf -- '\n';
done;

}

main "$@";

Artfaith
  • 474
-1

For lengths between 1 and 32, you can use uuidgen from libuuid or util-linux, simply replacing <LENGTH> below:

uuidgen -r | tr -d '-' | head -c <LENGTH>

or

random=$(uuidgen -r | tr -d '-') && echo "${random:0:<LENGTH>}"

Note: 6–7 of 128 bits are pre-determined and fixed.

caw
  • 21
  • 9