[MUD-Dev] Introduction System
jon at callas.org
Thu Jul 20 21:45:09 New Zealand Standard Time 2000
That was a good discussion from Kaminsky. I'll add a few comments:
(1) You should *never* use a password as a key. The way to use a password
in a crypto function is to run the password through a hash function
(perhaps with salt) *first* and take the output of the hash function and
use it as a key.
(2) Good hash functions include SHA1 and MD5. If you are doing digital
signatures, you should avoid MD5, as it has some weaknesses in that arena.
For grinding up passwords into keys, either is suitable. (If you are in a
situation where speed is *really* important, you can consider using MD4.
MD4 has been broken as a hash function for digital signatures, but there
are other decent uses for it. However, don't use it unless you're savvy
enough with crypto to be able to answer the inevitable questions about it
with a straight face. And even then, I don't use it, myself.)
(3) If the goal of the exercise is to play with passwords, don't use a
cipher. Use a hash function. Salt it. The advantage of this is that the
passwords are *never* recoverable, and this algorithm can be done in
plaintext with eavesdroppers and they cannot break into the user's account.
Here's how you do this. This is what I did in Meeting Space:
On the server, you store in the user's database some salt, and the password
hashed with the salt. Salt is simple to understand. It's just an arbitrary
bit of data that you hash with the password. The reason you do it is make
dictionary attacks against the password database harder.
A dictionary attack is one where you hash up a suspected password (like a
word from a database) and compare it to the hashed password. If the hashes
are unsalted, then the attacker can pre-compute the dictionary.
Back to the algorithm, you pick a salt -- more is always better -- and hash
it and the password. A number of operating systems pick 2 random letters as
salt. That means that the dictionary has to be 26^2 times bigger. Four
random characters is a fine salt. Then you store in your database the salt
and resultant hash.
Now then, when a user wants to connect, they send you the account/object
they want to connect to. You look up the hash and the salt. You send them
back the following:
(1) The salt.
(2) A nonce. The nonce is a string you will never re-use. The current time
is a fine nonce. A slightly better one is the time with a count of the
number of times someone has attempted a login (either global or
per-reboot). You don't have to be fancy. A printf into "%d%d" is fine.
Now then, on the client, you take the salt, and hash it with the
hypothetical password the user handed you. Complete the hash, getting a
hash string. Then hash the nonce with the first hash (salt+password). That
gives you a new hash. Send that hash back to the server.
On the server, you already have the hash of the salt+password. So you take
that, hash it with the nonce, and compare it to the thing the client sends
you. If they match, the user typed the correct password. Tah dah.
This protocol does *not* address the problem of securely *changing* a password.
There's also an improvement that can be made here. If the user sends you an
invalid account name, you ideally want to run them through the whole
protocol. The reason is that if you give separate error messages for bad
account and bad password, you leak what the *good* accounts are. A good
protocol wants a single error message.
MUD-Dev mailing list
MUD-Dev at kanga.nu
More information about the MUD-Dev