0

I try to implement a secure user login in my .net application. The first password is hashed with argon2id. The salt and the hashed password is stored in a database. SSL encryption and HttpOnly Cookie is used.

Now i want to add a multifactor authentication (mfa). I want to use a TOTP Algorithm and the Google Authenticator App. I read that you need a secret key to generate the One Time Passwords. The secret key is not the One Time Password it is the secret key you calculate the One Time Passwords with.

Is it good practice to store the secret key for mfa like the password (argon2id hashed with salt)? Why or Why not?

The lib i want to use: Otp.NET.

// Creates totp based on the secret key
var totp = new Totp(secretKey);

//Computes totp
var totpCode = totp.ComputeTotp(DateTime.UtcNow);

//Verify totp
VerifyTotp(string totp, out long timeWindowUsed, VerificationWindow window = null);
1

2 Answers 2

3

You cannot hash the TOTP key, because the key itself is needed for the TOTP calculations. If the server only has a hash of the key, that doesn't help.

Instead, the user-specific TOTP keys should be encrypted with a single master key (using an algorithm like AES in GCM mode). The encrypted TOTP keys can be put into the database. For the master key, you should use a specialized key store like the Kernel Key Retention Service in Linux. Even better would be a hardware-based store like a Trusted Platform Module or a Hardware Security Module.

2
  • If used for 2fa, TOTP key could be symmetrically encrypted with user's password.
    – Basilevs
    Commented Sep 5 at 20:58
  • @Basilevs: This doesn’t sound like a good idea. If an attacker compromises the database(s) with the password hash and the encrypted TOTP key, and if they manage to brute-force the password, they get the TOTP key for free. So now they’re able to completely impersonate the user. For 2FA to make sense, both factors really should be independent from each other even on the server.
    – Ja1024
    Commented Sep 5 at 22:38
2

Unlike passwords, the server needs to know the actual key for TOTP. Therefore, any kind of one-way hash is unacceptable; you can store TOTP keys under reversible encryption, but not hashed.

However, also unlike passwords, TOTP keys are machine-generated, high entropy, unique for every user and every site (barring infinitesimal chance of collisions), and don't have to be human-memorable. Because users don't even have the option of reusing them on other sites, some of the usual considerations behind password storage (like risk of an admin trying passwords they saw in the database on other apps) don't apply.

The high entropy, incidentally, means that even if you were hashing the TOTP keys, you definitely shouldn't use a password hashing function like the argon2 family (which are designed to be slow and memory-costly); that would just be wasting server resources. With a high-entropy input, a single round of a fast secure hashing function (like a member of the SHA2 or SHA3 families) is fine... assuming one-way hashing is desirable at all (it's not, here).

Thus, in many cases, TOTP keys are probably stored in plain text within a database (though the DB as a whole and/or the storage on which it lives may be encrypted). If you want better protection for the keys than that, you can encrypt the keys with... another key, which you have to store somewhere. There are lots of options, but no obviously-right answer. Simply storing the TOTP-key-encrypting-key (KEK) on the web/app server rather than in the database provides some protection; an attacker who gets access to the database but nothing else can't decrypt the TOTP keys. Storing the KEK in a platform-provided key storage (such as a Key Management System/Service, or a software cryptography module) - or better yet, a hardware key storage (such as a Trusted Platform Module or Hardware Security Module) provides a little additional security; an attacker who gets access to your entire install footprint won't find the KEK anywhere; they'll need to either compromise your platform or fully compromise (like, memory-reading or code-execution) your app server. That's far more privileges than are needed to simply log in as an arbitrary app user, so there's no point worrying about the security of the TOTP keys at that point.

For what it's worth, consider using a better MFA method. Webauthn (in its various flavors, including the range of things that get called "passkeys") is much more secure than TOTP. For one thing, the server only sees the user's public key, which is only usable for verification; the secret that the user uses to authenticate never touches your server at all. For another thing, it's phishing-resistant; the site requesting authentication is part of the cryptographic challenge on the client, so if a user accidentally clicks a link to bam.example thinking it's barn.example, bam.example could steal the password but couldn't authenticate the webauthn flow, not even by relaying the challenge from the server; the client will note the different domain even if the user doesn't. Finally, unlike TOTP apps which use all sorts of levels of security for the key storage, webauthn authenticators are expected to (and mostly do) use the strongest, ideally hardware-backed, key storage available.

4
  • Passkeys are not supported in most environments. What Webauthn flavors are actually useful?
    – Basilevs
    Commented Sep 5 at 20:56
  • Security keys (e.g. Yubikeys) and platform authenticators (Windows Hello, Face/Touch ID, Android platform auth, etc.) are widely available; every major browser and most operating systems support them now. With the right library, they shouldn't be any harder to support than TOTP; both require a row in a DB for a key, some logic around enrolling and verifying, and basically nothing else.
    – CBHacking
    Commented Sep 6 at 13:53
  • nothing on Linux, partial support that never works in Firefox. No compatibility. I would not say this is "widely supported"
    – Basilevs
    Commented Sep 6 at 14:21
  • I use Yubikeys every day on Linux, and both Yubikey and platform auth every day on Firefox (the latter admittedly not on desktop Linux, though Android works fine). It's true that specific scenarios don't work everywhere, but desktop Linux and Firefox are both relatively niche right now. "Widely" != "Universally" and even with that caveat, in practice some form of webauthn works on basically everything.
    – CBHacking
    Commented Sep 6 at 20:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .