Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I store Argon2 passwords in my database?

Tags:

passwords

hash

I'm trying to store user passwords in my DB using Argon2 algorithm.

This is what I obtain by using it:

$echo -n "password" | argon2 "smallsalt" -id -t 4 -m 18 -p 4
Type:           Argon2id
Iterations:     4
Memory:         262144 KiB
Parallelism:    4
Hash:           cb4447d91dd62b085a555e13ebcc6f04f4c666388606b2c401ddf803055f54ac
Encoded:        $argon2id$v=19$m=262144,t=4,p=4$c21hbGxzYWx0$y0RH2R3WKwhaVV4T68xvBPTGZjiGBrLEAd34AwVfVKw
1.486 seconds
Verification ok

In this case, what should I store in the DB?

  • The "encoded" value as shown above?
  • The "hash" value as shown above?
  • Neither, but another solution?

Please, could you help me? I'm a newbie with this and I'm a little bit lost.

like image 429
Ommadawn Avatar asked Dec 22 '19 11:12

Ommadawn


People also ask

How are passwords stored in a database?

The password entered by user is concatenated with a random generated salt as well as a static salt. The concatenated string is passed as the input of hashing function. The result obtained is stored in database. Dynamic salt is required to be stored in the database since it is different for different users.

Is Argon2 better than Bcrypt?

Argon2 is the best memory-hard password hashing algorithm, but it is not "cache hard", and this is the reason you shouldn't upgrade to Argon2. Just stay with bcrypt, it is stronger than Argon2 for < 1 second hashing time.

Is Argon2 better than SHA256?

The advantage of algorithms like Argon2 is that they are way harder to implement scalably in hardware than SHA256 is. Or in other words, it's easy to build an ASIC that's 1000x as powerful to compute SHA256 hashes as a recent Intel CPU than to build something that's 1000x as powerful to compute Argon2 hashes.

How does Argon2 work?

Argon2 is a cryptographic algorithm that allows you to store your entries safely. It is dedicated to password encryption and doesn't have any uses apart from that. It's a modern algorithm that allows you to choose which protection you want to apply, be it resistance to GPU attacks, side-channel attacks, or even both.


4 Answers

I'm a bit late to the party, but I disagree with the previous answers.
You should store the field: Encoded
The $argon2id$.... value.

(At least if you are using normal Argon2 libraries having the verify() function. It does not look like the man-page for argon2 command does this, however.

Only if you are stuck with the command line, you should consider storing each field individually.)

The $argon2id$ encoded hash
The argon2 encoded hash follows the same as its older cousin bcrypt's syntax.

The encoded hash includes all you ever need to verify the hash when the user logs in.

It is most likely more future proof. When a newer and better argon2 comes along: You can upgrade your one column hashed passwords. Just like you could detect bcrypt's $2a$-hashes, and re-hash them as $argon2id$-hashes, next time the user logs in. (If you were moving from bcrypt to agron2.)

TL;DR
Store the $-encoded value encoded_hash in your database.
Use argon2.verify(password, encoded_hash) to verify that the password is correct.

Don't bother about all the values inside the hash. Let the library do that for you. :)

like image 57
Vbakke Avatar answered Oct 05 '22 14:10

Vbakke


Neither. Save following as a single value:

  • algorithm ID (e.g. argon2id)
  • salt
  • number of iterations (4)
  • memory usage factor (18)
  • parallelism (4)

The output of the field "encoded" is misleading because you cannot use it as is for password check (i.e. for hash generation), e.g. m=262144 where as for password check you need the original factor m=18.

Are you going to launch an OS process each time you check password? I would discourage you from doing this. I'd suggest you use a library (C++, Java, ...). They produce a string that contains all these data concatenated and separated with "$".

like image 39
mentallurg Avatar answered Oct 05 '22 14:10

mentallurg


I'd put the type, iterations, memory, parallelism, hash, salt and corresponding user id into separate columns and leave the encoded bit out, because it's just all the attributes joined together. If they're in separate columns then you can reference the attributes more easily than having to split and index the encoded string.

The other option is to just store the encoded string in 1 column, but as I said its more tedious to look at certain attributes, as you'd have to split the encoded string and then index it.

like image 36
SamG101 Avatar answered Sep 25 '22 22:09

SamG101


I had the same question and read this post while gathering some information. Now after some days and thoughts about all this, I'll personally take a different route than the accepted answer and therefore slightly disagree with it. I thought I would share my perspective so that it might help others as well.

I suppose it will depend on everyone's context. I don't think there is a one size fits all answer here. I'm sure there are situations where it is perfectly valid and even better/simpler to store the encoded string ($argon2...).

However, I would argue that depending on the context, storing the encoded string doesn't seem to be the right approach.

First of all, it makes the hashing method very obvious. It is probably not that important but for some reasons it makes me a bit more comfortable not having it ^^. But, more importantly, it means that implementation details are stored in your persistence layer (db or else). At the time of writing, argon2id is the recommended hashing mechanism by OWASP but these things can change (eventually do change...). Some day, it might be considered unsecure, or another function will be considered more secure.

As a result, I would suggest this more function "agnostic" starting point:

  • The hash (for argon2 -> the hex string)
  • The salt
  • The last_modified date
  • A string with hashing parameters (for argon2, you could put the parameters here in the form of your choosing)

The last_modified allows to know if the hash needs updating or not and the parameters allows to support the verification and update of "old" hashes.

Of course this means that you have to work a bit more in the code and can't simply use every libraries shortcuts straight away. But, I would say that this increased complexity offer more flexibility in other circumstances (like moving away from a given hashing function). As always there are no free lunch.

That's why I suppose it depends on your context and why personally I wouldn't go with the accepted answer in my situation.

PS: I'm no cryptography expert nor some devsecop guru. So feel free to contradict, enrich, agree or disagree. I just like to keep my implementation details contained ;)

like image 29
debu Avatar answered Sep 23 '22 22:09

debu