Score:1

Remembering user credentials by double-hashing

tt flag

I'm developing a desktop application where the users will login with username and password, which is then verified against a database. After the initial login, the current user should be automatically logged in each time the application is started (until the user logs out or 1 month has passed).

I could encrypt and store the last successful username and password on the computer, but the decryption key would have to be known by the application and hence possible to extract. I could use the Windows Data Protection API to store the credentials, but I might need to support other platforms so I would rather not. Storing the hashed password (same as in the database) on the computer is not safe, since a malicious user with read access to the database could replace the username and hash on the computer with another user's data from the database.

So, my plan is this...

Create user account

  • Generate random salt
  • Hash the initial password twice using argon2id(argon2id(password, salt), salt)
  • Store username, salt and hashed password in the database

User login

  • Read user's salt from the database
  • Calculate hash1 = argon2id(password, salt)
  • Calculate hash2 = argon2id(hash1, salt)
  • Check that hash2 is equal to the hash stored in the database
  • If successful, store hash1 on computer

Restart application

  • Read user's salt from the database
  • Read hash1 from computer
  • Calculate hash2 = argon2id(hash1, salt)
  • Check that hash2 is equal to the hash stored in the database

This way, neither the plaintext password nor the hash used for verification in the database is stored on the computer. But since the general advice regarding encryption and hashing is "don't roll your own", I wonder if there is some better method that I have missed - or if there is some serious drawbacks with my method? (I'm probably overthinking this since the application is for internal use only and the data is not sensitive either - top notch security is not required.)

I do see the problem that the stored username and hash1 can be stolen from the computer but that will be covered by operating system security.

I have read about layered hash shucking but since the inner hash is both salted and using a modern hash algorithm, I don't think that will be a problem.

Is there a problem with reusing the random salt for both the inner and outer hashes?

Maarten Bodewes avatar
in flag
It seems you are looking to create an authentication framework. This use case is normally solved by storing tokens, not by storing the primary authentication data as that might be used for any subsequent login attempt.
Score:2
ph flag

The way this is typically implemented is by storing a token that is issued by the server. The token does not have to have any relationship to the user's credentials. So instead of it being a hash and validating it against the hash-of-hash in the database, there's a whole separate table for tokens that have been issued, their validity period, info about the machine it was issued to, etc. Complicated scenarios can use digital signatures or MACs, but in the simplest case the token can just be a random string.

The benefits to this approach are:

  1. It doesn't impact your normal authentication flow, this is a separate authentication process for tokens.
  2. The tokens can be invalidated by the server for any reason.
  3. It doesn't require cooperation from the client with respect to the validity period.
  4. The server has some ability to detect if the token is used from a different context than it was created in.
Score:1
bn flag

I'm not sure how replacing the password itself with a hashed version would do you much better. Are you not still storing a vector of authentication material on the local host, that if compromised, resulted in access to the remote system?

I understand your concept of attempting to prevent attackers from brute-forcing the clear-text password with the original salted password on the host, but I don't see the good in that besides preventing an offline-attack to then be used online at a later date (possibly after the 1-month period that you described initially).

I am not sure of a solution and am newer to cryptography, however I thought it was worth pointing out that you basically just add an extra step to the process, that I believe provides you almost no added security.

This is my thought process:

If hash1 is stored on the computer, it might as well just be the salted original password, because while that could be recovered using a brute-force/dictionary attack, it is still the same idea where even if it is hashed again, it is still a secret that cannot be disclosed. This surrounds the idea that the salt is reused in both hashes, because I think it has to be in your use case.

I'd love to listen to feedback from others, as I am here to learn. Thank you!

Anlo avatar
tt flag
The main advantage I see of not storing the password in plain text on the computer is that if it is stolen, the adversary could potentially access other (more sensitive) systems if the user is using the same password for different systems.
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.