33

On web applications I build I don't hash the passwords. Instead I symmetrically encrypt the username using the user's password and store the result in the password field. I use RijndaelManaged on dotnet.

On login I do it again and check if there is a match.

My question is, how secure is this now when more and more databases are hacked? I do not know at any given time the user's real password. What the hacker would get from db is the username encrypted with an unknown password. With hashing there is the rainbow tables problem, but with this method not.

Knowing the decrypted value already (username) makes it easier to find the password?

  • 30
    In broad terms this is the same as using a fast hash with the user name as a salt. Not horrifically insecure, but you would do better to use a standard approach. Don't roll your own – paj28 Sep 23 '15 at 11:30
  • I don't understand, if you are using a different password exclusive to the server to encrypt the user name, and as you said you never know the user's real password, then how are you able to confirm a given login (with a valid user name) is being submitted with the user's valid password? – WDS Sep 23 '15 at 11:39
  • 1
    @WDS - On login I do it again and check if there is a match. – Rudy Sep 23 '15 at 11:44
  • 5
    @Rudy - Although you're using a library for the raw crypto, you're still rolling your own scheme. I think this is explained if you read down the link, or it might be in another answer linked off that. – paj28 Sep 23 '15 at 11:54
  • 3
85

What you do really is hashing: you built a hashing function out of a block cipher. Incidentally, "encryption of a known value with the password as key" is how the traditional DES-based crypt scheme for Unix was designed.

On the plus side, your construction includes the user name, which partially provides the effect of a salt: parallel cracking is discouraged because two users using the same password will end up with two distinct hash outputs. "Partially", because upon password change, the user keeps his username, so some form of parallelism is still feasible here; and, perhaps more importantly, the same username may be used in several Web apps (e.g. 'admin'), which makes precomputed tables worthwhile (and the point of the salt is to prevent parallelism, in particular the efficient use of precomputed tables).

On the minus side:

  • This is a homemade construction. 50 years of research in cryptography have taught us that homemade crypto is very rarely good. In fact, we can "know" that a given algorithm is correct only through years of review by other skilled researchers, and homemade schemes, by definition, never got much of a review.

  • This is limited. Rijndael is a block cipher that can accept keys up to 256 bits; thus, if you use the password as key, then it must fit within 256 bits. This prevents using so-called "passphrases" which can be strong but easy to memorize passwords by using a lot of space for its entropy (human brains don't like concentrated entropy, but are happy with diluted entropy).

  • This is way too fast, and this is the biggest immediate problem in your scheme. With a basic PC, an attacker can try a lot of passwords per second, in particular since modern PC have dedicated opcodes for AES. With a quad-core PC, one should be able to try up to about half a billion of passwords per second. Not many user-chosen password can survive such an onslaught for long.

If you are interested in how password hashing works, then read this. The short answer, though, is still the same: don't use a homemade scheme; use bcrypt.

  • Thank you, I will research more about bcrypt for dotnet. – Rudy Sep 23 '15 at 13:13
  • As you say in the linked answer, bcrypt shares the limited input problem. – otus Sep 23 '15 at 15:06
  • @otus: that's true, but with a higher limit (at least 50 characters, more for most implementations). – Thomas Pornin Sep 23 '15 at 15:29
  • 2
    @otus You can get around the limited input problem by performing a hash of the whole string in secure hashing environment that doesn't have the limited input problem to condense the entropy and bcrypting that. – corsiKa Sep 23 '15 at 15:53
  • 1
    @kasperd: If there is no good source of entropy, using a "purely-random" salt may yield results inferior to combining username+hostname or username+hostname+passwordChangeDatestamp. Adding a little extra randomness to the latter form wouldn't hurt, but I'd consider it a small-cost-small-benefit proposition. – supercat Sep 24 '15 at 19:29
11

The other answers already say No, "roll your own" is rarely a good password storage scheme and yours is no exception.

I'd like to add: It isn't a good scheme for storing/communicating the username either.
You're basically hashing. Nothing wrong with that except:

  • You're using a function not designed as a secure hash function. Being a cipher it's surely on the "secure" end of scale but hashing also involves avoiding hash collisions. A cipher isn't typically optimized for having no collision. One-Time Pads are known to be unbreakable, because they have the maximal number of collisions. So a strong cipher makes a poor hash in terms of collisions.
  • If you store username and username-encrypted-with-password there are more vulnerabilities:
    • In this case, if your database is hacked the attacker doesn't only get the username encrypted with an unknown password. He also gets the clear text aka. username. So it's a clear text analysis, which for some ciphers is much easier than brute force.
    • Hash collisions: The attacker doesn't need to know the password but any that produces the same encryption for a short and given clear text. This might be even easier than clear text analysis.
  • If you don't store the username but rely on a single combined transmitted value, there are still drawbacks:
    • In this case, you probably didn't consider hash collisions. What about two users, who have the same username? What about two idiots, who have the same username and the same password? What about hash collisions of different usernames and passwords by pure chance (remember: ciphers are not optimized to avoid collisions!)?
  • In any case there's the "Pass the hash" attack: An attacker sniffing network communication can simply emulate your application to pass the same data as the user. Did you do anything about that? If not, that's why you shouldn't "roll your own".

Often times the protocol of transmission is as important to security as a strong cryptographic function, independent of hashing vs. encrypting. A bad protocol can expose your function to attacks it's unsuited for, especially "side channel attacks" like "pass the hash" or "man in the middle" that are circumventing the actual crypto-analysis on the side of the attacker.

Your password storage scheme may be prone to such attacks, because you didn't specify, if the username is also stored in clear text. Doing so exposes your scheme to the attacks described above. Not storing it in clear text may require a transmission protocol prone to attacks as described above.

Here are some additional thoughts on transmission protocols in your case, slightly generalized:

If you didn't do anything about the "pass the hash" attack, then your scheme is worse than a whole lot of others. An attacker neither needs to hack your data base nor crack your cipher. He gets what he needs for free by sniffing network traffic.

HTTPS may suffice, although it can be worked around by "man in the middle": Users aren't checking for authentication certificates, are they? An attacker simply opens an unauthenticated but encrypted connection to your user and whatever is expected connection to you.

An additional Challenge-Response scheme may add security. Prior to login the client receives a one-time random string (challenge) that he's required to build into the hash (response). An attacker couldn't reuse a sniffed hash, because the challenge isn't reused either.
But again, no need to "roll you own".

  • 1
    Welcome to Security Stack Exchange. Your answer shows some good writing skills and knowledge. However, there's some dubious parts. For example, duplicate user names would not normally be allowed. Can I encourage you to recheck your facts, and focus on the question. The question did not involve transmission of credentials, so HTTPS and "pass the hash" are not strictly relevant. – paj28 Sep 24 '15 at 11:55
  • 1
    Reconsider the indention of paragraphs: More indented bullet points are applying only in case of the previous normal bullet point, i.e. you can only check for duplicate usernames when storing the username in plain text => Plain Text + Hash collision attacks. The question doesn't specify, if the username is stored in plain text. Actually it indicates otherwise, because it claims hackers would only get the encrypted username. This is wrong, if username is stored. If username isn't stored the other problems arise, because of transmission. Not involving transmission can open any cipher for attack. – NoAnswer Sep 24 '15 at 12:08
  • Edited to clarify your points. – NoAnswer Sep 24 '15 at 12:23
  • Ok, that's an improvement. I still have issues with some of your claims, but overall this is a reasonable answer. Issues: Clear text analysis is not known to be a problem with Rijndael; nothing he has done is particularly bad for hash collisions; you've mentioned pass-the-hash repeatedly, but as a web app it's highly likely the server takes an unhashed password over SSL so PTH is not applicable. Anyway, don't worry too much, I've been accused of being a pedant in the past :-) – paj28 Sep 24 '15 at 12:39
  • I'm being accused a pedant regularly. I'm proud of it. That's why I think you can't leave anything out unless it's clearly specified to not be an issue. The question specifies neither storage of username nor transmission. So there might be an issue. SSL should be ok, too. HTTPS is problematic for unauthenticated connections. If that's a problem, depends on interpretation of "web application". I didn't expect clear text analysis to be a problem. Still ciphers are rarely optimized to reduce collisions. Those are just points to be considered, which could be skipped by not "rolling your own". – NoAnswer Sep 24 '15 at 12:55
5

TL;DR: use scrypt. Why roll your own when there's a perfectly good standard?

(I consider scrypt superior to bcrypt, but bcrypt is still miles better than grow-your-own.)

One thing you're missing so far is stretching. Imagine you get hacked and your database gets dumped on pastebin - it can happen to the best of us.

The people who use 123456 or one of the other top 20 passwords will get found out whatever you do, and they deserve no better. For the people who've choosen moderately good passwords, it makes a difference if the time the attacker has to spend per entry is on the order of microseconds or seconds.

You're also not salting - imagine that two of your web applications get hacked and one person has accounts under the same username with the same password for both of them. It sounds to me like the attacker will get identical ciphertexts in both dumps, telling them that there's a crack-one-get-one-free offer.

  • My one comment on the final paragraph is this - use a different Salt for each site so two sites using the same technique wouldn't have the same data :-) – Rycochet Sep 25 '15 at 8:27
  • @Rycochet: Um, you should always be using a different salt per-password (randomly generated via a secure random number source) not per-site. – R.. Sep 25 '15 at 16:52
  • True - but you still need to generate a salt in a repeatable way - so if that part is generated then the way it's generated should be different - so long as it's not the same salt on the two (or more) sites then that's the goal, regardless of the method used ;-) – Rycochet Sep 25 '15 at 22:00
  • Repeatable? I'm not sure I understand. I usually draw some bits from /dev/random and store them in a separate column next to their name; when someone logs in, use the name to look up their row and read out the salt. No need to regenerate it. – Bristol Sep 26 '15 at 20:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.