public BlobDecryptStream(Stream userStream, IDictionary<string, string> metadata, long? userProvidedLength, int discardFirst, bool bufferIV, bool noPadding, BlobEncryptionPolicy policy, bool? requireEncryption)
 {
     this.userStream = userStream;
     this.metadata = metadata;
     this.userProvidedLength = userProvidedLength;
     this.discardFirst = discardFirst;
     this.encryptionPolicy = policy;
     this.bufferIV = bufferIV;
     this.noPadding = noPadding;
     this.requireEncryption = requireEncryption;
 }
Exemplo n.º 2
0
        static void Main(string[] args)
        {
            // This is standard code to interact with Blob Storage
            StorageCredentials creds = new StorageCredentials(
                ConfigurationManager.AppSettings["accountName"],
                ConfigurationManager.AppSettings["accountKey"]);
            CloudStorageAccount account = new CloudStorageAccount(creds, useHttps: true);
            CloudBlobClient client = account.CreateCloudBlobClient();
            CloudBlobContainer contain = client.GetContainerReference(ConfigurationManager.AppSettings["container"]);
            contain.CreateIfNotExists();

            // The Resolver object is used to interact with Key Vault for Azure Storage
            // This is where the GetToken method from above is used
            KeyVaultKeyResolver cloudResolver = new KeyVaultKeyResolver(GetToken);

            // Retrieve the key that you created previously
            // The IKey that is returned here is an RsaKey
            // Remember that we used the names contosokeyvault and testrsakey1
            var rsa = cloudResolver.ResolveKeyAsync("https://contosokeyvault.vault.azure.net/keys/TestRSAKey1", CancellationToken.None).GetAwaiter().GetResult();


            // Now you simply use the RSA key to encrypt by setting it in the BlobEncryptionPolicy. 
            BlobEncryptionPolicy policy = new BlobEncryptionPolicy(rsa, null);
            BlobRequestOptions options = new BlobRequestOptions() { EncryptionPolicy = policy };

            // Reference a block blob
            CloudBlockBlob blob = contain.GetBlockBlobReference("MyFile.txt");

            // Upload using the UploadFromStream method
            using (var stream = System.IO.File.OpenRead(@"C:\data\MyFile.txt"))
                blob.UploadFromStream(stream, stream.Length, null, options, null);


            // In this case we will not pass a key and only pass the resolver because 
            //  this policy will only be used for downloading / decrypting
            policy = new BlobEncryptionPolicy(null, cloudResolver);
            options = new BlobRequestOptions() { EncryptionPolicy = policy };

            using (var np = File.Open(@"C:\data\MyFileDecrypted.txt", FileMode.Create))
                blob.DownloadToStream(np, null, options, null);
        }
Exemplo n.º 3
0
        //protected CancellationToken cancellationToken;

        public LargeDownloadToFileSettings(CloudBlob blob, string filePath, FileMode fileMode, long?offset, long?length, int parallelIOCount = 16,
                                           long maxRangeSizeInBytes  = 100 *1024 *1024, TimeSpan?maxExecutionTimePerRange = null, IRetryPolicy retryPolicy = null, BlobEncryptionPolicy encryptionPolicy = null, bool?requireEncryption = null,
                                           LocationMode?locationMode = null)
        {
            //CommonUtility.AssertNotNull("blob", blob);
            //CommonUtility.AssertNotNull("filePath", filePath);
            //CommonUtility.AssertInBounds("parallelIOCount", parallelIOCount, 1, int.MaxValue);

            this.Blob                     = blob;
            this.FilePath                 = filePath;
            this.FileMode                 = fileMode;
            this.Offset                   = offset;
            this.Length                   = length;
            this.ParallelIOCount          = parallelIOCount;
            this.MaxRangeSizeInBytes      = maxRangeSizeInBytes;
            this.MaxExecutionTimePerRange = maxExecutionTimePerRange;
            this.RetryPolicy              = retryPolicy;
            this.EncryptionPolicy         = encryptionPolicy;
            this.RequireEncryption        = requireEncryption;
            this.LocationMode             = locationMode;
        }
        private void DoCloudBlobEncryption(BlobType type, bool partial)
        {
            CloudBlobContainer container = GetRandomContainerReference();

            try
            {
                container.Create();
                int size = 5 * 1024 * 1024;
                byte[] buffer = GetRandomBuffer(size);
                
                if (partial)
                {
                    size = 2 * 1024 * 1024;
                }

                ICloudBlob blob;
                if (type == BlobType.BlockBlob)
                {
                    blob = container.GetBlockBlobReference("blockblob");
                }
                else if (type == BlobType.PageBlob)
                {
                    blob = container.GetPageBlobReference("pageblob");
                }
                else
                {
                    blob = container.GetAppendBlobReference("appendblob");
                }

                // Create the Key to be used for wrapping.
                SymmetricKey aesKey = new SymmetricKey("symencryptionkey");

                // Create the resolver to be used for unwrapping.
                DictionaryKeyResolver resolver = new DictionaryKeyResolver();
                resolver.Add(aesKey);

                // Create the encryption policy to be used for upload.
                BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(aesKey, null);

                // Set the encryption policy on the request options.
                BlobRequestOptions uploadOptions = new BlobRequestOptions() { EncryptionPolicy = uploadPolicy };

                MemoryStream stream;
                // Upload the encrypted contents to the blob.
                using (stream = new MemoryStream(buffer))
                {
                    blob.UploadFromStream(stream, size, null, uploadOptions, null);

                    // Ensure that the user stream is open.
                    Assert.IsTrue(stream.CanSeek);
                }

                // Download the encrypted blob.
                // Create the decryption policy to be used for download. There is no need to specify the
                // key when the policy is only going to be used for downloads. Resolver is sufficient.
                BlobEncryptionPolicy downloadPolicy = new BlobEncryptionPolicy(null, resolver);

                // Set the decryption policy on the request options.
                BlobRequestOptions downloadOptions = new BlobRequestOptions() { EncryptionPolicy = downloadPolicy };

                // Download and decrypt the encrypted contents from the blob.
                MemoryStream outputStream = new MemoryStream();
                blob.DownloadToStream(outputStream, null, downloadOptions, null);

                // Ensure that the user stream is open.
                outputStream.Seek(0, SeekOrigin.Begin);

                // Compare that the decrypted contents match the input data.
                byte[] outputArray = outputStream.ToArray();
                TestHelper.AssertBuffersAreEqualUptoIndex(outputArray, buffer, size - 1);
            }
            finally
            {
                container.DeleteIfExists();
            }
        }
        private void DoBlobEncryptedWriteStreamTestAPM(BlobType type)
        {
            byte[] buffer = GetRandomBuffer(8 * 1024);

            CloudBlobContainer container = GetRandomContainerReference();
            try
            {
                container.Create();

                ICloudBlob blob = null;

                // Create the Key to be used for wrapping.
                SymmetricKey aesKey = new SymmetricKey("symencryptionkey");

                // Create the encryption policy to be used for upload.
                BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(aesKey, null);

                // Set the encryption policy on the request options.
                BlobRequestOptions uploadOptions = new BlobRequestOptions() { EncryptionPolicy = uploadPolicy };

                OperationContext opContext = new OperationContext();
                CloudBlobStream blobStream = null;
                using (AutoResetEvent waitHandle = new AutoResetEvent(false))
                {
                    IAsyncResult result;
                    if (type == BlobType.BlockBlob)
                    {
                        blob = container.GetBlockBlobReference("blob1");
                        blob.StreamWriteSizeInBytes = 16 * 1024;
                        result = ((CloudBlockBlob)blob).BeginOpenWrite(null, uploadOptions, opContext, ar => waitHandle.Set(), null);
                        waitHandle.WaitOne();
                        blobStream = ((CloudBlockBlob)blob).EndOpenWrite(result);
                    }
                    else if (type == BlobType.PageBlob)
                    {
                        blob = container.GetPageBlobReference("blob1");
                        blob.StreamWriteSizeInBytes = 16 * 1024;
                        result = ((CloudPageBlob)blob).BeginOpenWrite(40 * 1024, null, uploadOptions, opContext, ar => waitHandle.Set(), null);
                        waitHandle.WaitOne();
                        blobStream = ((CloudPageBlob)blob).EndOpenWrite(result);
                    }
                    else
                    {
                        blob = container.GetAppendBlobReference("blob1");
                        blob.StreamWriteSizeInBytes = 16 * 1024;
                        result = ((CloudAppendBlob)blob).BeginOpenWrite(true, null, uploadOptions, opContext, ar => waitHandle.Set(), null);
                        waitHandle.WaitOne();
                        blobStream = ((CloudAppendBlob)blob).EndOpenWrite(result);
                    }
                }

                using (MemoryStream wholeBlob = new MemoryStream())
                {
                    using (blobStream)
                    {
                        using (AutoResetEvent waitHandle = new AutoResetEvent(false))
                        {
                            IAsyncResult result;
                            for (int i = 0; i < 3; i++)
                            {
                                result = blobStream.BeginWrite(
                                    buffer,
                                    0,
                                    buffer.Length,
                                    ar => waitHandle.Set(),
                                    null);
                                waitHandle.WaitOne();
                                blobStream.EndWrite(result);
                                wholeBlob.Write(buffer, 0, buffer.Length);
                            }

                            // Append and Page blobs have one extra call due to create.
                            if (type == BlobType.BlockBlob)
                            {
                                Assert.AreEqual(1, opContext.RequestResults.Count);
                            }
                            else
                            {
                                Assert.AreEqual(2, opContext.RequestResults.Count);
                            }

                            result = blobStream.BeginWrite(
                                buffer,
                                0,
                                buffer.Length,
                                ar => waitHandle.Set(),
                                null);
                            waitHandle.WaitOne();
                            blobStream.EndWrite(result);
                            wholeBlob.Write(buffer, 0, buffer.Length);

                            result = blobStream.BeginWrite(
                                buffer,
                                0,
                                buffer.Length,
                                ar => waitHandle.Set(),
                                null);
                            waitHandle.WaitOne();
                            blobStream.EndWrite(result);
                            wholeBlob.Write(buffer, 0, buffer.Length);

                            // Append and Page blobs have one extra call due to create.
                            if (type == BlobType.BlockBlob)
                            {
                                Assert.AreEqual(2, opContext.RequestResults.Count);
                            }
                            else
                            {
                                Assert.AreEqual(3, opContext.RequestResults.Count);
                            }

                            result = blobStream.BeginCommit(
                                ar => waitHandle.Set(),
                                null);
                            waitHandle.WaitOne();
                            blobStream.EndCommit(result);

                            Assert.AreEqual(4, opContext.RequestResults.Count);
                        }
                    }

                    Assert.AreEqual(4, opContext.RequestResults.Count);

                    using (MemoryStream downloadedBlob = new MemoryStream())
                    {
                        blob.DownloadToStream(downloadedBlob, null, uploadOptions);
                        TestHelper.AssertStreamsAreEqual(wholeBlob, downloadedBlob);
                    }
                }
            }
            finally
            {
                container.DeleteIfExists();
            }
        }
        public void CloudBlockBlobValidateEncryptionAPM()
        {
            CloudBlobContainer container = GetRandomContainerReference();

            try
            {
                container.Create();
                int size = 5 * 1024 * 1024;
                byte[] buffer = GetRandomBuffer(size);

                CloudBlockBlob blob = container.GetBlockBlobReference("blob1");

                // Create the Key to be used for wrapping.
                SymmetricKey aesKey = new SymmetricKey("symencryptionkey");

                // Create the encryption policy to be used for upload.
                BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(aesKey, null);

                // Set the encryption policy on the request options.
                BlobRequestOptions uploadOptions = new BlobRequestOptions() { EncryptionPolicy = uploadPolicy };

                // Upload the encrypted contents to the blob.
                MemoryStream stream = new MemoryStream(buffer);
                using (AutoResetEvent waitHandle = new AutoResetEvent(false))
                {
                    ICancellableAsyncResult result = blob.BeginUploadFromStream(
                                        stream, size, null, uploadOptions, null, ar => waitHandle.Set(), null);
                    waitHandle.WaitOne();
                    blob.EndUploadFromStream(result);
                }

                // Encrypt locally.
                CryptoStream encryptedStream;
                using (AesCryptoServiceProvider myAes = new AesCryptoServiceProvider())
                {
                    string metadata = blob.Metadata[Constants.EncryptionConstants.BlobEncryptionData];
                    BlobEncryptionData encryptionData = JsonConvert.DeserializeObject<BlobEncryptionData>(metadata);
                    myAes.IV = encryptionData.ContentEncryptionIV;
                    myAes.Key = aesKey.UnwrapKeyAsync(encryptionData.WrappedContentKey.EncryptedKey, encryptionData.WrappedContentKey.Algorithm, CancellationToken.None).Result;

                    stream.Seek(0, SeekOrigin.Begin);
                    encryptedStream = new CryptoStream(stream, myAes.CreateEncryptor(), CryptoStreamMode.Read);
                }

                // Download the encrypted blob.
                MemoryStream outputStream = new MemoryStream();

                using (AutoResetEvent waitHandle = new AutoResetEvent(false))
                {
                    ICancellableAsyncResult result = blob.BeginDownloadToStream(outputStream, ar => waitHandle.Set(), null);
                    waitHandle.WaitOne();
                    blob.EndDownloadToStream(result);
                }

                outputStream.Seek(0, SeekOrigin.Begin);
                for (int i = 0; i < outputStream.Length; i++)
                {
                    Assert.AreEqual(encryptedStream.ReadByte(), outputStream.ReadByte());
                }
            }
            finally
            {
                container.DeleteIfExists();
            }
        }
        private void ValidateRangeDecryption(BlobType type, int blobSize, int? blobOffset, int? length, int? verifyLength = null)
        {
            CloudBlobContainer container = GetRandomContainerReference();

            try
            {
                container.Create();
                byte[] buffer = GetRandomBuffer(blobSize);

                ICloudBlob blob = GetCloudBlobReference(type, container);

                // Create the Key to be used for wrapping.
                SymmetricKey aesKey = new SymmetricKey("symencryptionkey");

                // Create the encryption policy to be used for upload.
                BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(aesKey, null);

                // Set the encryption policy on the request options.
                BlobRequestOptions options = new BlobRequestOptions() { EncryptionPolicy = uploadPolicy };

                // Upload the encrypted contents to the blob.
                MemoryStream stream = new MemoryStream(buffer);
                blob.UploadFromStream(stream, blobSize, null, options, null);

                // Download a range in the encrypted blob.
                MemoryStream outputStream = new MemoryStream();
                blob.DownloadRangeToStream(outputStream, blobOffset, length, null, options, null);

                outputStream.Seek(0, SeekOrigin.Begin);

                if (length.HasValue)
                {
                    if (verifyLength.HasValue)
                    {
                        Assert.AreEqual(verifyLength.Value, outputStream.Length);
                    }
                    else
                    {
                        Assert.AreEqual(length.Value, outputStream.Length);
                    }
                }

                // Compare that the decrypted contents match the input data.
                byte[] outputArray = outputStream.ToArray();
                
                for (int i = 0; i < outputArray.Length; i++)
                {
                    int bufferOffset = (int) (blobOffset.HasValue ? blobOffset : 0);
                    Assert.AreEqual(buffer[bufferOffset + i], outputArray[i]);
                }
            }
            finally
            {
                container.DeleteIfExists();
            }
        }
        public void CloudBlobEncryptionWithText()
        {
            CloudBlobContainer container = GetRandomContainerReference();

            try
            {
                container.Create();
                string data = "String data";

                CloudBlockBlob blob = container.GetBlockBlobReference("blockblob");

                // Create the Key to be used for wrapping.
                SymmetricKey aesKey = new SymmetricKey("symencryptionkey");

                // Create the resolver to be used for unwrapping.
                DictionaryKeyResolver resolver = new DictionaryKeyResolver();
                resolver.Add(aesKey);

                // Create the encryption policy to be used for upload.
                BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(aesKey, null);

                // Set the encryption policy on the request options.
                BlobRequestOptions uploadOptions = new BlobRequestOptions() { EncryptionPolicy = uploadPolicy };

                // Upload the encrypted contents to the blob.
                blob.UploadText(data, null, null, uploadOptions, null);

                // Download the encrypted blob.
                // Create the decryption policy to be used for download. There is no need to specify the
                // key when the policy is only going to be used for downloads. Resolver is sufficient.
                BlobEncryptionPolicy downloadPolicy = new BlobEncryptionPolicy(null, resolver);

                // Set the decryption policy on the request options.
                BlobRequestOptions downloadOptions = new BlobRequestOptions() { EncryptionPolicy = downloadPolicy };

                // Download and decrypt the encrypted contents from the blob.
                string outputData = blob.DownloadText(null, null, downloadOptions, null);

                // Compare that the decrypted contents match the input data.
                Assert.AreEqual(data, outputData);
            }
            finally
            {
                container.DeleteIfExists();
            }
        }
        private static void DoCloudBlockBlobEncryptionValidateWrappers(IKey key, DictionaryKeyResolver keyResolver)
        {
            CloudBlobContainer container = GetRandomContainerReference();

            try
            {
                container.Create();
                int size = 5 * 1024 * 1024;
                byte[] buffer = GetRandomBuffer(size);

                CloudBlockBlob blob = container.GetBlockBlobReference("blob1");

                // Create the encryption policy to be used for upload.
                BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(key, null);

                // Set the encryption policy on the request options.
                BlobRequestOptions uploadOptions = new BlobRequestOptions() { EncryptionPolicy = uploadPolicy };

                MemoryStream stream;
                // Upload the encrypted contents to the blob.
                using (stream = new MemoryStream(buffer))
                {
                    blob.UploadFromStream(stream, size, null, uploadOptions, null);

                    // Ensure that the user stream is open.
                    Assert.IsTrue(stream.CanSeek);
                }

                // Download the encrypted blob.
                // Create the decryption policy to be used for download. There is no need to specify the encryption mode 
                // and the key wrapper when the policy is only going to be used for downloads.
                BlobEncryptionPolicy downloadPolicy = new BlobEncryptionPolicy(null, keyResolver);

                // Set the decryption policy on the request options.
                BlobRequestOptions downloadOptions = new BlobRequestOptions() { EncryptionPolicy = downloadPolicy };

                // Download and decrypt the encrypted contents from the blob.
                MemoryStream outputStream = new MemoryStream();
                blob.DownloadToStream(outputStream, null, downloadOptions, null);

                // Ensure that the user stream is open.
                outputStream.Seek(0, SeekOrigin.Begin);

                // Compare that the decrypted contents match the input data.
                byte[] outputArray = outputStream.ToArray();
                TestHelper.AssertBuffersAreEqual(outputArray, buffer);
            }
            finally
            {
                container.DeleteIfExists();
            }
        }
Exemplo n.º 10
0
        static void Main(string[] args)
        {
            Console.WriteLine("Blob encryption with Key Vault integration");
            Console.WriteLine();

            // Get the key ID from App.config if it exists.
            string keyID = CloudConfigurationManager.GetSetting("KeyID");

            // If no key ID was specified, we will create a new secret in Key Vault.
            // To create a new secret, this client needs full permission to Key Vault secrets.
            // Once the secret is created, its ID can be added to App.config. Once this is done,
            // this client only needs read access to secrets.
            if (string.IsNullOrEmpty(keyID))
            {
                Console.WriteLine("No secret specified in App.config.");
                Console.WriteLine("Please enter the name of a new secret to create in Key Vault.");
                Console.WriteLine("WARNING: This will delete any existing secret with the same name.");
                Console.Write("Name of the new secret to create [{0}]: ", DefaultSecretName);
                string newSecretName = Console.ReadLine().Trim();

                if (string.IsNullOrEmpty(newSecretName))
                {
                    newSecretName = DefaultSecretName;
                }

                // Although it is possible to use keys (rather than secrets) stored in Key Vault, this prevents caching.
                // Therefore it is recommended to use secrets along with a caching resolver (see below).
                keyID = EncryptionShared.KeyVaultUtility.SetUpKeyVaultSecret(newSecretName);

                Console.WriteLine();
                Console.WriteLine("Created a secret with ID: {0}", keyID);
                Console.WriteLine("Copy the secret ID to App.config to reuse.");
                Console.WriteLine();
            }

            // Retrieve storage account information from connection string
            // How to create a storage connection string - https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/
            CloudStorageAccount storageAccount = EncryptionShared.Utility.CreateStorageAccountFromConnectionString();

            CloudBlobClient client = storageAccount.CreateCloudBlobClient();
            CloudBlobContainer container = client.GetContainerReference(DemoContainer + Guid.NewGuid().ToString("N"));

            // Construct a resolver capable of looking up keys and secrets stored in Key Vault.
            KeyVaultKeyResolver cloudResolver = new KeyVaultKeyResolver(EncryptionShared.KeyVaultUtility.GetAccessToken);

            // To demonstrate how multiple different types of key can be used, we also create a local key and resolver.
            // This key is temporary and won't be persisted.
            RsaKey rsaKey = new RsaKey("rsakey");
            LocalResolver resolver = new LocalResolver();
            resolver.Add(rsaKey);

            // If there are multiple key sources like Azure Key Vault and local KMS, set up an aggregate resolver as follows.
            // This helps users to define a plug-in model for all the different key providers they support.
            AggregateKeyResolver aggregateResolver = new AggregateKeyResolver()
                .Add(resolver)
                .Add(cloudResolver);

            // Set up a caching resolver so the secrets can be cached on the client. This is the recommended usage
            // pattern since the throttling targets for Storage and Key Vault services are orders of magnitude
            // different.
            CachingKeyResolver cachingResolver = new CachingKeyResolver(2, aggregateResolver);

            // Create a key instance corresponding to the key ID. This will cache the secret.
            IKey cloudKey = cachingResolver.ResolveKeyAsync(keyID, CancellationToken.None).GetAwaiter().GetResult();

            try
            {
                container.Create();
                int size = 5 * 1024 * 1024;
                byte[] buffer = new byte[size];

                Random rand = new Random();
                rand.NextBytes(buffer);

                // The first blob will use the key stored in Azure Key Vault.
                CloudBlockBlob blob = container.GetBlockBlobReference("blockblob1");

                // Create the encryption policy using the secret stored in Azure Key Vault to be used for upload.
                BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(cloudKey, null);

                // Set the encryption policy on the request options.
                BlobRequestOptions uploadOptions = new BlobRequestOptions() { EncryptionPolicy = uploadPolicy };

                Console.WriteLine("Uploading the 1st encrypted blob.");

                // Upload the encrypted contents to the blob.
                using (MemoryStream stream = new MemoryStream(buffer))
                {
                    blob.UploadFromStream(stream, size, null, uploadOptions, null);
                }

                // Download the encrypted blob.
                BlobEncryptionPolicy downloadPolicy = new BlobEncryptionPolicy(null, cachingResolver);

                // Set the decryption policy on the request options.
                BlobRequestOptions downloadOptions = new BlobRequestOptions() { EncryptionPolicy = downloadPolicy };

                Console.WriteLine("Downloading the 1st encrypted blob.");

                // Download and decrypt the encrypted contents from the blob.
                using (MemoryStream outputStream = new MemoryStream())
                {
                    blob.DownloadToStream(outputStream, null, downloadOptions, null);
                }

                // Upload second blob using the local key.
                blob = container.GetBlockBlobReference("blockblob2");

                // Create the encryption policy using the local key.
                uploadPolicy = new BlobEncryptionPolicy(rsaKey, null);

                // Set the encryption policy on the request options.
                uploadOptions = new BlobRequestOptions() { EncryptionPolicy = uploadPolicy };

                Console.WriteLine("Uploading the 2nd encrypted blob.");

                // Upload the encrypted contents to the blob.
                using (MemoryStream stream = new MemoryStream(buffer))
                {
                    blob.UploadFromStream(stream, size, null, uploadOptions, null);
                }

                // Download the encrypted blob. The same policy and options created before can be used because the aggregate resolver contains both
                // resolvers and will pick the right one based on the key ID stored in blob metadata on the service.
                Console.WriteLine("Downloading the 2nd encrypted blob.");

                // Download and decrypt the encrypted contents from the blob.
                using (MemoryStream outputStream = new MemoryStream())
                {
                    blob.DownloadToStream(outputStream, null, downloadOptions, null);
                }

                Console.WriteLine("Press enter key to exit");
                Console.ReadLine();
            }
            finally
            {
                container.DeleteIfExists();
            }
        }
        public void CloudBlobEncryptionOpenWriteStreamAPMWithAccessCondition()
        {
            CloudBlobContainer container = GetRandomContainerReference();

            try
            {
                int size = (int)(1 * Constants.MB);
                container.Create();
                byte[] buffer = GetRandomBuffer(size);

                CloudBlockBlob blob = container.GetBlockBlobReference("blockblob");
                blob.StreamWriteSizeInBytes = (int)(4 * Constants.MB);

                blob.UploadText("Sample initial text");

                // Create the Key to be used for wrapping.
                SymmetricKey aesKey = new SymmetricKey("symencryptionkey");

                // Create the resolver to be used for unwrapping.
                DictionaryKeyResolver resolver = new DictionaryKeyResolver();
                resolver.Add(aesKey);

                // Create the encryption policy to be used for upload.
                BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(aesKey, null);

                // Set the encryption policy on the request options.
                BlobRequestOptions uploadOptions = new BlobRequestOptions()
                {
                    EncryptionPolicy = uploadPolicy,
                    RequireEncryption = true
                };

                AccessCondition accessCondition = AccessCondition.GenerateIfMatchCondition(blob.Properties.ETag);

                using (MemoryStream stream = new NonSeekableMemoryStream(buffer))
                {
                    using (AutoResetEvent waitHandle = new AutoResetEvent(false))
                    {
                        blob.EndUploadFromStream(blob.BeginUploadFromStream(
                                            stream, size, accessCondition, uploadOptions, null, ar => waitHandle.Set(), null));
                    }
                }

                // Download the encrypted blob.
                // Create the decryption policy to be used for download. There is no need to specify the
                // key when the policy is only going to be used for downloads. Resolver is sufficient.
                BlobEncryptionPolicy downloadPolicy = new BlobEncryptionPolicy(null, resolver);

                // Set the decryption policy on the request options.
                BlobRequestOptions downloadOptions = new BlobRequestOptions()
                {
                    EncryptionPolicy = downloadPolicy,
                    RequireEncryption = true
                };

                // Download and decrypt the encrypted contents from the blob.
                MemoryStream outputStream = new MemoryStream();
                blob.DownloadToStream(outputStream, null, downloadOptions, null);

                // Ensure that the user stream is open.
                outputStream.Seek(0, SeekOrigin.Begin);

                // Compare that the decrypted contents match the input data.
                byte[] outputArray = outputStream.ToArray();
                TestHelper.AssertBuffersAreEqualUptoIndex(outputArray, buffer, size - 1);
            }
            finally
            {
                container.DeleteIfExists();
            }
        }
        private void DoCloudBlobEncryptionWithStrictMode(BlobType type)
        {
            CloudBlobContainer container = GetRandomContainerReference();

            try
            {
                container.Create();
                int size = 5 * 1024 * 1024;
                byte[] buffer = GetRandomBuffer(size);

                ICloudBlob blob;

                if (type == BlobType.BlockBlob)
                {
                    blob = container.GetBlockBlobReference("blob1");
                }
                else
                {
                    blob = container.GetPageBlobReference("blob1");
                }

                // Create the Key to be used for wrapping.
                SymmetricKey aesKey = new SymmetricKey("symencryptionkey");

                // Create the resolver to be used for unwrapping.
                DictionaryKeyResolver resolver = new DictionaryKeyResolver();
                resolver.Add(aesKey);

                // Create the encryption policy to be used for upload.
                BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(aesKey, null);

                // Set the encryption policy on the request options.
                BlobRequestOptions uploadOptions = new BlobRequestOptions() { EncryptionPolicy = uploadPolicy };

                // Set RequireEncryption flag to true.
                uploadOptions.RequireEncryption = true;

                // Upload an encrypted blob with the policy set.
                MemoryStream stream = new MemoryStream(buffer);
                blob.UploadFromStream(stream, size, null, uploadOptions, null);

                // Upload the blob when RequireEncryption is true and no policy is set. This should throw an error.
                uploadOptions.EncryptionPolicy = null;

                stream = new MemoryStream(buffer);
                TestHelper.ExpectedException<InvalidOperationException>( 
                    () => blob.UploadFromStream(stream, size, null, uploadOptions, null),
                    "Not specifying a policy when RequireEnryption is set to true should throw.");

                // Create the encryption policy to be used for download.
                BlobEncryptionPolicy downloadPolicy = new BlobEncryptionPolicy(null, resolver);

                // Set the encryption policy on the request options.
                BlobRequestOptions downloadOptions = new BlobRequestOptions() { EncryptionPolicy = downloadPolicy };

                // Set RequireEncryption flag to true.
                downloadOptions.RequireEncryption = true;

                // Download the encrypted blob.
                MemoryStream outputStream = new MemoryStream();
                blob.DownloadToStream(outputStream, null, downloadOptions, null);

                blob.Metadata.Clear();

                // Upload a plain text blob.
                stream = new MemoryStream(buffer);
                blob.UploadFromStream(stream, size);

                // Try to download an encrypted blob with RequireEncryption set to true. This should throw.
                outputStream = new MemoryStream();
                TestHelper.ExpectedException<StorageException>(
                    () => blob.DownloadToStream(outputStream, null, downloadOptions, null),
                    "Downloading with RequireEncryption set to true and no metadata on the service should fail.");

                // Set RequireEncryption to false and download.
                downloadOptions.RequireEncryption = false;
                blob.DownloadToStream(outputStream, null, downloadOptions, null);
            }
            finally
            {
                container.DeleteIfExists();
            }
        }
        private static void DoCloudBlobEncryptionAPM(BlobType type, bool partial)
        {
            CloudBlobContainer container = GetRandomContainerReference();

            try
            {
                container.Create();
                int size = 5 * 1024 * 1024;
                byte[] buffer = GetRandomBuffer(size);

                if (partial)
                {
                    size = 2 * 1024 * 1024;
                }

                ICloudBlob blob = GetCloudBlobReference(type, container);

                // Create the Key to be used for wrapping.
                SymmetricKey aesKey = new SymmetricKey("symencryptionkey");

                // Create the resolver to be used for unwrapping.
                DictionaryKeyResolver resolver = new DictionaryKeyResolver();
                resolver.Add(aesKey);

                // Create the encryption policy to be used for upload.
                BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(aesKey, null);

                // Set the encryption policy on the request options.
                BlobRequestOptions uploadOptions = new BlobRequestOptions() { EncryptionPolicy = uploadPolicy };

                MemoryStream stream;
                // Upload the encrypted contents to the blob.
                using (stream = new MemoryStream(buffer))
                {
                    using (AutoResetEvent waitHandle = new AutoResetEvent(false))
                    {
                        ICancellableAsyncResult result = blob.BeginUploadFromStream(
                                            stream, size, null, uploadOptions, null, ar => waitHandle.Set(), null);
                        waitHandle.WaitOne();
                        blob.EndUploadFromStream(result);
                    }

                    // Ensure that the user stream is open.
                    Assert.IsTrue(stream.CanSeek);
                }

                // Download the encrypted blob.
                // Create the decryption policy to be used for download. There is no need to specify the encryption mode 
                // and the key wrapper when the policy is only going to be used for downloads.
                BlobEncryptionPolicy downloadPolicy = new BlobEncryptionPolicy(null, resolver);

                // Set the decryption policy on the request options.
                BlobRequestOptions downloadOptions = new BlobRequestOptions() { EncryptionPolicy = downloadPolicy };

                // Download and decrypt the encrypted contents from the blob.
                MemoryStream outputStream = new MemoryStream();
                using (AutoResetEvent waitHandle = new AutoResetEvent(false))
                {
                    ICancellableAsyncResult result = blob.BeginDownloadToStream(outputStream, null, downloadOptions, null, ar => waitHandle.Set(), null);
                    waitHandle.WaitOne();
                    blob.EndDownloadToStream(result);
                }

                // Ensure that the user stream is open.
                outputStream.Seek(0, SeekOrigin.Begin);

                // Compare that the decrypted contents match the input data.
                byte[] outputArray = outputStream.ToArray();
                TestHelper.AssertBuffersAreEqualUptoIndex(outputArray, buffer, size - 1);
            }
            finally
            {
                container.DeleteIfExists();
            }
        }
        public void BlobUploadWorksWithDefaultRequestOptions()
        {
            CloudBlobContainer container = GetRandomContainerReference();

            byte[] buffer = GetRandomBuffer(16 * 1024);

            // Create the Key to be used for wrapping.
            SymmetricKey aesKey = new SymmetricKey("symencryptionkey");

            // Create the encryption policy to be used for upload.
            BlobEncryptionPolicy policy = new BlobEncryptionPolicy(aesKey, null);

            // Set the encryption policy on the request options.
            BlobRequestOptions options = new BlobRequestOptions() { EncryptionPolicy = policy };

            // Set default request options
            container.ServiceClient.DefaultRequestOptions = options;

            try
            {
                container.Create();

                using (MemoryStream stream = new MemoryStream(buffer))
                {
                    CloudBlockBlob blockBlob = container.GetBlockBlobReference("blockblob");
                    blockBlob.UploadFromStream(stream, buffer.Length);
                }
            }
            finally
            {
                container.DeleteIfExists();
            }
        }
        public void BlobUpdateShouldThrowWithEncryption()
        {
            CloudBlobContainer container = GetRandomContainerReference();

            try
            {
                byte[] buffer = GetRandomBuffer(16 * 1024);

                // Create the Key to be used for wrapping.
                SymmetricKey aesKey = new SymmetricKey("symencryptionkey");

                // Create the encryption policy to be used for upload.
                BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(aesKey, null);

                // Set the encryption policy on the request options.
                BlobRequestOptions uploadOptions = new BlobRequestOptions() { EncryptionPolicy = uploadPolicy };

                using (MemoryStream stream = new MemoryStream(buffer))
                {
                    CloudBlockBlob blockBlob = container.GetBlockBlobReference("blockblob");
                    TestHelper.ExpectedException<InvalidOperationException>(
                        () => blockBlob.PutBlock(Convert.ToBase64String(Guid.NewGuid().ToByteArray()), stream, null, null, uploadOptions, null),
                        "PutBlock does not support encryption.");

                    CloudAppendBlob appendBlob = container.GetAppendBlobReference("appendblob");
                    TestHelper.ExpectedException<InvalidOperationException>(
                        () => appendBlob.AppendBlock(stream, null, null, uploadOptions, null),
                        "AppendBlock does not support encryption.");

                    CloudPageBlob pageBlob = container.GetPageBlobReference("pageblob");
                    TestHelper.ExpectedException<InvalidOperationException>(
                        () => pageBlob.WritePages(stream, 0, null, null, uploadOptions, null),
                        "WritePages does not support encryption.");

                    TestHelper.ExpectedException<InvalidOperationException>(
                        () => pageBlob.ClearPages(0, 512, null, uploadOptions, null),
                        "ClearPages does not support encryption.");
                }
            }
            finally
            {
                container.DeleteIfExists();
            }
        }
        private void CountOperationsHelper(int size, int targetUploadOperations, bool streamSeekable, bool isAPM, BlobRequestOptions options)
        {
            CloudBlobContainer container = GetRandomContainerReference();

            try
            {
                container.Create();
                byte[] buffer = GetRandomBuffer(size);

                CloudBlockBlob blob = container.GetBlockBlobReference("blockblob");
                blob.StreamWriteSizeInBytes = (int)(4 * Constants.MB);

                // Create the Key to be used for wrapping.
                SymmetricKey aesKey = new SymmetricKey("symencryptionkey");

                // Create the resolver to be used for unwrapping.
                DictionaryKeyResolver resolver = new DictionaryKeyResolver();
                resolver.Add(aesKey);

                // Create the encryption policy to be used for upload.
                BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(aesKey, null);

                // Set the encryption policy on the request options.
                options.EncryptionPolicy = uploadPolicy;
                OperationContext opContext = new OperationContext();

                int uploadCount = 0;
                opContext.SendingRequest += (sender, e) => uploadCount++;

                using (MemoryStream stream = streamSeekable ? new MemoryStream(buffer) : new NonSeekableMemoryStream(buffer))
                {
                    if (isAPM)
                    {
                        using (AutoResetEvent waitHandle = new AutoResetEvent(false))
                        {
                            blob.EndUploadFromStream(blob.BeginUploadFromStream(
                                                stream, size, null, options, opContext, ar => waitHandle.Set(), null));
                        }
                    }
                    else
                    {
                        blob.UploadFromStream(stream, size, null, options, opContext);
                    }

                    // Ensure that the user stream is open if it's seekable.
                    if (streamSeekable)
                    {
                        Assert.IsTrue(stream.CanSeek);
                    }
                }

                // Download the encrypted blob.
                // Create the decryption policy to be used for download. There is no need to specify the
                // key when the policy is only going to be used for downloads. Resolver is sufficient.
                BlobEncryptionPolicy downloadPolicy = new BlobEncryptionPolicy(null, resolver);

                // Set the decryption policy on the request options.
                BlobRequestOptions downloadOptions = new BlobRequestOptions() { EncryptionPolicy = downloadPolicy };

                // Download and decrypt the encrypted contents from the blob.
                MemoryStream outputStream = new MemoryStream();
                blob.DownloadToStream(outputStream, null, downloadOptions, null);

                // Ensure that the user stream is open.
                outputStream.Seek(0, SeekOrigin.Begin);

                // Compare that the decrypted contents match the input data.
                byte[] outputArray = outputStream.ToArray();
                TestHelper.AssertBuffersAreEqualUptoIndex(outputArray, buffer, size - 1);
                Assert.AreEqual(targetUploadOperations, uploadCount, "Incorrect number of operations in encrypted blob upload.");
            }
            finally
            {
                container.DeleteIfExists();
            }
        }
Exemplo n.º 17
0
        static void Main(string[] args)
        {
            Console.WriteLine("Blob encryption sample");

            // Retrieve storage account information from connection string
            // How to create a storage connection string - https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/
            CloudStorageAccount storageAccount = EncryptionShared.Utility.CreateStorageAccountFromConnectionString();

            CloudBlobClient client = storageAccount.CreateCloudBlobClient();
            CloudBlobContainer container = client.GetContainerReference(DemoContainer + Guid.NewGuid().ToString("N"));

            try
            {
                container.Create();
                int size = 5 * 1024 * 1024;
                byte[] buffer = new byte[size];

                Random rand = new Random();
                rand.NextBytes(buffer);

                CloudBlockBlob blob = container.GetBlockBlobReference("blockblob");

                // Create the IKey used for encryption.
                RsaKey key = new RsaKey("private:key1");

                // Create the encryption policy to be used for upload.
                BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(key, null);

                // Set the encryption policy on the request options.
                BlobRequestOptions uploadOptions = new BlobRequestOptions() { EncryptionPolicy = uploadPolicy };

                Console.WriteLine("Uploading the encrypted blob.");

                // Upload the encrypted contents to the blob.
                using (MemoryStream stream = new MemoryStream(buffer))
                {
                    blob.UploadFromStream(stream, size, null, uploadOptions, null);
                }

                // Download the encrypted blob.
                // For downloads, a resolver can be set up that will help pick the key based on the key id.
                LocalResolver resolver = new LocalResolver();
                resolver.Add(key);

                BlobEncryptionPolicy downloadPolicy = new BlobEncryptionPolicy(null, resolver);

                // Set the decryption policy on the request options.
                BlobRequestOptions downloadOptions = new BlobRequestOptions() { EncryptionPolicy = downloadPolicy };

                Console.WriteLine("Downloading the encrypted blob.");

                // Download and decrypt the encrypted contents from the blob.
                using (MemoryStream outputStream = new MemoryStream())
                {
                    blob.DownloadToStream(outputStream, null, downloadOptions, null);
                }

                Console.WriteLine("Press enter key to exit"); 
                Console.ReadLine(); 
            }
            finally
            {
                container.DeleteIfExists();
            }
        }
        public void CloudBlobEncryptionWithByteArray()
        {
            CloudBlobContainer container = GetRandomContainerReference();

            try
            {
                container.Create();
                int size = 5 * 1024 * 1024;
                byte[] buffer = GetRandomBuffer(size);
                byte[] outputBuffer = new byte[size];

                CloudBlockBlob blob = container.GetBlockBlobReference("blockblob");

                // Create the Key to be used for wrapping.
                SymmetricKey aesKey = new SymmetricKey("symencryptionkey");

                // Create the resolver to be used for unwrapping.
                DictionaryKeyResolver resolver = new DictionaryKeyResolver();
                resolver.Add(aesKey);

                // Create the encryption policy to be used for upload.
                BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(aesKey, null);

                // Set the encryption policy on the request options.
                BlobRequestOptions uploadOptions = new BlobRequestOptions() { EncryptionPolicy = uploadPolicy };

                // Upload the encrypted contents to the blob.
                blob.UploadFromByteArray(buffer, 0, buffer.Length, null, uploadOptions, null);

                // Download the encrypted blob.
                // Create the decryption policy to be used for download. There is no need to specify the
                // key when the policy is only going to be used for downloads. Resolver is sufficient.
                BlobEncryptionPolicy downloadPolicy = new BlobEncryptionPolicy(null, resolver);

                // Set the decryption policy on the request options.
                BlobRequestOptions downloadOptions = new BlobRequestOptions() { EncryptionPolicy = downloadPolicy };

                // Download and decrypt the encrypted contents from the blob.
                blob.DownloadToByteArray(outputBuffer, 0, null, downloadOptions, null);

                // Compare that the decrypted contents match the input data.
                TestHelper.AssertBuffersAreEqual(buffer, outputBuffer);
            }
            finally
            {
                container.DeleteIfExists();
            }
        }
        public void CloudBlobEncryptionWithFile()
        {
            CloudBlobContainer container = GetRandomContainerReference();

            try
            {
                container.Create();
                int size = 5 * 1024 * 1024;
                byte[] buffer = GetRandomBuffer(size);

                CloudBlockBlob blob = container.GetBlockBlobReference("blockblob");

                // Create the Key to be used for wrapping.
                SymmetricKey aesKey = new SymmetricKey("symencryptionkey");

                // Create the resolver to be used for unwrapping.
                DictionaryKeyResolver resolver = new DictionaryKeyResolver();
                resolver.Add(aesKey);

                // Create the encryption policy to be used for upload.
                BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(aesKey, null);

                // Set the encryption policy on the request options.
                BlobRequestOptions uploadOptions = new BlobRequestOptions() { EncryptionPolicy = uploadPolicy };

                string inputFileName = Path.GetTempFileName();
                string outputFileName = Path.GetTempFileName();

                using (FileStream file = new FileStream(inputFileName, FileMode.Create, FileAccess.Write))
                {
                    file.Write(buffer, 0, buffer.Length);
                }

                // Upload the encrypted contents to the blob.
                blob.UploadFromFile(inputFileName, FileMode.Open, null, uploadOptions, null);

                // Download the encrypted blob.
                // Create the decryption policy to be used for download. There is no need to specify the
                // key when the policy is only going to be used for downloads. Resolver is sufficient.
                BlobEncryptionPolicy downloadPolicy = new BlobEncryptionPolicy(null, resolver);

                // Set the decryption policy on the request options.
                BlobRequestOptions downloadOptions = new BlobRequestOptions() { EncryptionPolicy = downloadPolicy };

                // Download and decrypt the encrypted contents from the blob.
                blob.DownloadToFile(outputFileName, FileMode.Create, null, downloadOptions, null);

                // Compare that the decrypted contents match the input data.
                using (FileStream inputFileStream = new FileStream(inputFileName, FileMode.Open, FileAccess.Read),
                        outputFileStream = new FileStream(outputFileName, FileMode.Open, FileAccess.Read))
                {
                    TestHelper.AssertStreamsAreEqual(inputFileStream, outputFileStream);
                }
            }
            finally
            {
                container.DeleteIfExists();
            }
        }
Exemplo n.º 20
0
        static void Main(string[] args)
        {
            Console.WriteLine("Blob encryption with Key Vault integration demonstrating key rotation from Key 1 to Key 2");
            Console.WriteLine();

            // Create two secrets and obtain their IDs. This is normally a one-time setup step.
            // Although it is possible to use keys (rather than secrets) stored in Key Vault, this prevents caching.
            // Therefore it is recommended to use secrets along with a caching resolver (see below).
            string keyID1 = EncryptionShared.KeyVaultUtility.SetUpKeyVaultSecret("KeyRotationSampleSecret1");
            string keyID2 = EncryptionShared.KeyVaultUtility.SetUpKeyVaultSecret("KeyRotationSampleSecret2");

            // Retrieve storage account information from connection string
            // How to create a storage connection string - https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/
            CloudStorageAccount storageAccount = EncryptionShared.Utility.CreateStorageAccountFromConnectionString();
            CloudBlobClient client = storageAccount.CreateCloudBlobClient();
            CloudBlobContainer container = client.GetContainerReference(DemoContainer + Guid.NewGuid().ToString("N"));

            // Construct a resolver capable of looking up keys and secrets stored in Key Vault.
            KeyVaultKeyResolver cloudResolver = new KeyVaultKeyResolver(EncryptionShared.KeyVaultUtility.GetAccessToken);

            // Set up a caching resolver so the secrets can be cached on the client. This is the recommended usage
            // pattern since the throttling targets for Storage and Key Vault services are orders of magnitude
            // different.
            CachingKeyResolver cachingResolver = new CachingKeyResolver(2, cloudResolver);

            // Create key instances corresponding to the key IDs. This will cache the secrets.
            IKey cloudKey1 = cachingResolver.ResolveKeyAsync(keyID1, CancellationToken.None).GetAwaiter().GetResult();
            IKey cloudKey2 = cachingResolver.ResolveKeyAsync(keyID2, CancellationToken.None).GetAwaiter().GetResult();

            // We begin with cloudKey1, and a resolver capable of resolving and caching Key Vault secrets.
            BlobEncryptionPolicy encryptionPolicy = new BlobEncryptionPolicy(cloudKey1, cachingResolver);
            client.DefaultRequestOptions.EncryptionPolicy = encryptionPolicy;
            client.DefaultRequestOptions.RequireEncryption = true;

            try
            {
                container.Create();
                int size = 5 * 1024 * 1024;
                byte[] buffer1 = new byte[size];
                byte[] buffer2 = new byte[size];

                Random rand = new Random();
                rand.NextBytes(buffer1);
                rand.NextBytes(buffer2);

                // Upload the first blob using the secret stored in Azure Key Vault.
                CloudBlockBlob blob = container.GetBlockBlobReference("blockblob1");

                Console.WriteLine("Uploading Blob 1 using Key 1.");

                // Upload the encrypted contents to the first blob.
                using (MemoryStream stream = new MemoryStream(buffer1))
                {
                    blob.UploadFromStream(stream, size);
                }

                Console.WriteLine("Downloading and decrypting Blob 1.");

                // Download and decrypt the encrypted contents from the first blob.
                using (MemoryStream outputStream = new MemoryStream())
                {
                    blob.DownloadToStream(outputStream);
                }

                // At this point we will rotate our keys so new encrypted content will use the
                // second key. Note that the same resolver is used, as this resolver is capable
                // of decrypting blobs encrypted using either key.
                Console.WriteLine("Rotating the active encryption key to Key 2.");

                client.DefaultRequestOptions.EncryptionPolicy = new BlobEncryptionPolicy(cloudKey2, cachingResolver);

                // Upload the second blob using the key stored in Azure Key Vault.
                CloudBlockBlob blob2 = container.GetBlockBlobReference("blockblob2");

                Console.WriteLine("Uploading Blob 2 using Key 2.");

                // Upload the encrypted contents to the second blob.
                using (MemoryStream stream = new MemoryStream(buffer2))
                {
                    blob2.UploadFromStream(stream, size);
                }

                Console.WriteLine("Downloading and decrypting Blob 2.");

                // Download and decrypt the encrypted contents from the second blob.
                using (MemoryStream outputStream = new MemoryStream())
                {
                    blob2.DownloadToStream(outputStream);
                }

                // Here we download and re-upload the first blob. This has the effect of updating
                // the blob to use the new key.
                using (MemoryStream memoryStream = new MemoryStream())
                {
                    Console.WriteLine("Downloading and decrypting Blob 1.");
                    blob.DownloadToStream(memoryStream);

                    memoryStream.Seek(0, SeekOrigin.Begin);

                    Console.WriteLine("Re-uploading Blob 1 using Key 2.");
                    blob.UploadFromStream(memoryStream);
                }

                // For the purposes of demonstration, we now override the encryption policy to only recognize key 2.
                BlobEncryptionPolicy key2OnlyPolicy = new BlobEncryptionPolicy(cloudKey2, null);
                BlobRequestOptions key2OnlyOptions = new BlobRequestOptions()
                {
                    EncryptionPolicy = key2OnlyPolicy
                };

                Console.WriteLine("Downloading and decrypting Blob 1.");

                // The first blob can still be decrypted because it is using the second key.
                using (MemoryStream outputStream = new MemoryStream())
                {
                    blob.DownloadToStream(outputStream, options: key2OnlyOptions);
                }

                Console.WriteLine("Press enter key to exit");
                Console.ReadLine();
            }
            finally
            {
                container.DeleteIfExists();
            }
        }