Generating Strong Passwords
I'm working on a project that requires several passwords that will be used only occasionally but are not “throw away” passwords. I also need them to be reasonably strong. I could just make some up and save them in an encrypted file, of course, but that would mean just one more file to update and maintain. What I really want is some way to generate then on the fly whenever I need them. The other day I saw a password generator, SHA1_Pass, that does pretty much what I need. What I don't need, though, is a heavy duty app with gui dialog boxes and all that.
So in the DIY/NIH spirit I rolled my own. I want to just type in a name such as “Joe” or “Mary” and get back a strong password. A simple way of doing that is to hash the name with SHA1 and map the result into printable characters. For a little extra security, I concatenated some random characters to the name before I hashed it. Here's the resulting c code:
1: /* 2: * makepw.c -- generate strong passwords given a key phrase 3: * 4: * Compile with: 5: * gcc -Wall -lcrypto -o makepw makepw.c 6: * 7: */ 8: 9: #include <openssl/sha.h> 10: #include <stdio.h> 11: #include <stdlib.h> 12: #include <string.h> 13: #include <stdint.h> 14: 15: int main (int argc, char **argv) 16: { 17: int i; 18: int j; 19: uint32_t wd; 20: char xlat[] = "abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLM" 21: "NOPQRSTUVWXYZ023456789.!-$"; 22: char buf[ 256 ] = "Some-Secret-Key"; 23: union 24: { 25: uint32_t s1[ 5 ]; 26: unsigned char md[ 20 ]; 27: } u; 28: 29: if ( argc != 2 ) 30: { 31: puts( "wrong number of arguments" ); 32: exit( 1 ); 33: } 34: strcat( buf, argv[ 1 ] ); 35: SHA1( (unsigned char *)buf, strlen( buf ), u.md ); 36: for ( i = 0; i < 2; i++ ) 37: { 38: wd = u.s1[ i ]; 39: for ( j = 0; j < 5; j++ ) 40: { 41: putchar( xlat[ wd & 0x3f ] ); 42: wd >>= 6; 43: } 44: } 45: exit( 0 ); 46: }
As you can see, the code is straightforward. The random characters are
already sitting in buf
so I just concatenate the input into buf
and call SHA1 to hash the result (lines 34–35). In lines 36–44, I
translate the result into printable characters 6 bits at a time using
xlat
and output each character as it's produced. The upper 2 bits of
each word are discarded. The astute reader will notice that the union
introduces an endian issue so if you are going to run this on machines
with different architectures you will have to compensate for that. An
easy way is to replace line 38 with
wd = htonl( u.sl[ i ] );
Also notice that there's a buffer overflow vulnerability because the size of the input isn't checked but this is just a quick hack for my own use so I kept it simple.
If you need more (or less) characters in the password, just adjust the i for loop end count—you get 5 characters for each time through the loop.
When I run makepw with input jcs
I get
WRQgWEN-2Z
This works well for me but if you want to do something like this you
may want to replace the Some-Secret-Key
in line 22 with a key that
you enter instead. Then you would call it as
makepw secret-key jcs
That provides a more secure application at the expense of having to remember and enter a master key.
On the other hand, you could make it more like SHA1_Pass and not worry about a secret key at all. Instead of entering just a name like “Joe” or “Yahoo!” you would enter some random phrase like “My sister Mary's password for Yahoo!”.
We can refine this a little further. One nice thing about SHA1_Pass is
that it puts the password into the clip board for you so that all you
have to do is paste it into wherever you need it. I'm too lazy to
figure out how to do that programmatically and since this is running
on a Mac I'd probably have to use Objective-C. Fortunately, there's
an easier way. I just wrote a tiny script that pipes the password
into pbcopy
, an Apple utility that copies its input to the paste
buffer. X users can use the xclip
utility instead.
#! /bin/bash makepw $1 | pbcopy
Now just name this script make-pw
, make it executable, and put it in
your execution path and you're good to go. If you're a Mac user, you
can use Automator to turn it into a service but if you're going to do
that you might as well use (the free) SHA1_Pass.
A final note: The above code was run as a Babel code block and
directly generated the resulting password. The #+begin_src
line is
#+begin_src c -n :flags -lcrypto :cmdline jcs :exports both
The more I use Babel, the more I like it.
No comments:
Post a Comment