Skip to content

Commit 74b9ecc

Browse files
committed
rubin@: Adding test to detect modification to encrypted attributes
hchar@: remove dependency on commons b64 codec + doc
1 parent bf6cf8e commit 74b9ecc

File tree

5 files changed

+26
-17
lines changed

5 files changed

+26
-17
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ For signing, the user specified signing key can be either symmetric or asymmetri
119119

120120
1. Currently the new data types in [Amazon DynamoDB][ddb] including Map, List, Boolean, and NULL are not yet supported by this library. In particular, this library would fail fast upon detecting the use of these new data types. We expect to support the new types soon in future releases.
121121

122-
2. During retrieval of an item, all the attributes of the item that has been involved for encryption or signing must be included for signature verification. Otherwise, the signature would fail to verify.
122+
2. During retrieval of an item, all the attributes of the item that have been involved for encryption or signing must also be included for signature verification. Otherwise, the signature would fail to verify.
123123

124124
[attrencryptor]: src/main/java/com/amazonaws/services/dynamodbv2/datamodeling/AttributeEncryptor.java
125125
[createtable]: https://github.com/aws/aws-sdk-java/blob/master/src/samples/AmazonDynamoDBDocumentAPI/quick-start/com/amazonaws/services/dynamodbv2/document/quickstart/A_CreateTableTest.java

src/main/java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/DynamoDBEncryptor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ public Map<String, AttributeValue> decryptRecord(
255255
if (!itemAttributes.containsKey(signatureFieldName) || itemAttributes.get(signatureFieldName).getB() == null) {
256256
signature = ByteBuffer.allocate(0);
257257
} else {
258-
signature = itemAttributes.get(signatureFieldName).getB();
258+
signature = itemAttributes.get(signatureFieldName).getB().asReadOnlyBuffer();
259259
}
260260
itemAttributes.remove(signatureFieldName);
261261

@@ -344,7 +344,7 @@ private void actualDecryption(Map<String, AttributeValue> itemAttributes,
344344
throw new IllegalArgumentException("All encrypted fields must be signed. Bad field: " + entry.getKey());
345345
}
346346
ByteBuffer plainText;
347-
ByteBuffer cipherText = entry.getValue().getB();
347+
ByteBuffer cipherText = entry.getValue().getB().asReadOnlyBuffer();
348348
cipherText.rewind();
349349
if (encryptionKey instanceof DelegatedKey) {
350350
plainText = ByteBuffer.wrap(((DelegatedKey)encryptionKey).decrypt(toByteArray(cipherText), null, encryptionMode));

src/main/java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/materials/WrappedRawMaterials.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
*/
1515
package com.amazonaws.services.dynamodbv2.datamodeling.encryption.materials;
1616

17-
import java.nio.charset.Charset;
1817
import java.security.GeneralSecurityException;
1918
import java.security.InvalidKeyException;
2019
import java.security.Key;
@@ -30,9 +29,8 @@
3029
import javax.crypto.NoSuchPaddingException;
3130
import javax.crypto.SecretKey;
3231

33-
import org.apache.commons.codec.binary.Base64;
34-
3532
import com.amazonaws.services.dynamodbv2.datamodeling.encryption.DelegatedKey;
33+
import com.amazonaws.util.Base64;
3634

3735
/**
3836
* Represents cryptographic materials used to manage unique record-level keys.
@@ -64,7 +62,6 @@ public class WrappedRawMaterials extends AbstractRawMaterials {
6462
* key.
6563
*/
6664
protected static final String ENVELOPE_KEY = "amzn-ddb-env-key";
67-
private static final Charset UTF8 = Charset.forName("utf-8");
6865
private static final String DEFAULT_ALGORITHM = "AES/256";
6966
private static final SecureRandom rand = new SecureRandom();
7067

@@ -125,7 +122,7 @@ protected SecretKey initEnvelopeKey() throws GeneralSecurityException {
125122
if (unwrappingKey == null) {
126123
throw new IllegalStateException("No private decryption key provided.");
127124
}
128-
byte[] encryptedKey = Base64.decodeBase64(description.get(ENVELOPE_KEY).getBytes(UTF8));
125+
byte[] encryptedKey = Base64.decode(description.get(ENVELOPE_KEY));
129126
String wrappingAlgorithm = unwrappingKey.getAlgorithm();
130127
if (description.containsKey(KEY_WRAPPING_ALGORITHM)) {
131128
wrappingAlgorithm = description.get(KEY_WRAPPING_ALGORITHM);
@@ -140,7 +137,7 @@ protected SecretKey initEnvelopeKey() throws GeneralSecurityException {
140137
description.get(KEY_WRAPPING_ALGORITHM) :
141138
getTransformation(wrappingKey.getAlgorithm());
142139
byte[] encryptedKey = wrapKey(key, wrappingAlg);
143-
description.put(ENVELOPE_KEY, new String(Base64.encodeBase64(encryptedKey), UTF8));
140+
description.put(ENVELOPE_KEY, Base64.encodeAsString(encryptedKey));
144141
description.put(CONTENT_KEY_ALGORITHM, key.getAlgorithm());
145142
description.put(KEY_WRAPPING_ALGORITHM, wrappingAlg);
146143
setMaterialDescription(description);

src/test/java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/DynamoDBEncryptorTest.java

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,25 +122,37 @@ public void fullEncryption() throws GeneralSecurityException {
122122
Map<String, AttributeValue> encryptedAttributes =
123123
encryptor.encryptAllFieldsExcept(Collections.unmodifiableMap(attribs), context, "hashKey", "rangeKey", "version");
124124
assertThat(encryptedAttributes, AttrMatcher.invert(attribs));
125+
125126
Map<String, AttributeValue> decryptedAttributes =
126127
encryptor.decryptAllFieldsExcept(Collections.unmodifiableMap(encryptedAttributes), context, "hashKey", "rangeKey", "version");
127128
assertThat(decryptedAttributes, AttrMatcher.match(attribs));
128-
129+
129130
// Make sure keys and version are not encrypted
130131
assertAttrEquals(attribs.get("hashKey"), encryptedAttributes.get("hashKey"));
131132
assertAttrEquals(attribs.get("rangeKey"), encryptedAttributes.get("rangeKey"));
132133
assertAttrEquals(attribs.get("version"), encryptedAttributes.get("version"));
133-
134+
134135
// Make sure String has been encrypted (we'll assume the others are correct as well)
135136
assertTrue(encryptedAttributes.containsKey("stringValue"));
136137
assertNull(encryptedAttributes.get("stringValue").getS());
137138
assertNotNull(encryptedAttributes.get("stringValue").getB());
138-
139+
139140
// Make sure we're calling the proper getEncryptionMaterials method
140141
assertEquals("Wrong getEncryptionMaterials() called",
141142
1, prov.getCallCount("getEncryptionMaterials(EncryptionContext context)"));
142143
}
143-
144+
145+
@Test
146+
public void ensureEncryptedAttributesUnmodified() throws GeneralSecurityException {
147+
Map<String, AttributeValue> encryptedAttributes =
148+
encryptor.encryptAllFieldsExcept(Collections.unmodifiableMap(attribs), context, "hashKey", "rangeKey", "version");
149+
String encryptedString = encryptedAttributes.toString();
150+
Map<String, AttributeValue> decryptedAttributes =
151+
encryptor.decryptAllFieldsExcept(Collections.unmodifiableMap(encryptedAttributes), context, "hashKey", "rangeKey", "version");
152+
153+
assertEquals(encryptedString, encryptedAttributes.toString());
154+
}
155+
144156
@Test(expected=SignatureException.class)
145157
public void fullEncryptionBadSignature() throws GeneralSecurityException {
146158
Map<String, AttributeValue> encryptedAttributes =
@@ -305,7 +317,7 @@ private <T> void assertSetsEqual(Collection<T> c1, Collection<T> c2) {
305317
Assert.assertEquals(s1, s2);
306318
}
307319
}
308-
320+
309321
private EncryptionMaterialsProvider getMaterialProviderwithECDSA()
310322
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchProviderException {
311323
Security.addProvider(new BouncyCastleProvider());

src/test/java/com/amazonaws/services/dynamodbv2/datamodeling/encryption/providers/KeyStoreMaterialsProviderTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@
3737
import javax.crypto.KeyGenerator;
3838
import javax.crypto.SecretKey;
3939

40-
import org.apache.commons.codec.binary.Base64;
4140
import org.junit.Before;
4241
import org.junit.BeforeClass;
4342
import org.junit.Test;
4443

4544
import com.amazonaws.services.dynamodbv2.datamodeling.encryption.EncryptionContext;
4645
import com.amazonaws.services.dynamodbv2.datamodeling.encryption.materials.DecryptionMaterials;
4746
import com.amazonaws.services.dynamodbv2.datamodeling.encryption.materials.EncryptionMaterials;
47+
import com.amazonaws.util.Base64;
4848

4949
public class KeyStoreMaterialsProviderTest {
5050
private static final String certPem =
@@ -124,10 +124,10 @@ public static void setUpBeforeClass() throws Exception {
124124
keyStore.load(null, password.toCharArray());
125125

126126
KeyFactory kf = KeyFactory.getInstance("RSA");
127-
PKCS8EncodedKeySpec rsaSpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(keyPem));
127+
PKCS8EncodedKeySpec rsaSpec = new PKCS8EncodedKeySpec(Base64.decode(keyPem));
128128
privateKey = kf.generatePrivate(rsaSpec);
129129
CertificateFactory cf = CertificateFactory.getInstance("X509");
130-
certificate = cf.generateCertificate(new ByteArrayInputStream(Base64.decodeBase64(certPem)));
130+
certificate = cf.generateCertificate(new ByteArrayInputStream(Base64.decode(certPem)));
131131

132132

133133
keyStore.setEntry("enc", new SecretKeyEntry(encryptionKey), passwordProtection);

0 commit comments

Comments
 (0)