in src/main/java/com/amazonaws/encryptionsdk/internal/DecryptionHandler.java [750:867]
private void readHeaderFields(final CiphertextHeaders ciphertextHeaders) {
cryptoAlgo_ = ciphertextHeaders.getCryptoAlgoId();
final CiphertextType ciphertextType = ciphertextHeaders.getType();
if (ciphertextType != CiphertextType.CUSTOMER_AUTHENTICATED_ENCRYPTED_DATA) {
throw new BadCiphertextException("Invalid type in ciphertext.");
}
final byte[] messageId = ciphertextHeaders.getMessageId();
if (!commitmentPolicy_.algorithmAllowedForDecrypt(cryptoAlgo_)) {
throw new AwsCryptoException(
"Configuration conflict. "
+ "Cannot decrypt message with ID "
+ messageId
+ " due to CommitmentPolicy "
+ commitmentPolicy_
+ " requiring only committed messages. Algorithm ID was "
+ cryptoAlgo_
+ ". See: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/troubleshooting-migration.html");
}
if (maxEncryptedDataKeys_ > 0
&& ciphertextHeaders_.getEncryptedKeyBlobCount() > maxEncryptedDataKeys_) {
throw new AwsCryptoException("Ciphertext encrypted data keys exceed maxEncryptedDataKeys");
}
if (!signaturePolicy_.algorithmAllowedForDecrypt(cryptoAlgo_)) {
throw new AwsCryptoException(
"Configuration conflict. "
+ "Cannot decrypt message with ID "
+ messageId
+ " because AwsCrypto.createUnsignedMessageDecryptingStream() "
+ " accepts only unsigned messages. Algorithm ID was "
+ cryptoAlgo_
+ ".");
}
DecryptionMaterialsRequest request =
DecryptionMaterialsRequest.newBuilder()
.setAlgorithm(cryptoAlgo_)
.setEncryptionContext(ciphertextHeaders.getEncryptionContextMap())
.setReproducedEncryptionContext(reproducedEncryptionContext_)
.setEncryptedDataKeys(ciphertextHeaders.getEncryptedKeyBlobs())
.build();
DecryptionMaterialsHandler result = cmmHandler_.decryptMaterials(request, commitmentPolicy_);
encryptionContext_ = result.getEncryptionContext();
List<String> reqKeys = result.getRequiredEncryptionContextKeys();
Map<String, String> reqEncryptionContext =
encryptionContext_.entrySet().stream()
.filter(x -> reqKeys.contains(x.getKey()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
// The authenticated only encryption context is all encryption context key-value pairs where the
// key exists in Required Encryption Context Keys. It is then serialized according to the
// message header Key Value Pairs.
final byte[] authOnlyEncryptionContext =
EncryptionContextSerializer.serialize(reqEncryptionContext);
//noinspection unchecked
dataKey_ = (DataKey<K>) result.getDataKey();
PublicKey trailingPublicKey = result.getTrailingSignatureKey();
try {
decryptionKey_ =
cryptoAlgo_.getEncryptionKeyFromDataKey(dataKey_.getKey(), ciphertextHeaders);
} catch (final InvalidKeyException ex) {
throw new AwsCryptoException(ex);
}
if (cryptoAlgo_.getTrailingSignatureLength() > 0) {
Utils.assertNonNull(trailingPublicKey, "trailing public key");
TrailingSignatureAlgorithm trailingSignatureAlgorithm =
TrailingSignatureAlgorithm.forCryptoAlgorithm(cryptoAlgo_);
try {
trailingSig_ = Signature.getInstance(trailingSignatureAlgorithm.getHashAndSignAlgorithm());
trailingSig_.initVerify(trailingPublicKey);
} catch (GeneralSecurityException e) {
throw new AwsCryptoException(e);
}
} else {
if (trailingPublicKey != null) {
throw new AwsCryptoException("Unexpected trailing signature key in context");
}
trailingSig_ = null;
}
final ContentType contentType = ciphertextHeaders.getContentType();
final short nonceLen = ciphertextHeaders.getNonceLength();
final int frameLen = ciphertextHeaders.getFrameLength();
verifyHeaderIntegrity(ciphertextHeaders, authOnlyEncryptionContext);
switch (contentType) {
case FRAME:
contentCryptoHandler_ =
new FrameDecryptionHandler(
decryptionKey_, (byte) nonceLen, cryptoAlgo_, messageId, frameLen);
break;
case SINGLEBLOCK:
contentCryptoHandler_ =
new BlockDecryptionHandler(decryptionKey_, (byte) nonceLen, cryptoAlgo_, messageId);
break;
default:
// should never get here because an invalid content type is
// detected when parsing.
break;
}
ciphertextHeadersParsed_ = true;
}