Using AWS KMS with AES GCM I am implementing client-side encryption for data stored in AWS DynamoDB, and was wondering about the correct use of AWS KMS for key management in addition to using AES/GCM.

I am using the master key stored in AWS KMS to generate a data key used for encryption. I am also using AWS KMS to generate a random number for initializing the IV.

My code looks roughly like so:

GenerateDataKeyResult dataKeyResult =
            kmsClient.generateDataKey(
                    new GenerateDataKeyRequest()
                            .withKeyId("masterKeyId")
                            .withKeySpec(DataKeySpec.AES_128)
                            .addEncryptionContextEntry("encContext", "aValue"));

ByteBuffer plaintextKey = dataKeyResult.getPlaintext();
ByteBuffer encryptedKey = dataKeyResult.getCiphertextBlob();

GenerateRandomRequest randomRequest = new GenerateRandomRequest().withNumberOfBytes(12);
GenerateRandomResult randomResult = kmsClient.generateRandom(randomRequest);
byte[] nonce = randomResult.getPlaintext().array();

GCMParameterSpec spec = new GCMParameterSpec(16 * 8, nonce);
SecretKeySpec secretKeySpec = new SecretKeySpec(plaintextKey.array(), "AES");

Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, spec);

byte[] aad = "Whatever I like".getBytes();
cipher.updateAAD(aad);

String data = "Hello, World!";

byte[] cipherText = cipher.doFinal(data.getBytes());


In theory that seems to work, but I am not fully confident in that I am using it correctly. In particular:


I will store the encryptedKey with the encrypted data, but can I use the same key for all rows or do I need to generate a new one for each one?
How does the AAD factor into this? Do I need to store it? Does it need to be unique per row?
Do I need to generate a new nonce for each row of data? Can I store it together with the data?


So far my assumptions are:


I can reuse the same key for all rows
I need to generate a new nonce for each row
I will store the nonce with each row, and additionally store the encryptedKey
The AAD is the same for all rows and I can generate it in a deterministic way so I do not need to store it


Am I in the ballpark regarding my assumptions?

(I also do apologize if the belongs in StackOverflow, I was a bit unsure of where to post this)
Yes, you are in the ballpark with your assumptions. 


  
  I will store the encryptedKey with the encrypted data, but can I use the same key for all rows or do I need to generate a new one for each one?
  


No you can use the same key.


  
  How does the AAD factor into this? Do I need to store it? Does it need to be unique per row?
  


If you don't need AAD then you don't need to supply it. AAD means "additional authenticated data", i.e. any data you also want to be authenticated together with the ciphertext, which you want to keep in plaintext.


  
  Do I need to generate a new nonce for each row of data? Can I store it together with the data?
  


Yes to both.



Notes on the implementation:



GCMParameterSpec spec = new GCMParameterSpec(16 * 8, nonce);


You should not use "magic literals". Instead use something like Cipher.getBlockSize() * Byte.SIZE. You would of course need to define the cipher earlier. Same goes for the number 12, use a constant e.g. GCM_DEFAULT_NONCE_SIZE_BYTES.



byte[] aad = "Whatever I like".getBytes();
byte[] cipherText = cipher.doFinal(data.getBytes());


You need to specify an explicit encoding here. StandardCharsets.UTF_8 is popular, and not without reason.



Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");


Oracles provider also contains GCM, and that may perform much better than the Bouncy Castle one (which will always be programmed in Java). In general, don't specify a provider unless you really need to (and then you may want to make it configurable).