No, it's not entirely secure. Let's look at each of the commands:
dd if=/dev/urandom bs=256 count=1 2> /dev/null
This will read a single 256 byte block from /dev/urandom
, a cryptographically secure random source. The problem starts here, and is related to this 256 byte limit. In fact, you do not even need to use dd
here. The next command is perfectly able to read from a block device on its own.
LC_ALL=C tr -dc 'A-Za-z0-9'
This command strips out all characters that are not alphanumeric. The LC_ALL=C
limits the charset to plain ASCII, where [:alnum:]
will match 62 characters. Symbols and unprintable characters will be removed. The issue now is that only 256 bytes are given to this command, so what if too few of those bytes are alphanumeric? The tr
command will happily take 256 bytes of input and spit out only a couple bytes of output if only a couple bytes match the filter.
head -c20
This command simply truncates the output to 20 bytes. The actual output will vary between 0 and 20 characters.* Statistically, it is most likely for it to output the entire 20 characters each time.
A superior way to get random alphanumeric characters can be done with fewer commands. This will have tr
read as much data from /dev/urandom
as it needs, continuously spitting out alphanumeric ASCII to the next command. As soon as head
has the 20 bytes it has asked for, it will close the pipe, causing tr
to stop reading random data and exit. This is what you should use:
LC_ALL=C tr -dc '[:alnum:]' < /dev/urandom | head -c20
This will guarantee 20 random characters, with an equivalent strength of log2(6220) ≈ 119.1 bits.
You can also turn this into a shell script function to make password generation from command line easier. This particular function takes the number of characters for the password as an argument. If no argument is specified, it defaults to 20 characters:
newpass() {
LC_ALL=C tr -dc '[:alnum:]' < /dev/urandom | head -c${1:-20}
}
* The risk is largely theoretical. Each byte has a (256 - 62) / 256 chance (about 76%) of not being alphanumeric. The probability that at least 256 - 20 bytes are not alphanumeric is very low, but non-zero: (194 / 256)236 ≈ 3.8 × 10-28.