Have you ever needed, say, an astonishing number of user names and passwords? I recently did and thought to myself: "I can automate that!"
But, first of all...
What kind of user names and passwords are we talking about?
Some tools use them a lot, especially for anonymous users: Positive adjectives together with animal names. For example: "Knowledgeable ibex" or... See, it's quite hard to come up with those, especially if English isn't your first language. I was thinking for a good 5 minutes and the ibex was the only example I could come up with. To be fair, I haven't had a coffee yet... I'm getting off topic. Where was I? Anyways, you get the idea: "Positive adjective + animal". Such user names can be used as testing data, anonymous users or basically any use case where a lot of unique user names are necessary.
The password should ideally be something random, too. 16 characters, including numbers, uppercase and lowercase letters, and some special characters like !._-,;?^$+"*%&/()=
.
Getting the data
So, let's first gather some data. I need animals and positive adjectives. I found a pretty large list of animals over at a-z-animals.com and a large list of positive adjectives at grammar.yourdictionary.com. Perfect. I create two lists, separated by newlines and put them in two files, namely animals.txt
and adjectives.txt
. So far so good, that's all the data I need, the rest is done with Bash.
Mapping a file using mapfile
Since Bash 4.0 there's a neat command called mapfile
that reads a file line by line and creates an array out of it. I use this to read out all adjectives and animals:
#!/bin/bash
mapfile ADJECTIVES < ./adjectives.txt
mapfile ANIMALS < ./animals.txt
Generating the usernames
To generate a large number of user names, I could now randomly select one of each and concatenate them:
#!/bin/bash
mapfile ADJECTIVES < ./adjectives.txt
mapfile ANIMALS < ./animals.txt
RANDOM_ADJECTIVE=$(echo ${ADJECTIVES[$RANDOM % ${#ADJECTIVES[@]} ]})
RANDOM_ANIMAL=$(echo ${ANIMALS[$RANDOM % ${#ANIMALS[@]} ]})
I'm using $RANDOM
here to generate a random number. This random number mod the size of the list guarantees to create a random number that is one of the array indices of that list. with ${LIST[...]}
I then get the randomly chosen element.
Next, I concatenate them and massage the string a bit:
# ...
RANDOM_ADJECTIVE=$(echo ${ADJECTIVES[$RANDOM % ${#ADJECTIVES[@]} ]})
RANDOM_ANIMAL=$(echo ${ANIMALS[$RANDOM % ${#ANIMALS[@]} ]})
# Concat
ADJECTIVE_ANIMAL=$(echo $RANDOM_ADJECTIVE-$RANDOM_ANIMAL)
# Make it machine readable
MACHINEREADABLE=$(echo $ADJECTIVE_ANIMAL | iconv -t ascii//TRANSLIT | sed -r s/[^a-zA-Z0-9]+/-/g | tr A-Z a-z)
First, all characters that are not ASCII are transliterated as such using iconv
, for example äàá
should all become a
. Then I replace all non-alphanumeric characters with -
using sed -r
. In the last step, I transform the string to lower case using tr
.
This now produces things like these:
fantastic-poodle
giving-dalmadoodle
glowing-sheepadoodle
focused-pointer
articulate-fly
glittering-stag-beetle
articulate-leopard-frog
unique-estrela-mountain-dog
excellent-russell-terrier
splendid-echidna
brilliant-italian-greyhound
magnificent-barnacle
polite-saint-bernard
glittering-eastern-bluebird
imaginative-manta-ray
willing-doberman-pinscher
faithful-drever
Gotta love the fantastic poodle
!
Generating the password
Now for the fun part: Generating a decent password. I rely on the OS here by using /dev/urandom
:
# ...
PASSWORD=$(cat /dev/urandom | tr -cd '[:graph:]' | fold -w 24 | head -n 1)
So a random bit string is read from /dev/urandom
, which is then transformed into a string containing all printable characters (using [:graph:]
). The string is then folded into words with 24 characters length. The first one of these words is then selected with head -n 1
. This produces passwords like these:
Lb6UR+-iF5xj5`q}g1t(d3Dn
W]Aai"t,<H:)M[QV$lJi~H.%
V~2=Jq2InaGAU^Y\Uzx^9500
+XuY\[7-]g<[FyYKpE+"G[r7
=LYmTQ$D"}MN5]wC{$;ySE.}
jsE:y+A)NV{0CHvO-D)wazx*
2TB1~~Q~8d<_'Zj)ED$1yQ8\
!=bV.w0ko0F/Y"98M`ZzS1'%
IVmd4XfNR3'iffVUuwJ"[_IT
CR,Iq`},c5X7JdFfF7b@bi3!
:{y%'0%M~ys1lhR=$d,xNE"%
D*0AJikOKcBUo&6hku]g<(ZC
fQK'%R8("+*/o;.Vfd<7;/"W
Looks pretty secure to me. Let's test =LYmTQ$D"}MN5]wC{$;ySE.}
with some "password security testing tools" that a popular search engine is suggesting.
Ok, those numbers are dizzying, but differ widely. Here's a checker that actually tells you how they calculate the strength of a password:
Sounds good to me. For a one time login/password, that should be more than enough.
The final script
I also added a loop around the thing to generate multiple usernames and passwords.
#!/bin/bash
mapfile ANIMALS < ./animals.txt
mapfile ADJECTIVES < ./adjectives.txt
for ((N=0; N<$1; N++))
do
RANDOM_ADJECTIVE=$(echo ${ADJECTIVES[$RANDOM % ${#ADJECTIVES[@]} ]})
RANDOM_ANIMAL=$(echo ${ANIMALS[$RANDOM % ${#ANIMALS[@]} ]})
ADJECTIVE_ANIMAL=$(echo $RANDOM_ADJECTIVE-$RANDOM_ANIMAL)
MACHINEREADABLE=$(echo $ADJECTIVE_ANIMAL | iconv -t ascii//TRANSLIT | sed -r s/[^a-zA-Z0-9]+/-/g | tr A-Z a-z)
PASSWORD=$(cat /dev/urandom | tr -cd '[:graph:]' | fold -w 24 | head -n 1)
echo $MACHINEREADABLE $PASSWORD
done
The first parameter of the script now determines the number of user name/password pairs generated:
user@dir $ ./create-users.sh 10
amazing-carp ACytS~_(Z+|<4fi}V<Mjy*g~
splendid-glen-of-imaal-terrier \#AK@]m[7R*>hzuOO^%r1ZY@
capable-blue-lacy-dog ?;CnSkJW's.<|PN:wQDOikI/
considerate-eastern-lowland-gorilla zQxT`]miaE4m$*W`Z8tpa@N5
powerful-puffin Kh=SUqh<no18.[A$Fea+LLXg
philosophical-bernese-shepherd 1h),NV(hi<vG)~{A]x^2I?bH
hardworking-american-foxhound \pbzUC~*~VLk}$wy6dHWFcw(
amazing-canadian-eskimo-dog -x{8PIwiI$/NcZ5#}'$Wlod-
responsible-umbrellabird eDzW\1H/U/(L_fHS^(U&:ltd
agreeable-termite |Kcgx-go>$7`:}nn7-\P&"}b
Amazing! Only need to copy/paste that now.
Whats your favorite positive-adjective + animal username you could generate? Leave a comment!
I hope you enjoyed reading this article as much as I enjoyed writing it! If so, leave a ❤️ or a 🦄! I write tech articles in my free time and like to drink coffee every once in a while.
If you want to support my efforts, buy me a coffee ☕ or follow me on Twitter 🐦! You can also support me directly via Paypal!
Top comments (6)
This is very interesting to me. I've created an app which allows you to draw your password. It generates a SHA-256 based password and it remembers the site's password requirements (add an uppercase, add a special char, max length).
I wrote it as FOSS (Fully Open Source Software - get all source at GitHub) using ElectronJS so it runs on all platforms (Windows, Mac, Linux).
You can even get the app directly from the Win10 store : microsoft.com/en-us/p/cyapass/9pfd...
And you can also get it (For Linux distros) in the snap store: snapcraft.io/cyapass
check it out and see what you think.
If you're wondering about the details of how it works, check out my LinkedIn article.
That's a really interesting tool, will definitely check that out :) How does the generation out of the pattern work?
Every pattern you create generates a mathematical value -- based upon the line segments that are drawn. that mathematical value is used to salt your SiteKey value. Together the two values are used to generate a unique SHA-256 hash + any password requirements (add uppercase, add special char(s), maxlength).
Also, if you draw a pattern that has four segments, no matter which order you draw them in will generate the same mathematical value. That way if you draw a pattern in one order then later in another order you get the same mathematical value for the salt value. Thanks for asking
Very cool! I wonder if you could somehow extend this to store the passwords securely in Bash and retrieve them with a passcode, sort of like Chrome does. That might be involved, though. You'd probably need to encrypt and decrypt them to store them safely.
Glad you liked it! Encrypting them sounds like a good idea indeed. GPG sounds like the right tool for that, according to a tutorial on techrepublic it can be used to encrypt and decrypt files. Theoretically, executing something like
./create-users.sh 10 > usernames.txt && gpg -c usernames.txt
would achieve that. Having that in the script itself would be a lot more convenient, of course!