in src/main/java/com/amazonaws/encryptionsdk/kms/AwsKmsMrkAwareMasterKeyProvider.java [662:737]
public DataKey<AwsKmsMrkAwareMasterKey> decryptDataKey(
final CryptoAlgorithm algorithm,
final Collection<? extends EncryptedDataKey> encryptedDataKeys,
final Map<String, String> encryptionContext)
throws AwsCryptoException {
final List<Exception> exceptions = new ArrayList<>();
return encryptedDataKeys.stream()
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.9
// # The set of encrypted data keys MUST first be filtered to match this
// # master key's configuration.
.filter(
edk -> {
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.9
// # To match the encrypted data key's
// # provider ID MUST exactly match the value "aws-kms".
if (!canProvide(edk.getProviderId())) return false;
final String providerInfo =
new String(edk.getProviderInformation(), StandardCharsets.UTF_8);
final AwsKmsCmkArnInfo providerArnInfo = parseInfoFromKeyArn(providerInfo);
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.9
// # Additionally
// # each provider info MUST be a valid AWS KMS ARN (aws-kms-key-arn.md#a-
// # valid-aws-kms-arn) with a resource type of "key".
if (providerArnInfo == null || !"key".equals(providerArnInfo.getResourceType())) {
throw new IllegalStateException("Invalid provider info in message.");
}
return true;
})
.map(
edk -> {
try {
final String keyArn =
new String(edk.getProviderInformation(), StandardCharsets.UTF_8);
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.9
// # For each encrypted data key in the filtered set, one at a time, the
// # master key provider MUST call Get Master Key (aws-kms-mrk-aware-
// # master-key-provider.md#get-master-key) with the encrypted data key's
// # provider info as the AWS KMS key ARN.
// This will throw if we can't use this key for whatever reason
return getMasterKey(edk.getProviderId(), keyArn)
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.9
// # It MUST call Decrypt Data Key
// # (aws-kms-mrk-aware-master-key.md#decrypt-data-key) on this master key
// # with the input algorithm, this single encrypted data key, and the
// # input encryption context.
.decryptDataKey(algorithm, singletonList(edk), encryptionContext);
} catch (final Exception ex) {
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.9
// # If this attempt results in an error, then
// # these errors MUST be collected.
exceptions.add(ex);
return null;
}
})
/* Need to filter null because an Optional of a null is crazy.
* `findFirst` will throw if it sees `null`.
*/
.filter(Objects::nonNull)
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.9
// # If the decrypt data key call is
// # successful, then this function MUST return this result and not
// # attempt to decrypt any more encrypted data keys.
.findFirst()
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.9
// # If all the input encrypted data keys have been processed then this
// # function MUST yield an error that includes all the collected errors.
//
// = compliance/framework/aws-kms/aws-kms-mrk-aware-master-key-provider.txt#2.9
// # The output MUST be the same as the Master Key Provider Decrypt Data
// # Key (../master-key-provider-interface.md#decrypt-data-key) interface.
.orElseThrow(() -> buildCannotDecryptDksException(exceptions));
}