in DynamoDbEncryption/runtimes/java/src/main/sdkv1/com/amazonaws/services/dynamodbv2/datamodeling/encryption/DynamoDBEncryptor.java [544:614]
private void actualEncryption(
Map<String, AttributeValue> itemAttributes,
Map<String, Set<EncryptionFlags>> attributeActionsOnEncrypt,
Map<String, String> materialDescription,
SecretKey encryptionKey
) throws GeneralSecurityException {
String encryptionMode = null;
if (encryptionKey != null) {
materialDescription.put(
this.symmetricEncryptionModeHeader,
SYMMETRIC_ENCRYPTION_MODE
);
encryptionMode = encryptionKey.getAlgorithm() + SYMMETRIC_ENCRYPTION_MODE;
}
Cipher cipher = null;
int blockSize = -1;
for (Map.Entry<String, AttributeValue> entry : itemAttributes.entrySet()) {
Set<EncryptionFlags> flags = attributeActionsOnEncrypt.get(
entry.getKey()
);
if (flags != null && flags.contains(EncryptionFlags.ENCRYPT)) {
if (!flags.contains(EncryptionFlags.SIGN)) {
throw new IllegalArgumentException(
"All encrypted fields must be signed. Bad field: " + entry.getKey()
);
}
ByteBuffer plainText = AttributeValueMarshaller.marshall(
entry.getValue()
);
plainText.rewind();
ByteBuffer cipherText;
if (encryptionKey instanceof DelegatedKey) {
DelegatedKey dk = (DelegatedKey) encryptionKey;
cipherText =
ByteBuffer.wrap(
dk.encrypt(toByteArray(plainText), null, encryptionMode)
);
} else {
if (cipher == null) {
blockSize = getBlockSize(encryptionMode);
cipher = Cipher.getInstance(encryptionMode);
}
// Encryption format: <iv><ciphertext>
// Note a unique iv is generated per attribute
cipher.init(Cipher.ENCRYPT_MODE, encryptionKey, Utils.getRng());
cipherText =
ByteBuffer.allocate(
blockSize + cipher.getOutputSize(plainText.remaining())
);
cipherText.position(blockSize);
cipher.doFinal(plainText, cipherText);
cipherText.flip();
final byte[] iv = cipher.getIV();
if (iv.length != blockSize) {
throw new IllegalStateException(
String.format(
"Generated IV length (%d) not equal to block size (%d)",
iv.length,
blockSize
)
);
}
cipherText.put(iv);
cipherText.rewind();
}
// Replace the plaintext attribute value with the encrypted content
entry.setValue(new AttributeValue().withB(cipherText));
}
}
}