I am looking into using AES256-GCM for encrypting some database fields. I know that for AES256-CBC, I need to generate a new IV for each encrypt, but I can use the same key. The IV can be openly stored alongside the ciphertext (ie, it can be public).
I started to read about GCM, but I don't quite understand some things. On this Stackexchange Thread, it is stated that:
- GCM does not need an IV supplied.
- Associated Tag is not necessary, but may improve security (example they gave is using a database id)
But Wikipedia states about GCM:
GCM has been proven secure in the concrete security model.[13] It is secure when it is used with a block cipher mode of operation that is indistinguishable from a random permutation; however security depends on choosing a unique initialization vector for every encryption performed with the same key (see stream cipher attack).
Which implies that the IV still needs to be randomly generated and supplied for each encrypt with GCM, so why does the user in the stackexchange answer post say that we are not required to provide the IV?
Wikipedia also states:
The authentication strength depends on the length of the authentication tag, as with all symmetric message authentication codes. However, the use of shorter authentication tags with GCM is discouraged. The bit-length of the tag, denoted t, is a security parameter. In general, it may be any one of the following five values: 128, 120, 112, 104, or 96.
In OP's post in that stackexchange thread, OP uses
tag = cipher.auth_tag
. Is this by default 96? If so, is there a way to change it? Are there significant performance issues in using 128 than 96?Does both the Associated Tag (
cipher.auth_data
) and the Authentication Tag (cipher.auth_tag
) need to be kept secret? Or can they be kept open like the IV?Finally, can someone explain further what is meant by the Associated Tag? The example in the answer that was given in OP's thread was that we can use a database id to ensure that the data belongs to a certain database user. Let's say that a user has the following database fields:
User - primary_id - encrypted_email
And we want to encrypt the User's email before insertion. With User
primary_id==10
(modifying OP's ruby code):cipher = OpenSSL::Cipher::AES.new(128, :GCM) cipher.encrypt key = cipher.random_key iv = cipher.random_iv cipher.auth_data = "10" # Using DB user's id! encrypted = cipher.update(data) + cipher.final tag = cipher.auth_tag
I replaced
cipher.auth_data
with the database user's primary_id. Is this correct?
auth_data
. $\endgroup$auth_data
is arbitrary contextual information (for instance, the database primary key of the encrypted message, or a username, or a string scoping the action to a specific "purpose") that must be provided verbatim upon decryption. It can be public, but it shouldn't be controllable by the entity providing ciphertexts to be decrypted. Theauth_tag
is the output of the authentication half of the cipher, and is what is used upon decryption to detect any changes to the key, ciphertext, IV, or auth data. It can be stored alongside the encrypted output. $\endgroup$