# Is this correct/incorrect password for file encryption scheme secure?

I'm writing an AES file encryption program, and I'd like to put in a way to tell whether or not the user has entered the correct password without decrypting the entire file and GCM telling me the tag is invalid.

My process is as follows:

• Get the user to enter a password ($$p$$), generate a salt/nonce/IV ($$n$$), and use Scrypt to generate 2 keys (The first and second half of the generated key); $$k_1, k_2 = Scrypt(salt:n, keylen:32, n:2^{16}, r:8, p:1).derive(p)$$

• Encrypt the data of a file with $$\text{AES-GCM-128(}k_1, \text{iv/nonce=n})$$ and empty associated data.

• Write encrypted data to the file so that the contents of the file is $$n || gcmtag || data$$

Would it be secure if I instead wrote the following to the file: $$n || gcmtag || k_2 || data$$

That means I can load $$n$$ from the file, take the user-inputted password, derive the keys, and check if the value of $$k_2$$ is equivalent to the $$k_2$$ loaded from the file.

Your $$k_2$$ value is functioning effectively the same way as conventional password verification methods, where you store a salted password hash of the users' passwords. So it allows for an adversary to test password guesses, but—

1. So does the authenticated GCM $$(c, tag)$$ pair;
2. The memory hard scrypt function is your main line of defense against this attack anyway.

Alternative to very strongly consider: instead of encrypting the whole file in one GCM encryption call, split it into chunks to be encrypted separately with some construction that protects against reordering, deletion and truncation. Study these examples:

The main reason for this is that way you can encrypt/decrypt very large files with a fixed memory footprint, and yet abort decryption as soon as you hit an inauthentic chunk. And secondarily to this, it also indirectly tackles your problem: if the user enters the wrong password, then decryption will fail on the first block.

Potential downsides are:

• Encryption produces larger files by some percentage of the plaintext size (and not just a fixed overhead like your proposal);
• If an encrypted file is adulterated later than the first block you may output a prefix of the plaintext before you abort, which could be a problem in some applications (or not).
• Thanks but I'm already doing it in chunks. I just didn't mention it in the Q. – LittleBlueDragon Jan 29 at 10:37

You can use a similar method like VeraCrypt. Also, you can use a better Key derivation alternative like Argon2id. Argon2id is the combined version of Argon2d, data-dependent, and Argon2i data-independent modes.

For the encryption

1. Get/force a good password from user and use it with Argonid with application/usage dependent domain separation $$k = \operatorname{Argon2i}(passwd\|app)$$
2. Use $$k$$ for $$\operatorname{AES-GCM}$$ encryption of the file with a random or counter-based generated nonce;

$$(c,tag)\operatorname{AES-GCM-128}(k, nonce)$$

3. Store the $$(nonce\mathbin\|c\mathbin\|tag)$$
4. Also encrypt a small text with the $$k$$ $$check = \operatorname{AES-ENC}(k,\text{"myData"})$$
5. Store this $$check$$, too.
6. Delete the $$k$$ from the memory.

For the decryption;

1. Get the password from user and use $$k' = Argon2i(passwd\|app)$$
2. Decrypt the $$check$$ with the $$k'$$ $$check' = \operatorname{AES-DEC}(k',\text{"myData"})$$
3. If the plaintext is $$\text{"myData"}$$ then $$k'=k$$ ans start to use it, else warn the user.

Other methods;

There is no need to derive $$k_2$$ since it will be public. And, though it will be secure, you are giving direct testing for the attackers.
• @kelalaka Good point about the direct testing for the attackers, and thanks for the tip about Argon2, but I think I'll stick to Scrypt mainly because the crypto library I'm using doesn't have argon2 implemented - it's a wrapper to openssl. Would, instead of the $k_2$ scheme, encrypting password with CTR, the derived key, and the same nonce-iv and putting that in be better? – LittleBlueDragon Jan 23 at 22:12
• @kelalaka Of course... Would there be a security trade-off if I used $k_2$ as a nonce? – LittleBlueDragon Jan 24 at 7:38