10

I am creating a software with user + password. After autentification, the user can access some semi public services, but also encrypt some files that only the user can access.

The user must be stored as is, without modification, if possible. After auth, the user and the password are kept in memory as long as the software is running (i don't know if that's okay either).

The question is how should i store this user + password combination in a potentially unsecure database?

I don't really understand what should i expose.

Let's say I create an enhanced key like this:

salt = random 32 characters string (is it okay?)
key = hash(usr password + salt)
for 1 to 65000 do
  key = hash(key + usr password + salt)

Should I store the [plaintext user], [the enhanced key] and [the salt] in the database ?

Also, what should I use to encrypt (with AES or Blowfish) some files using a new password everytime ? Should I generate a new salt and create a new enhanced key using (the password stored in memory of the program + the salt) ? And in this case, if i store the encrypted file in the database, i should probably only store the salt. The database is the same as where i store the user + password combination.

The file can only be decrypted if someone can generate the key, but he doesn't know the password. Right ?

I use Python with PyCrypto, but it's not really important, a general example is just fine. I have read a few similar questions, but they are not very explicit.

Thank you very very much!

oz123
  • 27,559
  • 27
  • 125
  • 187
Cristi Constantin
  • 554
  • 1
  • 6
  • 19

2 Answers2

10

Crypto is hard to get right, it's good that you're asking questions.

Storing passwords: Passwords should be hashed using a key stretching algorithm. Typically, you want to use a library rather than implement it yourself. Key stretching algorithms are designed to chew up processor cycles, so it's nice to evaluate them with nice C code. If you are on a Linux system with glibc, you can use the crypt.crypt module (read man crypt):

import crypt
encrypted = crypt.crypt(password, '$6$' + salt + '$')

This returns an ASCII string which you can safely store in your database. (The $6$ is a glibc extension that uses a key stretching function based on SHA-512. If you don't have this extension, then don't use crypt.crypt). (Edit: The algorithm is very similar to the one you asked about in your question. However, best practice is usually to let a library do that stuff rather than rolling your own.)

Encrypting files: Do not do this yourself. Install GnuPG (or scrypt, bcrypt, ncrypt, what have you). There are a few things that can easily go wrong when you design your own way to encrypt files. These tools use the proper key derivation functions, authentication hashes, and cipher modes without any additional configuration. They're not Python libraries, but executables, so you'll have to write a wrapper that uses the subprocess module.

Passwords in memory: Don't. Once you've checked the user's password against your password database, convert the password to a key using a key derivation function. You can then use the key to unlock encrypted files, but you can no longer use it to get the original password back.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • 1
    Regarding password hashing, there is also a [cross-platform](http://packages.python.org/passlib/lib/passlib.apps.html#passlib.apps.custom_app_context) SHA512-Crypt implementation available. – Eli Collins May 19 '11 at 18:19
  • Thank you very much for the advice, it's great! @Elis: wow, that python library is absolutely great! // However, there is one thing i don't understand!... If I don't keep the password in memory, what should I send scrypt/ bcrypt/ ncrypt program as password for encrypting a file? – Cristi Constantin May 20 '11 at 10:09
  • @Cristi: You can use a key derivation function with a different salt to turn the password into a key for encrypted files. – Dietrich Epp May 20 '11 at 10:15
  • @Cristi: Regarding key derivation functions, I'd strongly recommend PBKDF2, you can even use the user's password hash as the salt, but definitely use >10000 rounds in any case. Regarding PBKDF2, there's the [passlib implementation](http://packages.python.org/passlib/lib/passlib.utils.pbkdf2.html#passlib.utils.pbkdf2.pbkdf2), a [pycrypto-based module](http://www.dlitz.net/software/python-pbkdf2/) from the pycrypto author, and an [m2crypto implementation](http://www.heikkitoivonen.net/m2crypto/api/M2Crypto.EVP-module.html#pbkdf2), though those last two only do SHA1. – Eli Collins May 20 '11 at 16:00
2

If you use a different salt for each user, you must store it somewhere (ideally in a different place). If you use the same salt for every user, you can hardcode it in your app, but it can be considered less secure. If you don't keep the salt, you will not be able to match a given password against the one in your database.

The aim of the salt is to make bruteforce or dictionnary attacks a lot harder. That is why it is more secure if store separately, to avoid someone having both hash passwords and corresponding salts.

Yannick Loiseau
  • 1,394
  • 8
  • 8
  • 1
    Storing salts in a separate place has no real point. See http://stackoverflow.com/questions/1219899/where-do-you-store-your-salt-strings – Dietrich Epp May 19 '11 at 13:03
  • Salt is different for each user and is stored in the same database. – Cristi Constantin May 19 '11 at 13:08
  • @Dietrich Epp: just to avoid social engineering discovery on passwords (just a single password though) or in the case of multiple accounts for the same user (e.g. a client for multiple services) to check if the same password is used for othe accounts. – Yannick Loiseau May 19 '11 at 13:09
  • Because every application which requires access to the hash requires access to the salt and vice versa, it is unlikely that one would be compromised without the other. If the same password is used twice the salt will still be different, which is the point of using a salt in the first place. So you cannot check if two passwords are the same. – Dietrich Epp May 19 '11 at 13:12
  • @Dietrich Epp: seems that you can check if you have one clear password and each salt, by re-hashing every account password with the corresponding hash (the number of password to test is quite small in this senario). However, I agree that both are likely to be compromised together. – Yannick Loiseau May 19 '11 at 13:16
  • If you have one clear password, you don't need the hashes OR the salts, you can just try logging in through the normal interface. – Dietrich Epp May 19 '11 at 13:19
  • depends on your application and the situation. Imagine a database for a mail client containing credentials for all your mail account. If someone doesn't have access to the application itself, but has stolen the database... but it's a complicated senario, and we're sliding off topic I think. – Yannick Loiseau May 19 '11 at 13:29
  • @Yannick: That's not just complicated, that's downright bizarre: a password compromise, combined with a database compromise, but no access to the application at all, and the only information it leaks is information you could get without a database compromise, and the proposed solution wouldn't likely work. – Dietrich Epp May 19 '11 at 14:05