DEV Community

Cover image for How to generate thousands of usernames and halfway decent passwords with Bash💯💯
Pascal Thormeier
Pascal Thormeier

Posted on

How to generate thousands of usernames and halfway decent passwords with Bash💯💯

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
Enter fullscreen mode Exit fullscreen mode

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[@]} ]})
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

Password strength checker number 1

Password strength checker number 2

Password strength checker number 3

Ok, those numbers are dizzying, but differ widely. Here's a checker that actually tells you how they calculate the strength of a password:

A verbose password strength checker

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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!

Buy me a coffee button

Top comments (6)

Collapse
 
raddevus profile image
raddevus • Edited

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).
https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rupsl8v12d4bdrz0tbk8.jpg
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.

Collapse
 
thormeier profile image
Pascal Thormeier

That's a really interesting tool, will definitely check that out :) How does the generation out of the pattern work?

Collapse
 
raddevus profile image
raddevus • Edited

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

Collapse
 
aleksandrhovhannisyan profile image
Aleksandr Hovhannisyan

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.

Collapse
 
thormeier profile image
Pascal Thormeier

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!

Collapse
 
Sloan, the sloth mascot
Comment deleted