Let’s say you want unique passwords for every website you use. But you don’t want to memorize all of them. Yeah, you should use a password manager. Yet, it’s always fun to build your own and learn the basics of how these things work.
That’s where my password generator comes in.
Here are the specs:
- It takes in the address of a website
- And a couple of secret words from you
- Then mashes these things together and runs it all through a predictable encryption algorithm
- The result is a unique combination of characters and numbers that you use as a password
- For every address, the password will be unique, but it won’t be random.
Every time you generate a password for a specific address, you’ll get the same password. That way, if you forget your password, you can re-generate it, and it will fit.
A word of warning. This algorithm is not cryptographically secure. If someone knows your secret word from step 2, they will be able to recreate your password. So it would be unwise to use these passwords in mission-critical and sensitive areas. But it’s still worth trying to develop.
MD5 Hashing
At the heart of our algorithm will be the MD5 hashing engine (you see it in step 3). Hashing is an algorithm that turns text into a string of 32 characters, a kind of a digital fingerprint.
For example, if you encode google.com, you’ll always get the hash 1d5920f4b44b27a802bd77c4f0536f5a
.
And if your string is https://google.com, your hash is always 99999ebcfdb78df077ad2727fd00969f
.
Here is what’s important to know
The hash (or the digital fingerprint) cannot be reverse engineered to reveal the original string (at least, not easily and not directly).
Encoding the same string with MD5 will always create the same hash.
So if you have a collection of possible source texts and a target hash that you want to decrypt, you can just make hashes from the source texts and compare it to the target hash. That’s a common way to crack leaked password databases.
The algorithm is widely known and well-studied.
No cryptography is unbreakable. MD5 hashing is not 100% secure. Nothing in life really is.
One of the common methods to make MD5 more secure is adding salt. Salt is some secret word or character that is added to your encrypted string and that nobody knows about. With salt, reverse-matching pre-hashed passwords becomes much harder.
Here is an example
Say, you wanted to hash the string ‘mail.google.com’. This string would always give you the hash be5cab0695415d9363d18ad1345c73eb
. A hacker intercepts this password without knowing where this password came from and what it means. But he wants to find out. He makes a table of possible strings, hashes them and matches the resulting hashes against your hash:
But what if your original string was ‘mail.google.comJacko’, where would ‘Jacko’ be the salt? In that case, your hash will be 397ea03e8e23b5b0127dffc6db629eab
, and unless the hacker somehow guessed your salt, he’d be unable to reverse-match this hash.
So it all comes down to the hacker’s knowing what your salt is and where you put it.
The interface
I’ll start with some basic interface. Create a text document in Notepad, paste this and save as HTML. If you have little understanding of what’s going on, read the comments inside:
<html>
<!-- service area -->
<head>
<title>Password generator</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- next line loads the MD5 hashing function -->
<script src="https://thecode.media/wp-content/uploads/2019/05/js-md5.js"></script>
<style type="text/css">
/*Adding some basic design*/
body{ text-align: center; margin: 10;
font-family: Verdana, Arial, sans-serif;
font-size: 16px;}
input{ display: inline-block; margin: 20px auto;
border: 2px solid #eee; padding: 10px 20px;
font-family:Verdana, Arial, sans-serif;
font-size: 16px;}
</style>
</head>
<body>
<!-- Our page will be here -->
<div class="container" "margin: auto;">
<h2 class="todo__caption">Password generator</h2>
<br>
<!-- Interface begins -->
<input type="text" id="site_url" size="50" placeholder="Where do you need this password? Paste the address">
<br>
<input type="text" id="keyword" size="50" placeholder="Some key word here">
<br> <br>
<!-- Main button -->
<button style="font-size: 100%; padding:5px 10px 10px 10px" onclick="generate()">Generate password</button>
<p>Your password is:</p>
<div id = "pass_text" style="font-weight: bold"></div>
</div>
<script>
<!-- Your main script -->
</script>
</body>
</html>
If you save this text as a .html file and open it in Chrome or other browser, you’ll get something like this. It looks nice, but it won’t work just yet:
Next, I’ll write a script that will run in browser and make sure all the encryption magic happens. Follow the steps:
Step 0: Housekeeping
I want to keep our code clean, so I’ll start with declaring some variables and setting up a function that will later be triggered by a button. This code won’t do anything yet, but I need it for proper running of the actually useful code. All this goes inside the block at the end of the previous document:
// setting up variables
var site, salt;
var text, password;
// The function to run all the useful code
function generate(){
// Some useful code
}
Step 1. Take the address from the site
I am writing in Javascript, which runs in the browser and has direct access to everything that’s going on in your web page. On the page, I have some input fields. Reading from these fields is a matter of one line:
site = document.getElementById('site_url').value;
Notice the site_url thing? That’s the ID of the input field. This command real like this: ‘Find whatever object on the page that has an ID ‘site_url’, look at its value, and pass whatever is in there into the variable called ‘site’, which I declared earlier.
This line goes under the comment ‘Some useful code’.
Step 2. Take the secret word
Same way, I read the secret word:
salt = document.getElementById('keyword').value;
This line goes under the previous line.
Step 3. Mash them together
Now I need to combine what is in ‘site’ and in ‘salt’. I can also add a little extra something for more saltiness. In Javascript, connecting two bits of text is done by simply adding:
text = site + salt + 'Practicum Rules';
Our ‘text’ variable will now have a combination of what is written in two input blocks on the page, and the secret word ‘Practicum Rules’. It’s not really protecting our algorithm since it’s hard-coded into the page and therefore, can be read by whoever looks into the source code of this generator. But it’s fun nevertheless.
Step 4. Encrypt them
I loaded the MD5 script earlier, so now all I have to do is use it:
password = md5(text);
This line reads: take the function called md5 and give it whatever is in the ‘text’ variable. What it spits out, put it into the ‘password’ variable.
Step 5. Output password
With JavaScript, outputting into the page is easy:
document.getElementById('pass_text').innerHTML=password;
This means: in the document, find an element with id ‘pass_text’, and put into its inner HTML whatever is in variable ‘password’. And I know I just put the encoded password there, so I’ll see the encoded result on the page.
Running the code
Now I need to make sure that all the useful code goes inside the function called ‘generate’, and I have this function mapped to our button on the page. Which I have, look at the bold part:
<button style="font-size: 100%; padding:5px 10px 10px 10px" onclick="generate()">Generate password</button>
Here is the final code
<html>
<!-- service area -->
<head>
<title>Password generator</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- next line loads the MD5 hashing function -->
<script src="https://thecode.media/wp-content/uploads/2019/05/js-md5.js"></script>
<style type="text/css">
/*This will be some basic design*/
body{ text-align: center; margin: 10; font-family: Verdana, Arial, sans-serif; font-size: 16px;}
input{ display: inline-block;
margin: 20px auto; border: 2px solid #eee;
padding: 10px 20px;
font-family:Verdana, Arial, sans-serif;
font-size: 16px;}
</style>
</head>
<body>
<!-- Our page will be here -->
<div class="container" margin: auto;">
<h2 class="todo__caption">Password generator</h2>
<br>
<!-- interface begins -->
<input type="text" id="site_url" size="50" placeholder="Where do you need this password? Paste the address">
<br>
<input type="text" id="keyword" size="50" placeholder="Some key word here">
<br> <br>
<!-- Main button -->
<button style="font-size: 100%; padding:5px 10px 10px 10px" onclick="generate()">Generate password</button>
<p>Your password is:</p>
<div id = "pass_text" style="font-weight: bold"></div>
</div>
<script>
// setting up variables
var site, salt;
var text, password;
// The function to run all the useful code
function generate(){
//Step 1
site = document.getElementById('site_url').value;
//Step 2
salt = document.getElementById('keyword').value;
//Step 3
text = site + salt + 'Practicum Rules';
//Step 4
password = md5(text);
//Step 5
document.getElementById('pass_text').innerHTML=password;
}
</script>
</body>
</html>
Save it, load it, type in your secret word and the site URL, and press Generate. Yay, you got yourself a password generator. Congrats!
What can be done next:
You can make the encryption fancier by running the md5 algorithm many times.
You can work with upper- and lowercase letters and add extra characters to the generated password.
You can shorten the password to 9-12 characters to make it more manageable.
If you want to learn more things like this, check out our course in Web Development on Practicum. It has 20 hours of free lessons 🚀 Also I'm always looking for beta testers, so shoot me an email if you're interested!
Top comments (3)
Neat idea, but there's a couple problems.
Don't use MD5. If you're in the position of creating a new application, there's no reason to use it and about a dozen reasons not to. If a 256-bit hash is too long, crop it. Your quote,
"[MD5] is widely known and well-studied"
should have ended with "and MD5 is universally considered broken; not a single entity suggests using it.""Salt is some secret word or character that is added to your encrypted string and that nobody knows about. With salt, reverse-matching pre-hashed passwords becomes much harder."
That's not what a salt is. Salts are by definition public and only protect from pre-computed rainbow tables run against an entire database - salts do not, nor are intended to, protect a single user. What you're doing with your "salt" is actually just stretching the password.If a malicious user does get your generated password, if he or she knows you used this method, your real password will be compromised possibly within seconds. This therefore really just relies on security through obscurity - the more people that see and implement this article, the less secure using it will be.
Suggestions for the application:
Use a cryptographically secure hashing algorithm instead of MD5, like Argon2 or at least a SHA-2 variant. A user won't see the difference between a 0.000001ms hash function and a 100ms hash function, but attackers will. If you don't want to switch algorithms, at least re-hash the result 1,000,000 times or more. Your users likely won't see a difference because MD5 is that easy to hash; GPUs from a decade ago can do 10 million or more MD5 hashes a second.
Don't bother with a "salt". In this case it's relying on security through obscurity. Instead do key stretching or simply require users to supply a long password.
Suggestions for the user:
There's a difference between rolling your own crypto (what this article advocates) and hosting your password manager on your own computer rather than on the cloud. Take the article for what it is, an interesting exercise and learning opportunity, but at the end of the day, use a battle-tested password manager. Don't roll your own crypto. Even security-focused experts get it wrong all the time.
I hope I didn't come off as too harsh. However, it's really important to understand and peer review anything regarding cryptography and user passwords.
Good point! I just wanted to create a basic tutorial, so I've corrected the intro of the post.
Hopefully it doesn't sound misleading now and can be used for learning purposes together with your comments 👍
A simple method that I use for on the Mac terminal is
jot -rcs '' 64 32 126
This gives you a random list of 64 characters from ASCII 32 (
<SPC>
) to ASCII 126 (~
). I have this aliased in my.bashrc
torandpass
. On linux distributions I think you need to installjot
from the package manager, since this is a BSD tool which isn't usually pre-installed.