Is it possible to figure out the key from the original and the encrypted string?

Viewed 3347

Edit

I'm bumping this one since I still haven't got a conclusive answer (one or two are close though). What I'm looking for is basically a yes or no answer with some info to back it up.


We've got a system storing user passwords encrypted by a generic system key in the database. That could be catastrophic (obviously) if someone with DB access got a hold of that system key.

The correct way we now know (according to most(?)) is to store the salted hash of of the PW in the DB, but being relatively close to a release we'd like to minimize the code change and therefore thought a very simple way to prevent someone reading out PW's from the DB would be to simply reverse the process and switch the parameters.

That is, we'll encrypt a per system (hundreds of them) unique salted string (with a per encryption added random tail) using the users password as a key, storing the result in the DB. At PW verification we'll de-crypt the string stored in the DB with the entered PW and match with the system key for verification.

System key+random encrypt with password store in DB encrypted key.

I.e. the users passwords are never stored, and in our simple minds are irretrievable.

But being noobs in the encryption sector we wonder if someone with more experience in the area could answer the simple question -

Is it possible to figure out the key from the original and the encrypted string?

We think this a brilliant ;) way to ensure user passwords from being compromised, but can't find anything on the method online. This makes us unsure about it, hence asking this great community.

(And brute force is not a adequate answer, since that (under the circumstances) is impossible to protect from.)

Edit:

I'll paste one of my comments here to (hopefully) make some things clearer:


@zaph Thanks for your input, but I think most are missing the point here. We have a code-freeze in a few days for an upcoming release, and I've already implemented the method I've mentioned in the question. Until next release, I'll read up on the subject and implement a third party library like scrypt or similar. I really just need to know if there are existing viable algorithms for reverse the process and thus making my new implementation worse than the old encrypted password approach.

7 Answers

We've got a system storing user passwords encrypted by a generic system key in the database.

That's a VERY bad practice, as the password is potentially reversible. According to my experience - it is only matter of time until data are leaked and .. your potentially catastrophic scenario will come true.

The correct way we now know (according to most(?)) is to store the salted hash of of the PW in the DB,

The best option today is using "slow hashing", see https://security.stackexchange.com/questions/211/how-to-securely-hash-passwords/31846#31846

At PW verification we'll de-crypt the string stored in the DB with the entered PW and match with the system key for verification.

And there's the problem. Once the system key is leaked (or used by an insider), all the passwords are potentially compromised. Using hash is much more safe (and the difference in code should not be so big).

Is it possible to figure out the key from the original and the encrypted string?

Using any current modern cipher it is currently not possible to compute / guess the encryption key based on knowledge of the plain and encrypted value.

Sorry, but go with what most people do and hash the passwords with the salt using something like bcrypt or scrypt. Try using some well-known, popular library to make things quicker and easier (comment if you need help looking for one).

Yes, what you are describing sounds like it could be secure, but as @gusto2 mentioned you won't have enough entropy for secure encryption, forcing you to use a key-derivation scheme.

The only problem with using a key-derivation scheme is that key-derivation is basically a special kind of hashing, in which case, you should just go with the first option and do what everyone else does.

Sorry for jumping into the bounty in the last hours, but I have some important thoughts to contribute.

First of all, I didn't see any reference to OWASP here. They are probably the biggest software security community and you should always check their recommendations, not only for password protection but any other security subject. Every year they release a document called "OWASP Top 10", listing the most common web application vulnerabilities.

Based on last year's OWASP Top 10, the risk you are trying to mitigate is the number #3 in the list, called "Sensitive Data Exposure". It applies not only to passwords, but sensitive data like credit card number, for instance. For the problem described in your question, I would like to highlight the third attack scenario example:

Scenario #3: The password database uses unsalted or simple hashes to store everyone's passwords. A file upload flaw allows an attacker to retrieve the password database. All the unsalted hashes can be exposed with a rainbow table of pre-calculated hashes. Hashes generated by simple or fast hash functions may be cracked by GPUs, even if they were salted.

To prevent this kind of attack (sometimes called "rainbow attack"), these are OWASP's suggestions:

  1. Classify data processed, stored, or transmitted by an application. Identify which data is sensitive according to privacy laws, regulatory requirements, or business needs.
  2. Apply controls as per the classification.
  3. Don’t store sensitive data unnecessarily. Discard it as soon as possible or use PCI DSS compliant tokenization or even truncation. Data that is not retained cannot be stolen.
  4. Make sure to encrypt all sensitive data at rest.
  5. Ensure up-to-date and strong standard algorithms, protocols, and keys are in place; use proper key management.
  6. Encrypt all data in transit with secure protocols such as TLS with perfect forward secrecy (PFS) ciphers, cipher prioritization by the server, and secure parameters. Enforce encryption using directives like HTTP Strict Transport Security (HSTS).
  7. Disable caching for responses that contain sensitive data.
  8. Store passwords using strong adaptive and salted hashing functions with a work factor (delay factor), such as Argon2, scrypt, bcrypt, or PBKDF2.
  9. Verify independently the effectiveness of configuration and settings.

They are all equality important, but for your use case, take a special look at #8 and the links I included up there. In summary, you need a strong adaptive and salted hashing function with a work factor.

Also, don't forget to periodically run penetration tests (pen tests) against your production environment. This is VERY important.

If you want to start testing/validating your rainbow attack defenses, OWASP provides a tool called "OWASP Rainbow Maker".

OWASP Rainbow Maker is a tool aimed to break hash signatures. It allows testers to insert a hash value and possible keywords and values that might used by the application to create it, then it tried multiple combinations to find the format used to generate the hash value.

I hope it helps and if you have any question, shoot at the comments.

As requested: "an answer drawing from credible and/or official sources"— National Institute of Standards and Technology.

NIST Digital Identity Guidelines page 15: … Verifiers SHALL store memorized secrets in a form that is resistant to offline attacks. Memorized secrets SHALL be salted and hashed using a suitable one-way key derivation function. Key derivation functions take a password, a salt, and a cost factor as inputs then generate a password hash.

The salt must be a cryptographically secure and unique to each password, it may—and usually is—saved with the hashed password.The cost factor should be in the range of 1us of CPU (not elapsed) time. The cost factor can also be saved with the password and can thus be updated in the future as may be necessary.

The point is to make the attacker spend substantial time finding passwords by brute force.

Other functions with similar properties include PBKDF2, Rfc2898DeriveBytes, Argon2i, password_hash, Bcrypt.

Notes (moved from question comments):

In response to: And brute force is not a adequate answer, since that (under the circumstances) is impossible to protect from.
This is exact the type of attack that must and can be defended against. The current best practice is to require each attempt to be unique and time consuming. Thus a random salt and iteration of ~100ms. Thus each attempt of a trial password against a user hashed password requires substantial time. An attack for sale in the Dark Web needs a large number of user credentials so most of the passwords must be brute forced to be profitable.

In response to: I really just need to know if there are existing viable algorithms for reverse the process and thus making my new implementation worse than the old encrypted password approach.
Yes, the proposed method is extremely vulnerable to exposing most user passwords. It is not a question of better or worse than the existing method, it is a question of securing user's credentials with current practices to protect the users and your liability.

A potential attack against the OP's proposed solution:
I previously posted a possible and simple attack, here it is again: Get the DB and the system key for verification. Pick an entry from a list of frequent passwords and try it against the system key. This is very fast, less than a micro second, so most passwords will be found quickly. A general attack does not need to find all the passwords, just a high enough percentage to make the user info + password salable on the Dark Web.

I think gusto2 is being a bit OTT, although while it is better than the master-password solution you are trying to replace, it still falls a long way short of acceptable.

It's more or less how crypt works in DES mode. However in your implementation which does not use a unique salt per user, it will be obvious when 2 users have the same password (switching reversible encryption for a hash does nothing to mitigate this). You might be using a better algorithm with more bits but your implementation lags behind 40 year old technology.

As other users have suggested, you should not be storing decryptable passwords in your database, since, if the key is leaked (or mismanaged, used for fraudulent purposes by anyone in your organization) it could have catastrophic results.

As a security standard method, passwords should NEVER be retrievable by the database, either by a master key or a password recovery method. If an attacker were to gain access to the application source or the database, they still would have a hard time stealing the identity of a user, since they cannot possibly retrieve the user's password.

Thus, your approach could use your per system (hundreds of them) unique salted string (with a per encryption added random tail) for each user, store it in the database, and use the user's password input as the hash salt (instead of the key, as you suggested). The difference between this method and yours is that you wont be decrypting the stored hash, but will compare the hash generated by user input to the stored hash instead.

Here's a few other resources on password management that you can read to ensure your users' privacy.

From a quick google I found this Stack Exchange thread.

Trying to figure out the key based on plaintext and ciphertext is called Known-plaintext attack. Most encryption algorithms are not vulnerable to this attack.

Related