/******************************************************************************* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"). You may not use * this file except in compliance with the License. A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. * ***************************************************************************** * __ _ _ ___ * ( )( \/\/ )/ __) * /__\ \ / \__ \ * (_)(_) \/\/ (___/ * * AWS SDK for .NET * */ using System.IO; using Amazon.Runtime.Internal.Util; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.IO; namespace Amazon.Extensions.S3.Encryption.Util { /// /// A wrapper stream that decrypts the base stream using AES GCM algorithm as it /// is being read. /// public class AesGcmDecryptStream : DecryptStream { /// /// Constructor for initializing decryption stream /// /// Original data stream /// Key to be used for decryption /// Nonce to be used for decryption /// Tag size for the tag appended in the end of the stream /// Additional associated data public AesGcmDecryptStream(Stream baseStream, byte[] key, byte[] nonce, int tagSize, byte[] associatedText = null) : base(new CipherStream(baseStream, AesGcmUtils.CreateCipher(false, key, tagSize, nonce, associatedText), null)) { } /// /// Reads a sequence of encrypted bytes from the current stream and advances the position /// within the stream by the number of bytes read. /// /// /// An array of bytes. When this method returns, the buffer contains the specified /// byte array with the values between offset and (offset + count - 1) replaced /// by the bytes read from the current source. /// /// /// The zero-based byte offset in buffer at which to begin storing the data read /// from the current stream. /// /// /// The maximum number of bytes to be read from the current stream. /// /// /// The total number of bytes read into the buffer. This can be less than the /// number of bytes requested if that many bytes are not currently available, /// or zero (0) if the end of the stream has been reached. /// /// /// Underlying crypto exception wrapped in Amazon exception /// public override int Read(byte[] buffer, int offset, int count) { try { return BaseStream.Read(buffer, offset, count); } catch (CryptoException cryptoException) { throw new AmazonCryptoException($"Failed to decrypt: {cryptoException.Message}", cryptoException); } } #if AWS_ASYNC_API /// /// Asynchronously reads a sequence of decrypted bytes from the current stream, advances /// the position within the stream by the number of bytes read, and monitors /// cancellation requests. /// /// /// An array of bytes. When this method returns, the buffer contains the specified /// byte array with the values between offset and (offset + count - 1) replaced /// by the bytes read from the current source. /// /// /// The zero-based byte offset in buffer at which to begin storing the data read /// from the current stream. /// /// /// The maximum number of bytes to be read from the current stream. /// /// /// The token to monitor for cancellation requests. The default value is /// System.Threading.CancellationToken.None. /// /// /// A task that represents the asynchronous read operation. The value of the TResult /// parameter contains the total number of bytes read into the buffer. This can be /// less than the number of bytes requested if that many bytes are not currently /// available, or zero (0) if the end of the stream has been reached. /// /// /// Underlying crypto exception wrapped in Amazon exception /// public override async System.Threading.Tasks.Task ReadAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) { try { var readBytes = await BaseStream.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); return readBytes; } catch (CryptoException cryptoException) { throw new AmazonCryptoException($"Failed to decrypt: {cryptoException.Message}", cryptoException); } } #endif } }