|
|
||||
Generate passwords from the commandline
I needed to generate a random password from a shell script, I figured that this was solved long ago, so I turned to teh interwebz to quickly copy/paste a working solution.
Inspecting the first few links that turned up, I noticed many of the proposed solutions are dubious at best. The date ain’t random, buddy The most obviously wrong are: Code:
$ date +%s | sha256sum | base64 | head -c32 $ date | md5sum $ ping -c 1 yahoo.com | md5 | head -c8 Both SHA256 & MD5 also output in hex, so that would limit the total amount of characters to just 16, instead of 92. tr means translate characters Most of the other commands suffer from a dubious usage of tr(1) . tr(1) works on characters, not byte streams, /dev/urandom outputs a byte stream, not characters.If your locale is set to (extended) ASCII or a variant thereof (ISO-8859-1, Windows-1252) this is more or less okay, since every byte is a character or escape code. However, with UTF-8 or another multibyte character sets, it gets more complicated. Not every random byte stream is a valid set of UTF-8 characters, the chances of a random byte stream also being a valid UTF-8 character stream is quite small. Yet, it seems to work on Linux with GNU tr. Why? Here’s a clue: Code:
$ echo 'I løv€ π' | tr '[:lower:]' '[:upper:]' I LøV€ π $ echo 'I løv€ π' | tr øπ€ X I lXXvXXX XX The astute reader will have recognized what this means, GNU tr doesn’t handle multibyte characters, and always assumes an ASCII character set, which is somewhat disappointing, since it’s 2014, not 1974. FreeBSD, for example, does this correctly, it also gives an error message on invalid UTF-8 sequences: Code:
$ echo 'I løv€ π' | tr '[:lower:]' '[:upper:]' I LØV€ Π $ echo 'I løv€ π' | tr øπ€ X I lXvX X $ head -c5 /dev/urandom | tr X Y tr: Illegal byte sequence $ setenv LC_CTYPE C $ head -c5 /dev/urandom | tr X Y f��!� Other problems While I’m whining anyway… Code:
$ openssl rand -base64 8 | md5 | head -c8 openssl rand is a good idea, but piping it to md5 isn’t. base64 gives me 64 characters, md5 gives me 16, making the password a lot easier to brute force. Also, 8 characters is too short, use at least 15.Code:
$ curl -s http://sensiblepassword.com/?harder=1
I hope you can finish the scenario from here… Just don’t do this. Ever. Randomly banging on the keyboard is a lot better. Good solutions Code:
$ head -c100 /dev/urandom | strings -n1 | tr -d '[:space:]' | head -c15 $ openssl rand -base64 15 $ gpg2 --armor --gen-random 1 15 Lessons
__________________
UNIX was not designed to stop you from doing stupid things, because that would also stop you from doing clever things. |
|
||||
j65nko wrote somthing similar a few years ago: Generating passwords with jot(1).
jot is that it's something of a BSD-ism, and not available on any other UNIX or Linux... I prefer to avoid it if I can.
__________________
UNIX was not designed to stop you from doing stupid things, because that would also stop you from doing clever things. |
|
||||
Or you can use /dev/[u]random and hexdump(1).
Attached is a simple script I was working on recently to make WPA pre-shared keys or passphrases for wpa_supplicant. It could use a bit more investigation of a gray area, but not sure if I'll get around to it. The basic idea is there and since hexdump is in many unices, it should be very portable. You could use it to make other kinds of passwords, etc. BTW, the passphrase part of this assumes ASCII, so some may want to change that part depending on intended use. The file upload for attachment keeps failing, athough data is transferred. Is it a forum problem or is it me? Here's a link for the time being: randpass.sh.bz2 Last edited by IdOp; 10th February 2014 at 06:27 PM. |
|
||||
I've been thinking. Please bear with me as I try to establish my current understanding.
The urandom pseudo device is not available on every OS, but on those where it is still available I'd thought it was intended for use in transient functions, such as padding bytes or short lifespan keys (such as one might find in PKI for telecommunications). I ask because both of you have apparently made the recommendation. If I assume the quality of OpenSSL PRNG that seeds from /dev/urandom is of equivalent quality to the /dev/urandom stream itself, then $ openssl rand -hex ... produces the same quality of random hex stream as $ dd if=/dev/[u]random ... | hexdump ... I don't know if the PRNG seeded by urandom is of equivalent quality. But I cannot see it being better than urandom itself, and based only on what I know of urandom, I wouldn't recommend it as a base for static keys such as passwords. Have I misunderstood? It's an academic question if the OS doesn't have urandom, of course. Last edited by jggimi; 10th February 2014 at 07:24 PM. |
|
||||
About the differences between /dev/random and /dev/urandom for Linux, there is a good discussion on this man page:
random(4) Quote:
Last edited by IdOp; 10th February 2014 at 08:43 PM. Reason: added (4) |
|
||||
Quote:
/dev/random should to produce either a quality stream, or no output at all. From random(4): Code:
The kern.random.sys.seeded variable indicates whether or not the random device is in an acceptably secure state as a result of reseeding. If set to 0, the device will block (on read) until the next reseed (which can be from an explicit write, or as a result of entropy harvesting). A reseed will set the value to 1 (non-blocking). Quote:
Assuming that /dev/urandom isn't of spectacular low quality (which it doesn't seem to be), I don't think this has to be a problem, necessarily. Remember, we not generating keys for use in a stream cipher 100 times/minute, where even a small problem in your PRNG would indeed be a major problem. What we're doing is occasionally generate a short password, often with large time intervals (days, weeks) in between two runs. - An adversary needs n bits of output first to predict anything. Passwords (15 bytes in my example) generally aren't long enough to provide this output. My proposed solution even discards some output (not a security feature as such, obviously). - You're not generating a lot of passwords, and the passwords you generate have a lot of time in between them. So if an advisory has somehow managed to get 200 of yours passwords, it's extremely unlikely anything useful can be learned about a potential 201st password. - Even if an adversary examined all output of your PRNG, it needs to be *very* broken if you can learn enough to learn a 120 bit password to be truly useful. - If the output wouldn't be uniform, you'd still get a fairly good pseudo-random password, unless, of course, your PRNG starts outputing 80% 0's or something ... A system is only as strong as the weakest link, and there are quite a few weaker links I would worry about, such as: - Passwords getting stolen (many examples of this), and re-used on other accounts. Obviously easily preventable by using an unique password for every service. - Passwords not being stored securely, for as plaintext on the server, or as plaintext on your computer (such as your browser's cookie. Yes, people do this, often without the httponly flag set, meaning is ludicrously easy to steal it). - (Hardware) keyloggers (I wouldn't know how to protect against this, I've seen people glue USB ports, but I don't consider that to be truly secure. You would somehow need to tamper-proof your computer's connections, your keyboard, and the cable). - Various social engineering attacks (as described here, many other examples to be found). - Shoulder surfing (through eyeballs, or camera's). Open questions - How likely is it that /dev/random is unable to generate high quality randomness, and will block? - How low is the quality of /dev/urandom, exactly? - What is the best cross-platform, random source? /dev/{a,u}random isn't defined by any standard. POSIX only offers random(), which isn't considered secure.
__________________
UNIX was not designed to stop you from doing stupid things, because that would also stop you from doing clever things. |
|
||||
From the OpenBSD man page random(4):
Quote:
About the chance of /dev/random of blocking, I guess you could experiment a bit and see what happens on a given system. For a single-user system, at least there will be no other users purposely or accidentally draining the entropy pool, but there may be less entropy being collected too? I've had varied results with blocking on different systems and OSes. I'm not sure I can say anything definitive though. |
|
||||
Quote:
Quote:
|
|
||||
Quote:
Code:
$ ls -l /dev/*random crw-r--r-- 1 root wheel 45, 3 Jan 15 05:12 /dev/arandom crw-r--r-- 1 root wheel 45, 0 Jan 14 04:03 /dev/random crw-r--r-- 1 root wheel 45, 1 Jan 14 04:03 /dev/srandom crw-r--r-- 1 root wheel 45, 2 Jan 14 04:03 /dev/urandom |
|
||||
Looking at the patch, it seems to me that all devices use the same arc4random(3) PRNG.
|
|
|||
I use something similar to Carpetsmoker's first "good" option; OpenBSD's head, however, doesn't have the "-c" option; here's my hackish password generator (characters allowed are alphanumerics, underscore, and dash):
Code:
< /dev/urandom strings -n1 | tr -dc _A-Z-a-z-0-9 | dd count=1 bs=16 2>/dev/null;echo Comments appreciated since I am far from adept at the command line. |
|
||||
I'd like to subject the WPA passphrase part of my script to some needed criticism , as I realized it has a certain weakness, that I think is worth explaining.
The basic idea is that each input byte from /dev/[u]random, thought of as an integer in the domain {0, 1, ..., 255} is scaled into the desired output set { ASCII 32, ..., ASCII 126 }, which is a set of 95 values. (Actually, there is one less because I weed out the double quote " but let's ignore that, it just complicates the discussion.) The scaling idea was appealing to me, but since we're working with discrete sets, not real numbers, there can be problems. So basically there's a map from 256 values into 95 values. If you think of such maps generally, many of them would be very bad. E.g., if the map was a constant, it would always give the same output, which wouldn't be random at all! The scaling map I used isn't nearly that bad; it does map onto the whole desired output range, in a many-to-one way. The problem is that the "many" is not the same for each output value though. For example the map starts off like this: Code:
input output byte ASCII 0 32 1 32 2 32 3 33 4 33 5 33 6 34 7 34 8 34 9 35 10 35 11 36 12 36 13 36 ... 1 output has a single pre-image, 27 outputs have two pre-images, 67 outputs have three pre-images. Note: 1 + 27 + 67 = 95 and 1*1 + 27*2 + 67*3 = 256. What this means is that even if the inputs from /dev/[u]random are uniformly probable, the outputs are not. E.g., an output of ASCII 32 is 1.5 times as likely to occur as ASCII 35. I don't think there is a way around this kind of problem if you want to keep all the inputs, because 95 just doesn't divide evenly into 256. You could get around it by throwing out some of the inputs so that the range is uniformly covered, say 2-to-1 everywhere. But this would have the cost of reading more bytes from /dev/[u]random, and in principle the process might never finish! An alternative would be to restrict the size of the output set so it divides evenly into 256 (say, 64), and choose a map that covers it uniformly. But a smaller output set is a drawback too. So, all in all, I think there are several reasons to prefer the WPA pre-shared key (PSK) method, which as far as I can see is done very cleanly by my script (criticisms also welcome!). They are: 1) Passphrase has the above problem (in my script). (Though perhaps I'm making a mountain out of a molehill?) 2) Passphrase is at most 63 characters anyway, which doesn't seem to contain as much randomness as a 64-byte PSK chosen with each byte totally random. The passphrase, if used, is mixed with the ESSID to create a PSK, but this probably doesn't help since the ESSID is public knowledge. 3) A good passphrase should be long, contain characters from a large set, and be very random. This means you won't be able to remember it! If you can't remember the passphrase, you might as well use a random PSK (which you can't remember either), since it's better. Either way you'll have to cut-and-paste it into your wireless setups. Comments etc. also very welcome. Last edited by IdOp; 11th February 2014 at 11:51 PM. Reason: spelling, and molehill |
|
||||
Interesting thread!
Quote:
After a couple of failed attempts, I think I found something that works. Change the pipeline to this: Code:
< /dev/urandom tee file.tmp | strings -n1 | tr -dc _A-Z-a-z-0-9 | dd count=1 bs=16 2>/dev/null;echo Linux: 49152 OpenBSD: 196608 If this is showing what it seems, that's a lot of data to be reading from /dev/urandom just to get 16 password char's. If entropy is a valuable resource, this could deplete it. Also a comment and question about Carpetsmoker's suggestion: Quote:
Another thing that occurred to me. As I understand it UTF-8 characters can be encoded in 1, 2, 3, ... several bytes. Intuitively it seems to me that this means there will be a strongly non-uniform distribution of UTF-8 characters coming out of /dev/urandom. Consider a two-byte sample from /dev/urandom. A given 1-byte UTF-8 character would be found in this sample with probability 2/256 =1/128 (approximately, ignoring a repeat), since it can be in either byte. But a given 2-byte UTF-8 character will be found only with probability (1/256)^2. Similarly one can consider longer UTF-8 chars. So a question: When you use this method in a UTF-8 environment, do you find that the 2-byte characters (and longer) are indeed seen extremely rarely in the password? I am thinking if one could effectively turn the /dev/urandom output into some kind of pointer into a table of password characters, it might help with some of these problems. |
|
|||
Quote:
Code:
< /dev/urandom strings -n1 | tee file.tmp | tr -dc _A-Z-a-z-0-9 | dd count=1 bs=16 2>/dev/null;echo Anyways, I'm now just taking 500 out of /dev/random which gives me a final file that's ~100 characters on linux, plenty of wiggle room and 500 isn't that bad a pull: Code:
dd if=/dev/urandom count=1 bs=500 2>/dev/null | strings -n1 | tee file.tmp | tr -dc _A-Z-a-z-0-9 | tee file.tmpp | dd count=1 bs=16 2>/dev/null;echo Last edited by Alphalutra1; 15th February 2014 at 10:02 PM. |
|
|
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Generating passwords with jot(1) | J65nko | Guides | 9 | 29th August 2014 01:03 PM |
Security LinkedIn passwords in circulation | J65nko | News | 1 | 8th June 2012 04:49 AM |
Experts: We're stuck with passwords – and maybe they're best | J65nko | News | 1 | 17th January 2012 03:08 AM |
Passwords | zhorik | OpenBSD General | 5 | 14th January 2011 12:51 AM |
Generate xorg.conf.new and black screen | aleunix | OpenBSD Packages and Ports | 2 | 4th June 2008 10:49 AM |