3
$\begingroup$

For the purposes of learning, I'm writing a small utility that allows encrypting a list of passwords using a single master key (using AES-256 and PBKDF2)

Before encrypting or decrypting any password user has to enter the master key (which will be used to derive a key for AES).

I would like to know what is the best option to know if a user has entered a valid master key :

  1. To salt and then hash the master key (once). The resulting salt and hash are stored somewhere - for instance in a DB. Later on, when the user has entered his master key, I add the stored salt and compare the computed hash with hash stored in DB.

  2. To generate a salt. The salt is encrypted using the master key. I store both the salt and the encrypted salt in a DB. Later on, when the user enters the master key, I try to decrypt the encrypted salt value with the master key and compare it with the salt stored in DB.

$\endgroup$
6
  • $\begingroup$ For AES key : I generate a salt (which will be included in the encrypted password) and use PBKDF2 / HMAC SHA1 with 1000 iterations : nodejs.org/api/… $\endgroup$
    – tigrou
    Dec 19, 2018 at 18:42
  • $\begingroup$ I was thinking of a hash created using SHA-256 directly not PBKDF2. AFAIK it's probably more secure to use PBKDF2 with a given number of iterations (eg : 1000) as it's slower $\endgroup$
    – tigrou
    Dec 19, 2018 at 18:54
  • 2
    $\begingroup$ Am I understanding things right, that you essentially want a definitive and secure way to check whether the user has entered the correct password before trying to decrypt the data? $\endgroup$
    – SEJPM
    Dec 19, 2018 at 19:18
  • 1
    $\begingroup$ It would be much easier if you could formalize the cryptographic scheme you are proposing, like kelalaka tried to do in his answer using the $\TeX$ formulas. Given just text, we cannot be sure if you confuse passwords and keys and such, to name just one issue. $\endgroup$
    – Maarten Bodewes
    Dec 19, 2018 at 23:45
  • 1
    $\begingroup$ Note that 1000 iterations was the suggested number of iterations for PBKDF2 when it was introduced. You would expect a lot more iterations nowadays, say 40K to 100K. $\endgroup$
    – Maarten Bodewes
    Dec 19, 2018 at 23:47

1 Answer 1

3
$\begingroup$

Let call a user's Master Key for AES as $\mathit{MK}_u$ and generated as;

$$\mathit{MK}_u = \operatorname{PBKDF2}(\mathit{passwd}_u, \mathit{salt}, \mathit{Iteration})$$

where $\mathit{Iteration}$ between 40K to 100K

1. To salt and then hash the master key (once). The resulting salt and hash are stored somewhere - for instance in a DB. Later on, when the user has entered his master key, I add the stored salt and compare the computed hash with hash stored in DB.

$$\mathit{hashed} = \operatorname{SHA-256}(\mathit{salt} \mathbin\| \mathit{MK}_u)$$

A passive attacker can look at the DB and;

  • Password search on $\mathit{MK}_u$ with hashcat.

A better solution is also using;

  • a pepper which is stored in the application server: this totally prevents the passive DB attacker $$\mathit{hashed} = \operatorname{SHA-256}(\mathit{salt} \mathbin\| \mathit{MK}_u \mathbin\| \mathit{pepper})$$
  • Key-Stretching as PBKDF2 or Argon2: this also prevents and make it harder even pepper is accessed from the applications server.

$$\mathit{hashed} = \operatorname{PBKDF2}(\mathit{MK}_u, \mathit{salt} \mathbin\| \mathit{pepper}, \mathit{Iteration})$$

2. To generate a salt. The salt is encrypted using the master key. I store both the salt and the encrypted salt in a DB. Later on, when the user enters the master key, I try to decrypt the encrypted salt value with the master key and compare it with the salt stored in DB.

$$\mathit{salt}_e = E_{\mathit{MK}_u}(\mathit{salt}),$$ and store $\mathit{salt}$ and $\mathit{salt}_e$ on DB.

For the second approach, the attacker can execute a password search for $\mathit{MK}_u$, this is almost the same as the attack shown against the #1 case since the attacker only deals with one AES encryption. To increase the iteration, one can modify this as in bcrypt.

The modified #2 approach is the winner due to the pepper in the passive DB attacker model.

$\endgroup$
1
  • 2
    $\begingroup$ Actually you don't need the additional stretching on $MK_u$ and you want to use the computational resources there up-front on the initial derivation. And actually using HKDF instead of this ad-hoc SHA-256 based construction would probably be "more standard" these days... $\endgroup$
    – SEJPM
    Dec 29, 2018 at 23:09

Your Answer

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

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