< Summary

Class:Azure.Storage.Cryptography.ClientSideEncryptor
Assembly:Azure.Storage.Blobs
File(s):C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Common\src\Shared\ClientsideEncryption\ClientSideEncryptor.cs
Covered lines:0
Uncovered lines:55
Coverable lines:55
Total lines:135
Line coverage:0% (0 of 55)
Covered branches:0
Total branches:10
Branch coverage:0% (0 of 10)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.ctor(...)-0%100%
EncryptInternal()-0%0%
BufferedEncryptInternal()-0%0%
CreateKey(...)-0%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Common\src\Shared\ClientsideEncryption\ClientSideEncryptor.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System.IO;
 5using System.Security.Cryptography;
 6using System.Threading;
 7using System.Threading.Tasks;
 8using Azure.Core.Cryptography;
 9using Azure.Storage.Cryptography.Models;
 10
 11namespace Azure.Storage.Cryptography
 12{
 13    internal class ClientSideEncryptor
 14    {
 15        private readonly IKeyEncryptionKey _keyEncryptionKey;
 16        private readonly string _keyWrapAlgorithm;
 17
 018        public ClientSideEncryptor(ClientSideEncryptionOptions options)
 19        {
 020            _keyEncryptionKey = options.KeyEncryptionKey;
 021            _keyWrapAlgorithm = options.KeyWrapAlgorithm;
 022        }
 23
 24        /// <summary>
 25        /// Wraps the given read-stream in a CryptoStream and provides the metadata used to create
 26        /// that stream.
 27        /// </summary>
 28        /// <param name="plaintext">Stream to wrap.</param>
 29        /// <param name="async">Whether to wrap the content encryption key asynchronously.</param>
 30        /// <param name="cancellationToken">Cancellation token.</param>
 31        /// <returns>The wrapped stream to read from and the encryption metadata for the wrapped stream.</returns>
 32        public async Task<(Stream ciphertext, EncryptionData encryptionData)> EncryptInternal(
 33            Stream plaintext,
 34            bool async,
 35            CancellationToken cancellationToken)
 36        {
 037            if (_keyEncryptionKey == default || _keyWrapAlgorithm == default)
 38            {
 039                throw Errors.ClientSideEncryption.MissingRequiredEncryptionResources(nameof(_keyEncryptionKey), nameof(_
 40            }
 41
 042            var generatedKey = CreateKey(Constants.ClientSideEncryption.EncryptionKeySizeBits);
 043            EncryptionData encryptionData = default;
 044            Stream ciphertext = default;
 45
 046            using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider() { Key = generatedKey })
 47            {
 048                encryptionData = await EncryptionData.CreateInternalV1_0(
 049                    contentEncryptionIv: aesProvider.IV,
 050                    keyWrapAlgorithm: _keyWrapAlgorithm,
 051                    contentEncryptionKey: generatedKey,
 052                    keyEncryptionKey: _keyEncryptionKey,
 053                    async: async,
 054                    cancellationToken: cancellationToken).ConfigureAwait(false);
 55
 056                ciphertext = new CryptoStream(
 057                    plaintext,
 058                    aesProvider.CreateEncryptor(),
 059                    CryptoStreamMode.Read);
 060            }
 61
 062            return (ciphertext, encryptionData);
 063        }
 64
 65        /// <summary>
 66        /// Encrypts the given stream and provides the metadata used to encrypt. This method writes to a memory stream,
 67        /// optimized for known-size data that will already be buffered in memory.
 68        /// </summary>
 69        /// <param name="plaintext">Stream to encrypt.</param>
 70        /// <param name="async">Whether to wrap the content encryption key asynchronously.</param>
 71        /// <param name="cancellationToken">Cancellation token.</param>
 72        /// <returns>The encrypted data and the encryption metadata for the wrapped stream.</returns>
 73        public async Task<(byte[] ciphertext, EncryptionData encryptionData)> BufferedEncryptInternal(
 74            Stream plaintext,
 75            bool async,
 76            CancellationToken cancellationToken)
 77        {
 078            if (_keyEncryptionKey == default || _keyWrapAlgorithm == default)
 79            {
 080                throw Errors.ClientSideEncryption.MissingRequiredEncryptionResources(nameof(_keyEncryptionKey), nameof(_
 81            }
 82
 083            var generatedKey = CreateKey(Constants.ClientSideEncryption.EncryptionKeySizeBits);
 084            EncryptionData encryptionData = default;
 085            var ciphertext = new MemoryStream();
 086            byte[] bufferedCiphertext = default;
 87
 088            using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider() { Key = generatedKey })
 89            {
 090                encryptionData = await EncryptionData.CreateInternalV1_0(
 091                    contentEncryptionIv: aesProvider.IV,
 092                    keyWrapAlgorithm: _keyWrapAlgorithm,
 093                    contentEncryptionKey: generatedKey,
 094                    keyEncryptionKey: _keyEncryptionKey,
 095                    async: async,
 096                    cancellationToken: cancellationToken).ConfigureAwait(false);
 97
 098                var transformStream = new CryptoStream(
 099                    ciphertext,
 0100                    aesProvider.CreateEncryptor(),
 0101                    CryptoStreamMode.Write);
 102
 0103                if (async)
 104                {
 0105                    await plaintext.CopyToAsync(transformStream).ConfigureAwait(false);
 106                }
 107                else
 108                {
 0109                    plaintext.CopyTo(transformStream);
 110                }
 111
 0112                transformStream.FlushFinalBlock();
 113
 0114                bufferedCiphertext = ciphertext.ToArray();
 0115            }
 116
 0117            return (bufferedCiphertext, encryptionData);
 0118        }
 119
 120        /// <summary>
 121        /// Securely generate a key.
 122        /// </summary>
 123        /// <param name="numBits">Key size.</param>
 124        /// <returns>The generated key bytes.</returns>
 125        private static byte[] CreateKey(int numBits)
 126        {
 0127            using (var secureRng = new RNGCryptoServiceProvider())
 128            {
 0129                var buff = new byte[numBits / 8];
 0130                secureRng.GetBytes(buff);
 0131                return buff;
 132            }
 0133        }
 134    }
 135}