Skip to content

Commit 6a57734

Browse files
committed
Create algorithm suite and constants
1 parent 4202371 commit 6a57734

File tree

10 files changed

+124
-85
lines changed

10 files changed

+124
-85
lines changed

src/main/java/software/amazon/encryption/s3/S3EncryptionClient.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@
22

33
import java.io.ByteArrayInputStream;
44
import java.io.IOException;
5-
import java.nio.charset.Charset;
65
import java.nio.charset.StandardCharsets;
76
import java.security.InvalidAlgorithmParameterException;
87
import java.security.InvalidKeyException;
98
import java.security.NoSuchAlgorithmException;
109
import java.security.SecureRandom;
11-
import java.security.spec.InvalidParameterSpecException;
1210
import java.util.Base64;
1311
import java.util.Collections;
1412
import java.util.HashMap;
@@ -21,7 +19,6 @@
2119
import javax.crypto.NoSuchPaddingException;
2220
import javax.crypto.SecretKey;
2321
import javax.crypto.spec.GCMParameterSpec;
24-
import javax.crypto.spec.IvParameterSpec;
2522
import javax.crypto.spec.SecretKeySpec;
2623
import software.amazon.awssdk.awscore.exception.AwsServiceException;
2724
import software.amazon.awssdk.core.ResponseInputStream;
@@ -44,17 +41,18 @@
4441
import software.amazon.awssdk.utils.IoUtils;
4542
import software.amazon.encryption.s3.materials.DecryptionMaterials;
4643
import software.amazon.encryption.s3.materials.DefaultMaterialsManager;
47-
import software.amazon.encryption.s3.materials.DefaultMaterialsManager.DecryptionMaterialsRequest;
48-
import software.amazon.encryption.s3.materials.DefaultMaterialsManager.EncryptionMaterialsRequest;
44+
import software.amazon.encryption.s3.materials.DecryptionMaterialsRequest;
45+
import software.amazon.encryption.s3.materials.EncryptionMaterialsRequest;
4946
import software.amazon.encryption.s3.materials.EncryptedDataKey;
5047
import software.amazon.encryption.s3.materials.EncryptionMaterials;
48+
import software.amazon.encryption.s3.materials.MaterialsManager;
5149

5250
public class S3EncryptionClient implements S3Client {
5351

5452
private final S3Client _wrappedClient;
55-
private final DefaultMaterialsManager _materialsManager;
53+
private final MaterialsManager _materialsManager;
5654

57-
public S3EncryptionClient(S3Client client, DefaultMaterialsManager materialsManager) {
55+
public S3EncryptionClient(S3Client client, MaterialsManager materialsManager) {
5856
_wrappedClient = client;
5957
_materialsManager = materialsManager;
6058
}

src/main/java/software/amazon/encryption/s3/algorithms/AlgorithmSuite.java

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,48 @@
22

33

44
public enum AlgorithmSuite {
5-
// TODO: fill in these values
6-
// ALG_AES_256_GCM_IV12_TAG16_NO_KDF(12, 16, Constants.GCM_MAX_CONTENT_LEN, "AES", 32, 0x0078, "AES", 32),
5+
ALG_AES_256_GCM_NO_KDF(0x0078,
6+
"AES",
7+
256,
8+
"AES/GCM/NoPadding",
9+
128,
10+
96,
11+
128,
12+
Constants.GCM_MAX_CONTENT_LENGTH_BITS);
13+
14+
private int _id;
15+
private String _dataKeyAlgorithm;
16+
private int _dataKeyLengthBits;
17+
private String _cipherName;
18+
private int _cipherBlockSizeBits;
19+
private int _cipherNonceLengthBits;
20+
private int _cipherTagLengthBits;
21+
private long _cipherMaxContentLengthBits;
22+
23+
AlgorithmSuite(int id,
24+
String dataKeyAlgorithm,
25+
int dataKeyLengthBits,
26+
String cipherName,
27+
int cipherBlockSizeBits,
28+
int cipherNonceLengthBits,
29+
int cipherTagLengthBits,
30+
long cipherMaxContentLengthBits
31+
) {
32+
this._id = id;
33+
this._dataKeyAlgorithm = dataKeyAlgorithm;
34+
this._dataKeyLengthBits = dataKeyLengthBits;
35+
this._cipherName = cipherName;
36+
this._cipherBlockSizeBits = cipherBlockSizeBits;
37+
this._cipherNonceLengthBits = cipherNonceLengthBits;
38+
this._cipherTagLengthBits = cipherTagLengthBits;
39+
this._cipherMaxContentLengthBits = cipherMaxContentLengthBits;
40+
}
41+
42+
public String cipherName() {
43+
return _cipherName;
44+
}
45+
46+
public int nonceLengthBytes() {
47+
return _cipherNonceLengthBits / 8;
48+
}
749
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package software.amazon.encryption.s3.algorithms;
22

33
class Constants {
4-
/** Maximum length of the content that can be encrypted in GCM mode. */
5-
public static final long GCM_MAX_CONTENT_LEN = (1L << 36) - 32;
4+
// Maximum length of the content that can be encrypted in GCM mode.
5+
static final long GCM_MAX_CONTENT_LENGTH_BITS = (1L<<39) - 256;
66
}

src/main/java/software/amazon/encryption/s3/materials/AESKeyring.java

Lines changed: 25 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
package software.amazon.encryption.s3.materials;
22

33
import java.nio.charset.StandardCharsets;
4-
import java.security.NoSuchAlgorithmException;
54
import java.security.SecureRandom;
65
import java.util.ArrayList;
76
import java.util.List;
87
import javax.crypto.Cipher;
9-
import javax.crypto.NoSuchPaddingException;
108
import javax.crypto.SecretKey;
119
import javax.crypto.spec.GCMParameterSpec;
10+
import software.amazon.encryption.s3.algorithms.AlgorithmSuite;
1211

1312
public class AESKeyring implements Keyring {
1413

14+
private static final String KEY_ALGORITHM = "AES";
1515
private static final String KEY_PROVIDER_ID = "AES/GCM";
1616
private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
17-
private static final int IV_LENGTH_IN_BYTES = 12;
18-
private static final int TAG_LENGTH_IN_BYTES = 16;
19-
private static final int TAG_LENGTH_IN_BITS = TAG_LENGTH_IN_BYTES * 8;
17+
private static final int NONCE_LENGTH_BYTES = 12;
18+
private static final int TAG_LENGTH_BYTES = 16;
19+
private static final int TAG_LENGTH_BITS = TAG_LENGTH_BYTES * 8;
2020
private final SecretKey _wrappingKey;
2121

2222
public AESKeyring(SecretKey wrappingKey) {
23-
if (!wrappingKey.getAlgorithm().equals("AES")) {
23+
if (!wrappingKey.getAlgorithm().equals(KEY_ALGORITHM)) {
2424
// TODO: throw?
2525
}
2626

@@ -34,24 +34,24 @@ public EncryptionMaterials onEncrypt(EncryptionMaterials materials) {
3434
try {
3535
SecureRandom secureRandom = new SecureRandom();
3636

37-
byte[] iv = new byte[IV_LENGTH_IN_BYTES];
38-
secureRandom.nextBytes(iv);
39-
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(TAG_LENGTH_IN_BITS, iv);
37+
AlgorithmSuite algorithmSuite = materials.algorithmSuite();
38+
byte[] nonce = new byte[NONCE_LENGTH_BYTES];
39+
secureRandom.nextBytes(nonce);
40+
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(TAG_LENGTH_BITS, nonce);
4041

4142
final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
4243
cipher.init(Cipher.ENCRYPT_MODE, _wrappingKey, gcmParameterSpec, secureRandom);
4344

4445
// this is the CONTENT encryption, not the wrapping encryption
45-
// TODO: get this from encryption context or preferably algorithm suite
46-
cipher.updateAAD("AES/GCM/NoPadding".getBytes(StandardCharsets.UTF_8));
46+
cipher.updateAAD(algorithmSuite.cipherName().getBytes(StandardCharsets.UTF_8));
4747

4848
// The encrypted data key is the IV prepended to the ciphertext
49-
iv = cipher.getIV();
49+
nonce = cipher.getIV();
5050
byte[] ciphertext = cipher.doFinal(materials.plaintextDataKey());
5151

52-
byte[] encodedBytes = new byte[iv.length + ciphertext.length];
53-
System.arraycopy(iv, 0, encodedBytes, 0, iv.length);
54-
System.arraycopy(ciphertext, 0, encodedBytes, iv.length, ciphertext.length);
52+
byte[] encodedBytes = new byte[nonce.length + ciphertext.length];
53+
System.arraycopy(nonce, 0, encodedBytes, 0, nonce.length);
54+
System.arraycopy(ciphertext, 0, encodedBytes, nonce.length, ciphertext.length);
5555

5656
EncryptedDataKey encryptedDataKey = EncryptedDataKey.builder()
5757
.keyProviderId(KEY_PROVIDER_ID)
@@ -65,30 +65,12 @@ public EncryptionMaterials onEncrypt(EncryptionMaterials materials) {
6565
.encryptedDataKeys(encryptedDataKeys)
6666
.build();
6767
} catch (Exception e) {
68-
throw new UnsupportedOperationException("Unable to AES/GCM/NoPadding wrap", e);
68+
throw new UnsupportedOperationException("Unable to " + CIPHER_ALGORITHM + " wrap", e);
6969
}
7070
}
7171

7272
@Override
7373
public DecryptionMaterials onDecrypt(final DecryptionMaterials materials, List<EncryptedDataKey> encryptedDataKeys) {
74-
/*
75-
ByteBuffer encryptedCekBuff = ByteBuffer.wrap(encryptedCek);
76-
// Split the IV from the front of the ciphertext
77-
byte[] iv = new byte[IV_LENGTH_IN_BYTES];
78-
byte[] taggedCek = new byte[encryptedCek.length - IV_LENGTH_IN_BYTES];
79-
encryptedCekBuff.get(iv);
80-
encryptedCekBuff.get(taggedCek);
81-
82-
Cipher cipher = this.cipherProvider.createCipher();
83-
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(TAG_LENGTH_IN_BITS, iv);
84-
try {
85-
cipher.init(Cipher.DECRYPT_MODE, key, gcmParameterSpec);
86-
cipher.updateAAD(this.cekAlgorithm.getBytes(StandardCharsets.UTF_8));
87-
return cipher.doFinal(taggedCek);
88-
} catch (Exception e) {
89-
throw failure(e, "An exception was thrown when attempting to decrypt the Content Encryption Key");
90-
}
91-
*/
9274
if (materials.plaintextDataKey() != null) {
9375
return materials;
9476
}
@@ -99,25 +81,26 @@ public DecryptionMaterials onDecrypt(final DecryptionMaterials materials, List<E
9981
}
10082

10183
byte[] encodedBytes = encryptedDataKey.ciphertext();
102-
byte[] iv = new byte[IV_LENGTH_IN_BYTES];
103-
byte[] ciphertext = new byte[encodedBytes.length - iv.length];
84+
byte[] nonce = new byte[NONCE_LENGTH_BYTES];
85+
byte[] ciphertext = new byte[encodedBytes.length - nonce.length];
86+
87+
System.arraycopy(encodedBytes, 0, nonce, 0, nonce.length);
88+
System.arraycopy(encodedBytes, nonce.length, ciphertext, 0, ciphertext.length);
10489

105-
System.arraycopy(encodedBytes, 0, iv, 0, iv.length);
106-
System.arraycopy(encodedBytes, iv.length, ciphertext, 0, ciphertext.length);
10790

108-
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(TAG_LENGTH_IN_BITS, iv);
91+
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(TAG_LENGTH_BITS, nonce);
10992
try {
11093
final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
11194
cipher.init(Cipher.DECRYPT_MODE, _wrappingKey, gcmParameterSpec);
11295
// this is the CONTENT encryption, not the wrapping encryption
113-
// TODO: get this from encryption context or preferably algorithm suite
114-
cipher.updateAAD("AES/GCM/NoPadding".getBytes(StandardCharsets.UTF_8));
96+
AlgorithmSuite algorithmSuite = materials.algorithmSuite();
97+
cipher.updateAAD(algorithmSuite.cipherName().getBytes(StandardCharsets.UTF_8));
11598
byte[] plaintext = cipher.doFinal(ciphertext);
11699

117100
return materials.toBuilder().plaintextDataKey(plaintext).build();
118101
} catch (Exception e) {
119102
// TODO: maybe this should fall through?
120-
throw new UnsupportedOperationException("Unable to AES/GCM/NoPadding unwrap", e);
103+
throw new UnsupportedOperationException("Unable to " + CIPHER_ALGORITHM + " unwrap", e);
121104
}
122105
}
123106

src/main/java/software/amazon/encryption/s3/materials/DecryptionMaterials.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
package software.amazon.encryption.s3.materials;
22

33
import java.util.Collections;
4-
import java.util.List;
54
import java.util.Map;
65
import javax.crypto.SecretKey;
76
import javax.crypto.spec.SecretKeySpec;
7+
import software.amazon.encryption.s3.algorithms.AlgorithmSuite;
88

99
final public class DecryptionMaterials {
1010

1111
// Identifies what sort of crypto algorithms we want to use
12-
// In ESDK, this is an enum
13-
private final int _algorithmSuiteId;
12+
private final AlgorithmSuite _algorithmSuite;
1413

1514
// Additional information passed into encrypted that is required on decryption as well
1615
// Should NOT contain sensitive information
@@ -23,7 +22,7 @@ final public class DecryptionMaterials {
2322

2423

2524
private DecryptionMaterials(Builder builder) {
26-
this._algorithmSuiteId = builder._algorithmSuiteId;
25+
this._algorithmSuite = builder._algorithmSuite;
2726
this._encryptionContext = builder._encryptionContext;
2827
this._plaintextDataKey = builder._plaintextDataKey;
2928
}
@@ -32,8 +31,8 @@ static public Builder builder() {
3231
return new Builder();
3332
}
3433

35-
public int algorithmSuiteId() {
36-
return _algorithmSuiteId;
34+
public AlgorithmSuite algorithmSuite() {
35+
return _algorithmSuite;
3736
}
3837

3938
public Map<String, String> encryptionContext() {
@@ -50,22 +49,22 @@ public SecretKey dataKey() {
5049

5150
public Builder toBuilder() {
5251
return new Builder()
53-
.algorithmSuiteId(_algorithmSuiteId)
52+
.algorithmSuite(_algorithmSuite)
5453
.encryptionContext(_encryptionContext)
5554
.plaintextDataKey(_plaintextDataKey);
5655
}
5756

5857
static public class Builder {
5958

60-
private int _algorithmSuiteId = -1;
59+
private AlgorithmSuite _algorithmSuite = AlgorithmSuite.ALG_AES_256_GCM_NO_KDF;
6160
private Map<String, String> _encryptionContext = Collections.emptyMap();
6261
private byte[] _plaintextDataKey = null;
6362

6463
private Builder() {
6564
}
6665

67-
public Builder algorithmSuiteId(int id) {
68-
_algorithmSuiteId = id;
66+
public Builder algorithmSuite(AlgorithmSuite algorithmSuite) {
67+
_algorithmSuite = algorithmSuite;
6968
return this;
7069
}
7170

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package software.amazon.encryption.s3.materials;
2+
3+
import java.util.List;
4+
import java.util.Map;
5+
import software.amazon.encryption.s3.algorithms.AlgorithmSuite;
6+
7+
public class DecryptionMaterialsRequest {
8+
9+
public AlgorithmSuite algorithmSuite;
10+
public List<EncryptedDataKey> encryptedDataKeys;
11+
public Map<String, String> encryptionContext;
12+
}

src/main/java/software/amazon/encryption/s3/materials/DefaultMaterialsManager.java

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
import java.security.NoSuchAlgorithmException;
44
import java.security.SecureRandom;
5-
import java.util.List;
6-
import java.util.Map;
75
import javax.crypto.KeyGenerator;
86
import javax.crypto.SecretKey;
7+
import software.amazon.encryption.s3.algorithms.AlgorithmSuite;
98

10-
public class DefaultMaterialsManager {
9+
public class DefaultMaterialsManager implements MaterialsManager {
1110
// TODO: allow this to be configurable?
1211
private final SecureRandom _secureRandom = new SecureRandom();
1312
private final Keyring _keyring;
@@ -21,7 +20,7 @@ public EncryptionMaterials getEncryptionMaterials(EncryptionMaterialsRequest req
2120
SecretKey key = generateDataKey();
2221

2322
EncryptionMaterials materials = EncryptionMaterials.builder()
24-
.algorithmSuiteId(0x0078)
23+
.algorithmSuite(AlgorithmSuite.ALG_AES_256_GCM_NO_KDF)
2524
.encryptionContext(request.encryptionContext)
2625
.plaintextDataKey(key.getEncoded())
2726
.build();
@@ -43,20 +42,11 @@ private SecretKey generateDataKey() {
4342

4443
public DecryptionMaterials getDecryptionMaterials(DecryptionMaterialsRequest request) {
4544
DecryptionMaterials materials = DecryptionMaterials.builder()
46-
.algorithmSuiteId(request.algorithmSuiteId)
45+
.algorithmSuite(request.algorithmSuite)
4746
.encryptionContext(request.encryptionContext)
4847
.build();
4948

5049
return _keyring.onDecrypt(materials, request.encryptedDataKeys);
5150
}
5251

53-
public static class EncryptionMaterialsRequest {
54-
public Map<String, String> encryptionContext;
55-
}
56-
57-
public static class DecryptionMaterialsRequest {
58-
public int algorithmSuiteId;
59-
public List<EncryptedDataKey> encryptedDataKeys;
60-
public Map<String, String> encryptionContext;
61-
}
6252
}

0 commit comments

Comments
 (0)