diff --git a/Samples/GettingStarted/EncryptionSamples/BlobGettingStarted/App.config b/Samples/GettingStarted/EncryptionSamples/BlobGettingStarted/App.config new file mode 100644 index 000000000..f6da346b3 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/BlobGettingStarted/App.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Samples/GettingStarted/EncryptionSamples/BlobGettingStarted/BlobGettingStarted.csproj b/Samples/GettingStarted/EncryptionSamples/BlobGettingStarted/BlobGettingStarted.csproj new file mode 100644 index 000000000..dcb4b211b --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/BlobGettingStarted/BlobGettingStarted.csproj @@ -0,0 +1,140 @@ + + + + + Debug + AnyCPU + {6DFB68F9-ECAC-4105-95A7-0A51B840A691} + Exe + Properties + BlobGettingStarted + BlobGettingStarted + v4.5 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Hyak.Common.1.0.2\lib\net45\Hyak.Common.dll + True + + + ..\packages\Microsoft.Azure.Common.2.0.4\lib\net45\Microsoft.Azure.Common.dll + True + + + ..\packages\Microsoft.Azure.Common.2.0.4\lib\net45\Microsoft.Azure.Common.NetFramework.dll + True + + + ..\packages\Microsoft.Azure.KeyVault.0.9.1-preview\lib\net45\Microsoft.Azure.KeyVault.dll + True + + + ..\packages\Microsoft.Azure.KeyVault.Core.0.9.1-preview\lib\net40\Microsoft.Azure.KeyVault.Core.dll + True + + + ..\packages\Microsoft.Azure.KeyVault.Extensions.0.9.1-preview\lib\net45\Microsoft.Azure.KeyVault.Extensions.dll + True + + + ..\packages\Microsoft.Data.Edm.5.6.2\lib\net40\Microsoft.Data.Edm.dll + True + + + ..\packages\Microsoft.Data.OData.5.6.2\lib\net40\Microsoft.Data.OData.dll + True + + + ..\packages\Microsoft.Data.Services.Client.5.6.2\lib\net40\Microsoft.Data.Services.Client.dll + True + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll + True + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll + True + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll + True + + + ..\packages\Microsoft.WindowsAzure.ConfigurationManager.1.8.0.0\lib\net35-full\Microsoft.WindowsAzure.Configuration.dll + True + + + ..\packages\WindowsAzure.Storage.4.4.0-preview\lib\net40\Microsoft.WindowsAzure.Storage.dll + True + + + ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll + True + + + + + + + ..\packages\Microsoft.Net.Http.2.2.22\lib\net45\System.Net.Http.Extensions.dll + True + + + ..\packages\Microsoft.Net.Http.2.2.22\lib\net45\System.Net.Http.Primitives.dll + True + + + + ..\packages\System.Spatial.5.6.2\lib\net40\System.Spatial.dll + True + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/GettingStarted/EncryptionSamples/BlobGettingStarted/LocalResolver.cs b/Samples/GettingStarted/EncryptionSamples/BlobGettingStarted/LocalResolver.cs new file mode 100644 index 000000000..2d3a03b3e --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/BlobGettingStarted/LocalResolver.cs @@ -0,0 +1,42 @@ +//---------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. +//---------------------------------------------------------------------------------- +// The example companies, organizations, products, domain names, +// e-mail addresses, logos, people, places, and events depicted +// herein are fictitious. No association with any real company, +// organization, product, domain name, email address, logo, person, +// places, or events is intended or should be inferred. +//---------------------------------------------------------------------------------- +namespace BlobGettingStarted +{ + using Microsoft.Azure.KeyVault.Core; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading; + using System.Threading.Tasks; + + public class LocalResolver : IKeyResolver + { + private Dictionary keys = new Dictionary(); + + public void Add(IKey key) + { + keys[key.Kid] = key; + } + + public async Task ResolveKeyAsync(string kid, CancellationToken token) + { + IKey result; + + keys.TryGetValue(kid, out result); + + return await Task.FromResult(result); + } + } +} diff --git a/Samples/GettingStarted/EncryptionSamples/BlobGettingStarted/Program.cs b/Samples/GettingStarted/EncryptionSamples/BlobGettingStarted/Program.cs new file mode 100644 index 000000000..98cb46acc --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/BlobGettingStarted/Program.cs @@ -0,0 +1,122 @@ +//---------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. +//---------------------------------------------------------------------------------- +// The example companies, organizations, products, domain names, +// e-mail addresses, logos, people, places, and events depicted +// herein are fictitious. No association with any real company, +// organization, product, domain name, email address, logo, person, +// places, or events is intended or should be inferred. +//---------------------------------------------------------------------------------- +namespace BlobGettingStarted +{ + using Microsoft.Azure.KeyVault; + using Microsoft.Azure.KeyVault.Core; + using Microsoft.WindowsAzure; + using Microsoft.WindowsAzure.Storage; + using Microsoft.WindowsAzure.Storage.Blob; + using System; + using System.IO; + using System.Security.Cryptography; + + /// + /// Demonstrates how to use encryption with the Azure Blob service. + /// + public class Program + { + const string DemoContainer = "democontainer"; + + static void Main(string[] args) + { + Console.WriteLine("Blob encryption sample"); + + // Retrieve storage account information from connection string + // How to create a storage connection string - http://msdn.microsoft.com/en-us/library/azure/ee758697.aspx + CloudStorageAccount storageAccount = CreateStorageAccountFromConnectionString(CloudConfigurationManager.GetSetting("StorageConnectionString")); + 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(); + } + } + + private static CloudStorageAccount CreateStorageAccountFromConnectionString(string storageConnectionString) + { + CloudStorageAccount storageAccount; + try + { + storageAccount = CloudStorageAccount.Parse(storageConnectionString); + } + catch (FormatException) + { + Console.WriteLine("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the sample."); + Console.WriteLine("Press any key to exit"); + Console.ReadLine(); + throw; + } + catch (ArgumentException) + { + Console.WriteLine("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the sample."); + Console.WriteLine("Press any key to exit"); + Console.ReadLine(); + throw; + } + + return storageAccount; + } + } +} \ No newline at end of file diff --git a/Samples/GettingStarted/EncryptionSamples/BlobGettingStarted/Properties/AssemblyInfo.cs b/Samples/GettingStarted/EncryptionSamples/BlobGettingStarted/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..0d4b4b6d0 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/BlobGettingStarted/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("BlobGettingStarted")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BlobGettingStarted")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("66d06292-516c-41b4-9041-aa94b8115119")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Samples/GettingStarted/EncryptionSamples/BlobGettingStarted/packages.config b/Samples/GettingStarted/EncryptionSamples/BlobGettingStarted/packages.config new file mode 100644 index 000000000..2133f779f --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/BlobGettingStarted/packages.config @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/GettingStarted/EncryptionSamples/GettingStartedSamples.sln b/Samples/GettingStarted/EncryptionSamples/GettingStartedSamples.sln new file mode 100644 index 000000000..91d872789 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/GettingStartedSamples.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QueueGettingStarted", "QueueGettingStarted\QueueGettingStarted.csproj", "{96209F76-E19B-426E-8C02-6CE26B6187C9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TableGettingStartedUsingResolver", "TableGettingStarted\TableGettingStartedUsingResolver.csproj", "{449D75A7-140A-495A-B35A-9B056095F571}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlobGettingStarted", "BlobGettingStarted\BlobGettingStarted.csproj", "{6DFB68F9-ECAC-4105-95A7-0A51B840A691}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KVGettingStarted", "KVGettingStarted\KVGettingStarted.csproj", "{AB26C6E1-1375-45FD-BF32-4FAE7FFF078A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TableGettingStartedUsingAttributes", "TableGettingStartedUsingAttributes\TableGettingStartedUsingAttributes.csproj", "{804DF8D6-CCCC-4408-8B2E-2FF09CC3B266}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {96209F76-E19B-426E-8C02-6CE26B6187C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {96209F76-E19B-426E-8C02-6CE26B6187C9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {96209F76-E19B-426E-8C02-6CE26B6187C9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {96209F76-E19B-426E-8C02-6CE26B6187C9}.Release|Any CPU.Build.0 = Release|Any CPU + {449D75A7-140A-495A-B35A-9B056095F571}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {449D75A7-140A-495A-B35A-9B056095F571}.Debug|Any CPU.Build.0 = Debug|Any CPU + {449D75A7-140A-495A-B35A-9B056095F571}.Release|Any CPU.ActiveCfg = Release|Any CPU + {449D75A7-140A-495A-B35A-9B056095F571}.Release|Any CPU.Build.0 = Release|Any CPU + {6DFB68F9-ECAC-4105-95A7-0A51B840A691}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6DFB68F9-ECAC-4105-95A7-0A51B840A691}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6DFB68F9-ECAC-4105-95A7-0A51B840A691}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6DFB68F9-ECAC-4105-95A7-0A51B840A691}.Release|Any CPU.Build.0 = Release|Any CPU + {AB26C6E1-1375-45FD-BF32-4FAE7FFF078A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB26C6E1-1375-45FD-BF32-4FAE7FFF078A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB26C6E1-1375-45FD-BF32-4FAE7FFF078A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AB26C6E1-1375-45FD-BF32-4FAE7FFF078A}.Release|Any CPU.Build.0 = Release|Any CPU + {804DF8D6-CCCC-4408-8B2E-2FF09CC3B266}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {804DF8D6-CCCC-4408-8B2E-2FF09CC3B266}.Debug|Any CPU.Build.0 = Debug|Any CPU + {804DF8D6-CCCC-4408-8B2E-2FF09CC3B266}.Release|Any CPU.ActiveCfg = Release|Any CPU + {804DF8D6-CCCC-4408-8B2E-2FF09CC3B266}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Samples/GettingStarted/EncryptionSamples/KVGettingStarted/App.config b/Samples/GettingStarted/EncryptionSamples/KVGettingStarted/App.config new file mode 100644 index 000000000..dedb150a2 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/KVGettingStarted/App.config @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/GettingStarted/EncryptionSamples/KVGettingStarted/KVGettingStarted.csproj b/Samples/GettingStarted/EncryptionSamples/KVGettingStarted/KVGettingStarted.csproj new file mode 100644 index 000000000..fe4b7d00f --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/KVGettingStarted/KVGettingStarted.csproj @@ -0,0 +1,148 @@ + + + + + Debug + AnyCPU + {AB26C6E1-1375-45FD-BF32-4FAE7FFF078A} + Exe + Properties + KVGettingStarted + KVGettingStarted + v4.5 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Hyak.Common.1.0.2\lib\net45\Hyak.Common.dll + True + + + ..\packages\Microsoft.Azure.Common.2.0.4\lib\net45\Microsoft.Azure.Common.dll + True + + + ..\packages\Microsoft.Azure.Common.2.0.4\lib\net45\Microsoft.Azure.Common.NetFramework.dll + True + + + ..\packages\Microsoft.Azure.KeyVault.0.9.1-preview\lib\net45\Microsoft.Azure.KeyVault.dll + True + + + ..\packages\Microsoft.Azure.KeyVault.Core.0.9.1-preview\lib\net40\Microsoft.Azure.KeyVault.Core.dll + True + + + ..\packages\Microsoft.Azure.KeyVault.Extensions.0.9.1-preview\lib\net45\Microsoft.Azure.KeyVault.Extensions.dll + True + + + ..\packages\Microsoft.Data.Edm.5.6.2\lib\net40\Microsoft.Data.Edm.dll + True + + + ..\packages\Microsoft.Data.OData.5.6.2\lib\net40\Microsoft.Data.OData.dll + True + + + ..\packages\Microsoft.Data.Services.Client.5.6.2\lib\net40\Microsoft.Data.Services.Client.dll + True + + + ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.16.204221202\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll + True + + + ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.16.204221202\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll + True + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll + True + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll + True + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll + True + + + ..\packages\Microsoft.WindowsAzure.ConfigurationManager.1.8.0.0\lib\net35-full\Microsoft.WindowsAzure.Configuration.dll + True + + + ..\packages\WindowsAzure.Storage.4.4.0-preview\lib\net40\Microsoft.WindowsAzure.Storage.dll + True + + + ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll + True + + + + + + + ..\packages\Microsoft.Net.Http.2.2.22\lib\net45\System.Net.Http.Extensions.dll + True + + + ..\packages\Microsoft.Net.Http.2.2.22\lib\net45\System.Net.Http.Primitives.dll + True + + + + ..\packages\System.Spatial.5.6.2\lib\net40\System.Spatial.dll + True + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/GettingStarted/EncryptionSamples/KVGettingStarted/LocalResolver.cs b/Samples/GettingStarted/EncryptionSamples/KVGettingStarted/LocalResolver.cs new file mode 100644 index 000000000..27c34063b --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/KVGettingStarted/LocalResolver.cs @@ -0,0 +1,42 @@ +//---------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. +//---------------------------------------------------------------------------------- +// The example companies, organizations, products, domain names, +// e-mail addresses, logos, people, places, and events depicted +// herein are fictitious. No association with any real company, +// organization, product, domain name, email address, logo, person, +// places, or events is intended or should be inferred. +//---------------------------------------------------------------------------------- +namespace KVGettingStarted +{ + using Microsoft.Azure.KeyVault.Core; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading; + using System.Threading.Tasks; + + public class LocalResolver : IKeyResolver + { + private Dictionary keys = new Dictionary(); + + public void Add(IKey key) + { + keys[key.Kid] = key; + } + + public async Task ResolveKeyAsync(string kid, CancellationToken token) + { + IKey result; + + keys.TryGetValue(kid, out result); + + return await Task.FromResult(result); + } + } +} diff --git a/Samples/GettingStarted/EncryptionSamples/KVGettingStarted/Program.cs b/Samples/GettingStarted/EncryptionSamples/KVGettingStarted/Program.cs new file mode 100644 index 000000000..cb8ca10bd --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/KVGettingStarted/Program.cs @@ -0,0 +1,189 @@ +using Microsoft.Azure.KeyVault; +using Microsoft.Azure.KeyVault.Core; +using Microsoft.IdentityModel.Clients.ActiveDirectory; +using Microsoft.WindowsAzure; +using Microsoft.WindowsAzure.Storage; +using Microsoft.WindowsAzure.Storage.Blob; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace KVGettingStarted +{ + /// + /// Demonstrates how to use encryption along with Azure Key Vault integration for the Azure Blob service. + /// + public class Program + { + const string DemoContainer = "democontainer"; + + static async Task GetAccessToken(string authority, string resource, string scope) + { + ClientCredential credential = new ClientCredential(CloudConfigurationManager.GetSetting("KVClientId"), CloudConfigurationManager.GetSetting("KVClientKey")); + + AuthenticationContext ctx = new AuthenticationContext(new Uri(authority).AbsoluteUri, false); + AuthenticationResult result = await ctx.AcquireTokenAsync(resource, credential); + + return result.AccessToken; + } + + static void Main(string[] args) + { + Console.WriteLine("Blob encryption with Key Vault integration"); + + // Retrieve storage account information from connection string + // How to create a storage connection string - http://msdn.microsoft.com/en-us/library/azure/ee758697.aspx + CloudStorageAccount storageAccount = CreateStorageAccountFromConnectionString(CloudConfigurationManager.GetSetting("StorageConnectionString")); + CloudBlobClient client = storageAccount.CreateCloudBlobClient(); + CloudBlobContainer container = client.GetContainerReference(DemoContainer + Guid.NewGuid().ToString("N")); + + // Get reference to a Cloud Key Vault and key resolver. + KeyVaultClient cloudVault = new KeyVaultClient(GetAccessToken); + KeyVaultKeyResolver cloudResolver = new KeyVaultKeyResolver(GetAccessToken); + + // Get reference to a local key and key resolver. + 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 plugin 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); + + // Establish a symmetric KEK stored as a Secret in the cloud key vault + string vaultUri = CloudConfigurationManager.GetSetting("VaultUri"); + + try + { + cloudVault.DeleteSecretAsync(vaultUri, "secret").GetAwaiter().GetResult(); + } + catch (KeyVaultClientException ex) + { + if (ex.Status != System.Net.HttpStatusCode.NotFound) + throw; + } + + // Create a symmetric 256bit symmetric key and convert it to Base64 + SymmetricKey symmetricKey = new SymmetricKey("secret", SymmetricKey.KeySize256); + string symmetricBytes = Convert.ToBase64String(symmetricKey.Key); + + // Store the Base64 of the key in the key vault. This is shown inline for simplicity but + // the recommended approach is to create this key offline and upload it to key vault and + // then use secrets base identifier as a parameter to resolve the current version of the + // secret for encryption. Note that the content-type of the secret must + // be application/octet-stream or the KeyVaultKeyResolver will refuse to load it as a key. + Secret cloudSecret = cloudVault.SetSecretAsync(vaultUri, "secret", symmetricBytes, null, "application/octet-stream").GetAwaiter().GetResult(); + IKey cloudKey = cachingResolver.ResolveKeyAsync(cloudSecret.SecretIdentifier.BaseIdentifier, CancellationToken.None).GetAwaiter().GetResult(); + + try + { + container.Create(); + int size = 5 * 1024 * 1024; + byte[] buffer = new byte[size]; + + Random rand = new Random(); + rand.NextBytes(buffer); + + // Upload first blob using the secret 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(); + } + } + + private static CloudStorageAccount CreateStorageAccountFromConnectionString(string storageConnectionString) + { + CloudStorageAccount storageAccount; + try + { + storageAccount = CloudStorageAccount.Parse(storageConnectionString); + } + catch (FormatException) + { + Console.WriteLine("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the sample."); + Console.WriteLine("Press any key to exit"); + Console.ReadLine(); + throw; + } + catch (ArgumentException) + { + Console.WriteLine("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the sample."); + Console.WriteLine("Press any key to exit"); + Console.ReadLine(); + throw; + } + + return storageAccount; + } + } +} diff --git a/Samples/GettingStarted/EncryptionSamples/KVGettingStarted/Properties/AssemblyInfo.cs b/Samples/GettingStarted/EncryptionSamples/KVGettingStarted/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..91b9d360d --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/KVGettingStarted/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("KVGettingStarted")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("KVGettingStarted")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("137f7827-64e9-4893-932a-3bb9a29909f3")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Samples/GettingStarted/EncryptionSamples/KVGettingStarted/packages.config b/Samples/GettingStarted/EncryptionSamples/KVGettingStarted/packages.config new file mode 100644 index 000000000..618d3ced1 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/KVGettingStarted/packages.config @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/GettingStarted/EncryptionSamples/QueueGettingStarted/App.config b/Samples/GettingStarted/EncryptionSamples/QueueGettingStarted/App.config new file mode 100644 index 000000000..083ba01a6 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/QueueGettingStarted/App.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Samples/GettingStarted/EncryptionSamples/QueueGettingStarted/LocalResolver.cs b/Samples/GettingStarted/EncryptionSamples/QueueGettingStarted/LocalResolver.cs new file mode 100644 index 000000000..97f86dc30 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/QueueGettingStarted/LocalResolver.cs @@ -0,0 +1,42 @@ +//---------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. +//---------------------------------------------------------------------------------- +// The example companies, organizations, products, domain names, +// e-mail addresses, logos, people, places, and events depicted +// herein are fictitious. No association with any real company, +// organization, product, domain name, email address, logo, person, +// places, or events is intended or should be inferred. +//---------------------------------------------------------------------------------- +namespace QueueGettingStarted +{ + using Microsoft.Azure.KeyVault.Core; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading; + using System.Threading.Tasks; + + public class LocalResolver : IKeyResolver + { + private Dictionary keys = new Dictionary(); + + public void Add(IKey key) + { + keys[key.Kid] = key; + } + + public async Task ResolveKeyAsync(string kid, CancellationToken token) + { + IKey result; + + keys.TryGetValue(kid, out result); + + return await Task.FromResult(result); + } + } +} diff --git a/Samples/GettingStarted/EncryptionSamples/QueueGettingStarted/Program.cs b/Samples/GettingStarted/EncryptionSamples/QueueGettingStarted/Program.cs new file mode 100644 index 000000000..e42cf55c3 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/QueueGettingStarted/Program.cs @@ -0,0 +1,117 @@ +//---------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. +//---------------------------------------------------------------------------------- +// The example companies, organizations, products, domain names, +// e-mail addresses, logos, people, places, and events depicted +// herein are fictitious. No association with any real company, +// organization, product, domain name, email address, logo, person, +// places, or events is intended or should be inferred. +//---------------------------------------------------------------------------------- +namespace QueueGettingStarted +{ + using Microsoft.Azure.KeyVault; + using Microsoft.WindowsAzure; + using Microsoft.WindowsAzure.Storage; + using Microsoft.WindowsAzure.Storage.Core; + using Microsoft.WindowsAzure.Storage.Queue; + using System; + using System.IO; + using System.Security.Cryptography; + + /// + /// Demonstrates how to use encryption with the Azure Queue service. + /// + public class Program + { + const string DemoQueue = "demoqueue"; + + static void Main(string[] args) + { + Console.WriteLine("Queue encryption sample"); + + // Retrieve storage account information from connection string + // How to create a storage connection string - http://msdn.microsoft.com/en-us/library/azure/ee758697.aspx + CloudStorageAccount storageAccount = CreateStorageAccountFromConnectionString(CloudConfigurationManager.GetSetting("StorageConnectionString")); + CloudQueueClient client = storageAccount.CreateCloudQueueClient(); + CloudQueue queue = client.GetQueueReference(DemoQueue + Guid.NewGuid().ToString("N")); + + try + { + queue.Create(); + + // Create the IKey used for encryption. + RsaKey key = new RsaKey("private:key1"); + + // Create the encryption policy to be used for insert and update. + QueueEncryptionPolicy insertPolicy = new QueueEncryptionPolicy(key, null); + + // Set the encryption policy on the request options. + QueueRequestOptions insertOptions = new QueueRequestOptions() { EncryptionPolicy = insertPolicy }; + + string messageStr = Guid.NewGuid().ToString(); + CloudQueueMessage message = new CloudQueueMessage(messageStr); + + // Add message + Console.WriteLine("Inserting the encrypted message."); + queue.AddMessage(message, null, null, insertOptions, null); + + // For retrieves, a resolver can be set up that will help pick the key based on the key id. + LocalResolver resolver = new LocalResolver(); + resolver.Add(key); + + QueueEncryptionPolicy retrPolicy = new QueueEncryptionPolicy(null, resolver); + QueueRequestOptions retrieveOptions = new QueueRequestOptions() { EncryptionPolicy = retrPolicy }; + + // Retrieve message + Console.WriteLine("Retrieving the encrypted message."); + CloudQueueMessage retrMessage = queue.GetMessage(null, retrieveOptions, null); + + // Update message + Console.WriteLine("Updating the encrypted message."); + string updatedMessage = Guid.NewGuid().ToString("N"); + retrMessage.SetMessageContent(updatedMessage); + queue.UpdateMessage(retrMessage, TimeSpan.FromSeconds(0), MessageUpdateFields.Content | MessageUpdateFields.Visibility, insertOptions, null); + + // Retrieve updated message + Console.WriteLine("Retrieving the updated encrypted message."); + retrMessage = queue.GetMessage(null, retrieveOptions, null); + + Console.WriteLine("Press enter key to exit"); + Console.ReadLine(); + } + finally + { + queue.DeleteIfExists(); + } + } + + private static CloudStorageAccount CreateStorageAccountFromConnectionString(string storageConnectionString) + { + CloudStorageAccount storageAccount; + try + { + storageAccount = CloudStorageAccount.Parse(storageConnectionString); + } + catch (FormatException) + { + Console.WriteLine("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the sample."); + Console.WriteLine("Press any key to exit"); + Console.ReadLine(); + throw; + } + catch (ArgumentException) + { + Console.WriteLine("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the sample."); + Console.WriteLine("Press any key to exit"); + Console.ReadLine(); + throw; + } + + return storageAccount; + } + } +} \ No newline at end of file diff --git a/Samples/GettingStarted/EncryptionSamples/QueueGettingStarted/Properties/AssemblyInfo.cs b/Samples/GettingStarted/EncryptionSamples/QueueGettingStarted/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..ce5ce7026 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/QueueGettingStarted/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("QueueGettingStarted")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("QueueGettingStarted")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("88aebdfe-c738-41aa-9c66-6e52c0ac5e83")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Samples/GettingStarted/EncryptionSamples/QueueGettingStarted/QueueGettingStarted.csproj b/Samples/GettingStarted/EncryptionSamples/QueueGettingStarted/QueueGettingStarted.csproj new file mode 100644 index 000000000..c2696fc4a --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/QueueGettingStarted/QueueGettingStarted.csproj @@ -0,0 +1,140 @@ + + + + + Debug + AnyCPU + {96209F76-E19B-426E-8C02-6CE26B6187C9} + Exe + Properties + QueueGettingStarted + QueueGettingStarted + v4.5 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Hyak.Common.1.0.2\lib\net45\Hyak.Common.dll + True + + + ..\packages\Microsoft.Azure.Common.2.0.4\lib\net45\Microsoft.Azure.Common.dll + True + + + ..\packages\Microsoft.Azure.Common.2.0.4\lib\net45\Microsoft.Azure.Common.NetFramework.dll + True + + + ..\packages\Microsoft.Azure.KeyVault.0.9.1-preview\lib\net45\Microsoft.Azure.KeyVault.dll + True + + + ..\packages\Microsoft.Azure.KeyVault.Core.0.9.1-preview\lib\net40\Microsoft.Azure.KeyVault.Core.dll + True + + + ..\packages\Microsoft.Azure.KeyVault.Extensions.0.9.1-preview\lib\net45\Microsoft.Azure.KeyVault.Extensions.dll + True + + + ..\packages\Microsoft.Data.Edm.5.6.2\lib\net40\Microsoft.Data.Edm.dll + True + + + ..\packages\Microsoft.Data.OData.5.6.2\lib\net40\Microsoft.Data.OData.dll + True + + + ..\packages\Microsoft.Data.Services.Client.5.6.2\lib\net40\Microsoft.Data.Services.Client.dll + True + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll + True + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll + True + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll + True + + + ..\packages\Microsoft.WindowsAzure.ConfigurationManager.1.8.0.0\lib\net35-full\Microsoft.WindowsAzure.Configuration.dll + True + + + ..\packages\WindowsAzure.Storage.4.4.0-preview\lib\net40\Microsoft.WindowsAzure.Storage.dll + True + + + ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll + True + + + + + + + ..\packages\Microsoft.Net.Http.2.2.22\lib\net45\System.Net.Http.Extensions.dll + True + + + ..\packages\Microsoft.Net.Http.2.2.22\lib\net45\System.Net.Http.Primitives.dll + True + + + + ..\packages\System.Spatial.5.6.2\lib\net40\System.Spatial.dll + True + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/GettingStarted/EncryptionSamples/QueueGettingStarted/packages.config b/Samples/GettingStarted/EncryptionSamples/QueueGettingStarted/packages.config new file mode 100644 index 000000000..2133f779f --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/QueueGettingStarted/packages.config @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/GettingStarted/EncryptionSamples/TableGettingStarted/App.config b/Samples/GettingStarted/EncryptionSamples/TableGettingStarted/App.config new file mode 100644 index 000000000..083ba01a6 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/TableGettingStarted/App.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Samples/GettingStarted/EncryptionSamples/TableGettingStarted/LocalResolver.cs b/Samples/GettingStarted/EncryptionSamples/TableGettingStarted/LocalResolver.cs new file mode 100644 index 000000000..616a553e0 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/TableGettingStarted/LocalResolver.cs @@ -0,0 +1,42 @@ +//---------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. +//---------------------------------------------------------------------------------- +// The example companies, organizations, products, domain names, +// e-mail addresses, logos, people, places, and events depicted +// herein are fictitious. No association with any real company, +// organization, product, domain name, email address, logo, person, +// places, or events is intended or should be inferred. +//---------------------------------------------------------------------------------- +namespace TableGettingStartedUsingResolver +{ + using Microsoft.Azure.KeyVault.Core; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading; + using System.Threading.Tasks; + + public class LocalResolver : IKeyResolver + { + private Dictionary keys = new Dictionary(); + + public void Add(IKey key) + { + keys[key.Kid] = key; + } + + public async Task ResolveKeyAsync(string kid, CancellationToken token) + { + IKey result; + + keys.TryGetValue(kid, out result); + + return await Task.FromResult(result); + } + } +} diff --git a/Samples/GettingStarted/EncryptionSamples/TableGettingStarted/Program.cs b/Samples/GettingStarted/EncryptionSamples/TableGettingStarted/Program.cs new file mode 100644 index 000000000..b07afb969 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/TableGettingStarted/Program.cs @@ -0,0 +1,125 @@ +//---------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. +//---------------------------------------------------------------------------------- +// The example companies, organizations, products, domain names, +// e-mail addresses, logos, people, places, and events depicted +// herein are fictitious. No association with any real company, +// organization, product, domain name, email address, logo, person, +// places, or events is intended or should be inferred. +//---------------------------------------------------------------------------------- +namespace TableGettingStartedUsingResolver +{ + using Microsoft.Azure.KeyVault; + using Microsoft.WindowsAzure; + using Microsoft.WindowsAzure.Storage; + using Microsoft.WindowsAzure.Storage.Core; + using Microsoft.WindowsAzure.Storage.Table; + using System; + using System.IO; + using System.Security.Cryptography; + + /// + /// Demonstrates how to use encryption with the Azure Table service. + /// + public class Program + { + const string DemoTable = "demotable"; + + static void Main(string[] args) + { + Console.WriteLine("Table encryption sample"); + + // Retrieve storage account information from connection string + // How to create a storage connection string - http://msdn.microsoft.com/en-us/library/azure/ee758697.aspx + CloudStorageAccount storageAccount = CreateStorageAccountFromConnectionString(CloudConfigurationManager.GetSetting("StorageConnectionString")); + CloudTableClient client = storageAccount.CreateCloudTableClient(); + CloudTable table = client.GetTableReference(DemoTable + Guid.NewGuid().ToString("N")); + + try + { + table.Create(); + + // Create the IKey used for encryption. + RsaKey key = new RsaKey("private:key1"); + + DynamicTableEntity ent = new DynamicTableEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() }; + ent.Properties.Add("EncryptedProp1", new EntityProperty(string.Empty)); + ent.Properties.Add("EncryptedProp2", new EntityProperty("bar")); + ent.Properties.Add("NotEncryptedProp", new EntityProperty(1234)); + + // This is used to indicate whether a property should be encrypted or not given the partition key, row key, + // and the property name. + Func encryptionResolver = (pk, rk, propName) => + { + if (propName.StartsWith("EncryptedProp")) + { + return true; + } + + return false; + }; + + TableRequestOptions insertOptions = new TableRequestOptions() + { + EncryptionPolicy = new TableEncryptionPolicy(key, null), + + EncryptionResolver = encryptionResolver + }; + + // Insert Entity + Console.WriteLine("Inserting the encrypted entity."); + table.Execute(TableOperation.Insert(ent), insertOptions, null); + + // For retrieves, a resolver can be set up that will help pick the key based on the key id. + LocalResolver resolver = new LocalResolver(); + resolver.Add(key); + + TableRequestOptions retrieveOptions = new TableRequestOptions() + { + EncryptionPolicy = new TableEncryptionPolicy(null, resolver) + }; + + // Retrieve Entity + Console.WriteLine("Retrieving the encrypted entity."); + TableOperation operation = TableOperation.Retrieve(ent.PartitionKey, ent.RowKey); + TableResult result = table.Execute(operation, retrieveOptions, null); + + Console.WriteLine("Press enter key to exit"); + Console.ReadLine(); + } + finally + { + table.DeleteIfExists(); + } + } + + private static CloudStorageAccount CreateStorageAccountFromConnectionString(string storageConnectionString) + { + CloudStorageAccount storageAccount; + try + { + storageAccount = CloudStorageAccount.Parse(storageConnectionString); + } + catch (FormatException) + { + Console.WriteLine("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the sample."); + Console.WriteLine("Press any key to exit"); + Console.ReadLine(); + throw; + } + catch (ArgumentException) + { + Console.WriteLine("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the sample."); + Console.WriteLine("Press any key to exit"); + Console.ReadLine(); + throw; + } + + return storageAccount; + } + } +} \ No newline at end of file diff --git a/Samples/GettingStarted/EncryptionSamples/TableGettingStarted/Properties/AssemblyInfo.cs b/Samples/GettingStarted/EncryptionSamples/TableGettingStarted/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..ede1e7b02 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/TableGettingStarted/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("TableGettingStarted")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TableGettingStarted")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("abd0736d-ec22-437b-a2ad-a6235558513c")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Samples/GettingStarted/EncryptionSamples/TableGettingStarted/TableGettingStartedUsingResolver.csproj b/Samples/GettingStarted/EncryptionSamples/TableGettingStarted/TableGettingStartedUsingResolver.csproj new file mode 100644 index 000000000..74183bf48 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/TableGettingStarted/TableGettingStartedUsingResolver.csproj @@ -0,0 +1,142 @@ + + + + + Debug + AnyCPU + {449D75A7-140A-495A-B35A-9B056095F571} + Exe + Properties + TableGettingStarted + TableGettingStarted + v4.5 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Hyak.Common.1.0.2\lib\net45\Hyak.Common.dll + True + + + ..\packages\Microsoft.Azure.Common.2.0.4\lib\net45\Microsoft.Azure.Common.dll + True + + + ..\packages\Microsoft.Azure.Common.2.0.4\lib\net45\Microsoft.Azure.Common.NetFramework.dll + True + + + ..\packages\Microsoft.Azure.KeyVault.0.9.1-preview\lib\net45\Microsoft.Azure.KeyVault.dll + True + + + ..\packages\Microsoft.Azure.KeyVault.Core.0.9.1-preview\lib\net40\Microsoft.Azure.KeyVault.Core.dll + True + + + ..\packages\Microsoft.Azure.KeyVault.Extensions.0.9.1-preview\lib\net45\Microsoft.Azure.KeyVault.Extensions.dll + True + + + ..\packages\Microsoft.Data.Edm.5.6.2\lib\net40\Microsoft.Data.Edm.dll + True + + + ..\packages\Microsoft.Data.OData.5.6.2\lib\net40\Microsoft.Data.OData.dll + True + + + ..\packages\Microsoft.Data.Services.Client.5.6.2\lib\net40\Microsoft.Data.Services.Client.dll + True + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll + True + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll + True + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll + True + + + ..\packages\Microsoft.WindowsAzure.ConfigurationManager.1.8.0.0\lib\net35-full\Microsoft.WindowsAzure.Configuration.dll + True + + + ..\packages\WindowsAzure.Storage.4.4.0-preview\lib\net40\Microsoft.WindowsAzure.Storage.dll + True + + + ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll + True + + + + + + + ..\packages\Microsoft.Net.Http.2.2.22\lib\net45\System.Net.Http.Extensions.dll + True + + + ..\packages\Microsoft.Net.Http.2.2.22\lib\net45\System.Net.Http.Primitives.dll + True + + + + ..\packages\System.Spatial.5.6.2\lib\net40\System.Spatial.dll + True + + + + + + + + + + + + + + + Designer + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/GettingStarted/EncryptionSamples/TableGettingStarted/packages.config b/Samples/GettingStarted/EncryptionSamples/TableGettingStarted/packages.config new file mode 100644 index 000000000..2133f779f --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/TableGettingStarted/packages.config @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/App.config b/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/App.config new file mode 100644 index 000000000..083ba01a6 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/App.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/EncryptedEntity.cs b/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/EncryptedEntity.cs new file mode 100644 index 000000000..83d8ca46b --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/EncryptedEntity.cs @@ -0,0 +1,52 @@ +//---------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. +//---------------------------------------------------------------------------------- +// The example companies, organizations, products, domain names, +// e-mail addresses, logos, people, places, and events depicted +// herein are fictitious. No association with any real company, +// organization, product, domain name, email address, logo, person, +// places, or events is intended or should be inferred. +//---------------------------------------------------------------------------------- +namespace TableGettingStartedUsingAttributes +{ + using Microsoft.WindowsAzure.Storage.Table; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + + public class EncryptedEntity : TableEntity + { + public EncryptedEntity() + { + } + + public EncryptedEntity(string pk, string rk) + : base(pk, rk) + { + } + + public void Populate() + { + this.EncryptedProperty1 = string.Empty; + this.EncryptedProperty2 = "foo"; + this.NotEncryptedProperty = "b"; + this.NotEncryptedIntProperty = 1234; + } + + [EncryptProperty] + public string EncryptedProperty1 { get; set; } + + [EncryptProperty] + public string EncryptedProperty2 { get; set; } + + public string NotEncryptedProperty { get; set; } + + public int NotEncryptedIntProperty { get; set; } + } +} diff --git a/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/LocalResolver.cs b/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/LocalResolver.cs new file mode 100644 index 000000000..a24c6e309 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/LocalResolver.cs @@ -0,0 +1,42 @@ +//---------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. +//---------------------------------------------------------------------------------- +// The example companies, organizations, products, domain names, +// e-mail addresses, logos, people, places, and events depicted +// herein are fictitious. No association with any real company, +// organization, product, domain name, email address, logo, person, +// places, or events is intended or should be inferred. +//---------------------------------------------------------------------------------- +namespace TableGettingStartedUsingAttributes +{ + using Microsoft.Azure.KeyVault.Core; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading; + using System.Threading.Tasks; + + public class LocalResolver : IKeyResolver + { + private Dictionary keys = new Dictionary(); + + public void Add(IKey key) + { + keys[key.Kid] = key; + } + + public async Task ResolveKeyAsync(string kid, CancellationToken token) + { + IKey result; + + keys.TryGetValue(kid, out result); + + return await Task.FromResult(result); + } + } +} diff --git a/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/Program.cs b/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/Program.cs new file mode 100644 index 000000000..f2b1750b2 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/Program.cs @@ -0,0 +1,109 @@ +//---------------------------------------------------------------------------------- +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. +//---------------------------------------------------------------------------------- +// The example companies, organizations, products, domain names, +// e-mail addresses, logos, people, places, and events depicted +// herein are fictitious. No association with any real company, +// organization, product, domain name, email address, logo, person, +// places, or events is intended or should be inferred. +//---------------------------------------------------------------------------------- +namespace TableGettingStartedUsingAttributes +{ + using Microsoft.Azure.KeyVault; + using Microsoft.WindowsAzure; + using Microsoft.WindowsAzure.Storage; + using Microsoft.WindowsAzure.Storage.Core; + using Microsoft.WindowsAzure.Storage.Table; + using System; + using System.IO; + using System.Security.Cryptography; + + /// + /// Demonstrates how to use encryption with the Azure Table service. + /// + public class Program + { + const string DemoTable = "demotable"; + + static void Main(string[] args) + { + Console.WriteLine("Table encryption sample"); + + // Retrieve storage account information from connection string + // How to create a storage connection string - http://msdn.microsoft.com/en-us/library/azure/ee758697.aspx + CloudStorageAccount storageAccount = CreateStorageAccountFromConnectionString(CloudConfigurationManager.GetSetting("StorageConnectionString")); + CloudTableClient client = storageAccount.CreateCloudTableClient(); + CloudTable table = client.GetTableReference(DemoTable + Guid.NewGuid().ToString("N")); + + try + { + table.Create(); + + // Create the IKey used for encryption. + RsaKey key = new RsaKey("private:key1"); + + EncryptedEntity ent = new EncryptedEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() }; + ent.Populate(); + + TableRequestOptions insertOptions = new TableRequestOptions() + { + EncryptionPolicy = new TableEncryptionPolicy(key, null) + }; + + // Insert Entity + Console.WriteLine("Inserting the encrypted entity."); + table.Execute(TableOperation.Insert(ent), insertOptions, null); + + // For retrieves, a resolver can be set up that will help pick the key based on the key id. + LocalResolver resolver = new LocalResolver(); + resolver.Add(key); + + TableRequestOptions retrieveOptions = new TableRequestOptions() + { + EncryptionPolicy = new TableEncryptionPolicy(null, resolver) + }; + + // Retrieve Entity + Console.WriteLine("Retrieving the encrypted entity."); + TableOperation operation = TableOperation.Retrieve(ent.PartitionKey, ent.RowKey); + TableResult result = table.Execute(operation, retrieveOptions, null); + + Console.WriteLine("Press enter key to exit"); + Console.ReadLine(); + } + finally + { + table.DeleteIfExists(); + } + } + + private static CloudStorageAccount CreateStorageAccountFromConnectionString(string storageConnectionString) + { + CloudStorageAccount storageAccount; + try + { + storageAccount = CloudStorageAccount.Parse(storageConnectionString); + } + catch (FormatException) + { + Console.WriteLine("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the sample."); + Console.WriteLine("Press any key to exit"); + Console.ReadLine(); + throw; + } + catch (ArgumentException) + { + Console.WriteLine("Invalid storage account information provided. Please confirm the AccountName and AccountKey are valid in the app.config file - then restart the sample."); + Console.WriteLine("Press any key to exit"); + Console.ReadLine(); + throw; + } + + return storageAccount; + } + } +} \ No newline at end of file diff --git a/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/Properties/AssemblyInfo.cs b/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..109886864 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("TableGettingStartedUsingAttributes")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TableGettingStartedUsingAttributes")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("bbaa3e35-34d7-40f9-90db-7f3484022527")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/TableGettingStartedUsingAttributes.csproj b/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/TableGettingStartedUsingAttributes.csproj new file mode 100644 index 000000000..fb8fd4070 --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/TableGettingStartedUsingAttributes.csproj @@ -0,0 +1,141 @@ + + + + + Debug + AnyCPU + {804DF8D6-CCCC-4408-8B2E-2FF09CC3B266} + Exe + Properties + TableGettingStartedUsingAttributes + TableGettingStartedUsingAttributes + v4.5 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Hyak.Common.1.0.2\lib\net45\Hyak.Common.dll + True + + + ..\packages\Microsoft.Azure.Common.2.0.4\lib\net45\Microsoft.Azure.Common.dll + True + + + ..\packages\Microsoft.Azure.Common.2.0.4\lib\net45\Microsoft.Azure.Common.NetFramework.dll + True + + + ..\packages\Microsoft.Azure.KeyVault.0.9.1-preview\lib\net45\Microsoft.Azure.KeyVault.dll + True + + + ..\packages\Microsoft.Azure.KeyVault.Core.0.9.1-preview\lib\net40\Microsoft.Azure.KeyVault.Core.dll + True + + + ..\packages\Microsoft.Azure.KeyVault.Extensions.0.9.1-preview\lib\net45\Microsoft.Azure.KeyVault.Extensions.dll + True + + + ..\packages\Microsoft.Data.Edm.5.6.2\lib\net40\Microsoft.Data.Edm.dll + True + + + ..\packages\Microsoft.Data.OData.5.6.2\lib\net40\Microsoft.Data.OData.dll + True + + + ..\packages\Microsoft.Data.Services.Client.5.6.2\lib\net40\Microsoft.Data.Services.Client.dll + True + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll + True + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll + True + + + ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll + True + + + ..\packages\Microsoft.WindowsAzure.ConfigurationManager.1.8.0.0\lib\net35-full\Microsoft.WindowsAzure.Configuration.dll + True + + + ..\packages\WindowsAzure.Storage.4.4.0-preview\lib\net40\Microsoft.WindowsAzure.Storage.dll + True + + + ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll + True + + + + + + + ..\packages\Microsoft.Net.Http.2.2.22\lib\net45\System.Net.Http.Extensions.dll + True + + + ..\packages\Microsoft.Net.Http.2.2.22\lib\net45\System.Net.Http.Primitives.dll + True + + + + ..\packages\System.Spatial.5.6.2\lib\net40\System.Spatial.dll + True + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/packages.config b/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/packages.config new file mode 100644 index 000000000..2133f779f --- /dev/null +++ b/Samples/GettingStarted/EncryptionSamples/TableGettingStartedUsingAttributes/packages.config @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file