3
3
4
4
package com .amazonaws .encryptionsdk .kmsv2 ;
5
5
6
- import com .amazonaws .AmazonServiceException ;
7
- import com . amazonaws . AmazonWebServiceRequest ;
6
+ import static com .amazonaws .encryptionsdk . internal . AwsKmsCmkArnInfo .* ;
7
+
8
8
import com .amazonaws .encryptionsdk .*;
9
9
import com .amazonaws .encryptionsdk .exception .AwsCryptoException ;
10
10
import com .amazonaws .encryptionsdk .internal .AwsKmsCmkArnInfo ;
11
11
import com .amazonaws .encryptionsdk .internal .VersionInfo ;
12
12
import com .amazonaws .encryptionsdk .kms .KmsMethods ;
13
- import com .amazonaws .services .kms .AWSKMS ;
14
- import com .amazonaws .services .kms .model .*;
15
-
16
- import javax .crypto .SecretKey ;
17
- import javax .crypto .spec .SecretKeySpec ;
18
13
import java .nio .ByteBuffer ;
19
14
import java .nio .charset .StandardCharsets ;
20
15
import java .util .*;
16
+ import java .util .function .Consumer ;
21
17
import java .util .function .Supplier ;
22
-
23
- import static com .amazonaws .encryptionsdk .internal .AwsKmsCmkArnInfo .*;
18
+ import javax .crypto .SecretKey ;
19
+ import javax .crypto .spec .SecretKeySpec ;
20
+ import software .amazon .awssdk .awscore .AwsRequestOverrideConfiguration ;
21
+ import software .amazon .awssdk .awscore .exception .AwsServiceException ;
22
+ import software .amazon .awssdk .core .ApiName ;
23
+ import software .amazon .awssdk .core .SdkBytes ;
24
+ import software .amazon .awssdk .services .kms .KmsClient ;
25
+ import software .amazon .awssdk .services .kms .model .*;
24
26
25
27
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.5
26
28
// # MUST implement the Master Key Interface (../master-key-
38
40
*/
39
41
public final class AwsKmsMrkAwareMasterKey extends MasterKey <AwsKmsMrkAwareMasterKey >
40
42
implements KmsMethods {
41
- private static final String USER_AGENT = VersionInfo .loadUserAgent ();
42
- private final AWSKMS kmsClient_ ;
43
+
44
+ static final ApiName API_NAME =
45
+ ApiName .builder ().name (VersionInfo .apiName ()).version (VersionInfo .versionNumber ()).build ();
46
+ private static final Consumer <AwsRequestOverrideConfiguration .Builder > API_NAME_INTERCEPTOR =
47
+ builder -> builder .addApiName (API_NAME );
48
+
49
+ private final KmsClient kmsClient_ ;
43
50
private final List <String > grantTokens_ = new ArrayList <>();
44
51
private final String awsKmsIdentifier_ ;
45
52
private final MasterKeyProvider <AwsKmsMrkAwareMasterKey > sourceProvider_ ;
46
53
47
- private static <T extends AmazonWebServiceRequest > T updateUserAgent (T request ) {
48
- request .getRequestClientOptions ().appendUserAgent (USER_AGENT );
49
-
50
- return request ;
51
- }
52
-
53
54
/**
54
55
* A light builder method.
55
56
*
@@ -58,7 +59,7 @@ private static <T extends AmazonWebServiceRequest> T updateUserAgent(T request)
58
59
* @param awsKmsIdentifier An identifier for an AWS KMS key. May be a raw resource.
59
60
*/
60
61
static AwsKmsMrkAwareMasterKey getInstance (
61
- final AWSKMS kms ,
62
+ final KmsClient kms ,
62
63
final String awsKmsIdentifier ,
63
64
final MasterKeyProvider <AwsKmsMrkAwareMasterKey > provider ) {
64
65
return new AwsKmsMrkAwareMasterKey (awsKmsIdentifier , kms , provider );
@@ -68,7 +69,7 @@ static AwsKmsMrkAwareMasterKey getInstance(
68
69
// # On initialization, the caller MUST provide:
69
70
private AwsKmsMrkAwareMasterKey (
70
71
final String awsKmsIdentifier ,
71
- final AWSKMS kmsClient ,
72
+ final KmsClient kmsClient ,
72
73
final MasterKeyProvider <AwsKmsMrkAwareMasterKey > provider ) {
73
74
74
75
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.6
@@ -151,36 +152,40 @@ public DataKey<AwsKmsMrkAwareMasterKey> generateDataKey(
151
152
// # master key MUST use the configured AWS KMS client to make an AWS KMS
152
153
// # GenerateDatakey (https://docs.aws.amazon.com/kms/latest/APIReference/
153
154
// # API_GenerateDataKey.html) request constructed as follows:
154
- final GenerateDataKeyResult gdkResult =
155
+ final GenerateDataKeyResponse gdkResponse =
155
156
kmsClient_ .generateDataKey (
156
- updateUserAgent (
157
- new GenerateDataKeyRequest ()
158
- .withKeyId (awsKmsIdentifier_ )
159
- .withNumberOfBytes (algorithm .getDataKeyLength ())
160
- .withEncryptionContext (encryptionContext )
161
- .withGrantTokens (grantTokens_ )));
157
+ GenerateDataKeyRequest .builder ()
158
+ .overrideConfiguration (API_NAME_INTERCEPTOR )
159
+ .keyId (awsKmsIdentifier_ )
160
+ .numberOfBytes (algorithm .getDataKeyLength ())
161
+ .encryptionContext (encryptionContext )
162
+ .grantTokens (grantTokens_ )
163
+ .build ());
164
+
165
+ final ByteBuffer plaintextBuffer = gdkResponse .plaintext ().asByteBuffer ();
162
166
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.10
163
167
// # If the call succeeds the AWS KMS Generate Data Key response's
164
168
// # "Plaintext" MUST match the key derivation input length specified by
165
169
// # the algorithm suite included in the input.
166
- if (gdkResult . getPlaintext () .limit () != algorithm .getDataKeyLength ()) {
170
+ if (plaintextBuffer .limit () != algorithm .getDataKeyLength ()) {
167
171
throw new IllegalStateException ("Received an unexpected number of bytes from KMS" );
168
172
}
169
173
170
174
final byte [] rawKey = new byte [algorithm .getDataKeyLength ()];
171
- gdkResult . getPlaintext () .get (rawKey );
175
+ plaintextBuffer .get (rawKey );
172
176
173
177
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.10
174
178
// # The response's "KeyId"
175
179
// # MUST be valid.
176
- final String gdkResultKeyId = gdkResult . getKeyId ();
180
+ final String gdkResponseKeyId = gdkResponse . keyId ();
177
181
/* Exceptional Postcondition: Must have an AWS KMS ARN from AWS KMS generateDataKey. */
178
- if (parseInfoFromKeyArn (gdkResultKeyId ) == null ) {
182
+ if (parseInfoFromKeyArn (gdkResponseKeyId ) == null ) {
179
183
throw new IllegalStateException ("Received an empty or invalid keyId from KMS" );
180
184
}
181
185
182
- final byte [] encryptedKey = new byte [gdkResult .getCiphertextBlob ().remaining ()];
183
- gdkResult .getCiphertextBlob ().get (encryptedKey );
186
+ final ByteBuffer ciphertextBlobBuffer = gdkResponse .ciphertextBlob ().asByteBuffer ();
187
+ final byte [] encryptedKey = new byte [ciphertextBlobBuffer .remaining ()];
188
+ ciphertextBlobBuffer .get (encryptedKey );
184
189
185
190
final SecretKeySpec key = new SecretKeySpec (rawKey , algorithm .getDataKeyAlgo ());
186
191
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.10
@@ -195,7 +200,7 @@ public DataKey<AwsKmsMrkAwareMasterKey> generateDataKey(
195
200
// # The response's cipher text blob MUST be used as the
196
201
// # returned as the ciphertext for the encrypted data key in the output.
197
202
encryptedKey ,
198
- gdkResultKeyId .getBytes (StandardCharsets .UTF_8 ),
203
+ gdkResponseKeyId .getBytes (StandardCharsets .UTF_8 ),
199
204
this );
200
205
}
201
206
@@ -220,18 +225,21 @@ public DataKey<AwsKmsMrkAwareMasterKey> encryptDataKey(
220
225
// # key MUST use the configured AWS KMS client to make an AWS KMS Encrypt
221
226
// # (https://docs.aws.amazon.com/kms/latest/APIReference/
222
227
// # API_Encrypt.html) request constructed as follows:
223
- final EncryptResult encryptResult =
228
+ final EncryptResponse encryptResponse =
224
229
kmsClient_ .encrypt (
225
- updateUserAgent (
226
- new EncryptRequest ()
227
- .withKeyId (awsKmsIdentifier_ )
228
- .withPlaintext (ByteBuffer .wrap (key .getEncoded ()))
229
- .withEncryptionContext (encryptionContext )
230
- .withGrantTokens (grantTokens_ )));
231
-
232
- final byte [] edk = new byte [encryptResult .getCiphertextBlob ().remaining ()];
233
- encryptResult .getCiphertextBlob ().get (edk );
234
- final String encryptResultKeyId = encryptResult .getKeyId ();
230
+ EncryptRequest .builder ()
231
+ .overrideConfiguration (API_NAME_INTERCEPTOR )
232
+ .keyId (awsKmsIdentifier_ )
233
+ .plaintext (SdkBytes .fromByteArray (key .getEncoded ()))
234
+ .encryptionContext (encryptionContext )
235
+ .grantTokens (grantTokens_ )
236
+ .build ());
237
+
238
+ final ByteBuffer ciphertextBlobBuffer = encryptResponse .ciphertextBlob ().asByteBuffer ();
239
+ final byte [] edk = new byte [ciphertextBlobBuffer .remaining ()];
240
+ ciphertextBlobBuffer .get (edk );
241
+
242
+ final String encryptResultKeyId = encryptResponse .keyId ();
235
243
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.11
236
244
// # The AWS KMS Encrypt response MUST contain a valid "KeyId".
237
245
/* Postcondition: Must have an AWS KMS ARN from AWS KMS encrypt. */
@@ -251,16 +259,16 @@ public DataKey<AwsKmsMrkAwareMasterKey> encryptDataKey(
251
259
edk ,
252
260
encryptResultKeyId .getBytes (StandardCharsets .UTF_8 ),
253
261
this );
254
- } catch (final AmazonServiceException asex ) {
262
+ } catch (final AwsServiceException asex ) {
255
263
throw new AwsCryptoException (asex );
256
264
}
257
265
}
258
266
259
267
/**
260
268
* Will attempt to decrypt if awsKmsArnMatchForDecrypt returns true in {@link
261
- * AwsKmsMrkAwareMasterKey#filterEncryptedDataKeys(String, AwsKmsCmkArnInfo , EncryptedDataKey)}.
262
- * An extension of {@link KmsMasterKey#decryptDataKey(CryptoAlgorithm, Collection, Map)} but with
263
- * an awareness of the properties of multi-Region keys.
269
+ * AwsKmsMrkAwareMasterKey#filterEncryptedDataKeys(String, String , EncryptedDataKey)}. An
270
+ * extension of {@link KmsMasterKey#decryptDataKey(CryptoAlgorithm, Collection, Map)} but with an
271
+ * awareness of the properties of multi-Region keys.
264
272
*/
265
273
@ Override
266
274
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.9
@@ -293,7 +301,7 @@ public DataKey<AwsKmsMrkAwareMasterKey> decryptDataKey(
293
301
algorithm ,
294
302
edk ,
295
303
encryptionContext );
296
- } catch (final AmazonServiceException amazonServiceException ) {
304
+ } catch (final AwsServiceException amazonServiceException ) {
297
305
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.9
298
306
// # If this attempt
299
307
// # results in an error, then these errors MUST be collected.
@@ -333,7 +341,7 @@ public DataKey<AwsKmsMrkAwareMasterKey> decryptDataKey(
333
341
*/
334
342
static DataKey <AwsKmsMrkAwareMasterKey > decryptSingleEncryptedDataKey (
335
343
final AwsKmsMrkAwareMasterKey masterKey ,
336
- final AWSKMS client ,
344
+ final KmsClient client ,
337
345
final String awsKmsIdentifier ,
338
346
final List <String > grantTokens ,
339
347
final CryptoAlgorithm algorithm ,
@@ -345,39 +353,41 @@ static DataKey<AwsKmsMrkAwareMasterKey> decryptSingleEncryptedDataKey(
345
353
// # configured AWS KMS client to make an AWS KMS Decrypt
346
354
// # (https://docs.aws.amazon.com/kms/latest/APIReference/
347
355
// # API_Decrypt.html) request constructed as follows:
348
- final DecryptResult decryptResult =
356
+ final DecryptResponse decryptResponse =
349
357
client .decrypt (
350
- updateUserAgent (
351
- new DecryptRequest ()
352
- .withCiphertextBlob (ByteBuffer .wrap (edk .getEncryptedDataKey ()))
353
- .withEncryptionContext (encryptionContext )
354
- .withGrantTokens (grantTokens )
355
- .withKeyId (awsKmsIdentifier )));
356
-
357
- final String decryptResultKeyId = decryptResult .getKeyId ();
358
+ DecryptRequest .builder ()
359
+ .overrideConfiguration (API_NAME_INTERCEPTOR )
360
+ .ciphertextBlob (SdkBytes .fromByteArray (edk .getEncryptedDataKey ()))
361
+ .encryptionContext (encryptionContext )
362
+ .grantTokens (grantTokens )
363
+ .keyId (awsKmsIdentifier )
364
+ .build ());
365
+
366
+ final String decryptResponseKeyId = decryptResponse .keyId ();
358
367
/* Exceptional Postcondition: Must have a CMK ARN from AWS KMS to match. */
359
- if (decryptResultKeyId == null ) {
368
+ if (decryptResponseKeyId == null ) {
360
369
throw new IllegalStateException ("Received an empty keyId from KMS" );
361
370
}
362
371
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.9
363
372
// # If the call succeeds then the response's "KeyId" MUST be equal to the
364
373
// # configured AWS KMS key identifier otherwise the function MUST collect
365
374
// # an error.
366
- if (!awsKmsIdentifier .equals (decryptResultKeyId )) {
375
+ if (!awsKmsIdentifier .equals (decryptResponseKeyId )) {
367
376
throw new IllegalStateException (
368
377
"Received an invalid response from KMS Decrypt call: Unexpected keyId." );
369
378
}
370
379
380
+ final ByteBuffer plaintextBuffer = decryptResponse .plaintext ().asByteBuffer ();
371
381
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key.txt#2.9
372
382
// # The response's "Plaintext"'s length MUST equal the length
373
383
// # required by the requested algorithm suite otherwise the function MUST
374
384
// # collect an error.
375
- if (decryptResult . getPlaintext () .limit () != algorithm .getDataKeyLength ()) {
385
+ if (plaintextBuffer .limit () != algorithm .getDataKeyLength ()) {
376
386
throw new IllegalStateException ("Received an unexpected number of bytes from KMS" );
377
387
}
378
388
379
389
final byte [] rawKey = new byte [algorithm .getDataKeyLength ()];
380
- decryptResult . getPlaintext () .get (rawKey );
390
+ plaintextBuffer .get (rawKey );
381
391
382
392
return new DataKey <>(
383
393
new SecretKeySpec (rawKey , algorithm .getDataKeyAlgo ()),
0 commit comments