0
$\begingroup$

This is not a duplicate, I'm asking which method is better. I generate an encoded argon2 hash string, so it'll be stored in database to verify login passwords.

Saved encoded hash has salt of length 16 bytes and tag with length of 32 bytes. I need to derive second different key from the saved key using two parameters:

  • User password
  • Already existing saved hash

Methods

I have an idea how to do it, but I'm not sure how secure it'll be. I don't want to derive a double length hash and use first half to store in database and second to encryption. Methods:


  1. Take already existing salt of saved hash
    • Generate 64 byte tag and take the second half (skip 32 bytes)
      • stored hash will be only with a derived key length 32 bytes and NOT TRUNCATED, when verification program will generate anthoner longer (64 byte) tag and take the second half for encryption.
        • I would like to use this method cause it doesn't need two different salts, but is it secure? I don't know how to explain it, so example is on the bottom.

  1. Generate two different different salts and use one to derive tag for authentication and from second salt derive key for encryption.
    • Is Argon2id vulnerable to related-key attack?

Method 1 explaination

  1. User enter a password into a textbox "test" and press button for Registration

    • A hash of password is created with a random salt (16 bytes) and 32 byte tag
      • $argon2id$v=19$m=16,t=2,p=1$SXRkQkVmdGNEMkpMdVEzSg$E015KNeeAHdB0XViXANRjVQN+fKZjWxJbGaGq6CI7/A
  2. To derive encryption key

  • Take the same password, same parameters and same salt
    • Derive 64 bytes with the same parameters (so it'll be $argon2id$v=19$m=16,t=2,p=1$SXRkQkVmdGNEMkpMdVEzSg$H+6e3H9iFaRr4+lW/uAicAgb6y8LtSKn0DymU0/0/wnbsEOHQfHSYr9C1lDQmv1UfzyJzOShVKvJm17h6Hcr7Q)
      • Second half (skip 32 bytes and take other 32) will be the encryption key
        • bsEOHQfHSYr9C1lDQmv1UfzyJzOShVKvJm17h6Hcr7Q will be the encryption key

I'll not generate first 64 bytes and save only first 32 on user registration, I only generate 32 bytes and on verification 2 times more, so 64 bytes - and I'll take next 32 bytes for encryption.

Shortly, on registration will be generated a 32 byte tag. When loginning and deriving an encryption key, program will take stored hash and it's parameters (TimeCost, Parallelism, MemoryCost, Salt) and create a 64 byte tag from the same password. Second 32 bytes will be the encryption key.


I short: Are both methods secure? Which is better? I think first one is better.

Please note I use Argon2id, thank you. Also I know I cannot have more than 512bit security from Argon2 due to a Blake2 hash length.

$\endgroup$
2
  • 3
    $\begingroup$ There is some vocabulary ambiguity between encoded hash (or password token: a string starting in $, with hash id, version, parameters, base-64 formatted salt and hash output of Argon2id); and that hash itself. Also: it's wanted to "derive (a) second different key". But it's unclear what the first key is. Is it the hash in the password token (encoded hash) used for password recognition? $\endgroup$
    – fgrieu
    Commented Nov 21, 2022 at 10:00
  • 1
    $\begingroup$ Using different salts with the same keying maters isn’t really common practice and I haven’t seen much formal analysis of that. In your case you can easily follow the HKDF paradigm: 1) extract a good secret with argon 2) expand the master secret for different use cases( user identification like a hash, encryption, etc…). You can use HKDF-Expand to achieve 2) $\endgroup$ Commented Nov 22, 2022 at 0:40

2 Answers 2

3
$\begingroup$

I hope I have understood the request correctly. I don't see a great weakness in either method. But I think that the scheme as a whole becomes more insecure than with a single execution of Argon2. This sounds counterintuitive at first. With password-based key derivation, it also comes down to using as much memory as possible in an acceptable amount of time. You can use much more memory in the same time with one execution of Argon2 than if you split it up. If you want to derive the second key from the first key, then use a scheme like HMAC or HKDF, because you are not having a password with little entropy as input. Using Argon2 here just wastes time that you should invest in deriving the (first) key from the password.

To me, it also makes no sense to use the password twice. Actually, good practice is to delete the password as soon as possible.

Related-key attacks apply to ciphers.

$\endgroup$
2
$\begingroup$

I'm not sure, what your goal is, but here some ideas:

Only using

  • User password
  • Already existing saved hash

Goal

  • two secrets with 256 bit / 32 byte

Methods

  1. Different Salts: e.g. salt = salt1 + salt2 , keyE = argon(userPw,salt1) , keyR = argon(userPw,salt2)
  2. Different Salts: e.g. salt1 = h("SALT1" + salt) , salt2 = h("SALT2" + salt) , keyE = argon(userPw,salt1) , keyR = argon(userPw,salt2)
  3. Extend Secret: Use argon2 to get a secret 256 bit, than extend it with a given final value and using a cryptographic hash function e.g. keyB = argon(userPw,salt) , keyE = h("ENCRYPTION", keyB,10.000) , keyR = h("REGISTRATION", keyB,10.000)
  4. Extend Input: Modify input for argon2 to get two different secrets 256 bit e.g. keyE = argon("ENCRYPTION" + userPw,salt) , keyR = argon("REGISTRATION" + userPw,salt)
  5. use different hashes e.g. pbkdf and argon2
  6. ...

It highly depends on the implementation, goals and attack model.


Seems not to be the best

Take the same password, same parameters and same salt

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.