diff --git a/microsoft-azure-storage-samples/pom.xml b/microsoft-azure-storage-samples/pom.xml
index 8306b5cc2206..60414f8b1adb 100644
--- a/microsoft-azure-storage-samples/pom.xml
+++ b/microsoft-azure-storage-samples/pom.xml
@@ -26,7 +26,12 @@
com.microsoft.azure
azure-storage
- 4.0.0
+ 4.0-alpha-1
+
+
+ com.microsoft.azure
+ azure-keyvault-extensions
+ 0.8.0
\ No newline at end of file
diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/blob/gettingstarted/BlobGettingStarted.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/blob/gettingstarted/BlobGettingStarted.java
new file mode 100644
index 000000000000..51f17a7ac400
--- /dev/null
+++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/blob/gettingstarted/BlobGettingStarted.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright Microsoft Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.microsoft.azure.storage.encryption.blob.gettingstarted;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.util.Random;
+import java.util.UUID;
+
+import com.microsoft.azure.keyvault.extensions.RsaKey;
+import com.microsoft.azure.storage.CloudStorageAccount;
+import com.microsoft.azure.storage.StorageException;
+import com.microsoft.azure.storage.blob.BlobEncryptionPolicy;
+import com.microsoft.azure.storage.blob.BlobRequestOptions;
+import com.microsoft.azure.storage.blob.CloudBlobClient;
+import com.microsoft.azure.storage.blob.CloudBlobContainer;
+import com.microsoft.azure.storage.blob.CloudBlockBlob;
+import com.microsoft.azure.storage.util.LocalResolver;
+import com.microsoft.azure.storage.util.Utility;
+
+/**
+ * Demonstrates how to use encryption with the Azure Blob service.
+ */
+public class BlobGettingStarted {
+
+ public static void main(String[] args) throws InvalidKeyException,
+ URISyntaxException, StorageException, NoSuchAlgorithmException,
+ IOException {
+ Utility.printSampleStartInfo("BlobBasicsEncryption");
+
+ // Retrieve storage account information from connection string
+ // How to create a storage connection string -
+ // https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/
+ CloudStorageAccount account = CloudStorageAccount
+ .parse(Utility.storageConnectionString);
+ CloudBlobClient blobClient = account.createCloudBlobClient();
+
+ // Get a reference to a container
+ // The container name must be lower case
+ // Append a random UUID to the end of the container name so that
+ // this sample can be run more than once in quick succession.
+ CloudBlobContainer container = blobClient
+ .getContainerReference("blobencryptioncontainer"
+ + UUID.randomUUID().toString().replace("-", ""));
+
+ try {
+ // Create the container if it does not exist
+ container.createIfNotExists();
+
+ 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.
+ final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+ keyGen.initialize(1024);
+ final KeyPair wrapKey = keyGen.generateKeyPair();
+ RsaKey key = new RsaKey("rsaKey1", wrapKey);
+
+ // 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();
+ uploadOptions.setEncryptionPolicy(uploadPolicy);
+
+ System.out.println("Uploading the encrypted blob.");
+
+ // Upload the encrypted contents to the blob.
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(buffer);
+ blob.upload(inputStream, 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.
+ // Create the encryption policy to be used for download.
+ 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();
+ downloadOptions.setEncryptionPolicy(downloadPolicy);
+
+ System.out.println("Downloading the encrypted blob.");
+
+ // Download and decrypt the encrypted contents from the blob.
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ blob.download(outputStream, null, downloadOptions, null);
+ } finally {
+ // Delete the container
+ container.deleteIfExists();
+ Utility.printSampleCompleteInfo("BlobBasicsEncryption");
+ }
+ }
+}
diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/keyvault/gettingstarted/KeyVaultGettingStarted.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/keyvault/gettingstarted/KeyVaultGettingStarted.java
new file mode 100644
index 000000000000..3f6b14166873
--- /dev/null
+++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/keyvault/gettingstarted/KeyVaultGettingStarted.java
@@ -0,0 +1,182 @@
+/**
+ * Copyright Microsoft Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.microsoft.azure.storage.encryption.keyvault.gettingstarted;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.util.Random;
+import java.util.UUID;
+import java.util.concurrent.ExecutionException;
+
+import com.microsoft.azure.keyvault.core.IKey;
+import com.microsoft.azure.keyvault.extensions.AggregateKeyResolver;
+import com.microsoft.azure.keyvault.extensions.CachingKeyResolver;
+import com.microsoft.azure.keyvault.extensions.KeyVaultKeyResolver;
+import com.microsoft.azure.keyvault.extensions.RsaKey;
+import com.microsoft.azure.storage.CloudStorageAccount;
+import com.microsoft.azure.storage.StorageException;
+import com.microsoft.azure.storage.blob.BlobEncryptionPolicy;
+import com.microsoft.azure.storage.blob.BlobRequestOptions;
+import com.microsoft.azure.storage.blob.CloudBlobClient;
+import com.microsoft.azure.storage.blob.CloudBlobContainer;
+import com.microsoft.azure.storage.blob.CloudBlockBlob;
+import com.microsoft.azure.storage.util.KeyVaultUtility;
+import com.microsoft.azure.storage.util.LocalResolver;
+import com.microsoft.azure.storage.util.Utility;
+
+public class KeyVaultGettingStarted {
+
+ public static void main(String[] args) throws StorageException,
+ NoSuchAlgorithmException, InterruptedException, ExecutionException,
+ URISyntaxException, InvalidKeyException, IOException {
+ Utility.printSampleStartInfo("KeyVaultGettingStarted");
+
+ // Get the key ID from App.config if it exists.
+ String keyID = Utility.keyVaultKeyID;
+
+ // If no key ID was specified, we will create a new secret in Key Vault.
+ // To create a new secret, this client needs full permission to Key
+ // Vault secrets.
+ // Once the secret is created, its ID can be added to App.config. Once
+ // this is done,
+ // this client only needs read access to secrets.
+ if (keyID == null || keyID.isEmpty()) {
+ keyID = KeyVaultUtility.createSecret("KVGettingStartedSecret");
+ }
+
+ // Retrieve storage account information from connection string
+ // How to create a storage connection string -
+ // https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/
+ CloudStorageAccount storageAccount = CloudStorageAccount
+ .parse(Utility.storageConnectionString);
+
+ CloudBlobClient client = storageAccount.createCloudBlobClient();
+ CloudBlobContainer container = client
+ .getContainerReference("blobencryptioncontainer"
+ + UUID.randomUUID().toString().replace("-", ""));
+
+ // Construct a resolver capable of looking up keys and secrets stored in
+ // Key Vault.
+
+ KeyVaultKeyResolver cloudResolver = new KeyVaultKeyResolver(
+ KeyVaultUtility.GetKeyVaultClient());
+
+ // To demonstrate how multiple different types of key can be used, we
+ // also create a local key and resolver.
+ // This key is temporary and won't be persisted.
+ final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+ keyGen.initialize(1024);
+ final KeyPair wrapKey = keyGen.generateKeyPair();
+
+ RsaKey rsaKey = new RsaKey("rsaKey1", wrapKey);
+ LocalResolver resolver = new LocalResolver();
+ resolver.add(rsaKey);
+
+ // If there are multiple key sources like Azure Key Vault and local KMS,
+ // set up an aggregate resolver as follows.
+ // This helps users to define a plug-in model for all the different key
+ // providers they support.
+ AggregateKeyResolver aggregateResolver = new AggregateKeyResolver();
+ aggregateResolver.Add(resolver);
+ aggregateResolver.Add(cloudResolver);
+
+ // Set up a caching resolver so the secrets can be cached on the client.
+ // This is the recommended usage
+ // pattern since the throttling targets for Storage and Key Vault
+ // services are orders of magnitude
+ // different.
+ CachingKeyResolver cachingResolver = new CachingKeyResolver(2,
+ aggregateResolver);
+
+ // Create a key instance corresponding to the key ID. This will cache
+ // the secret.
+ IKey cloudKey = cachingResolver.resolveKeyAsync(keyID).get();
+
+ try {
+ container.createIfNotExists();
+ int size = 5 * 1024 * 1024;
+ byte[] buffer = new byte[size];
+
+ Random rand = new Random();
+ rand.nextBytes(buffer);
+
+ // The first blob will use the key stored in Azure Key Vault.
+ CloudBlockBlob blob = container.getBlockBlobReference("blockblob1");
+
+ // Create the encryption policy using the secret stored in Azure Key
+ // Vault to be used for upload.
+ BlobEncryptionPolicy uploadPolicy = new BlobEncryptionPolicy(
+ cloudKey, null);
+
+ // Set the encryption policy on the request options.
+ BlobRequestOptions uploadOptions = new BlobRequestOptions();
+ uploadOptions.setEncryptionPolicy(uploadPolicy);
+
+ System.out.println("Uploading the 1st encrypted blob.");
+
+ // Upload the encrypted contents to the blob.
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(buffer);
+ blob.upload(inputStream, 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();
+ downloadOptions.setEncryptionPolicy(downloadPolicy);
+
+ System.out.println("Downloading the 1st encrypted blob.");
+
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ blob.download(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();
+ uploadOptions.setEncryptionPolicy(uploadPolicy);
+
+ System.out.println("Uploading the 2nd encrypted blob.");
+
+ // Upload the encrypted contents to the blob.
+ inputStream = new ByteArrayInputStream(buffer);
+ blob.upload(inputStream, 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.
+ System.out.println("Downloading the 2nd encrypted blob.");
+
+ // Download and decrypt the encrypted contents from the blob.
+ outputStream = new ByteArrayOutputStream();
+ blob.download(outputStream, null, downloadOptions, null);
+ } finally {
+ container.deleteIfExists();
+ Utility.printSampleCompleteInfo("KeyVaultGettingStarted");
+ }
+ }
+}
diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/keyvault/keyrotation/gettingstarted/KeyRotationGettingStarted.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/keyvault/keyrotation/gettingstarted/KeyRotationGettingStarted.java
new file mode 100644
index 000000000000..ba2fec7db216
--- /dev/null
+++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/keyvault/keyrotation/gettingstarted/KeyRotationGettingStarted.java
@@ -0,0 +1,183 @@
+/**
+ * Copyright Microsoft Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.microsoft.azure.storage.encryption.keyvault.keyrotation.gettingstarted;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Random;
+import java.util.UUID;
+import java.util.concurrent.ExecutionException;
+
+import com.microsoft.azure.keyvault.core.IKey;
+import com.microsoft.azure.keyvault.extensions.CachingKeyResolver;
+import com.microsoft.azure.keyvault.extensions.KeyVaultKeyResolver;
+import com.microsoft.azure.storage.CloudStorageAccount;
+import com.microsoft.azure.storage.StorageException;
+import com.microsoft.azure.storage.blob.BlobEncryptionPolicy;
+import com.microsoft.azure.storage.blob.BlobRequestOptions;
+import com.microsoft.azure.storage.blob.CloudBlobClient;
+import com.microsoft.azure.storage.blob.CloudBlobContainer;
+import com.microsoft.azure.storage.blob.CloudBlockBlob;
+import com.microsoft.azure.storage.util.KeyVaultUtility;
+import com.microsoft.azure.storage.util.Utility;
+
+public class KeyRotationGettingStarted {
+
+ public static void main(String[] args) throws StorageException,
+ InterruptedException, ExecutionException, URISyntaxException,
+ NoSuchAlgorithmException, InvalidKeyException, IOException {
+ Utility.printSampleStartInfo("KeyRotationGettingStarted");
+
+ // Create two secrets and obtain their IDs. This is normally a one-time
+ // setup step.
+ // Although it is possible to use keys (rather than secrets) stored in
+ // Key Vault, this prevents caching.
+ // Therefore it is recommended to use secrets along with a caching
+ // resolver (see below).
+ String keyID1 = Utility.keyVaultKeyIDForRotation1;
+ String keyID2 = Utility.keyVaultKeyIDForRotation2;
+
+ if (keyID1 == null || keyID1.isEmpty()) {
+ keyID1 = KeyVaultUtility.createSecret("KeyRotationSampleSecret1");
+ }
+
+ if (keyID2 == null || keyID2.isEmpty()) {
+ keyID2 = KeyVaultUtility.createSecret("KeyRotationSampleSecret2");
+ }
+
+ // Retrieve storage account information from connection string
+ // How to create a storage connection string -
+ // https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/
+ CloudStorageAccount storageAccount = CloudStorageAccount
+ .parse(Utility.storageConnectionString);
+ CloudBlobClient client = storageAccount.createCloudBlobClient();
+ CloudBlobContainer container = client
+ .getContainerReference("blobencryptioncontainer"
+ + UUID.randomUUID().toString().replace("-", ""));
+
+ // Construct a resolver capable of looking up keys and secrets stored in
+ // Key Vault.
+ KeyVaultKeyResolver cloudResolver = new KeyVaultKeyResolver(
+ KeyVaultUtility.GetKeyVaultClient());
+
+ // Set up a caching resolver so the secrets can be cached on the client.
+ // This is the recommended usage
+ // pattern since the throttling targets for Storage and Key Vault
+ // services are orders of magnitude
+ // different.
+ CachingKeyResolver cachingResolver = new CachingKeyResolver(2,
+ cloudResolver);
+
+ // Create key instances corresponding to the key IDs. This will cache
+ // the secrets.
+ IKey cloudKey1 = cachingResolver.resolveKeyAsync(keyID1).get();
+ IKey cloudKey2 = cachingResolver.resolveKeyAsync(keyID2).get();
+
+ // We begin with cloudKey1, and a resolver capable of resolving and
+ // caching Key Vault secrets.
+ BlobEncryptionPolicy encryptionPolicy = new BlobEncryptionPolicy(
+ cloudKey1, cachingResolver);
+ BlobRequestOptions defaultRequestOptions = client
+ .getDefaultRequestOptions();
+ defaultRequestOptions.setEncryptionPolicy(encryptionPolicy);
+ defaultRequestOptions.setRequireEncryption(true);
+
+ try {
+ container.createIfNotExists();
+ int size = 5 * 1024 * 1024;
+ byte[] buffer1 = new byte[size];
+ byte[] buffer2 = new byte[size];
+
+ Random rand = new Random();
+ rand.nextBytes(buffer1);
+ rand.nextBytes(buffer2);
+
+ // Upload the first blob using the secret stored in Azure Key Vault.
+ CloudBlockBlob blob = container.getBlockBlobReference("blockblob1");
+
+ System.out.println("Uploading Blob 1 using Key 1.");
+
+ // Upload the encrypted contents to the first blob.
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(buffer1);
+ blob.upload(inputStream, size);
+
+ System.out.println("Downloading and decrypting Blob 1.");
+
+ // Download and decrypt the encrypted contents from the first blob.
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ blob.download(outputStream);
+
+ // At this point we will rotate our keys so new encrypted content
+ // will use the
+ // second key. Note that the same resolver is used, as this resolver
+ // is capable
+ // of decrypting blobs encrypted using either key.
+ System.out.println("Rotating the active encryption key to Key 2.");
+
+ client.getDefaultRequestOptions().setEncryptionPolicy(
+ new BlobEncryptionPolicy(cloudKey2, cachingResolver));
+
+ // Upload the second blob using the key stored in Azure Key Vault.
+ CloudBlockBlob blob2 = container
+ .getBlockBlobReference("blockblob2");
+
+ System.out.println("Uploading Blob 2 using Key 2.");
+
+ // Upload the encrypted contents to the second blob.
+ inputStream = new ByteArrayInputStream(buffer2);
+ blob2.upload(inputStream, size);
+
+ System.out.println("Downloading and decrypting Blob 2.");
+
+ // Download and decrypt the encrypted contents from the second blob.
+ outputStream = new ByteArrayOutputStream();
+ blob2.download(outputStream);
+
+ // Here we download and re-upload the first blob. This has the
+ // effect of updating
+ // the blob to use the new key.
+ System.out.println("Downloading and decrypting Blob 1.");
+ outputStream = new ByteArrayOutputStream();
+ blob.download(outputStream);
+
+ System.out.println("Re-uploading Blob 1 using Key 2.");
+ inputStream = new ByteArrayInputStream(outputStream.toByteArray());
+ blob.upload(inputStream, size);
+
+ // For the purposes of demonstration, we now override the encryption
+ // policy to only recognize key 2.
+ BlobEncryptionPolicy key2OnlyPolicy = new BlobEncryptionPolicy(
+ cloudKey2, null);
+ BlobRequestOptions key2OnlyOptions = new BlobRequestOptions();
+ key2OnlyOptions.setEncryptionPolicy(key2OnlyPolicy);
+
+ System.out.println("Downloading and decrypting Blob 1.");
+
+ outputStream = new ByteArrayOutputStream();
+ blob.download(outputStream, null, key2OnlyOptions, null);
+ // The first blob can still be decrypted because it is using the
+ // second key.
+ } finally {
+ container.deleteIfExists();
+ Utility.printSampleCompleteInfo("KeyRotationGettingStarted");
+ }
+
+ }
+
+}
diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/queue/gettingstarted/QueueGettingStarted.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/queue/gettingstarted/QueueGettingStarted.java
new file mode 100644
index 000000000000..98fedfcc6a40
--- /dev/null
+++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/queue/gettingstarted/QueueGettingStarted.java
@@ -0,0 +1,112 @@
+/**
+ * Copyright Microsoft Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.microsoft.azure.storage.encryption.queue.gettingstarted;
+
+import java.net.URISyntaxException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.util.EnumSet;
+import java.util.UUID;
+
+import com.microsoft.azure.keyvault.extensions.RsaKey;
+import com.microsoft.azure.storage.CloudStorageAccount;
+import com.microsoft.azure.storage.StorageException;
+import com.microsoft.azure.storage.queue.CloudQueue;
+import com.microsoft.azure.storage.queue.CloudQueueClient;
+import com.microsoft.azure.storage.queue.CloudQueueMessage;
+import com.microsoft.azure.storage.queue.MessageUpdateFields;
+import com.microsoft.azure.storage.queue.QueueEncryptionPolicy;
+import com.microsoft.azure.storage.queue.QueueRequestOptions;
+import com.microsoft.azure.storage.util.LocalResolver;
+import com.microsoft.azure.storage.util.Utility;
+
+public class QueueGettingStarted {
+
+ public static void main(String[] args) throws InvalidKeyException,
+ URISyntaxException, StorageException {
+
+ Utility.printSampleStartInfo("QueueBasicsEncryption");
+
+ // Retrieve storage account information from connection string
+ // How to create a storage connection string -
+ // https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/
+ CloudStorageAccount account = CloudStorageAccount
+ .parse(Utility.storageConnectionString);
+ CloudQueueClient client = account.createCloudQueueClient();
+ CloudQueue queue = client.getQueueReference("encryptionqueue"
+ + UUID.randomUUID().toString().replace("-", ""));
+
+ try {
+ queue.createIfNotExists();
+
+ // Create the IKey used for encryption.
+ final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+ keyGen.initialize(1024);
+ final KeyPair wrapKey = keyGen.generateKeyPair();
+
+ RsaKey key = new RsaKey("rsaKey1", wrapKey);
+
+ // 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();
+ insertOptions.setEncryptionPolicy(insertPolicy);
+
+ String messageStr = UUID.randomUUID().toString();
+ CloudQueueMessage message = new CloudQueueMessage(messageStr);
+
+ // Add message
+ System.out.println("Inserting the encrypted message.");
+ queue.addMessage(message, 0, 0, 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();
+ retrieveOptions.setEncryptionPolicy(retrPolicy);
+
+ // Retrieve message
+ System.out.println("Retrieving the encrypted message.");
+ CloudQueueMessage retrMessage = queue.retrieveMessage(1,
+ retrieveOptions, null);
+
+ // Update message
+ System.out.println("Updating the encrypted message.");
+ String updatedMessage = UUID.randomUUID().toString();
+ retrMessage.setMessageContent(updatedMessage);
+ queue.updateMessage(retrMessage, 0, EnumSet
+ .of(MessageUpdateFields.CONTENT,
+ MessageUpdateFields.VISIBILITY), insertOptions,
+ null);
+
+ // Retrieve updated message
+ System.out.println("Retrieving the updated encrypted message.");
+ retrMessage = queue.retrieveMessage(1, retrieveOptions, null);
+ } catch (Throwable t) {
+ Utility.printException(t);
+ } finally {
+ queue.deleteIfExists();
+ Utility.printSampleCompleteInfo("QueueBasicsEncryption");
+ }
+ }
+
+}
diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/attributes/EncryptedEntity.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/attributes/EncryptedEntity.java
new file mode 100644
index 000000000000..ab5b049249c4
--- /dev/null
+++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/attributes/EncryptedEntity.java
@@ -0,0 +1,63 @@
+package com.microsoft.azure.storage.encryption.table.gettingstarted.attributes;
+
+import com.microsoft.azure.storage.table.Encrypt;
+import com.microsoft.azure.storage.table.TableServiceEntity;
+
+public class EncryptedEntity extends TableServiceEntity {
+
+ private String encryptedProperty1;
+ private String encryptedProperty2;
+ private String notEncryptedProperty;
+ private int notEncryptedIntProperty;
+
+ @Encrypt
+ public String getEncryptedProperty1() {
+ return this.encryptedProperty1;
+ }
+
+ @Encrypt
+ public String getEncryptedProperty2() {
+ return this.encryptedProperty2;
+ }
+
+ public String getNotEncryptedProperty() {
+ return this.notEncryptedProperty;
+ }
+
+ public int getNotEncryptedIntProperty() {
+ return this.notEncryptedIntProperty;
+ }
+
+ @Encrypt
+ public void setEncryptedProperty1(String encryptedProperty1) {
+ this.encryptedProperty1 = encryptedProperty1;
+ }
+
+ @Encrypt
+ public void setEncryptedProperty2(String encryptedProperty2) {
+ this.encryptedProperty2 = encryptedProperty2;
+ }
+
+ public void setNotEncryptedProperty(String notEncryptedProperty) {
+ this.notEncryptedProperty = notEncryptedProperty;
+ }
+
+ public void setNotEncryptedIntProperty(int notEncryptedIntProperty) {
+ this.notEncryptedIntProperty = notEncryptedIntProperty;
+ }
+
+ public EncryptedEntity() {
+
+ }
+
+ public EncryptedEntity(String pk, String rk) {
+ super(pk, rk);
+ }
+
+ public void Populate() {
+ this.setEncryptedProperty1("");
+ this.setEncryptedProperty2("foo");
+ this.setNotEncryptedProperty("b");
+ this.setNotEncryptedIntProperty(1234);
+ }
+}
diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/attributes/TableGettingStartedAttributes.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/attributes/TableGettingStartedAttributes.java
new file mode 100644
index 000000000000..0f4faf30fd4d
--- /dev/null
+++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/attributes/TableGettingStartedAttributes.java
@@ -0,0 +1,92 @@
+/**
+ * Copyright Microsoft Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.microsoft.azure.storage.encryption.table.gettingstarted.attributes;
+
+import java.net.URISyntaxException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Date;
+import java.util.UUID;
+
+import com.microsoft.azure.keyvault.extensions.RsaKey;
+import com.microsoft.azure.storage.CloudStorageAccount;
+import com.microsoft.azure.storage.StorageException;
+import com.microsoft.azure.storage.table.CloudTable;
+import com.microsoft.azure.storage.table.CloudTableClient;
+import com.microsoft.azure.storage.table.TableEncryptionPolicy;
+import com.microsoft.azure.storage.table.TableOperation;
+import com.microsoft.azure.storage.table.TableRequestOptions;
+import com.microsoft.azure.storage.table.TableResult;
+import com.microsoft.azure.storage.util.LocalResolver;
+import com.microsoft.azure.storage.util.Utility;
+
+public class TableGettingStartedAttributes {
+
+ public static void main(String[] args) throws URISyntaxException,
+ StorageException, InvalidKeyException, NoSuchAlgorithmException {
+ Utility.printSampleStartInfo("TableResolverAttributes");
+
+ // Retrieve storage account information from connection string
+ // How to create a storage connection string -
+ // https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/
+ CloudStorageAccount storageAccount = CloudStorageAccount
+ .parse(Utility.storageConnectionString);
+ CloudTableClient client = storageAccount.createCloudTableClient();
+ CloudTable table = client.getTableReference("encryptiontableattributes"
+ + UUID.randomUUID().toString().replace("-", ""));
+
+ try {
+ table.createIfNotExists();
+
+ // Create the IKey used for encryption.
+ RsaKey key = new RsaKey("private:key1");
+
+ EncryptedEntity ent = new EncryptedEntity(UUID.randomUUID()
+ .toString(), String.valueOf(new Date().getTime()));
+ ent.Populate();
+
+ TableRequestOptions insertOptions = new TableRequestOptions();
+ insertOptions.setEncryptionPolicy(new TableEncryptionPolicy(key,
+ null));
+
+ // Insert Entity
+ System.out.println("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();
+ retrieveOptions.setEncryptionPolicy(new TableEncryptionPolicy(null,
+ resolver));
+
+ // Retrieve Entity
+ System.out.println("Retrieving the encrypted entity.");
+ TableOperation operation = TableOperation.retrieve(
+ ent.getPartitionKey(), ent.getRowKey(),
+ EncryptedEntity.class);
+ TableResult result = table
+ .execute(operation, retrieveOptions, null);
+ EncryptedEntity resultEntity = result.getResultAsType();
+ System.out.println("EncryptedProperty2 = "
+ + resultEntity.getEncryptedProperty2());
+ } finally {
+ table.deleteIfExists();
+ Utility.printSampleCompleteInfo("TableResolverAttributes");
+ }
+ }
+}
diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/resolver/TableGettingStartedResolver.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/resolver/TableGettingStartedResolver.java
new file mode 100644
index 000000000000..1544bd30a76c
--- /dev/null
+++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/encryption/table/gettingstarted/resolver/TableGettingStartedResolver.java
@@ -0,0 +1,115 @@
+/**
+ * Copyright Microsoft Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.microsoft.azure.storage.encryption.table.gettingstarted.resolver;
+
+import java.net.URISyntaxException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Date;
+import java.util.UUID;
+
+import com.microsoft.azure.storage.table.CloudTable;
+import com.microsoft.azure.storage.table.CloudTableClient;
+import com.microsoft.azure.storage.table.DynamicTableEntity;
+import com.microsoft.azure.storage.table.EntityProperty;
+import com.microsoft.azure.storage.table.TableEncryptionPolicy;
+import com.microsoft.azure.storage.table.TableOperation;
+import com.microsoft.azure.storage.table.TableRequestOptions;
+import com.microsoft.azure.storage.table.TableRequestOptions.EncryptionResolver;
+import com.microsoft.azure.storage.table.TableResult;
+import com.microsoft.azure.storage.util.LocalResolver;
+import com.microsoft.azure.storage.util.Utility;
+import com.microsoft.azure.keyvault.extensions.RsaKey;
+import com.microsoft.azure.storage.CloudStorageAccount;
+import com.microsoft.azure.storage.StorageException;
+
+public class TableGettingStartedResolver {
+
+ public static void main(String[] args) throws StorageException,
+ URISyntaxException, InvalidKeyException, NoSuchAlgorithmException {
+ Utility.printSampleStartInfo("TableResolverEncryption");
+
+ // Retrieve storage account information from connection string
+ // How to create a storage connection string -
+ // https://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/
+ CloudStorageAccount storageAccount = CloudStorageAccount
+ .parse(Utility.storageConnectionString);
+ CloudTableClient client = storageAccount.createCloudTableClient();
+ CloudTable table = client.getTableReference("encryptiontableresolver"
+ + UUID.randomUUID().toString().replace("-", ""));
+
+ try {
+ table.createIfNotExists();
+
+ // Create the IKey used for encryption.
+ RsaKey key = new RsaKey("private:key1");
+
+ DynamicTableEntity ent = new DynamicTableEntity();
+ ent.setPartitionKey(UUID.randomUUID().toString());
+ ent.setRowKey(String.valueOf(new Date().getTime()));
+ ent.getProperties().put("EncryptedProp1", new EntityProperty(""));
+ ent.getProperties()
+ .put("EncryptedProp2", new EntityProperty("bar"));
+ ent.getProperties().put("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.
+ EncryptionResolver encryptionResolver = new EncryptionResolver() {
+ public boolean encryptionResolver(String pk, String rk,
+ String key) {
+ if (key.startsWith("EncryptedProp")) {
+ return true;
+ }
+ return false;
+ }
+ };
+
+ TableRequestOptions insertOptions = new TableRequestOptions();
+ insertOptions.setEncryptionPolicy(new TableEncryptionPolicy(key,
+ null));
+ insertOptions.setEncryptionResolver(encryptionResolver);
+
+ // Insert Entity
+ System.out.println("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();
+ retrieveOptions.setEncryptionPolicy(new TableEncryptionPolicy(null,
+ resolver));
+
+ // Retrieve Entity
+ System.out.println("Retrieving the encrypted entity.");
+ TableOperation operation = TableOperation.retrieve(
+ ent.getPartitionKey(), ent.getRowKey(),
+ DynamicTableEntity.class);
+ TableResult result = table
+ .execute(operation, retrieveOptions, null);
+ DynamicTableEntity resultEntity = result.getResultAsType();
+ System.out.println("EncryptedProp2 = "
+ + resultEntity.getProperties().get("EncryptedProp2")
+ .getValueAsString());
+ } finally {
+ table.deleteIfExists();
+ Utility.printSampleCompleteInfo("TableResolverEncryption");
+ }
+ }
+}
diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/KVCredentials.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/KVCredentials.java
new file mode 100644
index 000000000000..2732eae5c027
--- /dev/null
+++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/KVCredentials.java
@@ -0,0 +1,115 @@
+/**
+ * Copyright Microsoft Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.microsoft.azure.storage.util;
+
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import org.apache.http.Header;
+import org.apache.http.message.BasicHeader;
+
+import com.microsoft.aad.adal4j.AuthenticationContext;
+import com.microsoft.aad.adal4j.AuthenticationResult;
+import com.microsoft.aad.adal4j.ClientCredential;
+import com.microsoft.azure.keyvault.authentication.KeyVaultCredentials;
+import com.microsoft.windowsazure.core.pipeline.filter.ServiceRequestContext;
+
+/**
+ * A class that stores KeyVault credentials and knows how to respond to
+ * authentication challenges. See KeyVaultCredentials for more information.
+ */
+public class KVCredentials extends KeyVaultCredentials {
+
+ private String authClientID;
+
+ // Note: It's very important, in a real application, to keep this secure.
+ private String authClientSecret;
+
+ /**
+ * Constructs a new KVCredentials object.
+ *
+ * @param clientID
+ * The ClientID for this application
+ * @param clientSecret
+ * The client secret for this application
+ */
+ public KVCredentials(String clientID, String clientSecret) {
+ this.authClientID = clientID;
+ this.authClientSecret = clientSecret;
+ }
+
+ /**
+ * Actually do the authentication. This method will be called by the super
+ * class.
+ *
+ * @param request
+ * The request being sent
+ * @param challenge
+ * Information about the challenge from the service.
+ */
+ @Override
+ public Header doAuthenticate(ServiceRequestContext request,
+ Map challenge) {
+ String authorization = challenge.get("authorization");
+ String resource = challenge.get("resource");
+ String clientId = this.authClientID;
+ String clientKey = this.authClientSecret;
+ AuthenticationResult token = getAccessTokenFromClientCredentials(
+ authorization, resource, clientId, clientKey);
+ return new BasicHeader("Authorization", token.getAccessTokenType()
+ + " " + token.getAccessToken());
+ }
+
+ /**
+ * Creates the access token
+ *
+ * @param authorization
+ * The authorization from the service
+ * @param resource
+ * The resource being accessed
+ * @param clientId
+ * The ClientID for this application
+ * @param clientKey
+ * The Client Secret for this application
+ * @return The access token to use to authenticate to the service
+ */
+ private static AuthenticationResult getAccessTokenFromClientCredentials(
+ String authorization, String resource, String clientId,
+ String clientKey) {
+ AuthenticationContext context = null;
+ AuthenticationResult result = null;
+ ExecutorService service = null;
+ try {
+ service = Executors.newFixedThreadPool(1);
+ context = new AuthenticationContext(authorization, false, service);
+ ClientCredential credentials = new ClientCredential(clientId,
+ clientKey);
+ Future future = context.acquireToken(
+ resource, credentials, null);
+ result = future.get();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ } finally {
+ service.shutdown();
+ }
+
+ if (result == null) {
+ throw new RuntimeException("authentication result was null");
+ }
+ return result;
+ }
+}
diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/KeyVaultUtility.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/KeyVaultUtility.java
new file mode 100644
index 000000000000..330d1641e34e
--- /dev/null
+++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/KeyVaultUtility.java
@@ -0,0 +1,182 @@
+/**
+ * Copyright Microsoft Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.microsoft.azure.storage.util;
+
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Scanner;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.http.impl.client.HttpClientBuilder;
+
+import com.microsoft.azure.keyvault.KeyVaultClient;
+import com.microsoft.azure.keyvault.KeyVaultClientImpl;
+import com.microsoft.azure.keyvault.models.Secret;
+import com.microsoft.windowsazure.exception.ServiceException;
+
+/**
+ * A utility class for interacting with KeyVault
+ */
+public class KeyVaultUtility {
+ /**
+ * Creates a secret in Azure Key Vault and returns its ID.
+ *
+ * @param secretName
+ * The name of the secret to create
+ * @return The ID of the created secret
+ * @throws InterruptedException
+ * @throws ExecutionException
+ * @throws NoSuchAlgorithmException
+ * @throws URISyntaxException
+ * @throws MalformedURLException
+ */
+ public static String SetUpKeyVaultSecret(String secretName)
+ throws InterruptedException, ExecutionException,
+ NoSuchAlgorithmException, URISyntaxException, MalformedURLException {
+ KeyVaultClient cloudVault = GetKeyVaultClient();
+
+ if (Utility.vaultURL == null || Utility.vaultURL.isEmpty()) {
+ throw new IllegalArgumentException("No Keyvault URL specified.");
+ }
+
+ try {
+ // Delete the secret if it exists.
+ cloudVault.deleteSecretAsync(Utility.vaultURL, secretName).get();
+ } catch (ExecutionException ex) {
+ boolean keyNotFound = false;
+ if (ex.getCause().getClass() == ServiceException.class) {
+ ServiceException serviceException = (ServiceException) ex
+ .getCause();
+ if (serviceException.getHttpStatusCode() == 404) {
+ keyNotFound = true;
+ }
+ }
+
+ if (!keyNotFound) {
+ System.out
+ .println("Unable to access the specified vault. Please confirm the KVClientId, KVClientKey, and VaultUri are valid in the app.config file.");
+ System.out
+ .println("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.");
+ System.out.println("Press any key to exit");
+ Scanner input = new Scanner(System.in);
+ input.nextLine();
+ input.close();
+ throw ex;
+ }
+ }
+
+ // Create a 256bit symmetric key and convert it to Base64.
+ KeyGenerator keyGen = KeyGenerator.getInstance("AES");
+ keyGen.init(256); // Note that we cannot use SymmetricKey.KeySize256,
+ // because this resolves to '0x20'.
+ SecretKey wrapKey = keyGen.generateKey();
+
+ // 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.
+ Map headers = new HashMap();
+ headers.put("Content-Type", "application/octet-stream");
+ Secret cloudSecret = cloudVault.setSecretAsync(Utility.vaultURL,
+ secretName, Base64.encodeBase64String(wrapKey.getEncoded()),
+ "application/octet-stream", null, null).get();
+
+ // Return the base identifier of the secret. This will be resolved to
+ // the current version of the secret.
+ return cloudSecret.getSecretIdentifier().getBaseIdentifier();
+ }
+
+ /**
+ * Creates the KeyVaultClient using the credentials specified in the Utility
+ * class.
+ *
+ * @return
+ * @throws URISyntaxException
+ * @throws MalformedURLException
+ * @throws InterruptedException
+ * @throws ExecutionException
+ */
+ public static KeyVaultClient GetKeyVaultClient() throws URISyntaxException,
+ MalformedURLException, InterruptedException, ExecutionException {
+ if (Utility.AuthClientId == null || Utility.AuthClientId.isEmpty()
+ || Utility.AuthClientSecret == null
+ || Utility.AuthClientSecret.isEmpty()) {
+ throw new IllegalArgumentException(
+ "Invalid AuthClientID or AuthClientSecret specified.");
+ }
+
+ HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
+ ExecutorService executorService = Executors.newCachedThreadPool();
+ KVCredentials creds = new KVCredentials(Utility.AuthClientId,
+ Utility.AuthClientSecret);
+ KeyVaultClient cloudVault = new KeyVaultClientImpl(httpClientBuilder,
+ executorService, creds);
+ return cloudVault;
+ }
+
+ /**
+ * Helper method to create a new secret on the KeyVault service.
+ *
+ * @param defaultKeyName
+ * The default key name to use if the user does not provide one
+ * @return The keyID for the newly-created secret (or the existing secret,
+ * if one was passed in.)
+ * @throws InterruptedException
+ * @throws ExecutionException
+ * @throws NoSuchAlgorithmException
+ * @throws URISyntaxException
+ * @throws MalformedURLException
+ */
+ public static String createSecret(String defaultKeyName)
+ throws InterruptedException, ExecutionException,
+ NoSuchAlgorithmException, URISyntaxException, MalformedURLException {
+ System.out.println("No secret specified in Utility class.");
+ System.out
+ .println("Please enter the name of a new secret to create in Key Vault.");
+ System.out
+ .println("WARNING: This will delete any existing secret with the same name.");
+ System.out.println("If nothing is entered, the value \""
+ + defaultKeyName + "\" will be used.");
+
+ @SuppressWarnings("resource")
+ Scanner input = new Scanner(System.in);
+ String newSecretName = input.nextLine();
+
+ if (newSecretName == null || newSecretName.isEmpty()) {
+ newSecretName = defaultKeyName;
+ }
+
+ // Although it is possible to use keys (rather than secrets) stored in
+ // Key Vault, this prevents caching.
+ // Therefore it is recommended to use secrets along with a caching
+ // resolver (see below).
+ String keyID = KeyVaultUtility.SetUpKeyVaultSecret(newSecretName);
+
+ System.out.println();
+ System.out.println("Created a secret with ID: " + keyID);
+ System.out.println("Copy the secret ID to App.config to reuse.");
+ System.out.println();
+ return keyID;
+ }
+}
diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/LocalResolver.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/LocalResolver.java
new file mode 100644
index 000000000000..75a8faf8fdd4
--- /dev/null
+++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/LocalResolver.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright Microsoft Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.microsoft.azure.storage.util;
+
+import java.util.HashMap;
+import java.util.concurrent.Future;
+
+import org.apache.commons.lang3.concurrent.ConcurrentUtils;
+
+import com.microsoft.azure.keyvault.core.IKey;
+import com.microsoft.azure.keyvault.core.IKeyResolver;
+
+/**
+ * A sample key resolver class
+ *
+ */
+public class LocalResolver implements IKeyResolver {
+
+ private HashMap keys = new HashMap();
+
+ /**
+ * Map from a keyID to a key. This will be called when decrypting. The data
+ * to decrypt will include the keyID used to encrypt it.
+ *
+ * @param keyId
+ * The KeyID to map to a key
+ */
+ @Override
+ public Future resolveKeyAsync(String keyId) {
+ return ConcurrentUtils.constantFuture(this.keys.get(keyId));
+ }
+
+ /**
+ * Add a key to the local resolver.
+ *
+ * @param key
+ * The key to add to the local resolver.
+ */
+ public void add(IKey key) {
+ keys.put(key.getKid(), key);
+ }
+}
diff --git a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/Utility.java b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/Utility.java
index e9df627cec40..3762892866d9 100644
--- a/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/Utility.java
+++ b/microsoft-azure-storage-samples/src/com/microsoft/azure/storage/util/Utility.java
@@ -22,43 +22,69 @@
*
*/
public final class Utility {
- static {
- // Uncomment the following to use Fiddler
- // System.setProperty("http.proxyHost", "localhost");
- // System.setProperty("http.proxyPort", "8888");
- }
+ static {
+ // Uncomment the following to use Fiddler
+ // System.setProperty("http.proxyHost", "localhost");
+ // System.setProperty("http.proxyPort", "8888");
+ }
- /**
- * MODIFY THIS!
- *
- * Stores the storage connection string.
- */
- public static final String storageConnectionString = "DefaultEndpointsProtocol=https;"
- + "AccountName=[MY_ACCOUNT_NAME];"
- + "AccountKey=[MY_ACCOUNT_KEY]";
+ /**
+ * MODIFY THIS!
+ *
+ * Stores the storage connection string.
+ */
+ public static final String storageConnectionString = "DefaultEndpointsProtocol=https;"
+ + "AccountName=[MY_ACCOUNT_NAME];"
+ + "AccountKey=[MY_ACCOUNT_KEY]";
- /**
- * Prints out the exception information .
- */
- public static void printException(Throwable t) {
- StringWriter stringWriter = new StringWriter();
- PrintWriter printWriter = new PrintWriter(stringWriter);
- t.printStackTrace(printWriter);
- System.out.println(String.format("Got an exception from running samples. Exception details:\n%s\n",
- stringWriter.toString()));
- }
+ /**
+ * You only need to modify the following values if you want to run the
+ * KeyVault Encryption samples. Otherwise, leave empty.
+ */
+ public static final String vaultURL = null;
+ public static final String AuthClientId = null;
+ public static final String AuthClientSecret = null;
- /**
- * Prints out the sample start information .
- */
- public static void printSampleStartInfo(String sampleName) {
- System.out.println(String.format("The Azure storage client library sample %s starting...", sampleName));
- }
+ /**
+ * Optional. Modify this if you want to run the KeyVaultGettingStarted
+ * sample.
+ */
+ public static final String keyVaultKeyID = null;
- /**
- * Prints out the sample complete information .
- */
- public static void printSampleCompleteInfo(String sampleName) {
- System.out.println(String.format("The Azure storage client library sample %s completed.", sampleName));
- }
+ /**
+ * Optional. Modify these if you want to run the KeyRotationGettingStarted
+ * sample.
+ */
+ public static final String keyVaultKeyIDForRotation1 = null;
+ public static final String keyVaultKeyIDForRotation2 = null;
+
+ /**
+ * Prints out the exception information .
+ */
+ public static void printException(Throwable t) {
+ StringWriter stringWriter = new StringWriter();
+ PrintWriter printWriter = new PrintWriter(stringWriter);
+ t.printStackTrace(printWriter);
+ System.out.println(String.format(
+ "Got an exception from running samples. Exception details:\n%s\n",
+ stringWriter.toString()));
+ }
+
+ /**
+ * Prints out the sample start information .
+ */
+ public static void printSampleStartInfo(String sampleName) {
+ System.out.println(String.format(
+ "The Azure storage client library sample %s starting...",
+ sampleName));
+ }
+
+ /**
+ * Prints out the sample complete information .
+ */
+ public static void printSampleCompleteInfo(String sampleName) {
+ System.out.println(String.format(
+ "The Azure storage client library sample %s completed.",
+ sampleName));
+ }
}