This is a bit of a rehash of a post I did back in 2005, but Novell did it right when it came to handling user credentials way back in the late 80's and early 90's. The original documents have pretty much fallen off the web, but Novell chose to use a one-way RSA method (or possibly a two-way RSA method but elected to not retain the decryption key, which is much the same thing) to encipher the passwords. The certificate used in this method was generated by the tree itself at creation time, so was unique per tree.
The authentication process looked something like this (from memory, see also: primary documentation is offline)
- Client connects to a server, says, I want to log in a user, here is a temporary key.
- Server replies using the temporary key, "Sure. Here is my public key and a salt."
- Client says, "I want to log in bobjoe42.employees.corporate"
- Server replies, "Here is the public key for bobjoe42.employees.corporate"
- Client crypts the password with bobjoe42's certificate.
- Client crypts the cryptotext+salt with the server's signing key.
- Client says, "Here is the login for bobjoe42.emploees.corporate"
- Server decrypts login request to get at the cryptotext+salt of bobjoe42.emploees.corporate.
- Removes salt.
- Server compares the submitted cryptotext to the cryptotext on bobjoe42.employees.corporate's object. It matches.
- Server says, "You're good."
Unfortunately, the passwords were monocased before crypting computation.
Fortunately, they allowed really long passwords unlike many systems (ahem 1993 version of UNIX-crypt).
That said, this system does a lot of password-handling things right:
- Passwords are never passed in the clear over the network, only the enciphered values are transferred.
- Passwords are never stored in the clear.
- Passwords are never stored in a reversable way.
- Reversible keys are never transferred in the clear.
- The password submission process prevents replay attacks through the use of a random salt with each login transaction.
- The passwords themselves were stored encrypted with tree-unique crypto certificates, so the ciphertext of a password in one tree would look different than the same password in a different tree.
You can get a similar system using modern web technologies:
- Client connects to server over SSL. A secure channel is created.
- Client says, "I'm about to log in, give me a salt."
- Server returns a salt to the client.
- Client computes a salted hash from the user-supplied password.
- Client submits, "I'm logging in firstname.lastname@example.org with this hashtext."
- Server compares the hashtext to the password database, finds a match.
- Server replies, "You're good, use this token."
However, a lot of systems don't even bother going that complex, relying instead on the SSL channel to provide transaction security and allowing unhashed passwords to be passed over that crypted channel. That's "good enough" for a lot of things, and clearly Novell with rather paranoid back in the day.
As it happened, that method ended up being so secure they had to change their authentication system when it came time to handle systems that wanted to authenticate using non-NCP methods like, oh, CIFS, or Appletalk. Those other protocols don't have mechanisms to handle the sort of handshake that NCP allows so something else had to be created, and thus the Universal Password was born. But that's kind of beyond the scope of this article.
Yep, they did it right back then. A network sniffer on the network (a lot easier in the days of hubbed networks) was much less likely to yield tasty numnums. SMB wasn't so lucky.