All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.amazonaws.encryptionsdk.AwsCrypto Maven / Gradle / Ivy

// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package com.amazonaws.encryptionsdk;

import com.amazonaws.encryptionsdk.exception.AwsCryptoException;
import com.amazonaws.encryptionsdk.exception.BadCiphertextException;
import com.amazonaws.encryptionsdk.internal.*;
import com.amazonaws.encryptionsdk.model.CiphertextHeaders;
import com.amazonaws.encryptionsdk.model.EncryptionMaterials;
import com.amazonaws.encryptionsdk.model.EncryptionMaterialsRequest;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Map;

/**
 * Provides the primary entry-point to the AWS Encryption SDK. All encryption and decryption
 * operations should start here. Most people will want to use either {@link
 * #encryptData(MasterKeyProvider, byte[], Map)} and {@link #decryptData(MasterKeyProvider, byte[])}
 * to encrypt/decrypt things.
 *
 * 

The core concepts (and classes) in this SDK are: * *

    *
  • {@link AwsCrypto} *
  • {@link DataKey} *
  • {@link MasterKey} *
  • {@link MasterKeyProvider} *
* *

{@link AwsCrypto} provides the primary way to encrypt/decrypt data. It can operate on * byte-arrays, streams, or {@link java.lang.String Strings}. This data is encrypted using the * specifed {@link CryptoAlgorithm} and a {@link DataKey} which is unique to each encrypted message. * This {@code DataKey} is then encrypted using one (or more) {@link MasterKey MasterKeys}. The * process is reversed on decryption with the code selecting a copy of the {@code DataKey} protected * by a usable {@code MasterKey}, decrypting the {@code DataKey}, and then decrypted the message. * *

The main way to get a {@code MasterKey} is through the use of a {@link MasterKeyProvider}. * This provides a common interface for the AwsEncryptionSdk to find and retrieve {@code * MasterKeys}. (Some {@code MasterKeys} can also be constructed directly.) * *

{@code AwsCrypto} uses the {@code MasterKeyProvider} to determine which {@code MasterKeys} * should be used to encrypt the {@code DataKeys} by calling {@link * MasterKeyProvider#getMasterKeysForEncryption(MasterKeyRequest)} . When more than one {@code * MasterKey} is returned, the first {@code MasterKeys} is used to create the {@code DataKeys} by * calling {@link MasterKey#generateDataKey(CryptoAlgorithm,java.util.Map)} . All of the other * {@code MasterKeys} are then used to re-encrypt that {@code DataKey} with {@link * MasterKey#encryptDataKey(CryptoAlgorithm,java.util.Map,DataKey)} . This list of {@link * EncryptedDataKey EncryptedDataKeys} (the same {@code DataKey} possibly encrypted multiple times) * is stored in the {@link com.amazonaws.encryptionsdk.model.CiphertextHeaders}. * *

{@code AwsCrypto} also uses the {@code MasterKeyProvider} to decrypt one of the {@link * EncryptedDataKey EncryptedDataKeys} from the header to retrieve the actual {@code DataKey} * necessary to decrypt the message. * *

Any place a {@code MasterKeyProvider} is used, a {@link MasterKey} can be used instead. The * {@code MasterKey} will behave as a {@code MasterKeyProvider} which is only capable of providing * itself. This is often useful when only one {@code MasterKey} is being used. * *

Note regarding the use of generics: This library makes heavy use of generics to provide type * safety to advanced developers. The great majority of users should be able to just use the * provided type parameters or the {@code ?} wildcard. */ @SuppressWarnings("WeakerAccess") // this is a public API public class AwsCrypto { private static final Map EMPTY_MAP = Collections.emptyMap(); // These are volatile because we allow unsynchronized writes via our setters, // and without setting volatile we could see strange results. // E.g. copying these to a local might give different values on subsequent reads from the local. // By setting them volatile we ensure that proper memory barriers are applied // to ensure things behave in a sensible manner. private volatile CryptoAlgorithm encryptionAlgorithm_ = null; private volatile int encryptionFrameSize_ = getDefaultFrameSize(); private final CommitmentPolicy commitmentPolicy_; /** * The maximum number of encrypted data keys to unwrap (resp. wrap) on decrypt (resp. encrypt), if * positive. If zero, do not limit EDKs. */ private final int maxEncryptedDataKeys_; /** * @deprecated This constructor implicitly configures the Aws Crypto client with a commitment * policy that allows reading encrypted messages without commitment values. Use {@link * AwsCrypto.Builder} and {@link AwsCrypto.Builder#withCommitmentPolicy(CommitmentPolicy)} to * explicitly build the AwsCrypto client with your desired policy. */ @Deprecated public AwsCrypto() { commitmentPolicy_ = CommitmentPolicy.ForbidEncryptAllowDecrypt; maxEncryptedDataKeys_ = CiphertextHeaders.NO_MAX_ENCRYPTED_DATA_KEYS; } private AwsCrypto(Builder builder) { if (builder.commitmentPolicy_ == null) { throw new IllegalArgumentException("Must specify a commitment policy on the client."); } // only allow to encrypt with version 1 crypto algorithms if (builder.encryptionAlgorithm_ != null && builder.encryptionAlgorithm_.getMessageFormatVersion() != 1) { throw new AwsCryptoException( "Configuration conflict. Cannot encrypt due to CommitmentPolicy " + builder.commitmentPolicy_ + " requiring only non-committed messages. Algorithm ID was " + builder.encryptionAlgorithm_ + ". See: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/troubleshooting-migration.html"); } encryptionAlgorithm_ = builder.encryptionAlgorithm_; encryptionFrameSize_ = builder.encryptionFrameSize_; commitmentPolicy_ = builder.commitmentPolicy_; maxEncryptedDataKeys_ = builder.maxEncryptedDataKeys_; } public static class Builder { private CryptoAlgorithm encryptionAlgorithm_; private int encryptionFrameSize_ = getDefaultFrameSize(); private CommitmentPolicy commitmentPolicy_; private int maxEncryptedDataKeys_ = CiphertextHeaders.NO_MAX_ENCRYPTED_DATA_KEYS; private Builder() {} private Builder(final AwsCrypto client) { encryptionAlgorithm_ = client.encryptionAlgorithm_; encryptionFrameSize_ = client.encryptionFrameSize_; commitmentPolicy_ = client.commitmentPolicy_; maxEncryptedDataKeys_ = client.maxEncryptedDataKeys_; } /** * Sets the {@link CryptoAlgorithm} to encrypt with. The Aws Crypto client will use the last * crypto algorithm set with either {@link * AwsCrypto.Builder#withEncryptionAlgorithm(CryptoAlgorithm)} or {@link * #setEncryptionAlgorithm(CryptoAlgorithm)} to encrypt with. * * @param encryptionAlgorithm The {@link CryptoAlgorithm} * @return The Builder, for method chaining */ public Builder withEncryptionAlgorithm(CryptoAlgorithm encryptionAlgorithm) { this.encryptionAlgorithm_ = encryptionAlgorithm; return this; } /** * Sets the frame size of the encrypted messages that the Aws Crypto client produces. The Aws * Crypto client will use the last frame size set with either {@link * AwsCrypto.Builder#withEncryptionFrameSize(int)} or {@link #setEncryptionFrameSize(int)}. * * @param frameSize The frame size to produce encrypted messages with. * @return The Builder, for method chaining */ public Builder withEncryptionFrameSize(int frameSize) { this.encryptionFrameSize_ = frameSize; return this; } /** * Sets the {@link CommitmentPolicy} of this Aws Crypto client. * * @param commitmentPolicy The commitment policy to enforce during encryption and decryption * @return The Builder, for method chaining */ public Builder withCommitmentPolicy(CommitmentPolicy commitmentPolicy) { this.commitmentPolicy_ = commitmentPolicy; return this; } /** * Sets the maximum number of encrypted data keys that this Aws Crypto client will wrap when * encrypting, or unwrap when decrypting, a single message. * * @param maxEncryptedDataKeys The maximum number of encrypted data keys; must be positive * @return The Builder, for method chaining */ public Builder withMaxEncryptedDataKeys(int maxEncryptedDataKeys) { if (maxEncryptedDataKeys < 1) { throw new IllegalArgumentException("maxEncryptedDataKeys must be positive"); } this.maxEncryptedDataKeys_ = maxEncryptedDataKeys; return this; } public AwsCrypto build() { return new AwsCrypto(this); } } public static Builder builder() { return new Builder(); } public Builder toBuilder() { return new Builder(this); } /** * Returns the {@link CryptoAlgorithm} to be used for encryption when none is explicitly selected. * Currently it is {@link CryptoAlgorithm#ALG_AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384}. * * @deprecated The recommended crypto algorithm may change in the future. Instead of using this * method, the Aws Crypto client will choose a sensible default for encryption if none is * specified and you are passing in either a {@link MasterKeyProvider} or a {@link * DefaultCryptoMaterialsManager} to the encrypt methods. */ @Deprecated public static CryptoAlgorithm getDefaultCryptoAlgorithm() { return CryptoAlgorithm.ALG_AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384; } /** * Returns the frame size to use for encryption when none is explicitly selected. Currently it is * 4096. */ public static int getDefaultFrameSize() { return 4096; } /** * Sets the {@link CryptoAlgorithm} to use when encrypting data. This has no impact on * decryption. */ public void setEncryptionAlgorithm(final CryptoAlgorithm alg) { // only allow to encrypt with version 1 crypto algorithms if (alg.getMessageFormatVersion() != 1) { throw new AwsCryptoException( "Configuration conflict. Cannot encrypt due to CommitmentPolicy " + commitmentPolicy_ + " requiring only non-committed messages. Algorithm ID was " + alg + ". See: https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/troubleshooting-migration.html"); } encryptionAlgorithm_ = alg; } public CryptoAlgorithm getEncryptionAlgorithm() { return encryptionAlgorithm_; } /** * Sets the framing size to use when encrypting data. This has no impact on decryption. * If {@code frameSize} is 0, then framing is disabled and the entire plaintext will be encrypted * in a single block. * *

Note that during encryption arrays of this size will be allocated. Using extremely large * frame sizes may pose compatibility issues when the decryptor is running on 32-bit systems. * Additionally, Java VM limits may set a platform-specific upper bound to frame sizes. */ public void setEncryptionFrameSize(final int frameSize) { if (frameSize < 0) { throw new IllegalArgumentException("frameSize must be non-negative"); } encryptionFrameSize_ = frameSize; } public int getEncryptionFrameSize() { return encryptionFrameSize_; } /** * Returns the best estimate for the output length of encrypting a plaintext with the provided * {@code plaintextSize} and {@code encryptionContext}. The actual ciphertext may be shorter. * *

This method is equivalent to calling {@link #estimateCiphertextSize(CryptoMaterialsManager, * int, Map)} with a {@link DefaultCryptoMaterialsManager} based on the given provider. */ public > long estimateCiphertextSize( final MasterKeyProvider provider, final int plaintextSize, final Map encryptionContext) { return estimateCiphertextSize( new DefaultCryptoMaterialsManager(provider), plaintextSize, encryptionContext); } /** * Returns the best estimate for the output length of encrypting a plaintext with the provided * {@code plaintextSize} and {@code encryptionContext}. The actual ciphertext may be shorter. */ public long estimateCiphertextSize( CryptoMaterialsManager materialsManager, final int plaintextSize, final Map encryptionContext) { EncryptionMaterialsRequest request = EncryptionMaterialsRequest.newBuilder() .setContext(encryptionContext) .setRequestedAlgorithm(getEncryptionAlgorithm()) // We're not actually encrypting any data, so don't consume any bytes from the cache's // limits. We do need to // pass /something/ though, or the cache will be bypassed (as it'll assume this is a // streaming encrypt of // unknown size). .setPlaintextSize(0) .build(); final MessageCryptoHandler cryptoHandler = new EncryptionHandler( getEncryptionFrameSize(), checkAlgorithm(materialsManager.getMaterialsForEncrypt(request))); return cryptoHandler.estimateOutputSize(plaintextSize); } /** * Returns the equivalent to calling {@link #estimateCiphertextSize(MasterKeyProvider, int, Map)} * with an empty {@code encryptionContext}. */ public > long estimateCiphertextSize( final MasterKeyProvider provider, final int plaintextSize) { return estimateCiphertextSize(provider, plaintextSize, EMPTY_MAP); } /** * Returns the equivalent to calling {@link #estimateCiphertextSize(CryptoMaterialsManager, int, * Map)} with an empty {@code encryptionContext}. */ public long estimateCiphertextSize( final CryptoMaterialsManager materialsManager, final int plaintextSize) { return estimateCiphertextSize(materialsManager, plaintextSize, EMPTY_MAP); } /** * Returns an encrypted form of {@code plaintext} that has been protected with {@link DataKey * DataKeys} that are in turn protected by {@link MasterKey MasterKeys} provided by {@code * provider}. * *

This method is equivalent to calling {@link #encryptData(CryptoMaterialsManager, byte[], * Map)} using a {@link DefaultCryptoMaterialsManager} based on the given provider. */ public > CryptoResult encryptData( final MasterKeyProvider provider, final byte[] plaintext, final Map encryptionContext) { //noinspection unchecked return (CryptoResult) encryptData(new DefaultCryptoMaterialsManager(provider), plaintext, encryptionContext); } /** * Returns an encrypted form of {@code plaintext} that has been protected with {@link DataKey * DataKeys} that are in turn protected by the given CryptoMaterialsProvider. */ public CryptoResult encryptData( CryptoMaterialsManager materialsManager, final byte[] plaintext, final Map encryptionContext) { EncryptionMaterialsRequest request = EncryptionMaterialsRequest.newBuilder() .setContext(encryptionContext) .setRequestedAlgorithm(getEncryptionAlgorithm()) .setPlaintext(plaintext) .build(); EncryptionMaterials encryptionMaterials = checkMaxEncryptedDataKeys(checkAlgorithm(materialsManager.getMaterialsForEncrypt(request))); final MessageCryptoHandler cryptoHandler = new EncryptionHandler(getEncryptionFrameSize(), encryptionMaterials); final int outSizeEstimate = cryptoHandler.estimateOutputSize(plaintext.length); final byte[] out = new byte[outSizeEstimate]; int outLen = cryptoHandler.processBytes(plaintext, 0, plaintext.length, out, 0).getBytesWritten(); outLen += cryptoHandler.doFinal(out, outLen); final byte[] outBytes = Utils.truncate(out, outLen); //noinspection unchecked return new CryptoResult(outBytes, cryptoHandler.getMasterKeys(), cryptoHandler.getHeaders()); } /** * Returns the equivalent to calling {@link #encryptData(MasterKeyProvider, byte[], Map)} with an * empty {@code encryptionContext}. */ public > CryptoResult encryptData( final MasterKeyProvider provider, final byte[] plaintext) { return encryptData(provider, plaintext, EMPTY_MAP); } /** * Returns the equivalent to calling {@link #encryptData(CryptoMaterialsManager, byte[], Map)} * with an empty {@code encryptionContext}. */ public CryptoResult encryptData( final CryptoMaterialsManager materialsManager, final byte[] plaintext) { return encryptData(materialsManager, plaintext, EMPTY_MAP); } /** * Calls {@link #encryptData(MasterKeyProvider, byte[], Map)} on the UTF-8 encoded bytes of {@code * plaintext} and base64 encodes the result. * * @deprecated Use the {@link #encryptData(MasterKeyProvider, byte[], Map)} and {@link * #decryptData(MasterKeyProvider, byte[])} APIs instead. {@code encryptString} and {@code * decryptString} work as expected if you use them together. However, to work with other * language implementations of the AWS Encryption SDK, you need to base64-decode the output of * {@code encryptString} and base64-encode the input to {@code decryptString}. These * deprecated APIs will be removed in the future. */ @Deprecated public > CryptoResult encryptString( final MasterKeyProvider provider, final String plaintext, final Map encryptionContext) { //noinspection unchecked return (CryptoResult) encryptString(new DefaultCryptoMaterialsManager(provider), plaintext, encryptionContext); } /** * Calls {@link #encryptData(CryptoMaterialsManager, byte[], Map)} on the UTF-8 encoded bytes of * {@code plaintext} and base64 encodes the result. * * @deprecated Use the {@link #encryptData(CryptoMaterialsManager, byte[], Map)} and {@link * #decryptData(CryptoMaterialsManager, byte[])} APIs instead. {@code encryptString} and * {@code decryptString} work as expected if you use them together. However, to work with * other language implementations of the AWS Encryption SDK, you need to base64-decode the * output of {@code encryptString} and base64-encode the input to {@code decryptString}. These * deprecated APIs will be removed in the future. */ @Deprecated public CryptoResult encryptString( CryptoMaterialsManager materialsManager, final String plaintext, final Map encryptionContext) { final CryptoResult ctBytes = encryptData( materialsManager, plaintext.getBytes(StandardCharsets.UTF_8), encryptionContext); return new CryptoResult<>( Utils.encodeBase64String(ctBytes.getResult()), ctBytes.getMasterKeys(), ctBytes.getHeaders()); } /** * Returns the equivalent to calling {@link #encryptString(MasterKeyProvider, String, Map)} with * an empty {@code encryptionContext}. * * @deprecated Use the {@link #encryptData(MasterKeyProvider, byte[])} and {@link * #decryptData(MasterKeyProvider, byte[])} APIs instead. {@code encryptString} and {@code * decryptString} work as expected if you use them together. However, to work with other * language implementations of the AWS Encryption SDK, you need to base64-decode the output of * {@code encryptString} and base64-encode the input to {@code decryptString}. These * deprecated APIs will be removed in the future. */ @Deprecated public > CryptoResult encryptString( final MasterKeyProvider provider, final String plaintext) { return encryptString(provider, plaintext, EMPTY_MAP); } /** * Returns the equivalent to calling {@link #encryptString(CryptoMaterialsManager, String, Map)} * with an empty {@code encryptionContext}. * * @deprecated Use the {@link #encryptData(CryptoMaterialsManager, byte[])} and {@link * #decryptData(CryptoMaterialsManager, byte[])} APIs instead. {@code encryptString} and * {@code decryptString} work as expected if you use them together. However, to work with * other language implementations of the AWS Encryption SDK, you need to base64-decode the * output of {@code encryptString} and base64-encode the input to {@code decryptString}. These * deprecated APIs will be removed in the future. */ @Deprecated public CryptoResult encryptString( final CryptoMaterialsManager materialsManager, final String plaintext) { return encryptString(materialsManager, plaintext, EMPTY_MAP); } /** * Decrypts the provided {@code ciphertext} by requesting that the {@code provider} unwrap any * usable {@link DataKey} in the ciphertext and then decrypts the ciphertext using that {@code * DataKey}. */ public > CryptoResult decryptData( final MasterKeyProvider provider, final byte[] ciphertext) { return decryptData( Utils.assertNonNull(provider, "provider"), new ParsedCiphertext(ciphertext, maxEncryptedDataKeys_)); } /** * Decrypts the provided ciphertext by delegating to the provided materialsManager to obtain the * decrypted {@link DataKey}. * * @param materialsManager the {@link CryptoMaterialsManager} to use for decryption operations. * @param ciphertext the ciphertext to attempt to decrypt. * @return the {@link CryptoResult} with the decrypted data. */ public CryptoResult decryptData( final CryptoMaterialsManager materialsManager, final byte[] ciphertext) { return decryptData( Utils.assertNonNull(materialsManager, "materialsManager"), new ParsedCiphertext(ciphertext, maxEncryptedDataKeys_)); } /** @see #decryptData(MasterKeyProvider, byte[]) */ @SuppressWarnings("unchecked") public > CryptoResult decryptData( final MasterKeyProvider provider, final ParsedCiphertext ciphertext) { Utils.assertNonNull(provider, "provider"); return (CryptoResult) decryptData(new DefaultCryptoMaterialsManager(provider), ciphertext); } /** @see #decryptData(CryptoMaterialsManager, byte[]) */ public CryptoResult decryptData( final CryptoMaterialsManager materialsManager, final ParsedCiphertext ciphertext) { Utils.assertNonNull(materialsManager, "materialsManager"); final MessageCryptoHandler cryptoHandler = DecryptionHandler.create( materialsManager, ciphertext, commitmentPolicy_, SignaturePolicy.AllowEncryptAllowDecrypt, maxEncryptedDataKeys_); final byte[] ciphertextBytes = ciphertext.getCiphertext(); final int contentLen = ciphertextBytes.length - ciphertext.getOffset(); final int outSizeEstimate = cryptoHandler.estimateOutputSize(contentLen); final byte[] out = new byte[outSizeEstimate]; final ProcessingSummary processed = cryptoHandler.processBytes(ciphertextBytes, ciphertext.getOffset(), contentLen, out, 0); if (processed.getBytesProcessed() != contentLen) { throw new BadCiphertextException( "Unable to process entire ciphertext. May have trailing data."); } int outLen = processed.getBytesWritten(); outLen += cryptoHandler.doFinal(out, outLen); final byte[] outBytes = Utils.truncate(out, outLen); //noinspection unchecked return new CryptoResult(outBytes, cryptoHandler.getMasterKeys(), cryptoHandler.getHeaders()); } /** * Base64 decodes the {@code ciphertext} prior to decryption and then treats the results as a * UTF-8 encoded string. * * @see #decryptData(MasterKeyProvider, byte[]) * @deprecated Use the {@link #decryptData(MasterKeyProvider, byte[])} and {@link * #encryptData(MasterKeyProvider, byte[], Map)} APIs instead. {@code encryptString} and * {@code decryptString} work as expected if you use them together. However, to work with * other language implementations of the AWS Encryption SDK, you need to base64-decode the * output of {@code encryptString} and base64-encode the input to {@code decryptString}. These * deprecated APIs will be removed in the future. */ @Deprecated @SuppressWarnings("unchecked") public > CryptoResult decryptString( final MasterKeyProvider provider, final String ciphertext) { return (CryptoResult) decryptString(new DefaultCryptoMaterialsManager(provider), ciphertext); } /** * Base64 decodes the {@code ciphertext} prior to decryption and then treats the results as a * UTF-8 encoded string. * * @see #decryptData(CryptoMaterialsManager, byte[]) * @deprecated Use the {@link #decryptData(CryptoMaterialsManager, byte[])} and {@link * #encryptData(CryptoMaterialsManager, byte[], Map)} APIs instead. {@code encryptString} and * {@code decryptString} work as expected if you use them together. However, to work with * other language implementations of the AWS Encryption SDK, you need to base64-decode the * output of {@code encryptString} and base64-encode the input to {@code decryptString}. These * deprecated APIs will be removed in the future. */ @Deprecated public CryptoResult decryptString( final CryptoMaterialsManager provider, final String ciphertext) { Utils.assertNonNull(provider, "provider"); final byte[] ciphertextBytes; try { ciphertextBytes = Utils.decodeBase64String(Utils.assertNonNull(ciphertext, "ciphertext")); } catch (final IllegalArgumentException ex) { throw new BadCiphertextException("Invalid base 64", ex); } final CryptoResult ptBytes = decryptData(provider, ciphertextBytes); //noinspection unchecked return new CryptoResult( new String(ptBytes.getResult(), StandardCharsets.UTF_8), ptBytes.getMasterKeys(), ptBytes.getHeaders()); } /** * Returns a {@link CryptoOutputStream} which encrypts the data prior to passing it onto the * underlying {@link OutputStream}. * * @see #encryptData(MasterKeyProvider, byte[], Map) * @see javax.crypto.CipherOutputStream */ public > CryptoOutputStream createEncryptingStream( final MasterKeyProvider provider, final OutputStream os, final Map encryptionContext) { //noinspection unchecked return (CryptoOutputStream) createEncryptingStream(new DefaultCryptoMaterialsManager(provider), os, encryptionContext); } /** * Returns a {@link CryptoOutputStream} which encrypts the data prior to passing it onto the * underlying {@link OutputStream}. * * @see #encryptData(MasterKeyProvider, byte[], Map) * @see javax.crypto.CipherOutputStream */ public CryptoOutputStream createEncryptingStream( final CryptoMaterialsManager materialsManager, final OutputStream os, final Map encryptionContext) { return new CryptoOutputStream<>( os, getEncryptingStreamHandler(materialsManager, encryptionContext)); } /** * Returns the equivalent to calling {@link #createEncryptingStream(MasterKeyProvider, * OutputStream, Map)} with an empty {@code encryptionContext}. */ public > CryptoOutputStream createEncryptingStream( final MasterKeyProvider provider, final OutputStream os) { return createEncryptingStream(provider, os, EMPTY_MAP); } /** * Returns the equivalent to calling {@link #createEncryptingStream(CryptoMaterialsManager, * OutputStream, Map)} with an empty {@code encryptionContext}. */ public CryptoOutputStream createEncryptingStream( final CryptoMaterialsManager materialsManager, final OutputStream os) { return createEncryptingStream(materialsManager, os, EMPTY_MAP); } /** * Returns a {@link CryptoInputStream} which encrypts the data after reading it from the * underlying {@link InputStream}. * * @see #encryptData(MasterKeyProvider, byte[], Map) * @see javax.crypto.CipherInputStream */ public > CryptoInputStream createEncryptingStream( final MasterKeyProvider provider, final InputStream is, final Map encryptionContext) { //noinspection unchecked return (CryptoInputStream) createEncryptingStream(new DefaultCryptoMaterialsManager(provider), is, encryptionContext); } /** * Returns a {@link CryptoInputStream} which encrypts the data after reading it from the * underlying {@link InputStream}. * * @see #encryptData(MasterKeyProvider, byte[], Map) * @see javax.crypto.CipherInputStream */ public CryptoInputStream createEncryptingStream( CryptoMaterialsManager materialsManager, final InputStream is, final Map encryptionContext) { final MessageCryptoHandler cryptoHandler = getEncryptingStreamHandler(materialsManager, encryptionContext); return new CryptoInputStream<>(is, cryptoHandler); } /** * Returns the equivalent to calling {@link #createEncryptingStream(MasterKeyProvider, * InputStream, Map)} with an empty {@code encryptionContext}. */ public > CryptoInputStream createEncryptingStream( final MasterKeyProvider provider, final InputStream is) { return createEncryptingStream(provider, is, EMPTY_MAP); } /** * Returns the equivalent to calling {@link #createEncryptingStream(CryptoMaterialsManager, * InputStream, Map)} with an empty {@code encryptionContext}. */ public CryptoInputStream createEncryptingStream( final CryptoMaterialsManager materialsManager, final InputStream is) { return createEncryptingStream(materialsManager, is, EMPTY_MAP); } /** * Returns a {@link CryptoOutputStream} which decrypts the data prior to passing it onto the * underlying {@link OutputStream}. This version only accepts unsigned messages. * * @see #decryptData(MasterKeyProvider, byte[]) * @see javax.crypto.CipherOutputStream */ public > CryptoOutputStream createUnsignedMessageDecryptingStream( final MasterKeyProvider provider, final OutputStream os) { final MessageCryptoHandler cryptoHandler = DecryptionHandler.create( provider, commitmentPolicy_, SignaturePolicy.AllowEncryptForbidDecrypt, maxEncryptedDataKeys_); return new CryptoOutputStream(os, cryptoHandler); } /** * Returns a {@link CryptoInputStream} which decrypts the data after reading it from the * underlying {@link InputStream}. This version only accepts unsigned messages. * * @see #decryptData(MasterKeyProvider, byte[]) * @see javax.crypto.CipherInputStream */ public > CryptoInputStream createUnsignedMessageDecryptingStream( final MasterKeyProvider provider, final InputStream is) { final MessageCryptoHandler cryptoHandler = DecryptionHandler.create( provider, commitmentPolicy_, SignaturePolicy.AllowEncryptForbidDecrypt, maxEncryptedDataKeys_); return new CryptoInputStream(is, cryptoHandler); } /** * Returns a {@link CryptoOutputStream} which decrypts the data prior to passing it onto the * underlying {@link OutputStream}. This version only accepts unsigned messages. * * @see #decryptData(CryptoMaterialsManager, byte[]) * @see javax.crypto.CipherOutputStream */ public CryptoOutputStream createUnsignedMessageDecryptingStream( final CryptoMaterialsManager materialsManager, final OutputStream os) { final MessageCryptoHandler cryptoHandler = DecryptionHandler.create( materialsManager, commitmentPolicy_, SignaturePolicy.AllowEncryptForbidDecrypt, maxEncryptedDataKeys_); return new CryptoOutputStream(os, cryptoHandler); } /** * Returns a {@link CryptoInputStream} which decrypts the data after reading it from the * underlying {@link InputStream}. This version only accepts unsigned messages. * * @see #encryptData(CryptoMaterialsManager, byte[], Map) * @see javax.crypto.CipherInputStream */ public CryptoInputStream createUnsignedMessageDecryptingStream( final CryptoMaterialsManager materialsManager, final InputStream is) { final MessageCryptoHandler cryptoHandler = DecryptionHandler.create( materialsManager, commitmentPolicy_, SignaturePolicy.AllowEncryptForbidDecrypt, maxEncryptedDataKeys_); return new CryptoInputStream(is, cryptoHandler); } /** * Returns a {@link CryptoOutputStream} which decrypts the data prior to passing it onto the * underlying {@link OutputStream}. * *

Note that if the encrypted message includes a trailing signature, by necessity it cannot be * verified until after the decrypted plaintext has been released to the underlying {@link * OutputStream}! This behavior can be avoided by using the non-streaming * #decryptData(MasterKeyProvider, byte[]) method instead, or * #createUnsignedMessageDecryptingStream(MasterKeyProvider, OutputStream) if you do not need to * decrypt signed messages. * * @see #decryptData(MasterKeyProvider, byte[]) * @see #createUnsignedMessageDecryptingStream(MasterKeyProvider, OutputStream) * @see javax.crypto.CipherOutputStream */ public > CryptoOutputStream createDecryptingStream( final MasterKeyProvider provider, final OutputStream os) { final MessageCryptoHandler cryptoHandler = DecryptionHandler.create( provider, commitmentPolicy_, SignaturePolicy.AllowEncryptAllowDecrypt, maxEncryptedDataKeys_); return new CryptoOutputStream(os, cryptoHandler); } /** * Returns a {@link CryptoInputStream} which decrypts the data after reading it from the * underlying {@link InputStream}. * *

Note that if the encrypted message includes a trailing signature, by necessity it cannot be * verified until after the decrypted plaintext has been produced from the {@link InputStream}! * This behavior can be avoided by using the non-streaming #decryptData(MasterKeyProvider, byte[]) * method instead, or #createUnsignedMessageDecryptingStream(MasterKeyProvider, InputStream) if * you do not need to decrypt signed messages. * * @see #decryptData(MasterKeyProvider, byte[]) * @see #createUnsignedMessageDecryptingStream(MasterKeyProvider, InputStream) * @see javax.crypto.CipherInputStream */ public > CryptoInputStream createDecryptingStream( final MasterKeyProvider provider, final InputStream is) { final MessageCryptoHandler cryptoHandler = DecryptionHandler.create( provider, commitmentPolicy_, SignaturePolicy.AllowEncryptAllowDecrypt, maxEncryptedDataKeys_); return new CryptoInputStream(is, cryptoHandler); } /** * Returns a {@link CryptoOutputStream} which decrypts the data prior to passing it onto the * underlying {@link OutputStream}. * *

Note that if the encrypted message includes a trailing signature, by necessity it cannot be * verified until after the decrypted plaintext has been released to the underlying {@link * OutputStream}! This behavior can be avoided by using the non-streaming * #decryptData(CryptoMaterialsManager, byte[]) method instead, or * #createUnsignedMessageDecryptingStream(CryptoMaterialsManager, OutputStream) if you do not need * to decrypt signed messages. * * @see #decryptData(CryptoMaterialsManager, byte[]) * @see #createUnsignedMessageDecryptingStream(CryptoMaterialsManager, OutputStream) * @see javax.crypto.CipherOutputStream */ public CryptoOutputStream createDecryptingStream( final CryptoMaterialsManager materialsManager, final OutputStream os) { final MessageCryptoHandler cryptoHandler = DecryptionHandler.create( materialsManager, commitmentPolicy_, SignaturePolicy.AllowEncryptAllowDecrypt, maxEncryptedDataKeys_); return new CryptoOutputStream(os, cryptoHandler); } /** * Returns a {@link CryptoInputStream} which decrypts the data after reading it from the * underlying {@link InputStream}. * *

Note that if the encrypted message includes a trailing signature, by necessity it cannot be * verified until after the decrypted plaintext has been produced from the {@link InputStream}! * This behavior can be avoided by using the non-streaming #decryptData(CryptoMaterialsManager, * byte[]) method instead, or #createUnsignedMessageDecryptingStream(CryptoMaterialsManager, * InputStream) if you do not need to decrypt signed messages. * * @see #decryptData(CryptoMaterialsManager, byte[]) * @see #createUnsignedMessageDecryptingStream(CryptoMaterialsManager, InputStream) * @see javax.crypto.CipherInputStream */ public CryptoInputStream createDecryptingStream( final CryptoMaterialsManager materialsManager, final InputStream is) { final MessageCryptoHandler cryptoHandler = DecryptionHandler.create( materialsManager, commitmentPolicy_, SignaturePolicy.AllowEncryptAllowDecrypt, maxEncryptedDataKeys_); return new CryptoInputStream(is, cryptoHandler); } private MessageCryptoHandler getEncryptingStreamHandler( CryptoMaterialsManager materialsManager, Map encryptionContext) { Utils.assertNonNull(materialsManager, "materialsManager"); Utils.assertNonNull(encryptionContext, "encryptionContext"); EncryptionMaterialsRequest.Builder requestBuilder = EncryptionMaterialsRequest.newBuilder() .setContext(encryptionContext) .setRequestedAlgorithm(getEncryptionAlgorithm()); return new LazyMessageCryptoHandler( info -> { // Hopefully we know the input size now, so we can pass it along to the CMM. if (info.getMaxInputSize() != -1) { requestBuilder.setPlaintextSize(info.getMaxInputSize()); } return new EncryptionHandler( getEncryptionFrameSize(), checkMaxEncryptedDataKeys( checkAlgorithm(materialsManager.getMaterialsForEncrypt(requestBuilder.build())))); }); } private EncryptionMaterials checkAlgorithm(EncryptionMaterials result) { if (encryptionAlgorithm_ != null && result.getAlgorithm() != encryptionAlgorithm_) { throw new AwsCryptoException( String.format( "Materials manager ignored requested algorithm; algorithm %s was set on AwsCrypto " + "but %s was selected", encryptionAlgorithm_, result.getAlgorithm())); } return result; } private EncryptionMaterials checkMaxEncryptedDataKeys(EncryptionMaterials materials) { if (maxEncryptedDataKeys_ > 0 && materials.getEncryptedDataKeys().size() > maxEncryptedDataKeys_) { throw new AwsCryptoException("Encrypted data keys exceed maxEncryptedDataKeys"); } return materials; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy