To manage the huge amount of my website logins, I wrote a bash script which takes
A string which, for me personally, identifies a certain account. Examples are [email protected]
or thisWebsiteIVistedLately
, but it can be possibly anything. It does not have to follow a certain pattern, it just should help me distinguish between different accounts I want to manage.
A master password.
The output is a combination of a username and a secure password for the account. I do not want to store any of the generated usernames/passwords, nor the master password. Therefore, similar to Honey Encryption, I want the script to generate a reasonable result for each input. If a bad guy entered a wrong master password, he would just get a different username/password combination, undistinguishable of the "real" one.
Here is the bash script I have come up with so far:
#!/bin/bash
# robust bash scripting
set -o errexit
set -o nounset
set -o pipefail
# external programs
OPENSSL=$(which openssl)
SED=$(which sed)
CUT=$(which cut)
# get identifier
read -s -p "id = " ID
echo ""
# read password
read -s -p "pw = " PW
echo ""
# generate username
printf "%s" "$ID" | { printf "%s" "$PW" | "$OPENSSL" enc -e -aes-256-cbc -pass stdin -salt -S "0000000000000000" -in /dev/fd/3; } 3<&0 | "$OPENSSL" dgst -sha512 -binary | "$OPENSSL" enc -base64 -A | "$SED" 's/[^a-zA-Z]//g' | "$CUT" -c -8
# generate password
printf "%s" "$ID" | { printf "%s" "$PW" | "$OPENSSL" enc -e -aes-256-cbc -pass stdin -salt -S "1111111111111111" -in /dev/fd/3; } 3<&0 | "$OPENSSL" dgst -sha512 -binary | "$OPENSSL" enc -base64 -A | "$CUT" -b -32
As you can see, username and password are generated by
Encrypting the identifier string with the given master password using AES,
hashing the result using SHA,
performing a base64 conversion, and
sed
ing and cut
ing the output to reasonable formats for a username and password.
I tried to make any aspect as secure as possible. For identifier and password input, the bash
internal read
is used. Also, when the password is piped to openssl
, the bash
internal printf
is used. Obviously, the used salts are just placeholders. In the final stage, these should be replaced by anyone using the script.
Here is an example (assuming that above script was saved as myscript.sh
:
$ ./myscript.sh
$ id = [email protected]
$ pw = 12345
$ CbAMaZar
$ XFTD9VRwQxFbU4tHKuiJvy5c18oJaDbg
The last two lines specify the generated username and password.
Now, assume someone knows anything about me, except for the master password (Kerckhoffs's principle). Here comes the bad guy:
$ ./myscript.sh
$ id = [email protected]
$ pw = 23456
$ MNLManDN
$ pczRREIy9+ag/0Y7jauAWpm5sllh5sjg
To check if this is correct, he would have to actually try the generated login.
Now, my question is how the security of this script can be improved (in terms of cryptography as well as bash scripting). Of course, if the bad guy has root access or knows the master password, all is lost. This is why I do not plan to manage important accounts using this approach.
But if someone knows my correct username and password for an account (e.g. via SQL injection), there should be no (realistic) way to find my master password or any other account username/password combinations. Also, it should be impossible for any non-root user on the system to find out the generated username/password pairs or my master password.
So, to all security, cryptography, and programming gurus of SO: are there any security issues in the script above or can it be considered "safe"?
I've been using a very similar scheme for my usernames/passwords. It has worked very well for me so far.
The first thing I'd say is to start with a standard cryptographic hashing algorithm. As far as I can tell for this application there is no real need to combine with encryption, you just need to get an output that is non-reversable back to your initial password. Use something standard and secure (not md5) and be sure that your key is complex enough to avoid any chance of one of your passwords showing up in a standard lookup table.
I just use something like MyHash(key + sitename)... You could make it more secure by encrypting/calculating something off the sitename and addign it back in as salt, however, I personally think this is overkill for this application... Not a security expert though - and it really depends on what you are using it for. You end up balancing ease of use with security - and I can say from experience that you want an algorithm that you can recreate if you have to.
A few things I've learned from using this for a few years-
A lot of sites like to enforce a maximum password length, I hate these sites and all they represent. I've been forced to truncate my base64 encoded result to 19 characters to standardize things so I don't have to remember my password + the arbitrary number of characters they truncate to.
Use something standard so you can reproduce your passwords when away from your computer.
Sometimes this scheme will randomly result in a password that is all letters and despite being better than 99.9% of passwords out there will be declared weak/unsuitable by the site you are using. Not too much you can do about this - I just add a number/increment until it stops complaining.
I use a standard username so my scheme differs from yours a bit, but hopefully the general idea here can be of use.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With