in sdk1/src/main/java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/DynamoDBEncryptor.java [425:477]
private void actualEncryption(
Map<String, AttributeValue> itemAttributes,
Map<String, Set<EncryptionFlags>> attributeFlags,
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 = attributeFlags.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));
}
}
}