/// <summary>
        /// Creates a secret in Azure Key Vault and returns its ID.
        /// </summary>
        /// <param name="secretName">The name of the secret to create.</param>
        /// <returns>The ID of the secret created.</returns>
        public static string SetUpKeyVaultSecret(string secretName)
        {
            KeyVaultClient cloudVault = new KeyVaultClient(GetAccessToken);
            string vaultUri = CloudConfigurationManager.GetSetting("VaultUri");

            try
            {
                // Delete the secret if it exists.
                cloudVault.DeleteSecretAsync(vaultUri, secretName).GetAwaiter().GetResult();
            }
            catch (KeyVaultClientException ex)
            {
                if (ex.Status != System.Net.HttpStatusCode.NotFound)
                {
                    Console.WriteLine("Unable to access the specified vault. Please confirm the KVClientId, KVClientKey, and VaultUri are valid in the app.config file.");
                    Console.WriteLine("Also ensure that the client ID has previously been granted full permissions for Key Vault secrets using the Set-AzureKeyVaultAccessPolicy command with the -PermissionsToSecrets parameter.");
                    Console.WriteLine("Press any key to exit");
                    Console.ReadLine();
                    throw;
                }
            }

            // Create a 256bit symmetric key and convert it to Base64.
            SymmetricKey symmetricKey = new SymmetricKey(secretName, SymmetricKey.KeySize256);
            string symmetricBytes = Convert.ToBase64String(symmetricKey.Key);

            // Store the Base64 of the key in the key vault. Note that the content-type of the secret must
            // be application/octet-stream or the KeyVaultKeyResolver will not load it as a key.
            Secret cloudSecret = cloudVault.SetSecretAsync(vaultUri, secretName, symmetricBytes, null, "application/octet-stream").GetAwaiter().GetResult();

            // Return the base identifier of the secret. This will be resolved to the current version of the secret.
            return cloudSecret.SecretIdentifier.BaseIdentifier;
        }
        public void CloudQueueAddUpdateEncryptedMessage()
        {
            // Create the Key to be used for wrapping.
            SymmetricKey aesKey = new SymmetricKey("symencryptionkey");
            RsaKey rsaKey = new RsaKey("asymencryptionkey");

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

            DoCloudQueueAddUpdateEncryptedMessage(aesKey, resolver);
            DoCloudQueueAddUpdateEncryptedMessage(rsaKey, resolver);
        }
        public void TableEncryptingUnsupportedPropertiesShouldThrow()
        {
            // Insert Entity
            DynamicTableEntity ent = new DynamicTableEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() };
            ent.Properties.Add("foo2", new EntityProperty(string.Empty));
            ent.Properties.Add("fooint", new EntityProperty(1234));

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

            TableRequestOptions options = new TableRequestOptions()
            {
                EncryptionPolicy = new TableEncryptionPolicy(aesKey, null),

                EncryptionResolver = (pk, rk, propName) =>
                {
                    if (propName.StartsWith("foo"))
                    {
                        return true;
                    }

                    return false;
                }
            };

            StorageException e = TestHelper.ExpectedException<StorageException>(
                () => currentTable.Execute(TableOperation.Insert(ent), options, null),
                "Encrypting non-string properties should fail");
            Assert.IsInstanceOfType(e.InnerException, typeof(InvalidOperationException));

            ent.Properties.Remove("fooint");
            ent.Properties.Add("foo", null);

            e = TestHelper.ExpectedException<StorageException>(
                () => currentTable.Execute(TableOperation.Insert(ent), options, null),
                "Encrypting null properties should fail");
            Assert.IsInstanceOfType(e.InnerException, typeof(InvalidOperationException));
        }
        private void DoTableOperationValidateEncryption(TablePayloadFormat format)
        {
            tableClient.DefaultRequestOptions.PayloadFormat = format;

            // Insert Entity
            DynamicTableEntity ent = new DynamicTableEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() };
            ent.Properties.Add("encprop", new EntityProperty(String.Empty));
            ent.Properties.Add("encprop2", new EntityProperty(String.Empty));
            ent.Properties.Add("encprop3", new EntityProperty("bar"));
            ent.Properties.Add("notencprop", new EntityProperty(1234));

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

            TableRequestOptions uploadOptions = new TableRequestOptions()
            {
                PropertyResolver = (pk, rk, propName, propValue) =>
                {
                    if (propName == "notencprop")
                    {
                        return EdmType.Int32;
                    }

                    return (EdmType)0;
                },

                EncryptionPolicy = new TableEncryptionPolicy(aesKey, null),

                EncryptionResolver = (pk, rk, propName) =>
                {
                    if (propName.StartsWith("encprop"))
                    {
                        return true;
                    }

                    return false;
                }
            };

            currentTable.Execute(TableOperation.Insert(ent), uploadOptions, null);

            TableRequestOptions downloadOptions = new TableRequestOptions()
            {
                PropertyResolver = (pk, rk, propName, propValue) =>
                {
                    if (propName == "notencprop")
                    {
                        return EdmType.Int32;
                    }

                    return (EdmType)0;
                }
            };

            // Retrieve Entity without decrypting
            TableOperation operation = TableOperation.Retrieve(ent.PartitionKey, ent.RowKey);
            Assert.IsFalse(operation.IsTableEntity);
            TableResult result = currentTable.Execute(operation, downloadOptions, null);

            DynamicTableEntity retrievedEntity = result.Result as DynamicTableEntity;
            Assert.IsNotNull(retrievedEntity);
            Assert.AreEqual(ent.PartitionKey, retrievedEntity.PartitionKey);
            Assert.AreEqual(ent.RowKey, retrievedEntity.RowKey);

            // Properties having the same value should be encrypted to different values.
            if (format == TablePayloadFormat.JsonNoMetadata)
            {
                // With DTE and Json no metadata, if an encryption policy is not set, the client lib just reads the byte arrays as strings.
                Assert.AreNotEqual(retrievedEntity.Properties["encprop"].StringValue, retrievedEntity.Properties["encprop2"].StringValue);
            }
            else
            {
                CollectionAssert.AreNotEqual(retrievedEntity.Properties["encprop"].BinaryValue, retrievedEntity.Properties["encprop2"].BinaryValue);
                Assert.AreNotEqual(ent.Properties["encprop"].PropertyType, retrievedEntity.Properties["encprop"].PropertyType);
                Assert.AreNotEqual(ent.Properties["encprop2"].PropertyType, retrievedEntity.Properties["encprop2"].PropertyType);
                Assert.AreNotEqual(ent.Properties["encprop3"].PropertyType, retrievedEntity.Properties["encprop3"].PropertyType);
            }

            Assert.AreEqual(ent.Properties["notencprop"].Int32Value, retrievedEntity.Properties["notencprop"].Int32Value);
        }
        private void DoTableBatchInsertOrReplaceEncryption(TablePayloadFormat format)
        {
            tableClient.DefaultRequestOptions.PayloadFormat = format;

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

            TableRequestOptions options = new TableRequestOptions()
            {
                EncryptionPolicy = new TableEncryptionPolicy(aesKey, null),

                EncryptionResolver = (pk, rk, propName) =>
                {
                    if (propName == "A" || propName == "B")
                    {
                        return true;
                    }

                    return false;
                }
            };

            // Insert Or Replace with no pre-existing entity
            DynamicTableEntity insertOrReplaceEntity = new DynamicTableEntity("insertOrReplace entity", "foo" + format.ToString());
            insertOrReplaceEntity.Properties.Add("A", new EntityProperty("a"));

            TableBatchOperation batch = new TableBatchOperation();
            batch.InsertOrReplace(insertOrReplaceEntity);
            currentTable.ExecuteBatch(batch, options);

            // Retrieve Entity & Verify Contents
            // Create the resolver to be used for unwrapping.
            DictionaryKeyResolver resolver = new DictionaryKeyResolver();
            resolver.Add(aesKey);

            TableRequestOptions retrieveOptions = new TableRequestOptions() { EncryptionPolicy = new TableEncryptionPolicy(null, resolver) };
            TableResult result = currentTable.Execute(TableOperation.Retrieve(insertOrReplaceEntity.PartitionKey, insertOrReplaceEntity.RowKey), retrieveOptions);
            DynamicTableEntity retrievedEntity = result.Result as DynamicTableEntity;
            Assert.IsNotNull(retrievedEntity);
            Assert.AreEqual(insertOrReplaceEntity.Properties.Count, retrievedEntity.Properties.Count);

            DynamicTableEntity replaceEntity = new DynamicTableEntity(insertOrReplaceEntity.PartitionKey, insertOrReplaceEntity.RowKey);
            replaceEntity.Properties.Add("B", new EntityProperty("b"));

            TableBatchOperation batch2 = new TableBatchOperation();
            batch2.InsertOrReplace(replaceEntity);
            currentTable.ExecuteBatch(batch2, options);

            // Retrieve Entity & Verify Contents
            result = currentTable.Execute(TableOperation.Retrieve(insertOrReplaceEntity.PartitionKey, insertOrReplaceEntity.RowKey), retrieveOptions);
            retrievedEntity = result.Result as DynamicTableEntity;
            Assert.IsNotNull(retrievedEntity);
            Assert.AreEqual(1, retrievedEntity.Properties.Count);
            Assert.AreEqual(replaceEntity.Properties["B"], retrievedEntity.Properties["B"]);
        }
        private void DoTableQueryDTEProjectionEncryption(TablePayloadFormat format, SymmetricKey aesKey)
        {
            tableClient.DefaultRequestOptions.PayloadFormat = format;

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

            TableRequestOptions options = new TableRequestOptions() { EncryptionPolicy = new TableEncryptionPolicy(null, resolver) };

            TableQuery query = new TableQuery().Select(new List<string>() { "A" });

            foreach (DynamicTableEntity ent in currentTable.ExecuteQuery(query, options))
            {
                Assert.IsNotNull(ent.PartitionKey);
                Assert.IsNotNull(ent.RowKey);
                Assert.IsNotNull(ent.Timestamp);

                Assert.IsTrue(ent.Properties["A"].StringValue == "a" || ent.Properties["A"].StringValue == String.Empty);
            }
        }
        public void TableQueryProjectionEncryptionNoSelect()
        {
            // Insert Entity
            EncryptedBaseEntity ent1 = new EncryptedBaseEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() };
            ent1.Populate();

            EncryptedBaseEntity ent2 = new EncryptedBaseEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() };
            ent2.Populate();

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

            TableRequestOptions options = new TableRequestOptions() { EncryptionPolicy = new TableEncryptionPolicy(aesKey, null) };
            currentTable.Execute(TableOperation.Insert(ent1), options, null);
            currentTable.Execute(TableOperation.Insert(ent2), options, null);

            tableClient.DefaultRequestOptions.PayloadFormat = TablePayloadFormat.Json;

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

            IEnumerable<EncryptedBaseEntity> entities = null;
            CloudTableClient encryptingTableClient = new CloudTableClient(this.tableClient.StorageUri, this.tableClient.Credentials);
            encryptingTableClient.DefaultRequestOptions.EncryptionPolicy = encryptionPolicy;
            encryptingTableClient.DefaultRequestOptions.RequireEncryption = true;

            entities = encryptingTableClient.GetTableReference(currentTable.Name).CreateQuery<EncryptedBaseEntity>().Select(ent => ent);

            foreach (EncryptedBaseEntity ent in entities)
            {
                ent.Validate();
            }
        }
        public void TableQueryPOCOProjectionEncryption()
        {
            // Insert Entity
            EncryptedBaseEntity ent1 = new EncryptedBaseEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() };
            ent1.Populate();

            EncryptedBaseEntity ent2 = new EncryptedBaseEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() };
            ent2.Populate();

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

            TableRequestOptions options = new TableRequestOptions() { EncryptionPolicy = new TableEncryptionPolicy(aesKey, null) };
            currentTable.Execute(TableOperation.Insert(ent1), options, null);
            currentTable.Execute(TableOperation.Insert(ent2), options, null);

            // Query with different payload formats.
            DoTableQueryPOCOProjectionEncryption(TablePayloadFormat.Json, aesKey);
            DoTableQueryPOCOProjectionEncryption(TablePayloadFormat.JsonNoMetadata, aesKey);
            DoTableQueryPOCOProjectionEncryption(TablePayloadFormat.JsonFullMetadata, aesKey);
            DoTableQueryPOCOProjectionEncryption(TablePayloadFormat.AtomPub, aesKey);
        }
        public void CloudBlockBlobEncryptionValidateWrappers()
        {
            // Create the Key to be used for wrapping.
            SymmetricKey aesKey = new SymmetricKey("symencryptionkey");
            RsaKey rsaKey = new RsaKey("asymencryptionkey");

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

            DoCloudBlockBlobEncryptionValidateWrappers(aesKey, resolver);
            DoCloudBlockBlobEncryptionValidateWrappers(rsaKey, resolver);
        }
        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();
            }
        }
        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();
            }
        }
        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 CloudBlobEncryptionWithStrictModeOnPartialBlob()
        {
            CloudBlobContainer container = GetRandomContainerReference();

            int size = 5 * 1024 * 1024;
            byte[] buffer = GetRandomBuffer(size);

            ICloudBlob blob;
            MemoryStream stream = new MemoryStream(buffer);
            String blockId = Convert.ToBase64String(Guid.NewGuid().ToByteArray());

            BlobRequestOptions options = new BlobRequestOptions()
            {
                RequireEncryption = true
            };

            blob = container.GetBlockBlobReference("blob1");
            try
            {
                ((CloudBlockBlob)blob).PutBlock(blockId, stream, null, null, options, null);
                Assert.Fail("PutBlock with RequireEncryption on should fail.");
            }
            catch (InvalidOperationException ex)
            {
                Assert.AreEqual(ex.Message, SR.EncryptionPolicyMissingInStrictMode);
            }

            blob = container.GetPageBlobReference("blob1");
            try
            {
                ((CloudPageBlob)blob).WritePages(stream, 0, null, null, options, null);
                Assert.Fail("WritePages with RequireEncryption on should fail.");
            }
            catch (InvalidOperationException ex)
            {
                Assert.AreEqual(ex.Message, SR.EncryptionPolicyMissingInStrictMode);
            }

            blob = container.GetAppendBlobReference("blob1");
            try
            {
                ((CloudAppendBlob)blob).AppendBlock(stream, null, null, options, null);
                Assert.Fail("AppendBlock with RequireEncryption on should fail.");
            }
            catch (InvalidOperationException ex)
            {
                Assert.AreEqual(ex.Message, SR.EncryptionPolicyMissingInStrictMode);
            }

            // Create the Key to be used for wrapping.
            SymmetricKey aesKey = new SymmetricKey("symencryptionkey");
            options.EncryptionPolicy = new BlobEncryptionPolicy(aesKey, null);

            blob = container.GetBlockBlobReference("blob1");
            try
            {
                ((CloudBlockBlob)blob).PutBlock(blockId, stream, null, null, options, null);
                Assert.Fail("PutBlock with an EncryptionPolicy should fail.");
            }
            catch (InvalidOperationException ex)
            {
                Assert.AreEqual(ex.Message, SR.EncryptionNotSupportedForOperation);
            }

            blob = container.GetPageBlobReference("blob1");
            try
            {
                ((CloudPageBlob)blob).WritePages(stream, 0, null, null, options, null);
                Assert.Fail("WritePages with an EncryptionPolicy should fail.");
            }
            catch (InvalidOperationException ex)
            {
                Assert.AreEqual(ex.Message, SR.EncryptionNotSupportedForOperation);
            }

            blob = container.GetAppendBlobReference("blob1");
            try
            {
                ((CloudAppendBlob)blob).AppendBlock(stream, null, null, options, null);
                Assert.Fail("AppendBlock with an EncryptionPolicy should fail.");
            }
            catch (InvalidOperationException ex)
            {
                Assert.AreEqual(ex.Message, SR.EncryptionNotSupportedForOperation);
            }
        }
        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 void DoInsertPOCOEntityEncryptionWithAttributes(TablePayloadFormat format)
        {
            tableClient.DefaultRequestOptions.PayloadFormat = format;

            // Insert Entity
            EncryptedBaseEntity ent = new EncryptedBaseEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() + format};
            ent.Populate();

            // 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);

            TableRequestOptions insertOptions = new TableRequestOptions() { EncryptionPolicy = new TableEncryptionPolicy(aesKey, null) };
            currentTable.Execute(TableOperation.Insert(ent), insertOptions, null);

            // Retrieve Entity
            // No need for an encryption resolver while retrieving the entity.
            TableRequestOptions retrieveOptions = new TableRequestOptions() { EncryptionPolicy = new TableEncryptionPolicy(null, resolver) };

            TableOperation operation = TableOperation.Retrieve<EncryptedBaseEntity>(ent.PartitionKey, ent.RowKey);
            Assert.IsFalse(operation.IsTableEntity);
            TableResult result = currentTable.Execute(operation, retrieveOptions, null);

            EncryptedBaseEntity retrievedEntity = result.Result as EncryptedBaseEntity;
            Assert.IsNotNull(retrievedEntity);
            Assert.AreEqual(ent.PartitionKey, retrievedEntity.PartitionKey);
            Assert.AreEqual(ent.RowKey, retrievedEntity.RowKey);
            retrievedEntity.Validate();
        }
        private void DoInsertPOCOEntityEncryptionWithAttributesAndResolver(TablePayloadFormat format)
        {
            tableClient.DefaultRequestOptions.PayloadFormat = format;

            // Insert Entity
            EncryptedBaseEntity ent = new EncryptedBaseEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() + format };
            ent.Populate();

            // 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);

            TableRequestOptions insertOptions = new TableRequestOptions() 
            { 
                EncryptionPolicy = new TableEncryptionPolicy(aesKey, null),

                EncryptionResolver = (pk, rk, propName) =>
                {
                    if (propName == "B")
                    {
                        return true;
                    }

                    return false;
                }
            };

            // Since we have specified attributes and resolver, properties A, B and foo will be encrypted.
            currentTable.Execute(TableOperation.Insert(ent), insertOptions, null);

            // Retrieve entity without decryption and confirm that all 3 properties were encrypted.
            // No need for an encryption resolver while retrieving the entity.
            TableOperation operation = TableOperation.Retrieve<EncryptedBaseEntity>(ent.PartitionKey, ent.RowKey);
            Assert.IsFalse(operation.IsTableEntity);
            TableResult result = currentTable.Execute(operation, null, null);
            
            EncryptedBaseEntity retrievedEntity = result.Result as EncryptedBaseEntity;
            Assert.IsNotNull(retrievedEntity);
            Assert.AreEqual(ent.PartitionKey, retrievedEntity.PartitionKey);
            Assert.AreEqual(ent.RowKey, retrievedEntity.RowKey);

            // Since we store encrypted properties as byte arrays, if a POCO entity is being read as-is, odata will not assign the binary
            // values to strings. In JSON no metadata, the service does not return the types and the client lib does the parsing and reads the 
            // base64 encoded string as-is.
            if (format == TablePayloadFormat.JsonNoMetadata)
            {
                Assert.IsNotNull(retrievedEntity.foo);
                Assert.IsNotNull(retrievedEntity.A);
                Assert.IsNotNull(retrievedEntity.B);
                Assert.AreEqual(ent.foo.GetType(), retrievedEntity.foo.GetType());
                Assert.AreEqual(ent.A.GetType(), retrievedEntity.A.GetType());
                Assert.AreEqual(ent.B.GetType(), retrievedEntity.B.GetType());
            }
            else
            {
                Assert.IsNull(retrievedEntity.foo);
                Assert.IsNull(retrievedEntity.A);
                Assert.IsNull(retrievedEntity.B);
            }

            // Retrieve entity without decryption and confirm that all 3 properties were encrypted.
            // No need for an encryption resolver while retrieving the entity.
            operation = TableOperation.Retrieve<DynamicTableEntity>(ent.PartitionKey, ent.RowKey);
            Assert.IsFalse(operation.IsTableEntity);
            result = currentTable.Execute(operation, null, null);

            DynamicTableEntity retrievedDynamicEntity = result.Result as DynamicTableEntity;
            Assert.IsNotNull(retrievedEntity);
            Assert.AreEqual(ent.PartitionKey, retrievedDynamicEntity.PartitionKey);
            Assert.AreEqual(ent.RowKey, retrievedDynamicEntity.RowKey);

            if (format == TablePayloadFormat.JsonNoMetadata)
            {
                Assert.AreEqual(EdmType.String, retrievedDynamicEntity.Properties["foo"].PropertyType);
                Assert.AreEqual(EdmType.String, retrievedDynamicEntity.Properties["A"].PropertyType);
                Assert.AreEqual(EdmType.String, retrievedDynamicEntity.Properties["B"].PropertyType);
            }
            else
            {
                Assert.AreEqual(EdmType.Binary, retrievedDynamicEntity.Properties["foo"].PropertyType);
                Assert.AreEqual(EdmType.Binary, retrievedDynamicEntity.Properties["A"].PropertyType);
                Assert.AreEqual(EdmType.Binary, retrievedDynamicEntity.Properties["B"].PropertyType);
            }

            // Retrieve entity and decrypt.
            TableRequestOptions retrieveOptions = new TableRequestOptions() { EncryptionPolicy = new TableEncryptionPolicy(null, resolver) };

            operation = TableOperation.Retrieve<EncryptedBaseEntity>(ent.PartitionKey, ent.RowKey);
            Assert.IsFalse(operation.IsTableEntity);
            result = currentTable.Execute(operation, retrieveOptions, null);

            retrievedEntity = result.Result as EncryptedBaseEntity;
            Assert.IsNotNull(retrievedEntity);
            Assert.AreEqual(ent.PartitionKey, retrievedEntity.PartitionKey);
            Assert.AreEqual(ent.RowKey, retrievedEntity.RowKey);
            retrievedEntity.Validate();
        }
        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 DoTableQueryPOCOProjectionEncryption(TablePayloadFormat format, SymmetricKey aesKey)
        {
            tableClient.DefaultRequestOptions.PayloadFormat = format;

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

            TableRequestOptions options = new TableRequestOptions() { EncryptionPolicy = new TableEncryptionPolicy(null, resolver) };

            TableQuery<EncryptedBaseEntity> query = new TableQuery<EncryptedBaseEntity>().Select(new List<string>() { "A", "C" });

            foreach (EncryptedBaseEntity ent in currentTable.ExecuteQuery(query, options))
            {
                Assert.IsNotNull(ent.PartitionKey);
                Assert.IsNotNull(ent.RowKey);
                Assert.IsNotNull(ent.Timestamp);

                Assert.AreEqual(ent.A, "a");
                Assert.IsNull(ent.B);
                Assert.AreEqual(ent.C, "c");
                Assert.IsNull(ent.D);
                Assert.AreEqual(ent.E, 0);
            }
        }
        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 TableQueryDTEProjectionEncryption()
        {
            // Insert Entity
            DynamicTableEntity ent1 = new DynamicTableEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() };
            ent1.Properties.Add("A", new EntityProperty(String.Empty));
            ent1.Properties.Add("B", new EntityProperty("b"));

            DynamicTableEntity ent2 = new DynamicTableEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() };
            ent2.Properties.Add("A", new EntityProperty("a"));
            ent2.Properties.Add("B", new EntityProperty("b"));

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

            TableRequestOptions options = new TableRequestOptions()
            {
                EncryptionPolicy = new TableEncryptionPolicy(aesKey, null),

                EncryptionResolver = (pk, rk, propName) =>
                {
                    if (propName == "A")
                    {
                        return true;
                    }

                    return false;
                }
            };

            currentTable.Execute(TableOperation.Insert(ent1), options, null);
            currentTable.Execute(TableOperation.Insert(ent2), options, null);

            // Query with different payload formats.
            DoTableQueryDTEProjectionEncryption(TablePayloadFormat.Json, aesKey);
            DoTableQueryDTEProjectionEncryption(TablePayloadFormat.JsonNoMetadata, aesKey);
            DoTableQueryDTEProjectionEncryption(TablePayloadFormat.JsonFullMetadata, aesKey);
            DoTableQueryDTEProjectionEncryption(TablePayloadFormat.AtomPub, aesKey);
        }
        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();
            }
        }
        public void TableEncryptionValidateSwappingPropertiesThrows()
        {
            // Create the Key to be used for wrapping.
            SymmetricKey aesKey = new SymmetricKey("symencryptionkey");

            TableRequestOptions options = new TableRequestOptions()
            {
                EncryptionPolicy = new TableEncryptionPolicy(aesKey, null),

                EncryptionResolver = (pk, rk, propName) =>
                {
                    if (propName == "Prop1")
                    {
                        return true;
                    }

                    return false;
                }
            };

            // Insert Entities
            DynamicTableEntity baseEntity1 = new DynamicTableEntity("test1", "foo1");
            baseEntity1.Properties.Add("Prop1", new EntityProperty("Value1"));
            currentTable.Execute(TableOperation.Insert(baseEntity1), options);

            DynamicTableEntity baseEntity2 = new DynamicTableEntity("test1", "foo2");
            baseEntity2.Properties.Add("Prop1", new EntityProperty("Value2"));
            currentTable.Execute(TableOperation.Insert(baseEntity2), options);

            // Retrieve entity1 (Do not set encryption policy)
            TableResult result = currentTable.Execute(TableOperation.Retrieve(baseEntity1.PartitionKey, baseEntity1.RowKey));
            DynamicTableEntity retrievedEntity = result.Result as DynamicTableEntity;

            // Replace entity2 with encrypted entity1's properties (Do not set encryption policy).
            DynamicTableEntity replaceEntity = new DynamicTableEntity(baseEntity2.PartitionKey, baseEntity2.RowKey) { ETag = baseEntity2.ETag };
            replaceEntity.Properties = retrievedEntity.Properties;
            currentTable.Execute(TableOperation.Replace(replaceEntity));

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

            TableRequestOptions retrieveOptions = new TableRequestOptions() { EncryptionPolicy = new TableEncryptionPolicy(null, resolver) };

            try
            {
                result = currentTable.Execute(TableOperation.Retrieve(baseEntity2.PartitionKey, baseEntity2.RowKey), retrieveOptions);
                Assert.Fail();
            }
            catch (StorageException ex)
            {
                Assert.IsInstanceOfType(ex.InnerException, typeof(CryptographicException));
            }
        }
        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();
            }
        }
        private void DoTableBatchRetrieveEncryptedEntitySync(TablePayloadFormat format)
        {
            tableClient.DefaultRequestOptions.PayloadFormat = format;

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

            TableRequestOptions options = new TableRequestOptions()
            {
                EncryptionPolicy = new TableEncryptionPolicy(aesKey, null),

                EncryptionResolver = (pk, rk, propName) =>
                {
                    if (propName == "A" || propName == "B")
                    {
                        return true;
                    }

                    return false;
                }
            };

            // Add insert
            DynamicTableEntity sendEnt = GenerateRandomEntity(Guid.NewGuid().ToString());

            // generate a set of properties for all supported Types
            sendEnt.Properties = new ComplexEntity().WriteEntity(null);
            sendEnt.Properties.Add("foo", new EntityProperty("bar"));

            TableBatchOperation batch = new TableBatchOperation();
            batch.Retrieve<DynamicTableEntity>(sendEnt.PartitionKey, sendEnt.RowKey);

            // not found
            IList<TableResult> results = currentTable.ExecuteBatch(batch, options);
            Assert.AreEqual(results.Count, 1);
            Assert.AreEqual(results.First().HttpStatusCode, (int)HttpStatusCode.NotFound);
            Assert.IsNull(results.First().Result);
            Assert.IsNull(results.First().Etag);

            // insert entity
            currentTable.Execute(TableOperation.Insert(sendEnt), options);
            
            // Create the resolver to be used for unwrapping.
            DictionaryKeyResolver resolver = new DictionaryKeyResolver();
            resolver.Add(aesKey);

            TableRequestOptions retrieveOptions = new TableRequestOptions() { EncryptionPolicy = new TableEncryptionPolicy(null, resolver) };

            // Success
            results = currentTable.ExecuteBatch(batch, retrieveOptions);
            Assert.AreEqual(results.Count, 1);
            Assert.AreEqual(results.First().HttpStatusCode, (int)HttpStatusCode.OK);

            DynamicTableEntity retrievedEntity = results.First().Result as DynamicTableEntity;

            // Validate entity
            Assert.AreEqual(sendEnt["foo"], retrievedEntity["foo"]);
        }
        public void TableOperationEncryptionWithStrictModeOnMerge()
        {
            // Insert Entity
            DynamicTableEntity ent = new DynamicTableEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() };
            ent.Properties.Add("foo2", new EntityProperty(string.Empty));
            ent.Properties.Add("foo", new EntityProperty("bar"));
            ent.Properties.Add("fooint", new EntityProperty(1234));
            ent.ETag = "*";

            TableRequestOptions options = new TableRequestOptions()
            {
                RequireEncryption = true
            };

            try
            {
                currentTable.Execute(TableOperation.Merge(ent), options, null);
                Assert.Fail("Merge with RequireEncryption on should fail.");
            }
            catch (StorageException ex)
            {
                Assert.AreEqual(ex.Message, SR.EncryptionPolicyMissingInStrictMode);
            }

            try
            {
                currentTable.Execute(TableOperation.InsertOrMerge(ent), options, null);
                Assert.Fail("InsertOrMerge with RequireEncryption on should fail.");
            }
            catch (StorageException ex)
            {
                Assert.AreEqual(ex.Message, SR.EncryptionPolicyMissingInStrictMode);
            }

            // Create the Key to be used for wrapping.
            SymmetricKey aesKey = new SymmetricKey("symencryptionkey");
            options.EncryptionPolicy = new TableEncryptionPolicy(aesKey, null);

            try
            {
                currentTable.Execute(TableOperation.Merge(ent), options, null);
                Assert.Fail("Merge with an EncryptionPolicy should fail.");
            }
            catch (StorageException ex)
            {
                Assert.AreEqual(ex.Message, SR.EncryptionNotSupportedForOperation);
            }

            try
            {
                currentTable.Execute(TableOperation.InsertOrMerge(ent), options, null);
                Assert.Fail("InsertOrMerge with an EncryptionPolicy should fail.");
            }
            catch (StorageException ex)
            {
                Assert.AreEqual(ex.Message, SR.EncryptionNotSupportedForOperation);
            }
        }
        private void DoInsertDynamicTableEntityEncryptionSync(TablePayloadFormat format)
        {
            tableClient.DefaultRequestOptions.PayloadFormat = format;

            // Insert Entity
            DynamicTableEntity ent = new DynamicTableEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() };
            ent.Properties.Add("foo2", new EntityProperty(string.Empty));
            ent.Properties.Add("foo", new EntityProperty("bar"));
            ent.Properties.Add("fooint", new EntityProperty(1234));

            // 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);

            TableRequestOptions options = new TableRequestOptions()
            {
                EncryptionPolicy = new TableEncryptionPolicy(aesKey, null),

                EncryptionResolver = (pk, rk, propName) =>
                {
                    if (propName == "foo" || propName == "foo2")
                    {
                        return true;
                    }

                    return false;
                }
            };

            currentTable.Execute(TableOperation.Insert(ent), options, null);

            // Retrieve Entity
            TableRequestOptions retrieveOptions = new TableRequestOptions()
            {
                PropertyResolver = (pk, rk, propName, propValue) =>
                {
                    if (propName == "fooint")
                    {
                        return EdmType.Int32;
                    }

                    return (EdmType)0;
                },

                EncryptionPolicy = new TableEncryptionPolicy(null, resolver)
            };

            TableOperation operation = TableOperation.Retrieve(ent.PartitionKey, ent.RowKey);
            Assert.IsFalse(operation.IsTableEntity);
            TableResult result = currentTable.Execute(operation, retrieveOptions, null);

            DynamicTableEntity retrievedEntity = result.Result as DynamicTableEntity;
            Assert.IsNotNull(retrievedEntity);
            Assert.AreEqual(ent.PartitionKey, retrievedEntity.PartitionKey);
            Assert.AreEqual(ent.RowKey, retrievedEntity.RowKey);
            Assert.AreEqual(ent.Properties.Count, retrievedEntity.Properties.Count);
            Assert.AreEqual(ent.Properties["foo"].StringValue, retrievedEntity.Properties["foo"].StringValue);
            Assert.AreEqual(ent.Properties["foo"], retrievedEntity.Properties["foo"]);
            Assert.AreEqual(ent.Properties["foo2"].StringValue, retrievedEntity.Properties["foo2"].StringValue);
            Assert.AreEqual(ent.Properties["foo2"], retrievedEntity.Properties["foo2"]);
            Assert.AreEqual(ent.Properties["fooint"], retrievedEntity.Properties["fooint"]);
            Assert.AreEqual(ent.Properties["fooint"].Int32Value, retrievedEntity.Properties["fooint"].Int32Value);
        }
        public void TableQueryEncryptionMixedMode()
        {
            // Insert Entity
            EncryptedBaseEntity ent1 = new EncryptedBaseEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() };
            ent1.Populate();

            EncryptedBaseEntity ent2 = new EncryptedBaseEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() };
            ent2.Populate();

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

            TableRequestOptions options = new TableRequestOptions() { EncryptionPolicy = new TableEncryptionPolicy(aesKey, null) };

            // Insert an encrypted entity.
            currentTable.Execute(TableOperation.Insert(ent1), options, null);

            // Insert a non-encrypted entity.
            currentTable.Execute(TableOperation.Insert(ent2), null, null);

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

            options = new TableRequestOptions() { EncryptionPolicy = new TableEncryptionPolicy(null, resolver) };

            // Set RequireEncryption to false and query. This will succeed.
            options.RequireEncryption = false;
            TableQuery<EncryptedBaseEntity> query = new TableQuery<EncryptedBaseEntity>();
            currentTable.ExecuteQuery(query, options).ToList();

            // Set RequireEncryption to true and query. This will fail because it can't find the metadata for the second enctity on the server.
            options.RequireEncryption = true;
            TestHelper.ExpectedException<StorageException>(
                () => currentTable.ExecuteQuery(query, options).ToList(),
                "All entities retrieved should be encrypted when RequireEncryption is set to true.");
        }
        public void TableOperationEncryptionWithStrictMode()
        {
            // Insert Entity
            DynamicTableEntity ent = new DynamicTableEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() };
            ent.Properties.Add("foo2", new EntityProperty(string.Empty));
            ent.Properties.Add("foo", new EntityProperty("bar"));
            ent.Properties.Add("fooint", new EntityProperty(1234));

            // 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);

            TableRequestOptions options = new TableRequestOptions()
            {
                EncryptionPolicy = new TableEncryptionPolicy(aesKey, null),

                EncryptionResolver = (pk, rk, propName) =>
                {
                    if (propName == "foo" || propName == "foo2")
                    {
                        return true;
                    }

                    return false;
                },

                RequireEncryption = true
            };

            currentTable.Execute(TableOperation.Insert(ent), options, null);

            // Insert an entity when RequireEncryption is set to true but no policy is specified. This should throw.
            options.EncryptionPolicy = null;

            TestHelper.ExpectedException<StorageException>(
                () => currentTable.Execute(TableOperation.Insert(ent), options, null),
                "Not specifying a policy when RequireEncryption is set to true should throw.");

            // Retrieve Entity
            TableRequestOptions retrieveOptions = new TableRequestOptions()
            {
                PropertyResolver = (pk, rk, propName, propValue) =>
                {
                    if (propName == "fooint")
                    {
                        return EdmType.Int32;
                    }

                    return (EdmType)0;
                },

                EncryptionPolicy = new TableEncryptionPolicy(null, resolver),

                RequireEncryption = true
            };

            TableOperation operation = TableOperation.Retrieve(ent.PartitionKey, ent.RowKey);
            Assert.IsFalse(operation.IsTableEntity);
            TableResult result = currentTable.Execute(operation, retrieveOptions, null);

            // Replace entity with plain text.
            ent.ETag = (result.Result as DynamicTableEntity).ETag;
            currentTable.Execute(TableOperation.Replace(ent));

            // Retrieve with RequireEncryption flag but no metadata on the service. This should throw.
            TestHelper.ExpectedException<StorageException>(
                () => currentTable.Execute(operation, retrieveOptions, null),
                "Retrieving with RequireEncryption set to true and no metadata on the service should fail.");

            // Set RequireEncryption flag to true and retrieve.
            retrieveOptions.RequireEncryption = false;
            result = currentTable.Execute(operation, retrieveOptions, null);
        }
        public void TableOperationsIgnoreEncryptionAsync()
        {
            SymmetricKey aesKey = new SymmetricKey("symencryptionkey");
            TableRequestOptions options = new TableRequestOptions() { EncryptionPolicy = new TableEncryptionPolicy(aesKey, null), RequireEncryption = true };

            CloudTable testTable = this.tableClient.GetTableReference(GenerateRandomTableName());

            try
            {
                // Check Create()
                testTable.CreateAsync(options, null).Wait();
                Assert.IsTrue(testTable.Exists(), "Table failed to be created when encryption policy was supplied.");

                // Check Exists()
                Assert.IsTrue(testTable.ExistsAsync(options, null).Result, "Table.Exists() failed when encryption policy was supplied.");

                // Check ListTables().
                Assert.AreEqual(testTable.Name, this.ListAllTablesAsync(this.tableClient, testTable.Name, options).Result.First().Name, "ListTables failed when an encryption policy was specified.");

                // Check Get and Set Permissions
                TablePermissions permissions = testTable.GetPermissions();
                string policyName = "samplePolicy";
                permissions.SharedAccessPolicies.Add(policyName, new SharedAccessTablePolicy() { Permissions = SharedAccessTablePermissions.Query, SharedAccessExpiryTime = DateTime.Now + TimeSpan.FromDays(1) });
                testTable.SetPermissionsAsync(permissions, options, null).Wait();
                Assert.AreEqual(policyName, testTable.GetPermissions().SharedAccessPolicies.First().Key);
                Assert.AreEqual(policyName, testTable.GetPermissionsAsync(options, null).Result.SharedAccessPolicies.First().Key);

                // Check Delete
                testTable.DeleteAsync(options, null).Wait();
                Assert.IsFalse(testTable.Exists());
            }
            finally
            {
                testTable.DeleteIfExists();
            }
        }