diff --git a/keyvault/data-plane/.gitignore b/keyvault/data-plane/.gitignore
new file mode 100644
index 000000000000..648fca8a9b3c
--- /dev/null
+++ b/keyvault/data-plane/.gitignore
@@ -0,0 +1,64 @@
+*.class
+
+#External libs
+extlib/
+
+# Auth files
+*.auth
+*.azureauth
+
+# Local checkstyle
+*.checkstyle
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.ear
+
+# Azure Tooling #
+node_modules
+packages
+
+# Eclipse #
+*.pydevproject
+.project
+.metadata
+bin/**
+tmp/**
+tmp/**/*
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.classpath
+.settings/
+.loadpath
+bin/
+
+# Other Tooling #
+.classpath
+.project
+**/target/classes/**
+**/target/generated-sources/**
+**/target/generate-test-sources/**
+**/target/maven-status/**
+**/target/test-classes/com/**
+**/target/surefire-reports/**
+**/target/maven-archiver/**
+!**/target/test-classes/session-records/**
+.idea
+*.iml
+
+# Mac OS #
+.DS_Store
+.DS_Store?
+
+# Windows #
+Thumbs.db
+
+# reduced pom files should not be included
+dependency-reduced-pom.xml
diff --git a/keyvault/data-plane/.travis.yml b/keyvault/data-plane/.travis.yml
new file mode 100644
index 000000000000..01a5fe53d22b
--- /dev/null
+++ b/keyvault/data-plane/.travis.yml
@@ -0,0 +1,19 @@
+language: java
+sudo: required
+jdk:
+- oraclejdk8
+env:
+ global:
+ -AZURE_TEST_MODE=Playback
+ -'keyvault.vaulturi'=https://tifchen-keyvault-fancy.vault.azure.net
+ -'keyvault.vaulturi.alt'=https://tifchen-keyvault-fancier.vault.azure.net
+script:
+- LOG_PARAMS='-Dorg.slf4j.simpleLogger.defaultLogLevel=error -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn --batch-mode' ;
+- mvn jetty:run & echo "==> Starting a Jetty server on the background ==" ;
+- mvn install -DskipTests=true $LOG_PARAMS || travis_terminate 1 ;
+
+- echo '==> Starting mvn test ===' ;
+- mvn test -Dsurefire.rerunFailingTestsCount=3 $LOG_PARAMS -Dparallel=classes -DthreadCount=2 -DforkCount=1C || travis_terminate 1 ;
+
+
+
diff --git a/keyvault/data-plane/LICENSE b/keyvault/data-plane/LICENSE
new file mode 100644
index 000000000000..4b1ad51b2f0e
--- /dev/null
+++ b/keyvault/data-plane/LICENSE
@@ -0,0 +1,21 @@
+ MIT License
+
+ Copyright (c) Microsoft Corporation. All rights reserved.
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE
diff --git a/keyvault/data-plane/README.md b/keyvault/data-plane/README.md
new file mode 100644
index 000000000000..d90d0450abdc
--- /dev/null
+++ b/keyvault/data-plane/README.md
@@ -0,0 +1,129 @@
+[](https://travis-ci.org/Azure/azure-keyvault-java)
+
+# Microsoft Azure Key Vault SDK for Java
+
+This is the Microsoft Azure Key Vault client library which allows for the consumption of Key Vault services. Azure Key Vault helps safeguard cryptographic keys and secrets used by cloud applications and services. By using Key Vault, you can encrypt keys and secrets (such as authentication keys, storage account keys, data encryption keys, .PFX files, and passwords) using keys protected by hardware security modules (HSMs). For added assurance, you can import or generate keys in HSMs. If you choose to do this, Microsoft processes your keys in FIPS 140-2 Level 2 validated HSMs (hardware and firmware).
+Key Vault streamlines the key management process and enables you to maintain control of keys that access and encrypt your data. Developers can create keys for development and testing in minutes, and then seamlessly migrate them to production keys. Security administrators can grant (and revoke) permission to keys, as needed.
+For more information refer to [What is Key Vault?](https://docs.microsoft.com/en-us/azure/key-vault/key-vault-whatis) or [Getting Started](https://docs.microsoft.com/en-us/azure/key-vault/key-vault-get-started).
+
+Documentation for this SDK can be found at [Azure Key Vault Java Documentation](https://docs.microsoft.com/en-us/java/api/overview/azure/keyvault)
+
+## Sample code
+You can find sample code that illustrates key vault usage scenarios [here](https://azure.microsoft.com/en-us/resources/samples/?sort=0&service=key-vault&platform=java).
+
+
+
+ Category
+ Samples
+
+
+ Authentication
+
+
+
+
+
+ Vault Management
+
+
+
+
+
+ Secret Management
+
+
+
+
+
+
+For more information on using Java with Azure, see [here](https://azure.microsoft.com/en-us/develop/java/)
+
+## Download
+
+To get the binaries of this library as distributed by Microsoft, ready for use within your project, you can use Maven. Add the following fragment to you POM's dependencies.
+
+```xml
+
+ com.microsoft.azure
+ azure-keyvault-complete
+ 1.1.2
+
+```
+
+## Pre-requisites
+- A Java Developer Kit (JDK), v 1.7 or later
+- Maven
+
+## Building and Testing
+
+Clone the repo, then run `mvn compile` from the root directory.
+
+To run the recorded tests:
+1. If you have not already, you need to install the [Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files](http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html) package.
+2. run `mvn jetty:run` to start a jetty server. This starts a service that will block the terminal so you will likely want to open a second terminal to run the actual tests.
+3. In your second terminal run `mvn test`.
+
+## Contributing
+
+If you would like to become an active contributor to this project please follow the instructions provided in [Microsoft Azure Projects Contribution Guidelines](http://azure.github.io/guidelines.html).
+
+1. Fork it
+2. Create your feature branch (`git checkout -b my-new-feature`)
+3. Commit your changes (`git commit -am 'Add some feature'`)
+4. Push to the branch (`git push origin my-new-feature`)
+5. Create new Pull Request
+
+# Previous Versions
+
+| Version | Comments |
+| :-------: | :-------- |
+| [1.1.1](https://github.com/Azure/azure-keyvault-java/tree/1.1.1) | Version 1.1.1 release |
+| [1.1](https://github.com/Azure/azure-keyvault-java/tree/1.1) | Version 1.1 release |
+| [1.1-beta-1](https://github.com/Azure/azure-keyvault-java/tree/1.1-beta-1) | Version 1.1.0 **beta** release |
+| [1.1-alpha-2](https://github.com/Azure/azure-keyvault-java/tree/v1.1-alpha-2) | Version 1.1.0 **alpha** release |
+| [1.0.0](https://github.com/Azure/azure-keyvault-java/tree/v1.0.0) | Version 1.0.0 release |
+
+# More information
+* [Azure Key Vault Java Documentation](https://docs.microsoft.com/en-us/java/api/overview/azure/keyvault)
+* [What is Key Vault?](https://docs.microsoft.com/en-us/azure/key-vault/key-vault-whatis)
+* [Get started with Azure Key Vault](https://docs.microsoft.com/en-us/azure/key-vault/key-vault-get-started)
+* [Azure Key Vault General Documentation](https://docs.microsoft.com/en-us/azure/key-vault/)
+* [Azure Key Vault REST API Reference](https://docs.microsoft.com/en-us/rest/api/keyvault/)
+* [Azure Active Directory Documenation](https://docs.microsoft.com/en-us/azure/active-directory/)
diff --git a/keyvault/data-plane/REGENERATING.md b/keyvault/data-plane/REGENERATING.md
new file mode 100644
index 000000000000..37b870bbbc34
--- /dev/null
+++ b/keyvault/data-plane/REGENERATING.md
@@ -0,0 +1,19 @@
+# Regenerating SDK
+
+The code in the azure-keyvault package is generated via AutoREST. After code generation, there are currently several manual modifications that need to be made for the build to succeed. In the root of the azure-keyvault-java repo, there is a Python script called "regenerate_and_fix_sdk.py" which will automatically regenerate the code and apply the necessary fixes. To regenerate the code using this script:
+
+- Install AutoREST: https://github.com/Azure/autorest/blob/master/docs/installing-autorest.md
+- Open the script in your favorite editor and change "swagger_source_branch" to contain the branch of the Azure REST spec API repo that you'd like the API spec to be sourced from – likely either "master" or "keyvault_preview"
+ - If there is a tag you'd like to pass to AutoREST – set the "autorest_tag" branch accordingly.
+- Using Python 3.6+, run the script from the root of the checked out repository. Verify that no errors appear, and then build/test the SDK.
+
+
+
+The changes made by the script post-regeneration are as follows:
+
+* The generated webkey models will be removed
+
+
+* Any generated model class which has a corresponding custom class in the "models/custom" folder will be changed to inherit from the custom class.
+* Any class which utilizes webkey models will have the correct imports from the azure-keyvault-webkey package added
+* AutoREST occasionally generates broken parameter declarations in the Javadoc comments - these are repaired.
\ No newline at end of file
diff --git a/keyvault/data-plane/azure-keyvault-complete/pom.xml b/keyvault/data-plane/azure-keyvault-complete/pom.xml
new file mode 100644
index 000000000000..11fd13065e2e
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-complete/pom.xml
@@ -0,0 +1,72 @@
+
+
+ 4.0.0
+
+
+ com.microsoft.azure
+ azure-keyvault-parent
+ 1.1.2
+ ../pom.xml
+
+
+ com.microsoft.azure
+ azure-keyvault-complete
+ 1.1.2
+ pom
+
+
+
+ The MIT License (MIT)
+ http://opensource.org/licenses/MIT
+ repo
+
+
+
+ Microsoft Azure Key Vault SDK Complete
+ This encapsulate all modules of the Microsoft Azure Key Vault SDK.
+ https://github.com/Azure/azure-keyvault-java
+
+
+ UTF-8
+
+
+
+
+ scm:git:https://github.com/Azure/azure-keyvault-java
+ scm:git:git@github.com:Azure/azure-keyvault-java.git
+ HEAD
+
+
+
+
+ microsoft
+ Microsoft
+
+
+
+
+
+ com.microsoft.azure
+ azure-keyvault
+
+
+ com.microsoft.azure
+ azure-keyvault-core
+
+
+ com.microsoft.azure
+ azure-keyvault-webkey
+
+
+ com.microsoft.azure
+ azure-keyvault-extensions
+
+
+ com.microsoft.azure
+ azure-keyvault-cryptography
+
+
+
+
diff --git a/keyvault/data-plane/azure-keyvault-core/pom.xml b/keyvault/data-plane/azure-keyvault-core/pom.xml
new file mode 100644
index 000000000000..cee82573a28b
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-core/pom.xml
@@ -0,0 +1,109 @@
+
+
+ 4.0.0
+
+ com.microsoft.azure
+ azure-keyvault-parent
+ 1.1.2
+ ../pom.xml
+
+
+ azure-keyvault-core
+ 1.1.2
+ jar
+
+ Microsoft Azure SDK for Key Vault Core
+ This package contains Microsoft Azure Key Vault Core SDK.
+ https://github.com/Azure/azure-sdk-for-java
+
+
+
+ The MIT License (MIT)
+ http://opensource.org/licenses/MIT
+ repo
+
+
+
+
+ scm:git:https://github.com/Azure/azure-sdk-for-java
+ scm:git:git@github.com:Azure/azure-sdk-for-java.git
+ HEAD
+
+
+
+ UTF-8
+
+
+
+
+
+ microsoft
+ Microsoft
+
+
+
+
+
+
+
+ org.apache.commons
+ commons-lang3
+
+
+ com.google.guava
+ guava
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.0.2
+
+
+
+ true
+ true
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+ 1.12
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.1
+
+ 1.7
+ 1.7
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 2.8
+
+ com.microsoft.schemas._2003._10.serialization
+ /**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */]]>
+
+
+
+
+
diff --git a/keyvault/data-plane/azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/IKey.java b/keyvault/data-plane/azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/IKey.java
new file mode 100644
index 000000000000..5eb18bd42677
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/IKey.java
@@ -0,0 +1,148 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.core;
+
+import java.io.Closeable;
+import java.security.NoSuchAlgorithmException;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.lang3.tuple.Triple;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+
+/**
+ * Interface for representing cryptographic keys with the Microsoft Azure Key
+ * Vault libraries.
+ */
+public interface IKey extends Closeable {
+
+ /**
+ * The default encryption algorithm for this key, using the representations
+ * from Json Web Key Algorithms, RFC7513.
+ *
+ * @return The default encryption algorithm for this key.
+ */
+ String getDefaultEncryptionAlgorithm();
+
+ /**
+ * The default key wrap algorithm for this key, using the representations
+ * from Json Web Key Algorithms, RFC7513.
+ *
+ * @return The default key wrap algorithm for this key.
+ */
+ String getDefaultKeyWrapAlgorithm();
+
+ /**
+ * The default signature algorithm for this key, using the representations
+ * from Json Web Key Algorithms, RFC7513.
+ *
+ * @return The default signature algorithm for this key.
+ */
+ String getDefaultSignatureAlgorithm();
+
+ /**
+ * The unique key identifier for this key.
+ *
+ * @return The key identifier
+ */
+ String getKid();
+
+ /**
+ * Decrypts the specified cipher text. Note that not all algorithms require,
+ * or support, all parameters.
+ *
+ * @param ciphertext
+ * The cipher text to decrypt
+ * @param iv
+ * The initialization vector (optional with some algorithms)
+ * @param authenticationData
+ * Additional authentication data (optional with some algorithms)
+ * @param authenticationTag
+ * The authentication tag from the encrypt operation (optional
+ * with some algorithms)
+ * @param algorithm
+ * The encryption algorithm to use, must be supplied
+ * @return A ListenableFuture containing the plain text
+ * @throws NoSuchAlgorithmException the algorithm is not valid
+ */
+ ListenableFuture decryptAsync(final byte[] ciphertext, final byte[] iv, final byte[] authenticationData, final byte[] authenticationTag, final String algorithm) throws NoSuchAlgorithmException;
+
+ /**
+ * Encrypts the specified plain text. Note that not all algorithms require,
+ * or support, all parameters.
+ *
+ * @param plaintext
+ * The plain text to encrypt
+ * @param iv
+ * The initialization vector (optional with some algorithms)
+ * @param authenticationData
+ * Additional authentication data (optional with some algorithms)
+ * @param algorithm
+ * The encryption algorithm to use, defaults to the keys
+ * DefaultEncryptionAlgorithm
+ * @return A ListenableFuture containing the cipher text, the authentication
+ * tag and the algorithm that was used
+ * @throws NoSuchAlgorithmException the algorithm is not valid
+ */
+ ListenableFuture> encryptAsync(final byte[] plaintext, final byte[] iv, final byte[] authenticationData, final String algorithm) throws NoSuchAlgorithmException;
+
+ /**
+ * Wraps (encrypts) the specified symmetric key material using the specified
+ * algorithm, or the keys DefaultKeyWrapAlgorithm if none is specified.
+ *
+ * @param key
+ * The symmetric key to wrap
+ * @param algorithm
+ * The wrapping algorithm to use, defaults to the keys
+ * DefaultKeyWrapAlgorithm
+ * @return ListenableFuture containing the encrypted key and the algorithm
+ * that was used
+ * @throws NoSuchAlgorithmException the algorithm is not valid
+ */
+ ListenableFuture> wrapKeyAsync(final byte[] key, final String algorithm) throws NoSuchAlgorithmException;
+
+ /**
+ * Unwraps (decrypts) the specified encryped key material.
+ *
+ * @param encryptedKey
+ * The encrypted key to decrypt
+ * @param algorithm
+ * The algorithm to use, must be supplied
+ * @return A ListenableFuture containing the unwrapped key
+ * @throws NoSuchAlgorithmException the algorithm is not valid
+ */
+ ListenableFuture unwrapKeyAsync(final byte[] encryptedKey, final String algorithm) throws NoSuchAlgorithmException;
+
+ /**
+ * Signs the specified digest using the specified algorithm, or the keys
+ * DefaultSignatureAlgorithm if no algorithm is specified.
+ *
+ * @param digest
+ * The digest to sign
+ * @param algorithm
+ * The signature algorithm to use
+ * @return A ListenableFuture containing the signature and the algorithm used.
+ * @throws NoSuchAlgorithmException the algorithm is not valid
+ */
+ ListenableFuture> signAsync(final byte[] digest, final String algorithm) throws NoSuchAlgorithmException;
+
+ /**
+ * Verifies the supplied signature value using the supplied digest and
+ * algorithm.
+ *
+ * @param digest
+ * The digest input
+ * @param signature
+ * The signature to verify
+ * @param algorithm
+ * The algorithm to use, must be provided
+ * @return A ListenableFuture containing the signature and the algorithm used.
+ * @throws NoSuchAlgorithmException the algorithm is not valid
+ */
+ ListenableFuture verifyAsync(final byte[] digest, final byte[] signature, final String algorithm) throws NoSuchAlgorithmException;
+}
diff --git a/keyvault/data-plane/azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/IKeyResolver.java b/keyvault/data-plane/azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/IKeyResolver.java
new file mode 100644
index 000000000000..635dd80c0287
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/IKeyResolver.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.core;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * Interface for representing key resolving operations with the Microsoft Azure Key
+ * Vault libraries.
+ */
+public interface IKeyResolver {
+
+ /**
+ * Retrieves an IKey implementation for the specified key identifier.
+ * Implementations should check the format of the kid to ensure that it is
+ * recognized. Null, rather than an exception, should be returned for
+ * unrecognized key identifiers to enable chaining of key resolvers.
+ *
+ * @param kid
+ * The key identifier to resolve.
+ * @return A ListenableFuture containing the resolved IKey
+ */
+ ListenableFuture resolveKeyAsync(String kid);
+}
diff --git a/keyvault/data-plane/azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/package-info.java b/keyvault/data-plane/azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/package-info.java
new file mode 100644
index 000000000000..b3417f38285d
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/package-info.java
@@ -0,0 +1,9 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for
+// license information.
+//
+
+/**
+ * This package contains the interface for IKey and IKeyResolver.
+ */
+package com.microsoft.azure.keyvault.core;
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/pom.xml b/keyvault/data-plane/azure-keyvault-cryptography/pom.xml
new file mode 100644
index 000000000000..edcde42ea81d
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/pom.xml
@@ -0,0 +1,89 @@
+
+
+ 4.0.0
+
+
+ com.microsoft.azure
+ azure-keyvault-parent
+ 1.1.2
+ ../pom.xml
+
+
+ azure-keyvault-cryptography
+ 1.1.2
+ jar
+
+ Microsoft Azure SDK for Key Vault Cryptography
+ This package contains Microsoft Azure SDK for Key Vault Cryptography.
+ https://github.com/Azure/azure-sdk-for-java
+
+
+
+ The MIT License (MIT)
+ http://opensource.org/licenses/MIT
+ repo
+
+
+
+
+ scm:git:https://github.com/Azure/azure-sdk-for-java
+ scm:git:git@github.com:Azure/azure-sdk-for-java.git
+ HEAD
+
+
+
+ UTF-8
+
+
+ true
+
+
+
+
+
+
+
+ com.microsoft.azure
+ azure-keyvault-webkey
+
+
+ com.microsoft.azure
+ azure-keyvault-core
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+
+
+ org.apache.commons
+ commons-lang3
+
+
+ commons-codec
+ commons-codec
+
+
+ com.google.guava
+ guava
+
+
+
+
+
+ junit
+ junit
+ test
+
+
+ org.bouncycastle
+ bcprov-jdk15on
+ test
+
+
+
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/Algorithm.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/Algorithm.java
new file mode 100644
index 000000000000..e80ccaf5a76b
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/Algorithm.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography;
+
+/**
+ * Abstract base class for all Algorithm objects.
+ *
+ */
+public abstract class Algorithm {
+
+ private final String _name;
+
+ /**
+ * Constructor.
+ *
+ * @param name The name of the algorithm.
+ */
+ protected Algorithm(String name) {
+ if (Strings.isNullOrWhiteSpace(name)) {
+ throw new IllegalArgumentException("name");
+ }
+
+ _name = name;
+ }
+
+ /**
+ * Gets the name of the algorithm.
+ *
+ * @return The name of the algorithm.
+ */
+ public String getName() {
+ return _name;
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AlgorithmResolver.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AlgorithmResolver.java
new file mode 100644
index 000000000000..1ac5c06c52d1
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AlgorithmResolver.java
@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import com.microsoft.azure.keyvault.cryptography.algorithms.Aes128Cbc;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Aes128CbcHmacSha256;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Aes192Cbc;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Aes192CbcHmacSha384;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Aes256Cbc;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Aes256CbcHmacSha512;
+import com.microsoft.azure.keyvault.cryptography.algorithms.AesKw128;
+import com.microsoft.azure.keyvault.cryptography.algorithms.AesKw192;
+import com.microsoft.azure.keyvault.cryptography.algorithms.AesKw256;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Es256k;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Es256;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Es384;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Es512;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Rs256;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Rsa15;
+import com.microsoft.azure.keyvault.cryptography.algorithms.RsaOaep;
+
+public class AlgorithmResolver {
+
+ public static final AlgorithmResolver Default = new AlgorithmResolver();
+
+ static {
+ Default.put(Aes128CbcHmacSha256.ALGORITHM_NAME, new Aes128CbcHmacSha256());
+ Default.put(Aes192CbcHmacSha384.ALGORITHM_NAME, new Aes192CbcHmacSha384());
+ Default.put(Aes256CbcHmacSha512.ALGORITHM_NAME, new Aes256CbcHmacSha512());
+
+ Default.put(Aes128Cbc.ALGORITHM_NAME, new Aes128Cbc());
+ Default.put(Aes192Cbc.ALGORITHM_NAME, new Aes192Cbc());
+ Default.put(Aes256Cbc.ALGORITHM_NAME, new Aes256Cbc());
+
+ Default.put(AesKw128.ALGORITHM_NAME, new AesKw128());
+ Default.put(AesKw192.ALGORITHM_NAME, new AesKw192());
+ Default.put(AesKw256.ALGORITHM_NAME, new AesKw256());
+
+ Default.put(Rsa15.ALGORITHM_NAME, new Rsa15());
+ Default.put(RsaOaep.ALGORITHM_NAME, new RsaOaep());
+
+ Default.put( Rs256.ALGORITHM_NAME, new Rs256() );
+ // Default.put( RsNull.ALGORITHM_NAME, new RsNull() );
+
+ Default.put(Es256k.ALGORITHM_NAME, new Es256k());
+ Default.put(Es256.ALGORITHM_NAME, new Es256());
+ Default.put(Es384.ALGORITHM_NAME, new Es384());
+ Default.put(Es512.ALGORITHM_NAME, new Es512());
+ }
+
+ private final ConcurrentMap _algorithms = new ConcurrentHashMap();
+
+ /**
+ * Returns the implementation for an algorithm name.
+ *
+ * @param algorithmName The algorithm name.
+ * @return The implementation for the algorithm or null.
+ */
+ public Algorithm get(String algorithmName) {
+ return _algorithms.get(algorithmName);
+ }
+
+ /**
+ * Add/Update a named algorithm implementation.
+ *
+ * @param algorithmName The algorithm name.
+ * @param provider The implementation of the algorithm.
+ */
+ public void put(String algorithmName, Algorithm provider) {
+ _algorithms.put(algorithmName, provider);
+ }
+
+ /**
+ * Remove a named algorithm implementation.
+ *
+ * @param algorithmName The algorithm name
+ */
+ public void remove(String algorithmName) {
+ _algorithms.remove(algorithmName);
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AsymmetricEncryptionAlgorithm.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AsymmetricEncryptionAlgorithm.java
new file mode 100644
index 000000000000..b239a41d8530
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AsymmetricEncryptionAlgorithm.java
@@ -0,0 +1,86 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography;
+
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+
+import javax.crypto.NoSuchPaddingException;
+
+/**
+ * Abstract base class for all asymmetric encryption algorithms.
+ *
+ */
+public abstract class AsymmetricEncryptionAlgorithm extends EncryptionAlgorithm {
+
+ /**
+ * Constructor.
+ *
+ * @param name The name of the algorithm.
+ */
+ protected AsymmetricEncryptionAlgorithm(String name) {
+ super(name);
+ }
+
+ /**
+ * Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for encryption that
+ * uses the specified {@link java.security.KeyPair} and the default {@link java.security.Provider} provider.
+ *
+ * @param keyPair
+ * The key pair to use.
+ * @return
+ * @throws InvalidKeyException
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchPaddingException
+ */
+ public abstract ICryptoTransform CreateEncryptor(KeyPair keyPair) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException;
+
+ /**
+ * Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for encryption that
+ * uses the specified {@link java.security.KeyPair} and {@link java.security.Provider}.
+ *
+ * @param keyPair
+ * The key pair to use.
+ * @param provider
+ * The provider to use.
+ * @return
+ * @throws InvalidKeyException
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchPaddingException
+ */
+ public abstract ICryptoTransform CreateEncryptor(KeyPair keyPair, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException;
+
+ /**
+ * Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for decryption that
+ * uses the specified {@link java.security.KeyPair} and the default {@link java.security.Provider} provider.
+ *
+ * @param keyPair
+ * The key pair to use.
+ * @return
+ * @throws InvalidKeyException
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchPaddingException
+ */
+ public abstract ICryptoTransform CreateDecryptor(KeyPair keyPair) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException;
+
+ /**
+ * Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for decryption that
+ * uses the specified {@link java.security.KeyPair} and {@link java.security.Provider}.
+ *
+ * @param keyPair
+ * The key pair to use.
+ * @param provider
+ * The provider to use.
+ * @return
+ * @throws InvalidKeyException
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchPaddingException
+ */
+ public abstract ICryptoTransform CreateDecryptor(KeyPair keyPair, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException;
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AsymmetricSignatureAlgorithm.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AsymmetricSignatureAlgorithm.java
new file mode 100644
index 000000000000..ff5e1417ba5c
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AsymmetricSignatureAlgorithm.java
@@ -0,0 +1,15 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography;
+
+public abstract class AsymmetricSignatureAlgorithm extends SignatureAlgorithm {
+
+ protected AsymmetricSignatureAlgorithm(String name) {
+ super(name);
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ByteExtensions.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ByteExtensions.java
new file mode 100644
index 000000000000..07aee9a68949
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ByteExtensions.java
@@ -0,0 +1,100 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography;
+
+import java.util.Arrays;
+
+public final class ByteExtensions {
+
+ public static byte[] or( byte[] self, byte[] other )
+ {
+ return or( self, other, 0 );
+ }
+
+ public static byte[] or( byte[] self, byte[] other, int offset )
+ {
+ if ( self == null )
+ throw new IllegalArgumentException( "self" );
+
+ if ( other == null )
+ throw new IllegalArgumentException( "other" );
+
+ if ( self.length > other.length - offset )
+ throw new IllegalArgumentException( "self and other lengths do not match" );
+
+ byte[] result = new byte[self.length];
+
+ for ( int i = 0; i < self.length; i++ )
+ {
+ result[i] = (byte)( self[i] | other[offset + i] );
+ }
+
+ return result;
+ }
+
+ public static byte[] xor( byte[] self, byte[] other ) {
+ return xor( self, other, 0 );
+ }
+
+ static byte[] xor( byte[] self, byte[] other, int offset )
+ {
+ if ( self == null )
+ throw new IllegalArgumentException( "self" );
+
+ if ( other == null )
+ throw new IllegalArgumentException( "other" );
+
+ if ( self.length > other.length - offset )
+ throw new IllegalArgumentException( "self and other lengths do not match" );
+
+ byte[] result = new byte[self.length];
+
+ for ( int i = 0; i < self.length; i++ )
+ {
+ result[i] = (byte)( self[i] ^ other[offset + i] );
+ }
+
+ return result;
+ }
+
+ public static void zero( byte[] self )
+ {
+ if ( self != null ) {
+ Arrays.fill(self, (byte)0);
+ }
+ }
+
+ /**
+ * Compares two byte arrays in constant time.
+ *
+ * @param self
+ * The first byte array to compare
+ * @param other
+ * The second byte array to compare
+ * @return
+ * True if the two byte arrays are equal.
+ */
+ public static boolean sequenceEqualConstantTime( byte[] self, byte[] other )
+ {
+ if ( self == null )
+ throw new IllegalArgumentException( "self" );
+
+ if ( other == null )
+ throw new IllegalArgumentException( "other" );
+
+ // Constant time comparison of two byte arrays
+ long difference = ( self.length & 0xffffffffl ) ^ ( other.length & 0xffffffffl );
+
+ for ( int i = 0; i < self.length && i < other.length; i++ )
+ {
+ difference |= ( self[i] ^ other[i] ) & 0xffffffffl;
+ }
+
+ return difference == 0;
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/EcKey.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/EcKey.java
new file mode 100644
index 000000000000..fc82ad29025d
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/EcKey.java
@@ -0,0 +1,397 @@
+package com.microsoft.azure.keyvault.cryptography;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.EllipticCurve;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.lang3.tuple.Triple;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.microsoft.azure.keyvault.core.IKey;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Ecdsa;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Es256k;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Es256;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Es384;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Es512;
+import com.microsoft.azure.keyvault.webkey.JsonWebKey;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyCurveName;
+
+
+public class EcKey implements IKey {
+
+ public static final String P256 = "secp256r1";
+ public static final String P384 = "secp384r1";
+ public static final String P521 = "secp521r1";
+ public static final String P256K = "secp256k1";
+ public static final Map CURVE_TO_SIGNATURE = ImmutableMap.builder()
+ .put(JsonWebKeyCurveName.P_256, Es256.ALGORITHM_NAME)
+ .put(JsonWebKeyCurveName.P_384, Es384.ALGORITHM_NAME)
+ .put(JsonWebKeyCurveName.P_521, Es512.ALGORITHM_NAME)
+ .put(JsonWebKeyCurveName.P_256K, Es256k.ALGORITHM_NAME)
+ .build();
+ public static final Map CURVE_TO_SPEC_NAME = ImmutableMap.builder()
+ .put(JsonWebKeyCurveName.P_256, P256)
+ .put(JsonWebKeyCurveName.P_384, P384)
+ .put(JsonWebKeyCurveName.P_521, P521)
+ .put(JsonWebKeyCurveName.P_256K, P256K)
+ .build();
+
+
+ private final String _kid;
+ private final KeyPair _keyPair;
+ private final Provider _provider;
+ private final JsonWebKeyCurveName _curve;
+
+ protected final String _signatureAlgorithm;
+ protected String defaultEncryptionAlgorithm;
+
+ public static JsonWebKeyCurveName getDefaultCurve() {
+ return JsonWebKeyCurveName.P_256;
+ }
+
+ /**
+ * Constructor.
+ *
+ * Generates a new EcKey with a P_256 curve and a randomly generated kid.
+ *
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public EcKey() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+ this(UUID.randomUUID().toString());
+ }
+
+ /**
+ * Constructor.
+ *
+ * Generates a new EcKey with a P_256 curve and the given kid.
+ *
+ * @param kid
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public EcKey(String kid) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+ this(kid, getDefaultCurve(), Security.getProvider("SunEC"));
+ }
+
+ /**
+ * Constructor.
+ *
+ * Generates a new EcKey with the given curve and kid.
+ * @param kid
+ * @param curve
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public EcKey(String kid, JsonWebKeyCurveName curve) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+ this(kid, curve, Security.getProvider("SunEC"));
+ }
+
+ /**
+ * Constructor.
+ *
+ * Generates a new EcKey with the given curve and kid.
+ * @param kid
+ * @param curve
+ * @param provider Java security provider
+ * @throws InvalidAlgorithmParameterException
+ * @throws NoSuchAlgorithmException
+ */
+ public EcKey(String kid, JsonWebKeyCurveName curve, Provider provider) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
+ _kid = kid;
+ _provider = provider;
+ _curve = curve;
+
+ _signatureAlgorithm = CURVE_TO_SIGNATURE.get(curve);
+ if (_signatureAlgorithm == null) {
+ throw new NoSuchAlgorithmException("Curve not supported.");
+ }
+
+ final KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", provider);
+ ECGenParameterSpec gps = new ECGenParameterSpec(CURVE_TO_SPEC_NAME.get(curve));
+
+ generator.initialize(gps);
+ _keyPair = generator.generateKeyPair();
+
+ }
+
+ /**
+ * Constructor.
+ *
+ * Generates a new EcKey with the given keyPair.
+ * The keyPair must be an ECKey.
+ * @param kid
+ * @param keyPair
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public EcKey(String kid, KeyPair keyPair) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+ this(kid, keyPair, Security.getProvider("SunEC"));
+ }
+
+ /**
+ * Constructor.
+ *
+ * Generates a new EcKey with the given keyPair.
+ * The keyPair must be an ECKey.
+ * @param kid
+ * @param keyPair
+ * @param provider Java security provider
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public EcKey(String kid, KeyPair keyPair, Provider provider) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+
+ if (Strings.isNullOrWhiteSpace(kid)) {
+ throw new IllegalArgumentException("Please provide a kid");
+ }
+
+ if (keyPair == null) {
+ throw new IllegalArgumentException("Please provide an ECKey");
+ }
+
+ if (keyPair.getPublic() == null || !(keyPair.getPublic() instanceof ECPublicKey)) {
+ throw new IllegalArgumentException("The keyPair provided is not an ECKey");
+ }
+
+ _kid = kid;
+ _keyPair = keyPair;
+ _provider = provider;
+ _curve = getCurveFromKeyPair(keyPair);
+ _signatureAlgorithm = CURVE_TO_SIGNATURE.get(_curve);
+ if (_signatureAlgorithm == null) {
+ throw new IllegalArgumentException("Curve not supported.");
+ }
+ }
+
+ /**
+ * Converts JSON web key to EC key pair, does not include the private key.
+ * @param jwk
+ * @return EcKey
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidAlgorithmParameterException
+ * @throws InvalidKeySpecException
+ * @throws NoSuchProviderException
+ */
+ public static EcKey fromJsonWebKey(JsonWebKey jwk) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeySpecException, NoSuchProviderException {
+ return fromJsonWebKey(jwk, false, null);
+ }
+
+ /**
+ * Converts JSON web key to EC key pair and include the private key if set to true.
+ * @param jwk
+ * @param includePrivateParameters true if the EC key pair should include the private key. False otherwise.
+ * @return EcKey
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidAlgorithmParameterException
+ * @throws InvalidKeySpecException
+ * @throws NoSuchProviderException
+ */
+ public static EcKey fromJsonWebKey(JsonWebKey jwk, boolean includePrivateParameters) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeySpecException, NoSuchProviderException {
+ return fromJsonWebKey(jwk, includePrivateParameters, null);
+ }
+
+ /**
+ * Converts JSON web key to EC key pair and include the private key if set to true.
+ * @param jwk
+ * @param includePrivateParameters true if the EC key pair should include the private key. False otherwise.
+ * @param provider the Java Security Provider
+ * @return EcKey
+ */
+ public static EcKey fromJsonWebKey(JsonWebKey jwk, boolean includePrivateParameters, Provider provider) {
+ try {
+ if (jwk.kid() != null) {
+ return new EcKey(jwk.kid(), jwk.toEC(includePrivateParameters, provider));
+ } else {
+ throw new IllegalArgumentException("Json Web Key should have a kid");
+ }
+ } catch (GeneralSecurityException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Converts EcKey to JSON web key.
+ * @return
+ */
+ public JsonWebKey toJsonWebKey() {
+ return JsonWebKey.fromEC(_keyPair, _provider);
+ }
+
+ // Matches the curve of the keyPair to supported curves.
+ private JsonWebKeyCurveName getCurveFromKeyPair(KeyPair keyPair) {
+ try {
+ ECPublicKey key = (ECPublicKey) keyPair.getPublic();
+ ECParameterSpec spec = key.getParams();
+ EllipticCurve crv = spec.getCurve();
+
+ List curveList = Arrays.asList(JsonWebKeyCurveName.P_256, JsonWebKeyCurveName.P_384, JsonWebKeyCurveName.P_521, JsonWebKeyCurveName.P_256K);
+
+ for (JsonWebKeyCurveName curve : curveList) {
+ ECGenParameterSpec gps = new ECGenParameterSpec(CURVE_TO_SPEC_NAME.get(curve));
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", _provider);
+ kpg.initialize(gps);
+
+ // Generate dummy keypair to get parameter spec.
+ KeyPair apair = kpg.generateKeyPair();
+ ECPublicKey apub = (ECPublicKey) apair.getPublic();
+ ECParameterSpec aspec = apub.getParams();
+ EllipticCurve acurve = aspec.getCurve();
+
+ //Matches the parameter spec
+ if (acurve.equals(crv)) {
+ return curve;
+ }
+ }
+
+ //Did not find a supported curve.
+ throw new IllegalArgumentException ("Curve not supported.");
+ } catch (GeneralSecurityException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * @return curve of the key
+ */
+ public JsonWebKeyCurveName getCurve() {
+ return _curve;
+ }
+
+ /**
+ *
+ * @return the underlying keyPair of the key
+ */
+ public KeyPair getKeyPair() {
+ return _keyPair;
+ }
+
+ @Override
+ public void close() throws IOException {
+ // Intentionally empty
+ }
+
+ @Override
+ public String getDefaultEncryptionAlgorithm() {
+ return null;
+ }
+
+ @Override
+ public String getDefaultKeyWrapAlgorithm() {
+ return null;
+ }
+
+ @Override
+ public String getDefaultSignatureAlgorithm() {
+ return _signatureAlgorithm;
+ }
+
+ @Override
+ public String getKid() {
+ return _kid;
+ }
+
+ @Override
+ public ListenableFuture decryptAsync(byte[] ciphertext, byte[] iv, byte[] authenticationData,
+ byte[] authenticationTag, String algorithm) throws NoSuchAlgorithmException {
+ throw new UnsupportedOperationException("Decrypt Async is not supported");
+ }
+
+ @Override
+ public ListenableFuture> encryptAsync(byte[] plaintext, byte[] iv,
+ byte[] authenticationData, String algorithm) throws NoSuchAlgorithmException {
+ throw new UnsupportedOperationException("Encrypt Async is not supported");
+ }
+
+ @Override
+ public ListenableFuture> wrapKeyAsync(byte[] key, String algorithm)
+ throws NoSuchAlgorithmException {
+ throw new UnsupportedOperationException("Wrap key is not supported");
+ }
+
+ @Override
+ public ListenableFuture unwrapKeyAsync(byte[] encryptedKey, String algorithm)
+ throws NoSuchAlgorithmException {
+ throw new UnsupportedOperationException("Unwrap key is not supported");
+ }
+
+ @Override
+ public ListenableFuture> signAsync(byte[] digest, String algorithm) throws NoSuchAlgorithmException {
+
+ if (_keyPair.getPrivate() == null) {
+ throw new UnsupportedOperationException("Sign is not supported without a private key.");
+ }
+
+ if (digest == null) {
+ throw new IllegalArgumentException("Please provide a digest to sign.");
+ }
+
+ if (Strings.isNullOrWhiteSpace(algorithm)) {
+ throw new IllegalArgumentException("Please provide a signature algorithm to use.");
+ }
+
+ // Interpret the requested algorithm
+ Algorithm baseAlgorithm = AlgorithmResolver.Default.get(algorithm);
+
+ if (baseAlgorithm == null || !(baseAlgorithm instanceof AsymmetricSignatureAlgorithm)) {
+ throw new NoSuchAlgorithmException(algorithm);
+ }
+
+ Ecdsa algo = (Ecdsa) baseAlgorithm;
+ ISignatureTransform signer = algo.createSignatureTransform(_keyPair, _provider);
+
+ try {
+ return Futures.immediateFuture(Pair.of(signer.sign(digest), algorithm));
+ } catch (Exception e) {
+ return Futures.immediateFailedFuture(e);
+ }
+ }
+
+ @Override
+ public ListenableFuture verifyAsync(byte[] digest, byte[] signature, String algorithm) throws NoSuchAlgorithmException {
+
+ if (digest == null) {
+ throw new IllegalArgumentException("Please provide a digest input.");
+ }
+
+ if (Strings.isNullOrWhiteSpace(algorithm)) {
+ throw new IllegalArgumentException("Please provide an algorithm");
+ }
+
+ // Interpret the requested algorithm
+ Algorithm baseAlgorithm = AlgorithmResolver.Default.get(algorithm);
+
+ if (baseAlgorithm == null || !(baseAlgorithm instanceof AsymmetricSignatureAlgorithm)) {
+ throw new NoSuchAlgorithmException(algorithm);
+ }
+
+ Ecdsa algo = (Ecdsa) baseAlgorithm;
+
+ ISignatureTransform signer = algo.createSignatureTransform(_keyPair, _provider);
+
+ try {
+ return Futures.immediateFuture(signer.verify(digest, signature));
+ } catch (Exception e) {
+ return Futures.immediateFailedFuture(e);
+ }
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/EncryptionAlgorithm.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/EncryptionAlgorithm.java
new file mode 100644
index 000000000000..4d36c332b3be
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/EncryptionAlgorithm.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography;
+
+/**
+ * Abstract base class for all encryption algorithms.
+ *
+ */
+public abstract class EncryptionAlgorithm extends Algorithm {
+
+ /**
+ * Constructor.
+ * @param name The name of the algorithm.
+ */
+ protected EncryptionAlgorithm(String name) {
+ super(name);
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/IAuthenticatedCryptoTransform.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/IAuthenticatedCryptoTransform.java
new file mode 100644
index 000000000000..113a14404cf4
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/IAuthenticatedCryptoTransform.java
@@ -0,0 +1,12 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography;
+
+public interface IAuthenticatedCryptoTransform extends ICryptoTransform {
+
+ public byte[] getTag();
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ICryptoTransform.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ICryptoTransform.java
new file mode 100644
index 000000000000..4787a9d11a0f
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ICryptoTransform.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+
+/**
+ * Defines the basic operations of cryptographic transformations.
+ *
+ */
+public interface ICryptoTransform {
+
+ /**
+ * Transforms the specified region of the specified byte array as a single operation.
+ *
+ * @param input
+ * The byte array to be transformed
+ * @return
+ * The transformed result.
+ * @throws IllegalBlockSizeException
+ * @throws BadPaddingException
+ * @throws InvalidKeyException
+ * @throws NoSuchAlgorithmException
+ */
+ public byte[] doFinal(byte[] input) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException;
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ISignatureTransform.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ISignatureTransform.java
new file mode 100644
index 000000000000..484b1448fb51
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ISignatureTransform.java
@@ -0,0 +1,16 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography;
+
+import java.security.GeneralSecurityException;
+
+public interface ISignatureTransform {
+
+ public byte[] sign(final byte[] digest) throws GeneralSecurityException;
+
+ public boolean verify(final byte[] digest, final byte[] signature) throws GeneralSecurityException;
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/KeyWrapAlgorithm.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/KeyWrapAlgorithm.java
new file mode 100644
index 000000000000..e0028d51a507
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/KeyWrapAlgorithm.java
@@ -0,0 +1,152 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+
+import javax.crypto.NoSuchPaddingException;
+
+/**
+ * Abstract base class for all key wrap algorithms.
+ *
+ */
+public abstract class KeyWrapAlgorithm extends Algorithm {
+
+ /**
+ * Constructor.
+ *
+ * @param name The name of the algorithm.
+ */
+ protected KeyWrapAlgorithm(String name) {
+ super(name);
+ }
+
+ /**
+ * Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for encryption.
+ * Uses the default AES-KW initialization vector.
+ * @param key
+ * The AES key material to be used.
+ * @return A {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchPaddingException
+ * @throws InvalidKeyException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public abstract ICryptoTransform CreateEncryptor(byte[] key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException;
+
+ /**
+ * Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for encryption that
+ * uses the specified provider for the Java Security API. Uses the default AES-KW initialization vector.
+ *
+ * @param key
+ * The AES key material to be used.
+ * @param provider
+ * The provider to use.
+ * @return A {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchPaddingException
+ * @throws InvalidKeyException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public abstract ICryptoTransform CreateEncryptor(byte[] key, Provider provider) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException;
+
+ /**
+ * Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for encryption
+ * using the supplied initialization vector.
+ * @param key
+ * The AES key material to be used.
+ * @param iv
+ * The initialization vector to be used.
+ * @return A {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchPaddingException
+ * @throws InvalidKeyException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public abstract ICryptoTransform CreateEncryptor(byte[] key, byte[] iv) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException;
+
+ /**
+ * Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for encryption
+ * using the supplied initialization vector and the specific provider for the Java Security API.
+ * @param key
+ * The AES key material to be used.
+ * @param iv
+ * The initialization vector to be used.
+ * @param provider
+ * The provider to use.
+ * @return A {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchPaddingException
+ * @throws InvalidKeyException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public abstract ICryptoTransform CreateEncryptor(byte[] key, byte[] iv, Provider provider) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException;
+
+ /**
+ * Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for decryption.
+ * Uses the default AES-KW initialization vector.
+ * @param key
+ * The AES key material to be used.
+ * @return A {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchPaddingException
+ * @throws InvalidKeyException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public abstract ICryptoTransform CreateDecryptor(byte[] key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException;
+
+ /**
+ * Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for decryption that
+ * uses the specified provider for the Java Security API. Uses the default AES-KW initialization vector.
+ *
+ * @param key
+ * The AES key material to be used.
+ * @param provider
+ * The provider to use.
+ * @return A {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchPaddingException
+ * @throws InvalidKeyException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public abstract ICryptoTransform CreateDecryptor(byte[] key, Provider provider) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException;
+
+ /**
+ * Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for decryption
+ * using the supplied initialization vector.
+ * @param key
+ * The AES key material to be used.
+ * @param iv
+ * The initialization vector to be used.
+ * @return A {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchPaddingException
+ * @throws InvalidKeyException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public abstract ICryptoTransform CreateDecryptor(byte[] key, byte[] iv) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException;
+
+ /**
+ * Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for decryption
+ * using the supplied initialization vector and the specific provider for the Java Security API.
+ * @param key
+ * The AES key material to be used.
+ * @param iv
+ * The initialization vector to be used.
+ * @param provider
+ * The provider to use.
+ * @return A {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchPaddingException
+ * @throws InvalidKeyException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public abstract ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, Provider provider) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException;
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/RsaKey.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/RsaKey.java
new file mode 100644
index 000000000000..c0ae1b5995e7
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/RsaKey.java
@@ -0,0 +1,395 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography;
+
+import java.io.IOException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.interfaces.RSAPublicKey;
+import java.util.UUID;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.lang3.tuple.Triple;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.microsoft.azure.keyvault.core.IKey;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Rs256;
+import com.microsoft.azure.keyvault.cryptography.algorithms.RsaOaep;
+import com.microsoft.azure.keyvault.webkey.JsonWebKey;
+
+public class RsaKey implements IKey {
+
+ public static int KeySize1024 = 1024;
+ public static int KeySize2048 = 2048;
+ public static int KeySize4096 = 4096;
+
+ public static int getDefaultKeySize() {
+ return RsaKey.KeySize2048;
+ }
+
+ private final String _kid;
+ private final KeyPair _keyPair;
+ private final Provider _provider;
+
+ /**
+ * Constructor.
+ *
+ * Generates a new RsaKey with a 2048 size keypair and a randomly generated kid.
+ * @throws NoSuchAlgorithmException
+ */
+ public RsaKey() throws NoSuchAlgorithmException {
+ this(UUID.randomUUID().toString());
+ }
+
+ /**
+ * Constructor.
+ *
+ * Generates a new RsaKey with a 2048 size keypair and the kid given.
+ * @param kid
+ * @throws NoSuchAlgorithmException
+ */
+ public RsaKey(String kid) throws NoSuchAlgorithmException {
+ this(kid, getDefaultKeySize());
+ }
+
+ /**
+ * Constructor.
+ *
+ * Generates a new RsaKey with size keySize and the kid given.
+ * @param kid
+ * @param keySize
+ * @throws NoSuchAlgorithmException
+ */
+ public RsaKey(String kid, int keySize) throws NoSuchAlgorithmException {
+ this(kid, keySize, null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * Generates a new RsaKey with size keySize and the kid given. The given provider is used for algorithm implementation.
+ * @param kid
+ * @param keySize
+ * @param provider Java security provider.
+ * @throws NoSuchAlgorithmException
+ */
+ public RsaKey(String kid, int keySize, Provider provider) throws NoSuchAlgorithmException {
+
+ if (Strings.isNullOrWhiteSpace(kid)) {
+ throw new IllegalArgumentException("kid");
+ }
+
+ final KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", provider);
+
+ generator.initialize(keySize);
+
+ _kid = kid;
+ _keyPair = generator.generateKeyPair();
+ _provider = provider;
+ }
+
+ /**
+ * Constructor.
+ *
+ * Generates a new RsaKey with the given KeyPair.
+ * The keyPair must be an RSAKey.
+ * @param kid
+ * @param keyPair
+ */
+ public RsaKey(String kid, KeyPair keyPair) {
+ this(kid, keyPair, null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * Generates a new RsaKey with given KeyPair. The given provider is used for algorithm implementation.
+ * The keyPair must be an RSAKey.
+ * @param kid
+ * @param keyPair
+ * @param provider Java security provider
+ */
+ public RsaKey(String kid, KeyPair keyPair, Provider provider) {
+
+ if (Strings.isNullOrWhiteSpace(kid)) {
+ throw new IllegalArgumentException("Please provide a kid");
+ }
+
+ if (keyPair == null) {
+ throw new IllegalArgumentException("Please provide a KeyPair");
+ }
+
+ if (keyPair.getPublic() == null || !(keyPair.getPublic() instanceof RSAPublicKey)) {
+ throw new IllegalArgumentException("The KeyPair is not an RsaKey");
+ }
+
+ _kid = kid;
+ _keyPair = keyPair;
+ _provider = provider;
+ }
+
+ /**
+ * Converts JSON web key to RsaKey.
+ * @param jwk
+ * @return RsaKey
+ */
+ public static RsaKey fromJsonWebKey(JsonWebKey jwk) {
+ return fromJsonWebKey(jwk, false, null);
+ }
+
+ /**
+ * Converts JSON web key to RsaKey and include the private key if set to true.
+ * @param jwk
+ * @param includePrivateParameters true if the RSA key pair should include the private key. False otherwise.
+ * @return RsaKey
+ */
+ public static RsaKey fromJsonWebKey(JsonWebKey jwk, boolean includePrivateParameters) {
+ return fromJsonWebKey(jwk, includePrivateParameters, null);
+ }
+
+ /**
+ * Converts JSON web key to RsaKey and include the private key if set to true.
+ * @param provider the Java security provider.
+ * @param includePrivateParameters true if the RSA key pair should include the private key. False otherwise.
+ * @return RsaKey
+ */
+ public static RsaKey fromJsonWebKey(JsonWebKey jwk, boolean includePrivateParameters, Provider provider) {
+ if (jwk.kid() != null) {
+ return new RsaKey(jwk.kid(), jwk.toRSA(includePrivateParameters, provider));
+ } else {
+ throw new IllegalArgumentException("Json Web Key must have a kid");
+ }
+ }
+
+ /**
+ * Converts RsaKey to JSON web key.
+ * @return
+ */
+ public JsonWebKey toJsonWebKey() {
+ return JsonWebKey.fromRSA(_keyPair);
+ }
+
+ @Override
+ public String getDefaultEncryptionAlgorithm() {
+ return RsaOaep.ALGORITHM_NAME;
+ }
+
+ @Override
+ public String getDefaultKeyWrapAlgorithm() {
+ return RsaOaep.ALGORITHM_NAME;
+ }
+
+ @Override
+ public String getDefaultSignatureAlgorithm() {
+ return Rs256.ALGORITHM_NAME;
+ }
+
+ @Override
+ public String getKid() {
+ return _kid;
+ }
+
+ public KeyPair getKeyPair() {
+ return _keyPair;
+ }
+
+ @Override
+ public ListenableFuture decryptAsync(final byte[] ciphertext, final byte[] iv, final byte[] authenticationData, final byte[] authenticationTag, final String algorithm) throws NoSuchAlgorithmException {
+
+ if (ciphertext == null) {
+ throw new IllegalArgumentException("ciphertext");
+ }
+
+ // Interpret the requested algorithm
+ if (Strings.isNullOrWhiteSpace(algorithm)) {
+ throw new IllegalArgumentException("algorithm");
+ }
+
+ Algorithm baseAlgorithm = AlgorithmResolver.Default.get(algorithm);
+
+ if (baseAlgorithm == null || !(baseAlgorithm instanceof AsymmetricEncryptionAlgorithm)) {
+ throw new NoSuchAlgorithmException(algorithm);
+ }
+
+ AsymmetricEncryptionAlgorithm algo = (AsymmetricEncryptionAlgorithm)baseAlgorithm;
+
+ ICryptoTransform transform;
+ ListenableFuture result;
+
+ try {
+ transform = algo.CreateDecryptor(_keyPair, _provider);
+ result = Futures.immediateFuture(transform.doFinal(ciphertext));
+ } catch (Exception e) {
+ result = Futures.immediateFailedFuture(e);
+ }
+
+ return result;
+ }
+
+ @Override
+ public ListenableFuture> encryptAsync(final byte[] plaintext, final byte[] iv, final byte[] authenticationData, final String algorithm) throws NoSuchAlgorithmException {
+
+ if (plaintext == null) {
+ throw new IllegalArgumentException("plaintext");
+ }
+
+ // Interpret the requested algorithm
+ String algorithmName = (Strings.isNullOrWhiteSpace(algorithm) ? getDefaultEncryptionAlgorithm() : algorithm);
+ Algorithm baseAlgorithm = AlgorithmResolver.Default.get(algorithmName);
+
+ if (baseAlgorithm == null || !(baseAlgorithm instanceof AsymmetricEncryptionAlgorithm)) {
+ throw new NoSuchAlgorithmException(algorithmName);
+ }
+
+ AsymmetricEncryptionAlgorithm algo = (AsymmetricEncryptionAlgorithm)baseAlgorithm;
+
+ ICryptoTransform transform;
+ ListenableFuture> result;
+
+ try {
+ transform = algo.CreateEncryptor(_keyPair, _provider);
+ result = Futures.immediateFuture(Triple.of(transform.doFinal(plaintext), (byte[]) null, algorithmName));
+ } catch (Exception e) {
+ result = Futures.immediateFailedFuture(e);
+ }
+
+ return result;
+ }
+
+ @Override
+ public ListenableFuture> wrapKeyAsync(final byte[] key, final String algorithm) throws NoSuchAlgorithmException {
+
+ if (key == null) {
+ throw new IllegalArgumentException("key");
+ }
+
+ // Interpret the requested algorithm
+ String algorithmName = (Strings.isNullOrWhiteSpace(algorithm) ? getDefaultKeyWrapAlgorithm() : algorithm);
+ Algorithm baseAlgorithm = AlgorithmResolver.Default.get(algorithmName);
+
+ if (baseAlgorithm == null || !(baseAlgorithm instanceof AsymmetricEncryptionAlgorithm)) {
+ throw new NoSuchAlgorithmException(algorithmName);
+ }
+
+ AsymmetricEncryptionAlgorithm algo = (AsymmetricEncryptionAlgorithm)baseAlgorithm;
+
+ ICryptoTransform transform;
+ ListenableFuture> result;
+
+ try {
+ transform = algo.CreateEncryptor(_keyPair, _provider);
+ result = Futures.immediateFuture(Pair.of(transform.doFinal(key), algorithmName));
+ } catch (Exception e) {
+ result = Futures.immediateFailedFuture(e);
+ }
+
+ return result;
+ }
+
+ @Override
+ public ListenableFuture unwrapKeyAsync(final byte[] encryptedKey, final String algorithm) throws NoSuchAlgorithmException {
+
+ if (encryptedKey == null) {
+ throw new IllegalArgumentException("encryptedKey ");
+ }
+
+ // Interpret the requested algorithm
+ if (Strings.isNullOrWhiteSpace(algorithm)) {
+ throw new IllegalArgumentException("algorithm");
+ }
+
+ // Interpret the requested algorithm
+ Algorithm baseAlgorithm = AlgorithmResolver.Default.get(algorithm);
+
+ if (baseAlgorithm == null || !(baseAlgorithm instanceof AsymmetricEncryptionAlgorithm)) {
+ throw new NoSuchAlgorithmException(algorithm);
+ }
+
+ AsymmetricEncryptionAlgorithm algo = (AsymmetricEncryptionAlgorithm)baseAlgorithm;
+
+ ICryptoTransform transform;
+ ListenableFuture result;
+
+ try {
+ transform = algo.CreateDecryptor(_keyPair, _provider);
+ result = Futures.immediateFuture(transform.doFinal(encryptedKey));
+ } catch (Exception e) {
+ result = Futures.immediateFailedFuture(e);
+ }
+
+ return result;
+ }
+
+ @Override
+ public ListenableFuture> signAsync(final byte[] digest, final String algorithm) throws NoSuchAlgorithmException {
+
+ if (digest == null) {
+ throw new IllegalArgumentException("encryptedKey ");
+ }
+
+ // Interpret the requested algorithm
+ if (Strings.isNullOrWhiteSpace(algorithm)) {
+ throw new IllegalArgumentException("algorithm");
+ }
+
+ // Interpret the requested algorithm
+ Algorithm baseAlgorithm = AlgorithmResolver.Default.get(algorithm);
+
+ if (baseAlgorithm == null || !(baseAlgorithm instanceof AsymmetricSignatureAlgorithm)) {
+ throw new NoSuchAlgorithmException(algorithm);
+ }
+
+ Rs256 algo = (Rs256)baseAlgorithm;
+
+ ISignatureTransform signer = algo.createSignatureTransform(_keyPair);
+
+ try {
+ return Futures.immediateFuture(Pair.of(signer.sign(digest), Rs256.ALGORITHM_NAME));
+ } catch (Exception e) {
+ return Futures.immediateFailedFuture(e);
+ }
+ }
+
+ @Override
+ public ListenableFuture verifyAsync(final byte[] digest, final byte[] signature, final String algorithm) throws NoSuchAlgorithmException {
+
+ if (digest == null) {
+ throw new IllegalArgumentException("encryptedKey ");
+ }
+
+ // Interpret the requested algorithm
+ if (Strings.isNullOrWhiteSpace(algorithm)) {
+ throw new IllegalArgumentException("algorithm");
+ }
+
+ // Interpret the requested algorithm
+ Algorithm baseAlgorithm = AlgorithmResolver.Default.get(algorithm);
+
+ if (baseAlgorithm == null || !(baseAlgorithm instanceof AsymmetricSignatureAlgorithm)) {
+ throw new NoSuchAlgorithmException(algorithm);
+ }
+
+ Rs256 algo = (Rs256)baseAlgorithm;
+
+ ISignatureTransform signer = algo.createSignatureTransform(_keyPair);
+
+ try {
+ return Futures.immediateFuture(signer.verify(digest, signature));
+ } catch (Exception e) {
+ return Futures.immediateFailedFuture(e);
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ // Intentionally empty
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SignatureAlgorithm.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SignatureAlgorithm.java
new file mode 100644
index 000000000000..53d7459b9136
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SignatureAlgorithm.java
@@ -0,0 +1,15 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography;
+
+public abstract class SignatureAlgorithm extends Algorithm {
+
+ protected SignatureAlgorithm(String name) {
+ super(name);
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/Strings.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/Strings.java
new file mode 100644
index 000000000000..a1ead94749e6
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/Strings.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography;
+
+public final class Strings {
+
+ /**
+ * Determines whether the parameter string is either null or empty.
+ *
+ * @param arg The string to be checked.
+ * @return true if the string is null or empty.
+ */
+ public static boolean isNullOrEmpty(String arg) {
+
+ if (arg == null || arg.length() == 0) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Determines whether the parameter string is null, empty or whitespace.
+ *
+ * @param arg The string to be checked.
+ * @return true if the string is null, empty or whitespace.
+ */
+ public static boolean isNullOrWhiteSpace(String arg) {
+
+ if (Strings.isNullOrEmpty(arg) || arg.trim().isEmpty()) {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SymmetricEncryptionAlgorithm.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SymmetricEncryptionAlgorithm.java
new file mode 100644
index 000000000000..b582ced73492
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SymmetricEncryptionAlgorithm.java
@@ -0,0 +1,107 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+
+import javax.crypto.NoSuchPaddingException;
+
+/**
+ * Abstract base class for all symmetric encryption algorithms.
+ *
+ */
+public abstract class SymmetricEncryptionAlgorithm extends EncryptionAlgorithm {
+
+ /**
+ * Constructor.
+ *
+ * @param name The name of the algorithm.
+ */
+ protected SymmetricEncryptionAlgorithm(String name) {
+ super(name);
+ }
+
+ /**
+ * Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for encryption
+ * using the supplied initialization vector and the specific provider for the Java Security API.
+ * @param key
+ * The key material to be used.
+ * @param iv
+ * The initialization vector to be used.
+ * @param authenticationData
+ * The authentication data to be used with authenticating encryption algorithms (ignored for non-authenticating algorithms)
+ * @return A {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation
+ * @throws InvalidKeyException
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchPaddingException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public abstract ICryptoTransform CreateEncryptor(byte[] key, byte[] iv, byte[] authenticationData) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException;
+
+ /**
+ * Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for encryption
+ * using the supplied initialization vector and the specific provider for the Java Security API.
+ * @param key
+ * The key material to be used.
+ * @param iv
+ * The initialization vector to be used.
+ * @param authenticationData
+ * The authentication data to be used with authenticating encryption algorithms (ignored for non-authenticating algorithms)
+ * @param provider
+ * The provider to use.
+ * @return A {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation
+ * @throws InvalidKeyException
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchPaddingException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public abstract ICryptoTransform CreateEncryptor(byte[] key, byte[] iv, byte[] authenticationData, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException;
+
+ /**
+ * Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for decryption
+ * using the supplied initialization vector and the specific provider for the Java Security API.
+ * @param key
+ * The key material to be used.
+ * @param iv
+ * The initialization vector to be used.
+ * @param authenticationData
+ * The authentication data to be used with authenticating encryption algorithms (ignored for non-authenticating algorithms)
+ * @param authenticationTag
+ * The authentication tag to verify when using authenticating encryption algorithms (ignored for non-authenticating algorithms)
+ * @return A {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation
+ * @throws InvalidKeyException
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchPaddingException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public abstract ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, byte[] authenticationData, byte[] authenticationTag) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException;
+
+ /**
+ * Creates a {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation for decryption
+ * using the supplied initialization vector and the specific provider for the Java Security API.
+ * @param key
+ * The key material to be used.
+ * @param iv
+ * The initialization vector to be used.
+ * @param authenticationData
+ * The authentication data to be used with authenticating encryption algorithms (ignored for non-authenticating algorithms)
+ * @param authenticationTag
+ * The authentication tag to verify when using authenticating encryption algorithms (ignored for non-authenticating algorithms)
+ * @param provider
+ * The provider to use.
+ * @return A {@link com.microsoft.azure.keyvault.cryptography.ICryptoTransform} implementation
+ * @throws InvalidKeyException
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchPaddingException
+ * @throws InvalidAlgorithmParameterException
+ */
+ public abstract ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, byte[] authenticationData, byte[] authenticationTag, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException;
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SymmetricKey.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SymmetricKey.java
new file mode 100644
index 000000000000..c401d77251a8
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SymmetricKey.java
@@ -0,0 +1,389 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography;
+
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.util.UUID;
+
+import org.apache.commons.lang3.NotImplementedException;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.lang3.tuple.Triple;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.microsoft.azure.keyvault.core.IKey;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Aes128Cbc;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Aes128CbcHmacSha256;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Aes192Cbc;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Aes192CbcHmacSha384;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Aes256CbcHmacSha512;
+import com.microsoft.azure.keyvault.cryptography.algorithms.AesKw128;
+import com.microsoft.azure.keyvault.cryptography.algorithms.AesKw192;
+import com.microsoft.azure.keyvault.cryptography.algorithms.AesKw256;
+import com.microsoft.azure.keyvault.cryptography.Strings;
+
+/**
+ * A simple symmetric key implementation
+ *
+ */
+public class SymmetricKey implements IKey {
+
+ private static final SecureRandom Rng = new SecureRandom();
+
+ public static final int KeySize128 = 128 >> 3;
+ public static final int KeySize192 = 192 >> 3;
+ public static final int KeySize256 = 256 >> 3;
+ public static final int KeySize384 = 384 >> 3;
+ public static final int KeySize512 = 512 >> 3;
+
+ public static final int DefaultKeySize = KeySize256;
+
+ private final String _kid;
+ private final byte[] _key;
+ private final Provider _provider;
+
+ /**
+ * Creates a SymmetricKey with a random key identifier and
+ * a random key with DefaultKeySize bits.
+ */
+ public SymmetricKey() {
+ this(UUID.randomUUID().toString());
+ }
+
+ /**
+ * Creates a SymmetricKey with the specified key identifier and
+ * a random key with DefaultKeySize bits.
+ * @param kid
+ * The key identifier to use.
+ */
+ public SymmetricKey(String kid) {
+ this(kid, DefaultKeySize);
+ }
+
+ /**
+ * Creates a SymmetricKey with the specified key identifier and
+ * a random key with the specified size.
+ * @param kid
+ * The key identifier to use.
+ * @param keySizeInBytes
+ * The key size to use in bytes.
+ */
+ public SymmetricKey(String kid, int keySizeInBytes ) {
+ this(kid, keySizeInBytes, null);
+ }
+
+ /**
+ * Creates a SymmetricKey with the specified key identifier and
+ * a random key with the specified size that uses the specified provider.
+ * @param kid
+ * The key identifier to use.
+ * @param keySizeInBytes
+ * The key size to use in bytes.
+ * @param provider
+ * The provider to use (optional, null for default)
+ */
+ public SymmetricKey(String kid, int keySizeInBytes, Provider provider) {
+
+ if ( Strings.isNullOrWhiteSpace(kid) ) {
+ throw new IllegalArgumentException("kid");
+ }
+
+ if ( keySizeInBytes != KeySize128 && keySizeInBytes != KeySize192 && keySizeInBytes != KeySize256 && keySizeInBytes != KeySize384 && keySizeInBytes != KeySize512 ) {
+ throw new IllegalArgumentException("The key material must be 128, 192, 256, 384 or 512 bits of data");
+ }
+
+ _kid = kid;
+ _key = new byte[keySizeInBytes];
+ _provider = provider;
+
+ // Generate a random key
+ Rng.nextBytes(_key);
+ }
+
+ /**
+ * Creates a SymmetricKey with the specified key identifier and key material.
+ * @param kid
+ * The key identifier to use.
+ * @param keyBytes
+ * The key material to use.
+ */
+ public SymmetricKey(String kid, byte[] keyBytes) {
+ this(kid, keyBytes, null);
+ }
+
+ /**
+ * Creates a SymmetricKey with the specified key identifier and key material
+ * that uses the specified Provider.
+ * @param kid
+ * The key identifier to use.
+ * @param keyBytes
+ * The key material to use.
+ * @param provider
+ * The Provider to use (optional, null for default)
+ */
+ public SymmetricKey(String kid, byte[] keyBytes, Provider provider) {
+
+ if ( Strings.isNullOrWhiteSpace(kid) ) {
+ throw new IllegalArgumentException("kid");
+ }
+
+ if ( keyBytes == null ) {
+ throw new IllegalArgumentException("keyBytes");
+ }
+
+ if ( keyBytes.length != KeySize128 && keyBytes.length != KeySize192 && keyBytes.length != KeySize256 && keyBytes.length != KeySize384 && keyBytes.length != KeySize512 ) {
+ throw new IllegalArgumentException("The key material must be 128, 192, 256, 384 or 512 bits of data");
+ }
+
+ _kid = kid;
+ _key = keyBytes;
+ _provider = provider;
+ }
+
+ @Override
+ public String getDefaultEncryptionAlgorithm() {
+
+ switch (_key.length) {
+ case KeySize128:
+ return Aes128Cbc.ALGORITHM_NAME;
+
+ case KeySize192:
+ return Aes192Cbc.ALGORITHM_NAME;
+
+ case KeySize256:
+ return Aes128CbcHmacSha256.ALGORITHM_NAME;
+
+ case KeySize384:
+ return Aes192CbcHmacSha384.ALGORITHM_NAME;
+
+ case KeySize512:
+ return Aes256CbcHmacSha512.ALGORITHM_NAME;
+ }
+
+ return null;
+ }
+
+ @Override
+ public String getDefaultKeyWrapAlgorithm() {
+
+ switch (_key.length) {
+ case KeySize128:
+ return AesKw128.ALGORITHM_NAME;
+
+ case KeySize192:
+ return AesKw192.ALGORITHM_NAME;
+
+ case KeySize256:
+ return AesKw256.ALGORITHM_NAME;
+
+ case KeySize384:
+ // Default to longest allowed key length for wrap
+ return AesKw256.ALGORITHM_NAME;
+
+ case KeySize512:
+ // Default to longest allowed key length for wrap
+ return AesKw256.ALGORITHM_NAME;
+ }
+
+ return null;
+ }
+
+ @Override
+ public String getDefaultSignatureAlgorithm() {
+
+ return null;
+ }
+
+ @Override
+ public String getKid() {
+
+ return _kid;
+ }
+
+ @Override
+ public ListenableFuture decryptAsync(final byte[] ciphertext, final byte[] iv, final byte[] authenticationData, final byte[] authenticationTag, final String algorithm) throws NoSuchAlgorithmException {
+
+ if (Strings.isNullOrWhiteSpace(algorithm)) {
+ throw new IllegalArgumentException("algorithm");
+ }
+
+ if (ciphertext == null) {
+ throw new IllegalArgumentException("ciphertext");
+ }
+
+ if (iv == null) {
+ throw new IllegalArgumentException("iv");
+ }
+
+ // Interpret the algorithm
+ Algorithm baseAlgorithm = AlgorithmResolver.Default.get(algorithm);
+
+ if (baseAlgorithm == null || !(baseAlgorithm instanceof SymmetricEncryptionAlgorithm)) {
+ throw new NoSuchAlgorithmException(algorithm);
+ }
+
+ SymmetricEncryptionAlgorithm algo = (SymmetricEncryptionAlgorithm)baseAlgorithm;
+
+ ICryptoTransform transform = null;
+
+ try {
+ transform = algo.CreateDecryptor(_key, iv, authenticationData, authenticationTag, _provider );
+ } catch (Exception e) {
+ return Futures.immediateFailedFuture(e);
+ }
+
+ byte[] result = null;
+
+ try {
+ result = transform.doFinal(ciphertext);
+ } catch (Exception e) {
+ return Futures.immediateFailedFuture(e);
+ }
+
+ return Futures.immediateFuture(result);
+ }
+
+ @Override
+ public ListenableFuture> encryptAsync(final byte[] plaintext, final byte[] iv, final byte[] authenticationData, final String algorithm) throws NoSuchAlgorithmException {
+
+ if (plaintext == null) {
+ throw new IllegalArgumentException("plaintext");
+ }
+
+ if (iv == null) {
+ throw new IllegalArgumentException("iv");
+ }
+
+ // Interpret the algorithm
+ String algorithmName = (Strings.isNullOrWhiteSpace(algorithm)) ? getDefaultEncryptionAlgorithm() : algorithm;
+ Algorithm baseAlgorithm = AlgorithmResolver.Default.get(algorithmName);
+
+ if (baseAlgorithm == null || !(baseAlgorithm instanceof SymmetricEncryptionAlgorithm)) {
+ throw new NoSuchAlgorithmException(algorithm);
+ }
+
+ SymmetricEncryptionAlgorithm algo = (SymmetricEncryptionAlgorithm)baseAlgorithm;
+
+ ICryptoTransform transform = null;
+
+ try {
+ transform = algo.CreateEncryptor(_key, iv, authenticationData, _provider);
+ } catch (Exception e) {
+ return Futures.immediateFailedFuture(e);
+ }
+
+ byte[] cipherText = null;
+
+ try {
+ cipherText = transform.doFinal(plaintext);
+ } catch (Exception e) {
+ return Futures.immediateFailedFuture(e);
+ }
+
+ byte[] authenticationTag = null;
+
+ if (transform instanceof IAuthenticatedCryptoTransform) {
+
+ IAuthenticatedCryptoTransform authenticatedTransform = (IAuthenticatedCryptoTransform) transform;
+
+ authenticationTag = authenticatedTransform.getTag().clone();
+ }
+
+ return Futures.immediateFuture(Triple.of(cipherText, authenticationTag, algorithm));
+ }
+
+ @Override
+ public ListenableFuture> wrapKeyAsync(final byte[] key, final String algorithm) throws NoSuchAlgorithmException {
+
+ if (key == null || key.length == 0) {
+ throw new IllegalArgumentException("key");
+ }
+
+ // Interpret the algorithm
+ String algorithmName = (Strings.isNullOrWhiteSpace(algorithm)) ? getDefaultKeyWrapAlgorithm() : algorithm;
+ Algorithm baseAlgorithm = AlgorithmResolver.Default.get(algorithmName);
+
+ if (baseAlgorithm == null || !(baseAlgorithm instanceof KeyWrapAlgorithm)) {
+ throw new NoSuchAlgorithmException(algorithmName);
+ }
+
+ KeyWrapAlgorithm algo = (KeyWrapAlgorithm)baseAlgorithm;
+
+ ICryptoTransform transform = null;
+
+ try {
+ transform = algo.CreateEncryptor(_key, null, _provider);
+ } catch (Exception e) {
+ return Futures.immediateFailedFuture(e);
+ }
+
+ byte[] encrypted = null;
+
+ try {
+ encrypted = transform.doFinal(key);
+ } catch (Exception e) {
+ return Futures.immediateFailedFuture(e);
+ }
+
+ return Futures.immediateFuture(Pair.of(encrypted, algorithmName));
+ }
+
+ @Override
+ public ListenableFuture unwrapKeyAsync(final byte[] encryptedKey, final String algorithm) throws NoSuchAlgorithmException {
+
+ if (Strings.isNullOrWhiteSpace(algorithm)) {
+ throw new IllegalArgumentException("algorithm");
+ }
+
+ if (encryptedKey == null || encryptedKey.length == 0) {
+ throw new IllegalArgumentException("wrappedKey");
+ }
+
+ Algorithm baseAlgorithm = AlgorithmResolver.Default.get(algorithm);
+
+ if (baseAlgorithm == null || !(baseAlgorithm instanceof KeyWrapAlgorithm)) {
+ throw new NoSuchAlgorithmException(algorithm);
+ }
+
+ KeyWrapAlgorithm algo = (KeyWrapAlgorithm)baseAlgorithm;
+
+ ICryptoTransform transform = null;
+
+ try {
+ transform = algo.CreateDecryptor(_key, null, _provider);
+ } catch (Exception e) {
+ return Futures.immediateFailedFuture(e);
+ }
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = transform.doFinal(encryptedKey);
+ } catch (Exception e) {
+ return Futures.immediateFailedFuture(e);
+ }
+
+ return Futures.immediateFuture(decrypted);
+ }
+
+ @Override
+ public ListenableFuture> signAsync(final byte[] digest, final String algorithm) {
+ return Futures.immediateFailedFuture(new NotImplementedException("signAsync is not currently supported"));
+ }
+
+ @Override
+ public ListenableFuture verifyAsync(final byte[] digest, final byte[] signature, final String algorithm) {
+ return Futures.immediateFailedFuture(new NotImplementedException("verifyAsync is not currently supported"));
+ }
+
+ @Override
+ public void close() throws IOException {
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes128Cbc.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes128Cbc.java
new file mode 100644
index 000000000000..89a10584294d
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes128Cbc.java
@@ -0,0 +1,17 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+public class Aes128Cbc extends AesCbc {
+
+ private static final int KEY_SIZE = 128;
+ public static final String ALGORITHM_NAME = "A128CBC";
+
+ public Aes128Cbc() {
+ super(ALGORITHM_NAME, KEY_SIZE);
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes128CbcHmacSha256.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes128CbcHmacSha256.java
new file mode 100644
index 000000000000..f473aee20d11
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes128CbcHmacSha256.java
@@ -0,0 +1,16 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+public class Aes128CbcHmacSha256 extends AesCbcHmacSha2 {
+
+ public static final String ALGORITHM_NAME = "A128CBC-HS256";
+
+ public Aes128CbcHmacSha256() {
+ super(ALGORITHM_NAME);
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes192Cbc.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes192Cbc.java
new file mode 100644
index 000000000000..fe6f3ff8f1f1
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes192Cbc.java
@@ -0,0 +1,17 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+public class Aes192Cbc extends AesCbc {
+
+ private static final int KEY_SIZE = 192;
+ public static final String ALGORITHM_NAME = "A192CBC";
+
+ public Aes192Cbc() {
+ super(ALGORITHM_NAME, KEY_SIZE);
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes192CbcHmacSha384.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes192CbcHmacSha384.java
new file mode 100644
index 000000000000..ecfc65f49ff6
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes192CbcHmacSha384.java
@@ -0,0 +1,16 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+public class Aes192CbcHmacSha384 extends AesCbcHmacSha2 {
+
+ public static final String ALGORITHM_NAME = "A192CBC-HS384";
+
+ public Aes192CbcHmacSha384() {
+ super(ALGORITHM_NAME);
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes256Cbc.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes256Cbc.java
new file mode 100644
index 000000000000..f198b9012b54
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes256Cbc.java
@@ -0,0 +1,17 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+public class Aes256Cbc extends AesCbc {
+
+ private static final int KEY_SIZE = 256;
+ public static final String ALGORITHM_NAME = "A256CBC";
+
+ public Aes256Cbc() {
+ super(ALGORITHM_NAME, KEY_SIZE);
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes256CbcHmacSha512.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes256CbcHmacSha512.java
new file mode 100644
index 000000000000..61c1aead84b7
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes256CbcHmacSha512.java
@@ -0,0 +1,16 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+public class Aes256CbcHmacSha512 extends AesCbcHmacSha2 {
+
+ public static final String ALGORITHM_NAME = "A256CBC-HS512";
+
+ public Aes256CbcHmacSha512() {
+ super(ALGORITHM_NAME);
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesCbc.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesCbc.java
new file mode 100644
index 000000000000..f2b9d28f67e3
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesCbc.java
@@ -0,0 +1,118 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.util.Arrays;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import com.microsoft.azure.keyvault.cryptography.ICryptoTransform;
+import com.microsoft.azure.keyvault.cryptography.SymmetricEncryptionAlgorithm;
+
+public abstract class AesCbc extends SymmetricEncryptionAlgorithm {
+
+ final int keySizeInBytes;
+ final int keySize;
+ static class AesCbcDecryptor implements ICryptoTransform {
+
+ private final Cipher _cipher;
+
+ AesCbcDecryptor(byte[] key, byte[] iv, Provider provider) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
+
+ // Create the cipher using the Provider if specified
+ if (provider == null) {
+ _cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ } else {
+ _cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", provider);
+ }
+
+ _cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
+ }
+
+ @Override
+ public byte[] doFinal(byte[] plaintext) throws IllegalBlockSizeException, BadPaddingException {
+ return _cipher.doFinal(plaintext);
+ }
+ }
+
+ static class AesCbcEncryptor implements ICryptoTransform {
+
+ private final Cipher _cipher;
+
+ AesCbcEncryptor(byte[] key, byte[] iv, Provider provider) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
+
+ // Create the cipher using the Provider if specified
+ if (provider == null) {
+ _cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ } else {
+ _cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", provider);
+ }
+
+ _cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
+ }
+
+ @Override
+ public byte[] doFinal(byte[] plaintext) throws IllegalBlockSizeException, BadPaddingException {
+ return _cipher.doFinal(plaintext);
+ }
+ }
+
+ protected AesCbc(String name, int size) {
+ super(name);
+ keySize = size;
+ keySizeInBytes = size >> 3;
+ }
+
+ @Override
+ public ICryptoTransform CreateEncryptor(byte[] key, byte[] iv, byte[] authenticationData) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
+
+ if (key == null || key.length < keySizeInBytes) {
+ throw new InvalidKeyException("key must be at least " + keySize + " bits in length");
+ }
+
+ return new AesCbcEncryptor(Arrays.copyOfRange(key, 0, keySizeInBytes), iv, null);
+ }
+
+ @Override
+ public ICryptoTransform CreateEncryptor(byte[] key, byte[] iv, byte[] authenticationData, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
+
+ if (key == null || key.length < keySizeInBytes) {
+ throw new InvalidKeyException("key must be at least " + keySize + " bits in length");
+ }
+
+ return new AesCbcEncryptor(Arrays.copyOfRange(key, 0, keySizeInBytes), iv, provider);
+ }
+
+ @Override
+ public ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, byte[] authenticationData, byte[] authenticationTag) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
+
+ if (key == null || key.length < keySizeInBytes) {
+ throw new InvalidKeyException("key must be at least " + keySize + " bits in length");
+ }
+
+ return new AesCbcDecryptor(Arrays.copyOfRange(key, 0, keySizeInBytes), iv, null);
+ }
+
+ @Override
+ public ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, byte[] authenticationData, byte[] authenticationTag, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
+
+ if (key == null || key.length < keySizeInBytes) {
+ throw new InvalidKeyException("key must be at least " + keySize + " bits in length");
+ }
+
+ return new AesCbcDecryptor(Arrays.copyOfRange(key, 0, keySizeInBytes), iv, provider);
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesCbcHmacSha2.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesCbcHmacSha2.java
new file mode 100644
index 000000000000..9ab0a3cd2f1e
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesCbcHmacSha2.java
@@ -0,0 +1,279 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.commons.lang3.tuple.Triple;
+
+import com.microsoft.azure.keyvault.cryptography.ByteExtensions;
+import com.microsoft.azure.keyvault.cryptography.IAuthenticatedCryptoTransform;
+import com.microsoft.azure.keyvault.cryptography.ICryptoTransform;
+import com.microsoft.azure.keyvault.cryptography.SymmetricEncryptionAlgorithm;
+
+public abstract class AesCbcHmacSha2 extends SymmetricEncryptionAlgorithm {
+
+ static class AesCbcHmacSha2Decryptor implements IAuthenticatedCryptoTransform {
+
+ final byte[] _aad_length;
+ final Mac _hmac;
+ final byte[] _hmac_key;
+ final ICryptoTransform _inner;
+
+ byte[] _tag;
+
+ AesCbcHmacSha2Decryptor(String name, byte[] key, byte[] iv, byte[] authenticationData, byte[] authenticationTag, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
+
+ // Split the key to get the AES key, the HMAC key and the HMAC
+ // object
+ Triple parameters = GetAlgorithmParameters(name, key);
+
+ // Save the MAC provider and key
+ _hmac = parameters.getRight();
+ _hmac_key = parameters.getMiddle();
+
+ // Create the AES provider
+ _inner = new AesCbc.AesCbcDecryptor(parameters.getLeft(), iv, provider);
+
+ _aad_length = toBigEndian(authenticationData.length * 8);
+
+ // Save the tag
+ _tag = authenticationTag;
+
+ // Prime the hash.
+ _hmac.update(authenticationData);
+ _hmac.update(iv);
+ }
+
+ @Override
+ public byte[] getTag() {
+ return _tag;
+ }
+
+ @Override
+ public byte[] doFinal(byte[] input) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException {
+
+ // Add the cipher text to the running hash
+ _hmac.update(input);
+
+ // Add the associated_data_length bytes to the hash
+ byte[] hash = _hmac.doFinal(_aad_length);
+
+ // Compute the new tag
+ byte[] tag = new byte[_hmac_key.length];
+ System.arraycopy(hash, 0, tag, 0, _hmac_key.length);
+
+ // Check the tag before performing the final decrypt
+ if ( !ByteExtensions.sequenceEqualConstantTime(_tag, tag) ) {
+ throw new IllegalArgumentException("Data is not authentic");
+ }
+
+ return _inner.doFinal(input);
+ }
+ }
+
+ static class AesCbcHmacSha2Encryptor implements IAuthenticatedCryptoTransform {
+
+ final byte[] _aad_length;
+ final Mac _hmac;
+ final byte[] _hmac_key;
+ final ICryptoTransform _inner;
+
+ byte[] _tag;
+
+ AesCbcHmacSha2Encryptor(String name, byte[] key, byte[] iv, byte[] authenticationData, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
+ // Split the key to get the AES key, the HMAC key and the HMAC
+ // object
+ Triple parameters = GetAlgorithmParameters(name, key);
+
+ // Save the MAC provider and key
+ _hmac = parameters.getRight();
+ _hmac_key = parameters.getMiddle();
+
+ // Create the AES encryptor
+ _inner = new AesCbc.AesCbcEncryptor(parameters.getLeft(), iv, provider);
+
+ _aad_length = toBigEndian(authenticationData.length * 8);
+
+ // Prime the hash.
+ _hmac.update(authenticationData);
+ _hmac.update(iv);
+ }
+
+ @Override
+ public byte[] getTag() {
+ return _tag;
+ }
+
+ // public int TransformBlock( byte[] inputBuffer, int inputOffset, int
+ // inputCount, byte[] outputBuffer, int outputOffset )
+ // {
+ // // Encrypt the block
+ // var result = _inner.TransformBlock( inputBuffer, inputOffset,
+ // inputCount, outputBuffer, outputOffset );
+ //
+ // // Add it to the running hash
+ // _hmac.TransformBlock( outputBuffer, outputOffset, result,
+ // outputBuffer, outputOffset );
+ //
+ // return result;
+ // }
+
+ @Override
+ public byte[] doFinal(byte[] input) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException {
+
+ // Encrypt the block
+ byte[] output = _inner.doFinal(input);
+
+ // Add the cipher text to the running hash
+ _hmac.update(output);
+
+ // Add the associated_data_length bytes to the hash
+ byte[] hash = _hmac.doFinal(_aad_length);
+
+ // Compute the tag
+ _tag = new byte[_hmac_key.length];
+ System.arraycopy(hash, 0, _tag, 0, _tag.length);
+
+ return output;
+ }
+ }
+
+ protected AesCbcHmacSha2(String name) {
+ super(name);
+ }
+
+ @Override
+ public ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, byte[] authenticationData, byte[] authenticationTag) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
+ return CreateDecryptor(key, iv, authenticationData, authenticationTag, null);
+ }
+
+ @Override
+ public ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, byte[] authenticationData, byte[] authenticationTag, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
+ if (key == null) {
+ throw new IllegalArgumentException("No key material");
+ }
+
+ if (iv == null) {
+ throw new IllegalArgumentException("No initialization vector");
+ }
+
+ if (authenticationData == null) {
+ throw new IllegalArgumentException("No authentication data");
+ }
+
+ if (authenticationTag == null) {
+ throw new IllegalArgumentException("No authentication tag");
+ }
+
+ // Create the Decryptor
+ return new AesCbcHmacSha2Decryptor(getName(), key, iv, authenticationData, authenticationTag, provider);
+ }
+
+ @Override
+ public ICryptoTransform CreateEncryptor(byte[] key, byte[] iv, byte[] authenticationData) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
+ return CreateEncryptor(key, iv, authenticationData, null);
+ }
+
+ @Override
+ public ICryptoTransform CreateEncryptor(byte[] key, byte[] iv, byte[] authenticationData, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
+
+ if (key == null) {
+ throw new IllegalArgumentException("No key material");
+ }
+
+ if (iv == null) {
+ throw new IllegalArgumentException("No initialization vector");
+ }
+
+ if (authenticationData == null) {
+ throw new IllegalArgumentException("No authentication data");
+ }
+
+ // Create the Encryptor
+ return new AesCbcHmacSha2Encryptor(getName(), key, iv, authenticationData, provider);
+ }
+
+ private static Triple GetAlgorithmParameters(String algorithm, byte[] key) throws InvalidKeyException, NoSuchAlgorithmException {
+
+ byte[] aes_key;
+ byte[] hmac_key;
+ Mac hmac;
+
+ if (algorithm.equalsIgnoreCase(Aes128CbcHmacSha256.ALGORITHM_NAME)) {
+ if ((key.length << 3) < 256) {
+ throw new IllegalArgumentException(String.format("%s key length in bits %d < 256", algorithm, key.length << 3));
+ }
+
+ hmac_key = new byte[128 >> 3];
+ aes_key = new byte[128 >> 3];
+
+ // The HMAC key precedes the AES key
+ System.arraycopy(key, 0, hmac_key, 0, 128 >> 3);
+ System.arraycopy(key, 128 >> 3, aes_key, 0, 128 >> 3);
+
+ hmac = Mac.getInstance("HmacSHA256");
+ hmac.init(new SecretKeySpec(hmac_key, "HmacSHA256"));
+
+ } else if (algorithm.equalsIgnoreCase(Aes192CbcHmacSha384.ALGORITHM_NAME)) {
+
+ if ((key.length << 3) < 384) {
+ throw new IllegalArgumentException(String.format("%s key length in bits %d < 384", algorithm, key.length << 3));
+ }
+
+ hmac_key = new byte[192 >> 3];
+ aes_key = new byte[192 >> 3];
+
+ // The HMAC key precedes the AES key
+ System.arraycopy(key, 0, hmac_key, 0, 192 >> 3);
+ System.arraycopy(key, 192 >> 3, aes_key, 0, 192 >> 3);
+
+ hmac = Mac.getInstance("HmacSHA384");
+ hmac.init(new SecretKeySpec(hmac_key, "HmacSHA384"));
+ } else if (algorithm.equalsIgnoreCase(Aes256CbcHmacSha512.ALGORITHM_NAME)) {
+
+ if ((key.length << 3) < 512) {
+ throw new IllegalArgumentException(String.format("%s key length in bits %d < 512", algorithm, key.length << 3));
+ }
+
+ hmac_key = new byte[256 >> 3];
+ aes_key = new byte[256 >> 3];
+
+ // The HMAC key precedes the AES key
+ System.arraycopy(key, 0, hmac_key, 0, 256 >> 3);
+ System.arraycopy(key, 256 >> 3, aes_key, 0, 256 >> 3);
+
+ hmac = Mac.getInstance("HmacSHA512");
+ hmac.init(new SecretKeySpec(hmac_key, "HmacSHA512"));
+ } else {
+ throw new IllegalArgumentException(String.format("Unsupported algorithm: %s", algorithm));
+ }
+
+ return Triple.of(aes_key, hmac_key, hmac);
+ }
+
+ static byte[] toBigEndian(long i) {
+
+ byte[] shortRepresentation = BigInteger.valueOf(i).toByteArray();
+ byte[] longRepresentation = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ System.arraycopy(shortRepresentation, 0, longRepresentation, longRepresentation.length - shortRepresentation.length, shortRepresentation.length);
+
+ return longRepresentation;
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw.java
new file mode 100644
index 000000000000..6bd7dfc28c63
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw.java
@@ -0,0 +1,180 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import com.microsoft.azure.keyvault.cryptography.ICryptoTransform;
+import com.microsoft.azure.keyvault.cryptography.KeyWrapAlgorithm;
+
+public abstract class AesKw extends KeyWrapAlgorithm {
+
+ static final byte[] _defaultIv = new byte[] { (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6 };
+ static final String _cipherName = "AESWrap";
+
+ class AesKwDecryptor implements ICryptoTransform {
+
+ final Cipher _cipher;
+
+ AesKwDecryptor(byte[] key, byte[] iv, Provider provider) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
+
+ if (provider == null) {
+ _cipher = Cipher.getInstance(_cipherName);
+ } else {
+ _cipher = Cipher.getInstance(_cipherName, provider);
+ }
+
+ // The default provider does not support the specification of IV. This
+ // is guarded by the CreateEncrypter wrapper method and the iv parameter
+ // can be ignored when using the default provider
+ if (provider == null ) {
+ _cipher.init(Cipher.UNWRAP_MODE, new SecretKeySpec(key, "AES"));
+ } else {
+ _cipher.init(Cipher.UNWRAP_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
+ }
+ }
+
+ @Override
+ public byte[] doFinal(byte[] plaintext) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException {
+
+ return _cipher.unwrap(plaintext, "AESWrap", Cipher.SECRET_KEY).getEncoded();
+ }
+
+ }
+
+ class AesKwEncryptor implements ICryptoTransform {
+
+ final Cipher _cipher;
+
+ AesKwEncryptor(byte[] key, byte[] iv, Provider provider) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
+
+ if (provider == null) {
+ _cipher = Cipher.getInstance(_cipherName);
+ } else {
+ _cipher = Cipher.getInstance(_cipherName, provider);
+ }
+
+ // The default provider does not support the specification of IV. This
+ // is guarded by the CreateEncrypter wrapper method and the iv parameter
+ // can be ignored when using the default provider
+ if (provider == null ) {
+ _cipher.init(Cipher.WRAP_MODE, new SecretKeySpec(key, "AES"));
+ } else {
+ _cipher.init(Cipher.WRAP_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
+ }
+ }
+
+ @Override
+ public byte[] doFinal(byte[] plaintext) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException {
+
+ return _cipher.wrap(new SecretKeySpec(plaintext, "AES"));
+ }
+
+ }
+
+ protected AesKw(String name) {
+ super(name);
+ }
+
+ @Override
+ public ICryptoTransform CreateEncryptor(byte[] key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
+
+ return CreateEncryptor(key, null, null);
+ }
+
+ @Override
+ public ICryptoTransform CreateEncryptor(byte[] key, Provider provider) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
+
+ return CreateEncryptor(key, null, provider);
+ }
+
+ @Override
+ public ICryptoTransform CreateEncryptor(byte[] key, byte[] iv) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
+
+ return CreateEncryptor(key, iv, null);
+ }
+
+ @Override
+ public ICryptoTransform CreateEncryptor(byte[] key, byte[] iv, Provider provider) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
+
+ if (key == null) {
+ throw new IllegalArgumentException("key");
+ }
+
+ if (key.length != 128 >> 3 && key.length != 192 >> 3 && key.length != 256 >> 3) {
+ throw new IllegalArgumentException("key length must be 128, 192 or 256 bits");
+ }
+
+ if (iv != null ) {
+ // iv length must be 64 bits
+ if ( iv.length != 8) {
+ throw new IllegalArgumentException("iv length must be 64 bits");
+ }
+ // iv cannot be specified with the default provider
+ if (provider == null) {
+ throw new IllegalArgumentException("user specified iv is not supported with the default provider");
+ }
+ }
+
+ return new AesKwEncryptor(key, iv == null ? _defaultIv : iv, provider);
+
+ }
+
+ @Override
+ public ICryptoTransform CreateDecryptor(byte[] key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
+
+ return CreateDecryptor(key, null, null);
+ }
+
+ @Override
+ public ICryptoTransform CreateDecryptor(byte[] key, Provider provider) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
+
+ return CreateDecryptor(key, null, provider);
+ }
+
+ @Override
+ public ICryptoTransform CreateDecryptor(byte[] key, byte[] iv) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
+ return CreateDecryptor(key, iv, null);
+ }
+
+ @Override
+ public ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, Provider provider) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
+
+ if (key == null) {
+ throw new IllegalArgumentException("key");
+ }
+
+ if (key.length != 128 >> 3 && key.length != 192 >> 3 && key.length != 256 >> 3) {
+ throw new IllegalArgumentException("key length must be 128, 192 or 256 bits");
+ }
+
+
+ if (iv != null ) {
+ // iv length must be 64 bits
+ if ( iv.length != 8) {
+ throw new IllegalArgumentException("iv length must be 64 bits");
+ }
+ // iv cannot be specified with the default provider
+ if (provider == null) {
+ throw new IllegalArgumentException("user specified iv is not supported with the default provider");
+ }
+ }
+
+ return new AesKwDecryptor(key, iv == null ? _defaultIv : iv, provider);
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw128.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw128.java
new file mode 100644
index 000000000000..d5696f5998f3
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw128.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.util.Arrays;
+
+import javax.crypto.NoSuchPaddingException;
+
+import com.microsoft.azure.keyvault.cryptography.ICryptoTransform;
+
+public final class AesKw128 extends AesKw {
+
+ public static final String ALGORITHM_NAME = "A128KW";
+
+ static final int KeySizeInBytes = 128 >> 3;
+
+ public AesKw128() {
+ super(ALGORITHM_NAME);
+ }
+
+ @Override
+ public ICryptoTransform CreateEncryptor(byte[] key, byte[] iv, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
+
+ if (key == null) {
+ throw new IllegalArgumentException("key must not be null");
+ }
+
+ if (key.length < KeySizeInBytes) {
+ throw new IllegalArgumentException("key must be at least 128 bits long");
+ }
+
+ return super.CreateEncryptor(Arrays.copyOfRange(key, 0, KeySizeInBytes), iv, provider);
+ }
+
+ @Override
+ public ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
+
+ if (key == null) {
+ throw new IllegalArgumentException("key must not be null");
+ }
+
+ if (key.length < KeySizeInBytes) {
+ throw new IllegalArgumentException("key must be at least 128 bits long");
+ }
+
+ return super.CreateDecryptor(Arrays.copyOfRange(key, 0, KeySizeInBytes), iv, provider);
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw192.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw192.java
new file mode 100644
index 000000000000..43225d8e080d
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw192.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.util.Arrays;
+
+import javax.crypto.NoSuchPaddingException;
+
+import com.microsoft.azure.keyvault.cryptography.ICryptoTransform;
+
+public final class AesKw192 extends AesKw {
+
+ public static final String ALGORITHM_NAME = "A192KW";
+
+ static final int KeySizeInBytes = 192 >> 3;
+
+ public AesKw192() {
+ super(ALGORITHM_NAME);
+ }
+
+ @Override
+ public ICryptoTransform CreateEncryptor(byte[] key, byte[] iv, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
+
+ if (key == null) {
+ throw new IllegalArgumentException("key must not be null");
+ }
+
+ if (key.length < KeySizeInBytes) {
+ throw new IllegalArgumentException("key must be at least 192 bits long");
+ }
+
+ return super.CreateEncryptor(Arrays.copyOfRange(key, 0, KeySizeInBytes), iv, provider);
+ }
+
+ @Override
+ public ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
+
+ if (key == null) {
+ throw new IllegalArgumentException("key must not be null");
+ }
+
+ if (key.length < KeySizeInBytes) {
+ throw new IllegalArgumentException("key must be at least 192 bits long");
+ }
+
+ return super.CreateDecryptor(Arrays.copyOfRange(key, 0, KeySizeInBytes), iv, provider);
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw256.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw256.java
new file mode 100644
index 000000000000..b2b514713c96
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw256.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.util.Arrays;
+
+import javax.crypto.NoSuchPaddingException;
+
+import com.microsoft.azure.keyvault.cryptography.ICryptoTransform;
+
+public final class AesKw256 extends AesKw {
+
+ public static final String ALGORITHM_NAME = "A256KW";
+
+ static final int KeySizeInBytes = 256 >> 3;
+
+ public AesKw256() {
+ super(ALGORITHM_NAME);
+ }
+
+ @Override
+ public ICryptoTransform CreateEncryptor(byte[] key, byte[] iv, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
+
+ if (key == null) {
+ throw new IllegalArgumentException("key must not be null");
+ }
+
+ if (key.length < KeySizeInBytes) {
+ throw new IllegalArgumentException("key must be at least 256 bits long");
+ }
+
+ return super.CreateEncryptor(Arrays.copyOfRange(key, 0, KeySizeInBytes), iv, provider);
+ }
+
+ @Override
+ public ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
+
+ if (key == null) {
+ throw new IllegalArgumentException("key must not be null");
+ }
+
+ if (key.length < KeySizeInBytes) {
+ throw new IllegalArgumentException("key must be at least 256 bits long");
+ }
+
+ return super.CreateDecryptor(Arrays.copyOfRange(key, 0, KeySizeInBytes), iv, provider);
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ecdsa.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ecdsa.java
new file mode 100644
index 000000000000..a13fa0767997
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ecdsa.java
@@ -0,0 +1,54 @@
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.Provider;
+import java.security.Signature;
+
+import com.microsoft.azure.keyvault.cryptography.AsymmetricSignatureAlgorithm;
+import com.microsoft.azure.keyvault.cryptography.ISignatureTransform;
+
+public abstract class Ecdsa extends AsymmetricSignatureAlgorithm {
+
+ protected Ecdsa() {
+ super("NONEwithEDCSA");
+ }
+
+ public ISignatureTransform createSignatureTransform(KeyPair key, Provider provider) {
+ return new EcdsaSignatureTransform(key, provider);
+ }
+
+ abstract void checkDigestLength(byte[] digest);
+
+
+ class EcdsaSignatureTransform implements ISignatureTransform {
+ private final String ALGORITHM = "NONEwithECDSA";
+ private final KeyPair _keyPair;
+
+ private final Provider _provider;
+
+ public EcdsaSignatureTransform(KeyPair keyPair, Provider provider) {
+ _keyPair = keyPair;
+ _provider = provider;
+ }
+
+ @Override
+ public byte[] sign(byte[] digest) throws GeneralSecurityException {
+ checkDigestLength(digest);
+ Signature signature = Signature.getInstance(ALGORITHM, _provider);
+ signature.initSign(_keyPair.getPrivate());
+ signature.update(digest);
+ return signature.sign();
+ }
+
+ @Override
+ public boolean verify(byte[] digest, byte[] signature) throws GeneralSecurityException {
+ Signature verify = Signature.getInstance(ALGORITHM, _provider);
+ checkDigestLength(digest);
+ verify.initVerify(_keyPair.getPublic());
+ verify.update(digest);
+ return verify.verify(signature);
+ }
+
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256.java
new file mode 100644
index 000000000000..c9ae074fbb56
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256.java
@@ -0,0 +1,12 @@
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+public class Es256 extends Ecdsa {
+ public final static String ALGORITHM_NAME = "SHA256withECDSA";
+
+ @Override
+ public void checkDigestLength(byte[] digest) {
+ if (digest.length != 32) {
+ throw new IllegalArgumentException("Invalid digest length.");
+ }
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256k.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256k.java
new file mode 100644
index 000000000000..b788979f2b26
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256k.java
@@ -0,0 +1,12 @@
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+public class Es256k extends Ecdsa {
+ public final static String ALGORITHM_NAME = "NONEwithECDSA";
+
+ @Override
+ public void checkDigestLength(byte[] digest) {
+ if (digest.length != 32) {
+ throw new IllegalArgumentException("Invalid digest length.");
+ }
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es384.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es384.java
new file mode 100644
index 000000000000..7785fdbda61a
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es384.java
@@ -0,0 +1,13 @@
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+public class Es384 extends Ecdsa {
+
+ public final static String ALGORITHM_NAME = "SHA384withECDSA";
+
+ @Override
+ public void checkDigestLength(byte[] digest) {
+ if (digest.length != 48) {
+ throw new IllegalArgumentException("Invalid digest length.");
+ }
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es512.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es512.java
new file mode 100644
index 000000000000..32fdd3769951
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es512.java
@@ -0,0 +1,13 @@
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+public class Es512 extends Ecdsa {
+
+ public final static String ALGORITHM_NAME = "SHA512withECDSA";
+
+ @Override
+ public void checkDigestLength(byte[] digest) {
+ if (digest.length != 64) {
+ throw new IllegalArgumentException("Invalid digest length.");
+ }
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Rs256.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Rs256.java
new file mode 100644
index 000000000000..e443398bf040
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Rs256.java
@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+import com.microsoft.azure.keyvault.cryptography.ByteExtensions;
+import com.microsoft.azure.keyvault.cryptography.ISignatureTransform;
+
+/**
+ *
+ */
+public class Rs256 extends RsaSignature {
+
+ static final String RsaNone = "RSA/ECB/PKCS1Padding";
+
+ class Rs256SignatureTransform implements ISignatureTransform {
+
+ private final KeyPair _keyPair;
+ private final int _emLen;
+
+ Rs256SignatureTransform(KeyPair keyPair) {
+ _keyPair = keyPair;
+
+ BigInteger modulus = ((RSAPublicKey)_keyPair.getPublic()).getModulus();
+
+ _emLen = getOctetLength( modulus.bitLength() );
+
+ }
+
+ @Override
+ public byte[] sign(byte[] digest) throws NoSuchAlgorithmException {
+ // Signing isn't just a case of encrypting the digest, there is much more to do.
+ // For details of the algorithm, see https://tools.ietf.org/html/rfc3447#section-8.2
+
+ if ( _keyPair.getPrivate() == null ) {
+ // TODO
+ }
+
+ // Construct the encoded message
+ byte[] EM = EMSA_PKCS1_V1_5_ENCODE_HASH(digest, _emLen, "SHA-256");
+
+ // Convert to integer message
+ BigInteger s = OS2IP(EM);
+
+ // RSASP1(s)
+ s = RSASP1((RSAPrivateKey)_keyPair.getPrivate(), s);
+
+ // Convert to octet sequence
+ return I2OSP(s, _emLen );
+ }
+
+ @Override
+ public boolean verify(byte[] digest, byte[] signature) throws NoSuchAlgorithmException {
+
+ if ( signature.length != _emLen ) {
+ throw new IllegalArgumentException( "invalid signature length");
+ }
+
+ // Convert to integer signature
+ BigInteger s = OS2IP(signature);
+
+ // Convert integer message
+ BigInteger m = RSAVP1((RSAPublicKey)_keyPair.getPublic(), s);
+
+ byte[] EM = I2OSP(m, _emLen );
+ byte[] EM2 = EMSA_PKCS1_V1_5_ENCODE_HASH(digest, _emLen, "SHA-256");
+
+ // Use constant time compare
+ return ByteExtensions.sequenceEqualConstantTime(EM, EM2);
+ }
+
+ }
+
+ public final static String ALGORITHM_NAME = "RS256";
+
+ public Rs256() {
+ super(ALGORITHM_NAME);
+ }
+
+ @Override
+ public ISignatureTransform createSignatureTransform(KeyPair keyPair) {
+
+ return new Rs256SignatureTransform(keyPair);
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Rsa15.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Rsa15.java
new file mode 100644
index 000000000000..18ea8d28514f
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Rsa15.java
@@ -0,0 +1,101 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+
+import com.microsoft.azure.keyvault.cryptography.ICryptoTransform;
+
+public final class Rsa15 extends RsaEncryption {
+
+ class Rsa15Decryptor implements ICryptoTransform {
+
+ private final Cipher _cipher;
+
+ Rsa15Decryptor(KeyPair keyPair, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
+
+ // Create a cipher object using the provider, if specified
+ if (provider == null) {
+ _cipher = Cipher.getInstance(RSA15);
+ } else {
+ _cipher = Cipher.getInstance(RSA15, provider);
+ }
+
+ // encrypt the plain text using the public key
+ _cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
+ }
+
+ @Override
+ public byte[] doFinal(byte[] plaintext) throws IllegalBlockSizeException, BadPaddingException {
+
+ return _cipher.doFinal(plaintext);
+ }
+
+ }
+
+ class Rsa15Encryptor implements ICryptoTransform {
+
+ private final Cipher _cipher;
+
+ Rsa15Encryptor(KeyPair keyPair, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
+
+ // Create a cipher object using the provider, if specified
+ if (provider == null) {
+ _cipher = Cipher.getInstance(RSA15);
+ } else {
+ _cipher = Cipher.getInstance(RSA15, provider);
+ }
+
+ // encrypt the plain text using the public key
+ _cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
+ }
+
+ @Override
+ public byte[] doFinal(byte[] plaintext) throws IllegalBlockSizeException, BadPaddingException {
+
+ return _cipher.doFinal(plaintext);
+ }
+
+ }
+
+ final static String RSA15 = "RSA/ECB/PKCS1Padding";
+
+ public final static String ALGORITHM_NAME = "RSA1_5";
+
+ public Rsa15() {
+ super(ALGORITHM_NAME);
+ }
+
+ @Override
+ public ICryptoTransform CreateEncryptor(KeyPair keyPair) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
+ return CreateEncryptor(keyPair, null);
+ }
+
+ @Override
+ public ICryptoTransform CreateEncryptor(KeyPair keyPair, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
+ return new Rsa15Encryptor(keyPair, provider);
+ }
+
+ @Override
+ public ICryptoTransform CreateDecryptor(KeyPair keyPair) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
+ return CreateDecryptor(keyPair, null);
+ }
+
+ @Override
+ public ICryptoTransform CreateDecryptor(KeyPair keyPair, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
+ return new Rsa15Decryptor(keyPair, provider);
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaEncryption.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaEncryption.java
new file mode 100644
index 000000000000..83343057aa55
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaEncryption.java
@@ -0,0 +1,17 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+import com.microsoft.azure.keyvault.cryptography.AsymmetricEncryptionAlgorithm;
+
+public abstract class RsaEncryption extends AsymmetricEncryptionAlgorithm {
+
+ protected RsaEncryption(String name) {
+ super(name);
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaOaep.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaOaep.java
new file mode 100644
index 000000000000..38c3e4131231
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaOaep.java
@@ -0,0 +1,103 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+
+import com.microsoft.azure.keyvault.cryptography.ICryptoTransform;
+
+public final class RsaOaep extends RsaEncryption {
+
+ class RsaOaepDecryptor implements ICryptoTransform {
+
+ private final Cipher _cipher;
+
+ RsaOaepDecryptor(KeyPair keyPair, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
+
+ // Create a cipher object using the provider, if specified
+ if (provider == null) {
+ _cipher = Cipher.getInstance(RSAOAEP);
+ } else {
+ _cipher = Cipher.getInstance(RSAOAEP, provider);
+ }
+
+ // encrypt the plain text using the public key
+ _cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
+ }
+
+ @Override
+ public byte[] doFinal(byte[] plaintext) throws IllegalBlockSizeException, BadPaddingException {
+
+ return _cipher.doFinal(plaintext);
+ }
+
+ }
+
+ class RsaOaepEncryptor implements ICryptoTransform {
+
+ private final Cipher _cipher;
+
+ RsaOaepEncryptor(KeyPair keyPair, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
+
+ // Create a cipher object using the provider, if specified
+ if (provider == null) {
+ _cipher = Cipher.getInstance(RSAOAEP);
+ } else {
+ _cipher = Cipher.getInstance(RSAOAEP, provider);
+ }
+
+ // encrypt the plain text using the public key
+ _cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
+ }
+
+ @Override
+ public byte[] doFinal(byte[] plaintext) throws IllegalBlockSizeException, BadPaddingException {
+
+ return _cipher.doFinal(plaintext);
+ }
+
+ }
+
+ final static String RSAOAEP = "RSA/ECB/OAEPWithSHA1AndMGF1Padding";
+
+ public final static String ALGORITHM_NAME = "RSA-OAEP";
+
+ public RsaOaep() {
+ super(ALGORITHM_NAME);
+ }
+
+ @Override
+ public ICryptoTransform CreateEncryptor(KeyPair keyPair) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
+ return CreateEncryptor(keyPair, null);
+ }
+
+ @Override
+ public ICryptoTransform CreateEncryptor(KeyPair keyPair, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
+
+ return new RsaOaepEncryptor(keyPair, provider);
+ }
+
+ @Override
+ public ICryptoTransform CreateDecryptor(KeyPair keyPair) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
+ return CreateDecryptor(keyPair, null);
+ }
+
+ @Override
+ public ICryptoTransform CreateDecryptor(KeyPair keyPair, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
+
+ return new RsaOaepDecryptor(keyPair, provider);
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaSignature.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaSignature.java
new file mode 100644
index 000000000000..2e5a47548be9
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaSignature.java
@@ -0,0 +1,219 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Arrays;
+
+import com.microsoft.azure.keyvault.cryptography.AsymmetricSignatureAlgorithm;
+import com.microsoft.azure.keyvault.cryptography.ISignatureTransform;
+import com.microsoft.azure.keyvault.cryptography.Strings;
+
+public abstract class RsaSignature extends AsymmetricSignatureAlgorithm {
+
+ private static final BigInteger twoFiveSix = new BigInteger("256");
+ private static final byte[] sha256Prefix = new byte[] { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, (byte) 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 };
+
+ protected RsaSignature(String name) {
+ super(name);
+ }
+
+ protected int getOctetLength(int bits) {
+ return ( bits % 8 > 0 ) ? bits >> 3 + 1 : bits >> 3;
+ }
+
+ /*
+ * See https://tools.ietf.org/html/rfc3447#section-4.2
+ */
+ protected BigInteger OS2IP(byte[] x) {
+
+ if ( x == null || x.length == 0 ) {
+ throw new IllegalArgumentException("x");
+ }
+
+ return new BigInteger(1,x);
+ }
+
+ /*
+ * See https://tools.ietf.org/html/rfc3447#section-4.1
+ */
+ protected byte[] I2OSP(BigInteger x, int xLen) {
+
+ if ( x == null ) {
+ throw new IllegalArgumentException("x");
+ }
+
+ if ( xLen <= 0 ) {
+ throw new IllegalArgumentException("xLen");
+ }
+
+ if ( x.compareTo( twoFiveSix.pow(xLen) ) == 1 ) {
+ throw new IllegalArgumentException("integer too large");
+ }
+
+ // Even if x is less than 256^xLen, sometiems x.toByteArray() returns 257 bytes with leading zero
+ byte[] bigEndianBytes = x.toByteArray();
+ byte[] bytes;
+ if (bigEndianBytes.length == 257 && bigEndianBytes[0] == 0) {
+ bytes = Arrays.copyOfRange(bigEndianBytes, 1, 257);
+ } else {
+ bytes = bigEndianBytes;
+ }
+
+ if ( bytes.length > xLen ) {
+ throw new IllegalArgumentException("integer too large");
+ }
+
+ byte[] result = new byte[xLen];
+
+ System.arraycopy(bytes, 0, result, xLen - bytes.length, bytes.length);
+
+ return result;
+ }
+
+ /*
+ * See https://tools.ietf.org/html/rfc3447#section-5.2.1
+ */
+ protected BigInteger RSASP1(RSAPrivateKey K, BigInteger m) {
+
+ if ( K == null ) {
+ throw new IllegalArgumentException("K");
+ }
+
+ if ( m == null ) {
+ throw new IllegalArgumentException("m");
+ }
+
+ BigInteger n = K.getModulus();
+ BigInteger d = K.getPrivateExponent();
+
+ if ( m.compareTo(BigInteger.ONE) == -1 || m.compareTo(n) != -1 ) {
+ throw new IllegalArgumentException("message representative out of range");
+ }
+
+ return m.modPow(d, n);
+ }
+
+ /*
+ * See https://tools.ietf.org/html/rfc3447#section-5.2.2
+ */
+ protected BigInteger RSAVP1(RSAPublicKey K, BigInteger s) {
+
+ if ( K == null ) {
+ throw new IllegalArgumentException("K");
+ }
+
+ if ( s == null ) {
+ throw new IllegalArgumentException("s");
+ }
+ BigInteger n = K.getModulus();
+ BigInteger e = K.getPublicExponent();
+
+ if ( s.compareTo(BigInteger.ONE) == -1 || s.compareTo(n) != -1 ) {
+ throw new IllegalArgumentException("message representative out of range");
+ }
+
+ return s.modPow(e, n);
+ }
+
+ /*
+ * See https://tools.ietf.org/html/rfc3447#section-9.2
+ */
+ protected byte[] EMSA_PKCS1_V1_5_ENCODE(byte[] m, int emLen, String algorithm) throws NoSuchAlgorithmException {
+
+ // Check m
+ if ( m == null || m.length == 0 ) {
+ throw new IllegalArgumentException("m");
+ }
+
+ MessageDigest messageDigest = null;
+
+ // Check algorithm
+ if ( Strings.isNullOrWhiteSpace(algorithm) ) {
+ throw new IllegalArgumentException("algorithm");
+ }
+
+ // Only supported algorithms
+ if ( algorithm.equals("SHA-256") ) {
+
+ // Initialize digest
+ messageDigest = MessageDigest.getInstance("SHA-256");
+ } else {
+ throw new IllegalArgumentException("algorithm");
+ }
+
+ // Hash the message
+ byte[] digest = messageDigest.digest(m);
+
+ // Construct T, the DER encoded DigestInfo structure
+ return EMSA_PKCS1_V1_5_ENCODE_HASH(digest, emLen, algorithm);
+ }
+
+ /*
+ * See https://tools.ietf.org/html/rfc3447#section-9.2
+ */
+ protected byte[] EMSA_PKCS1_V1_5_ENCODE_HASH(byte[] h, int emLen, String algorithm) throws NoSuchAlgorithmException {
+
+ // Check m
+ if ( h == null || h.length == 0 ) {
+ throw new IllegalArgumentException("m");
+ }
+
+ byte[] algorithmPrefix = null;
+
+ // Check algorithm
+ if ( Strings.isNullOrWhiteSpace(algorithm) ) {
+ throw new IllegalArgumentException("algorithm");
+ }
+
+ // Only supported algorithms
+ if ( algorithm.equals("SHA-256") ) {
+
+ // Initialize prefix and digest
+ algorithmPrefix = sha256Prefix;
+
+ if ( h.length != 32 ) {
+ throw new IllegalArgumentException("h is incorrect length for SHA-256");
+ }
+ } else {
+ throw new IllegalArgumentException("algorithm");
+ }
+
+
+ // Construct T, the DER encoded DigestInfo structure
+ byte[] T = new byte[algorithmPrefix.length + h.length];
+
+ System.arraycopy(algorithmPrefix, 0, T, 0, algorithmPrefix.length);
+ System.arraycopy(h, 0, T, algorithmPrefix.length, h.length);
+
+ if ( emLen < T.length + 11 ) {
+ throw new IllegalArgumentException("intended encoded message length too short");
+ }
+
+ // Construct PS
+ byte[] PS = new byte[emLen - T.length - 3];
+
+ for ( int i = 0; i < PS.length; i++ ) PS[i] = (byte) 0xff;
+
+ // Construct EM
+ byte[] EM = new byte[PS.length + T.length + 3];
+
+ EM[0] = 0x00; EM[1] = 0x01; EM[PS.length + 2] = 0x00;
+
+ System.arraycopy(PS, 0, EM, 2, PS.length);
+ System.arraycopy(T, 0, EM, PS.length + 3, T.length);
+
+ return EM;
+ }
+
+ public abstract ISignatureTransform createSignatureTransform(KeyPair keyPair);
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/package-info.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/package-info.java
new file mode 100644
index 000000000000..f3101db3f04c
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/package-info.java
@@ -0,0 +1,9 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for
+// license information.
+//
+
+/**
+ * This package contains cryptographic functions and implementations.
+ */
+package com.microsoft.azure.keyvault.cryptography.algorithms;
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/package-info.java b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/package-info.java
new file mode 100644
index 000000000000..5492e8c67761
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/package-info.java
@@ -0,0 +1,10 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for
+// license information.
+//
+
+/**
+ * This package contains cryptographic functions and implementations
+ * of RSA and symmetric keys that conform with the IKey interface.
+ */
+package com.microsoft.azure.keyvault.cryptography;
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcBCProviderTest.java b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcBCProviderTest.java
new file mode 100644
index 000000000000..043b2b54808b
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcBCProviderTest.java
@@ -0,0 +1,18 @@
+package com.microsoft.azure.keyvault.cryptography.test;
+
+import java.security.Provider;
+
+import org.junit.Before;
+
+public class AesCbcBCProviderTest extends AesCbcTest {
+
+ @Before
+ public void setUp() throws Exception {
+ try {
+ super.setProvider((Provider) Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider").newInstance());
+ } catch (Exception ex) {
+ throw new RuntimeException(ex.getMessage());
+ }
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcHmacShaBCProviderTest.java b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcHmacShaBCProviderTest.java
new file mode 100644
index 000000000000..5c7e07a27347
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcHmacShaBCProviderTest.java
@@ -0,0 +1,17 @@
+package com.microsoft.azure.keyvault.cryptography.test;
+
+import java.security.Provider;
+
+import org.junit.Before;
+
+public class AesCbcHmacShaBCProviderTest extends AesCbcHmacShaTest {
+
+ @Before
+ public void setUp() throws Exception {
+ try {
+ super.setProvider((Provider) Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider").newInstance());
+ } catch (Exception ex) {
+ throw new RuntimeException(ex.getMessage());
+ }
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcHmacShaTest.java b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcHmacShaTest.java
new file mode 100644
index 000000000000..ef588b4830e9
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcHmacShaTest.java
@@ -0,0 +1,267 @@
+package com.microsoft.azure.keyvault.cryptography.test;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.fail;
+
+import java.security.Provider;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.microsoft.azure.keyvault.cryptography.IAuthenticatedCryptoTransform;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Aes128CbcHmacSha256;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Aes192CbcHmacSha384;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Aes256CbcHmacSha512;
+
+public class AesCbcHmacShaTest {
+
+ private Provider _provider = null;
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ setProvider(null);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ protected void setProvider(Provider provider) {
+ _provider = null;
+ }
+
+ @Test
+ public void testAes128CbcHmacSha256() {
+ // Arrange: These values are taken from Appendix B of the JWE specification at
+ // https://tools.ietf.org/html/draft-ietf-jose-json-web-encryption-40#appendix-B
+ byte[] K = { (byte)0x00, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08, (byte)0x09, (byte)0x0a, (byte)0x0b, (byte)0x0c, (byte)0x0d, (byte)0x0e, (byte)0x0f,
+ (byte)0x10, (byte)0x11, (byte)0x12, (byte)0x13, (byte)0x14, (byte)0x15, (byte)0x16, (byte)0x17, (byte)0x18, (byte)0x19, (byte)0x1a, (byte)0x1b, (byte)0x1c, (byte)0x1d, (byte)0x1e, (byte)0x1f };
+ byte[] P = { (byte)0x41, (byte)0x20, (byte)0x63, (byte)0x69, (byte)0x70, (byte)0x68, (byte)0x65, (byte)0x72, (byte)0x20, (byte)0x73, (byte)0x79, (byte)0x73, (byte)0x74, (byte)0x65, (byte)0x6d, (byte)0x20,
+ (byte)0x6d, (byte)0x75, (byte)0x73, (byte)0x74, (byte)0x20, (byte)0x6e, (byte)0x6f, (byte)0x74, (byte)0x20, (byte)0x62, (byte)0x65, (byte)0x20, (byte)0x72, (byte)0x65, (byte)0x71, (byte)0x75,
+ (byte)0x69, (byte)0x72, (byte)0x65, (byte)0x64, (byte)0x20, (byte)0x74, (byte)0x6f, (byte)0x20, (byte)0x62, (byte)0x65, (byte)0x20, (byte)0x73, (byte)0x65, (byte)0x63, (byte)0x72, (byte)0x65,
+ (byte)0x74, (byte)0x2c, (byte)0x20, (byte)0x61, (byte)0x6e, (byte)0x64, (byte)0x20, (byte)0x69, (byte)0x74, (byte)0x20, (byte)0x6d, (byte)0x75, (byte)0x73, (byte)0x74, (byte)0x20, (byte)0x62,
+ (byte)0x65, (byte)0x20, (byte)0x61, (byte)0x62, (byte)0x6c, (byte)0x65, (byte)0x20, (byte)0x74, (byte)0x6f, (byte)0x20, (byte)0x66, (byte)0x61, (byte)0x6c, (byte)0x6c, (byte)0x20, (byte)0x69,
+ (byte)0x6e, (byte)0x74, (byte)0x6f, (byte)0x20, (byte)0x74, (byte)0x68, (byte)0x65, (byte)0x20, (byte)0x68, (byte)0x61, (byte)0x6e, (byte)0x64, (byte)0x73, (byte)0x20, (byte)0x6f, (byte)0x66,
+ (byte)0x20, (byte)0x74, (byte)0x68, (byte)0x65, (byte)0x20, (byte)0x65, (byte)0x6e, (byte)0x65, (byte)0x6d, (byte)0x79, (byte)0x20, (byte)0x77, (byte)0x69, (byte)0x74, (byte)0x68, (byte)0x6f,
+ (byte)0x75, (byte)0x74, (byte)0x20, (byte)0x69, (byte)0x6e, (byte)0x63, (byte)0x6f, (byte)0x6e, (byte)0x76, (byte)0x65, (byte)0x6e, (byte)0x69, (byte)0x65, (byte)0x6e, (byte)0x63, (byte)0x65 };
+ byte[] IV = { (byte)0x1a, (byte)0xf3, (byte)0x8c, (byte)0x2d, (byte)0xc2, (byte)0xb9, (byte)0x6f, (byte)0xfd, (byte)0xd8, (byte)0x66, (byte)0x94, (byte)0x09, (byte)0x23, (byte)0x41, (byte)0xbc, (byte)0x04 };
+ byte[] A = { (byte)0x54, (byte)0x68, (byte)0x65, (byte)0x20, (byte)0x73, (byte)0x65, (byte)0x63, (byte)0x6f, (byte)0x6e, (byte)0x64, (byte)0x20, (byte)0x70, (byte)0x72, (byte)0x69, (byte)0x6e, (byte)0x63,
+ (byte)0x69, (byte)0x70, (byte)0x6c, (byte)0x65, (byte)0x20, (byte)0x6f, (byte)0x66, (byte)0x20, (byte)0x41, (byte)0x75, (byte)0x67, (byte)0x75, (byte)0x73, (byte)0x74, (byte)0x65, (byte)0x20,
+ (byte)0x4b, (byte)0x65, (byte)0x72, (byte)0x63, (byte)0x6b, (byte)0x68, (byte)0x6f, (byte)0x66, (byte)0x66, (byte)0x73 };
+ byte[] E = { (byte)0xc8, (byte)0x0e, (byte)0xdf, (byte)0xa3, (byte)0x2d, (byte)0xdf, (byte)0x39, (byte)0xd5, (byte)0xef, (byte)0x00, (byte)0xc0, (byte)0xb4, (byte)0x68, (byte)0x83, (byte)0x42, (byte)0x79,
+ (byte)0xa2, (byte)0xe4, (byte)0x6a, (byte)0x1b, (byte)0x80, (byte)0x49, (byte)0xf7, (byte)0x92, (byte)0xf7, (byte)0x6b, (byte)0xfe, (byte)0x54, (byte)0xb9, (byte)0x03, (byte)0xa9, (byte)0xc9,
+ (byte)0xa9, (byte)0x4a, (byte)0xc9, (byte)0xb4, (byte)0x7a, (byte)0xd2, (byte)0x65, (byte)0x5c, (byte)0x5f, (byte)0x10, (byte)0xf9, (byte)0xae, (byte)0xf7, (byte)0x14, (byte)0x27, (byte)0xe2,
+ (byte)0xfc, (byte)0x6f, (byte)0x9b, (byte)0x3f, (byte)0x39, (byte)0x9a, (byte)0x22, (byte)0x14, (byte)0x89, (byte)0xf1, (byte)0x63, (byte)0x62, (byte)0xc7, (byte)0x03, (byte)0x23, (byte)0x36,
+ (byte)0x09, (byte)0xd4, (byte)0x5a, (byte)0xc6, (byte)0x98, (byte)0x64, (byte)0xe3, (byte)0x32, (byte)0x1c, (byte)0xf8, (byte)0x29, (byte)0x35, (byte)0xac, (byte)0x40, (byte)0x96, (byte)0xc8,
+ (byte)0x6e, (byte)0x13, (byte)0x33, (byte)0x14, (byte)0xc5, (byte)0x40, (byte)0x19, (byte)0xe8, (byte)0xca, (byte)0x79, (byte)0x80, (byte)0xdf, (byte)0xa4, (byte)0xb9, (byte)0xcf, (byte)0x1b,
+ (byte)0x38, (byte)0x4c, (byte)0x48, (byte)0x6f, (byte)0x3a, (byte)0x54, (byte)0xc5, (byte)0x10, (byte)0x78, (byte)0x15, (byte)0x8e, (byte)0xe5, (byte)0xd7, (byte)0x9d, (byte)0xe5, (byte)0x9f,
+ (byte)0xbd, (byte)0x34, (byte)0xd8, (byte)0x48, (byte)0xb3, (byte)0xd6, (byte)0x95, (byte)0x50, (byte)0xa6, (byte)0x76, (byte)0x46, (byte)0x34, (byte)0x44, (byte)0x27, (byte)0xad, (byte)0xe5,
+ (byte)0x4b, (byte)0x88, (byte)0x51, (byte)0xff, (byte)0xb5, (byte)0x98, (byte)0xf7, (byte)0xf8, (byte)0x00, (byte)0x74, (byte)0xb9, (byte)0x47, (byte)0x3c, (byte)0x82, (byte)0xe2, (byte)0xdb };
+ byte[] T = { (byte)0x65, (byte)0x2c, (byte)0x3f, (byte)0xa3, (byte)0x6b, (byte)0x0a, (byte)0x7c, (byte)0x5b, (byte)0x32, (byte)0x19, (byte)0xfa, (byte)0xb3, (byte)0xa3, (byte)0x0b, (byte)0xc1, (byte)0xc4 };
+
+ Aes128CbcHmacSha256 algo = new Aes128CbcHmacSha256();
+
+ IAuthenticatedCryptoTransform transform = null;
+
+ byte[] encrypted = null;
+ byte[] tag = null;
+
+ try {
+ transform = (IAuthenticatedCryptoTransform) algo.CreateEncryptor(K, IV, A, _provider);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ try {
+ encrypted = transform.doFinal(P);
+ tag = transform.getTag();
+
+ assertArrayEquals(E, encrypted);
+ assertArrayEquals(T, tag);
+
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ try {
+ transform = (IAuthenticatedCryptoTransform)algo.CreateDecryptor(K, IV, A, T, _provider);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = transform.doFinal(encrypted);
+ tag = transform.getTag();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(P, decrypted);
+ assertArrayEquals(T, tag);
+ }
+
+
+ @Test
+ public void testAes192CbcHmacSha384() {
+ // Arrange: These values are taken from Appendix B of the JWE specification at
+ // https://tools.ietf.org/html/draft-ietf-jose-json-web-encryption-40#appendix-B
+ byte[] K = { (byte)0x00, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08, (byte)0x09, (byte)0x0a, (byte)0x0b, (byte)0x0c, (byte)0x0d, (byte)0x0e, (byte)0x0f,
+ (byte)0x10, (byte)0x11, (byte)0x12, (byte)0x13, (byte)0x14, (byte)0x15, (byte)0x16, (byte)0x17, (byte)0x18, (byte)0x19, (byte)0x1a, (byte)0x1b, (byte)0x1c, (byte)0x1d, (byte)0x1e, (byte)0x1f,
+ (byte)0x20, (byte)0x21, (byte)0x22, (byte)0x23, (byte)0x24, (byte)0x25, (byte)0x26, (byte)0x27, (byte)0x28, (byte)0x29, (byte)0x2a, (byte)0x2b, (byte)0x2c, (byte)0x2d, (byte)0x2e, (byte)0x2f };
+ byte[] P = { (byte)0x41, (byte)0x20, (byte)0x63, (byte)0x69, (byte)0x70, (byte)0x68, (byte)0x65, (byte)0x72, (byte)0x20, (byte)0x73, (byte)0x79, (byte)0x73, (byte)0x74, (byte)0x65, (byte)0x6d, (byte)0x20,
+ (byte)0x6d, (byte)0x75, (byte)0x73, (byte)0x74, (byte)0x20, (byte)0x6e, (byte)0x6f, (byte)0x74, (byte)0x20, (byte)0x62, (byte)0x65, (byte)0x20, (byte)0x72, (byte)0x65, (byte)0x71, (byte)0x75,
+ (byte)0x69, (byte)0x72, (byte)0x65, (byte)0x64, (byte)0x20, (byte)0x74, (byte)0x6f, (byte)0x20, (byte)0x62, (byte)0x65, (byte)0x20, (byte)0x73, (byte)0x65, (byte)0x63, (byte)0x72, (byte)0x65,
+ (byte)0x74, (byte)0x2c, (byte)0x20, (byte)0x61, (byte)0x6e, (byte)0x64, (byte)0x20, (byte)0x69, (byte)0x74, (byte)0x20, (byte)0x6d, (byte)0x75, (byte)0x73, (byte)0x74, (byte)0x20, (byte)0x62,
+ (byte)0x65, (byte)0x20, (byte)0x61, (byte)0x62, (byte)0x6c, (byte)0x65, (byte)0x20, (byte)0x74, (byte)0x6f, (byte)0x20, (byte)0x66, (byte)0x61, (byte)0x6c, (byte)0x6c, (byte)0x20, (byte)0x69,
+ (byte)0x6e, (byte)0x74, (byte)0x6f, (byte)0x20, (byte)0x74, (byte)0x68, (byte)0x65, (byte)0x20, (byte)0x68, (byte)0x61, (byte)0x6e, (byte)0x64, (byte)0x73, (byte)0x20, (byte)0x6f, (byte)0x66,
+ (byte)0x20, (byte)0x74, (byte)0x68, (byte)0x65, (byte)0x20, (byte)0x65, (byte)0x6e, (byte)0x65, (byte)0x6d, (byte)0x79, (byte)0x20, (byte)0x77, (byte)0x69, (byte)0x74, (byte)0x68, (byte)0x6f,
+ (byte)0x75, (byte)0x74, (byte)0x20, (byte)0x69, (byte)0x6e, (byte)0x63, (byte)0x6f, (byte)0x6e, (byte)0x76, (byte)0x65, (byte)0x6e, (byte)0x69, (byte)0x65, (byte)0x6e, (byte)0x63, (byte)0x65 };
+ byte[] IV = { (byte)0x1a, (byte)0xf3, (byte)0x8c, (byte)0x2d, (byte)0xc2, (byte)0xb9, (byte)0x6f, (byte)0xfd, (byte)0xd8, (byte)0x66, (byte)0x94, (byte)0x09, (byte)0x23, (byte)0x41, (byte)0xbc, (byte)0x04 };
+ byte[] A = { (byte)0x54, (byte)0x68, (byte)0x65, (byte)0x20, (byte)0x73, (byte)0x65, (byte)0x63, (byte)0x6f, (byte)0x6e, (byte)0x64, (byte)0x20, (byte)0x70, (byte)0x72, (byte)0x69, (byte)0x6e, (byte)0x63,
+ (byte)0x69, (byte)0x70, (byte)0x6c, (byte)0x65, (byte)0x20, (byte)0x6f, (byte)0x66, (byte)0x20, (byte)0x41, (byte)0x75, (byte)0x67, (byte)0x75, (byte)0x73, (byte)0x74, (byte)0x65, (byte)0x20,
+ (byte)0x4b, (byte)0x65, (byte)0x72, (byte)0x63, (byte)0x6b, (byte)0x68, (byte)0x6f, (byte)0x66, (byte)0x66, (byte)0x73 };
+ byte[] E = { (byte)0xea, (byte)0x65, (byte)0xda, (byte)0x6b, (byte)0x59, (byte)0xe6, (byte)0x1e, (byte)0xdb, (byte)0x41, (byte)0x9b, (byte)0xe6, (byte)0x2d, (byte)0x19, (byte)0x71, (byte)0x2a, (byte)0xe5,
+ (byte)0xd3, (byte)0x03, (byte)0xee, (byte)0xb5, (byte)0x00, (byte)0x52, (byte)0xd0, (byte)0xdf, (byte)0xd6, (byte)0x69, (byte)0x7f, (byte)0x77, (byte)0x22, (byte)0x4c, (byte)0x8e, (byte)0xdb,
+ (byte)0x00, (byte)0x0d, (byte)0x27, (byte)0x9b, (byte)0xdc, (byte)0x14, (byte)0xc1, (byte)0x07, (byte)0x26, (byte)0x54, (byte)0xbd, (byte)0x30, (byte)0x94, (byte)0x42, (byte)0x30, (byte)0xc6,
+ (byte)0x57, (byte)0xbe, (byte)0xd4, (byte)0xca, (byte)0x0c, (byte)0x9f, (byte)0x4a, (byte)0x84, (byte)0x66, (byte)0xf2, (byte)0x2b, (byte)0x22, (byte)0x6d, (byte)0x17, (byte)0x46, (byte)0x21,
+ (byte)0x4b, (byte)0xf8, (byte)0xcf, (byte)0xc2, (byte)0x40, (byte)0x0a, (byte)0xdd, (byte)0x9f, (byte)0x51, (byte)0x26, (byte)0xe4, (byte)0x79, (byte)0x66, (byte)0x3f, (byte)0xc9, (byte)0x0b,
+ (byte)0x3b, (byte)0xed, (byte)0x78, (byte)0x7a, (byte)0x2f, (byte)0x0f, (byte)0xfc, (byte)0xbf, (byte)0x39, (byte)0x04, (byte)0xbe, (byte)0x2a, (byte)0x64, (byte)0x1d, (byte)0x5c, (byte)0x21,
+ (byte)0x05, (byte)0xbf, (byte)0xe5, (byte)0x91, (byte)0xba, (byte)0xe2, (byte)0x3b, (byte)0x1d, (byte)0x74, (byte)0x49, (byte)0xe5, (byte)0x32, (byte)0xee, (byte)0xf6, (byte)0x0a, (byte)0x9a,
+ (byte)0xc8, (byte)0xbb, (byte)0x6c, (byte)0x6b, (byte)0x01, (byte)0xd3, (byte)0x5d, (byte)0x49, (byte)0x78, (byte)0x7b, (byte)0xcd, (byte)0x57, (byte)0xef, (byte)0x48, (byte)0x49, (byte)0x27,
+ (byte)0xf2, (byte)0x80, (byte)0xad, (byte)0xc9, (byte)0x1a, (byte)0xc0, (byte)0xc4, (byte)0xe7, (byte)0x9c, (byte)0x7b, (byte)0x11, (byte)0xef, (byte)0xc6, (byte)0x00, (byte)0x54, (byte)0xe3 };
+ byte[] T = { (byte)0x84, (byte)0x90, (byte)0xac, (byte)0x0e, (byte)0x58, (byte)0x94, (byte)0x9b, (byte)0xfe, (byte)0x51, (byte)0x87, (byte)0x5d, (byte)0x73, (byte)0x3f, (byte)0x93, (byte)0xac, (byte)0x20,
+ (byte)0x75, (byte)0x16, (byte)0x80, (byte)0x39, (byte)0xcc, (byte)0xc7, (byte)0x33, (byte)0xd7 };
+
+ Aes192CbcHmacSha384 algo = new Aes192CbcHmacSha384();
+
+ IAuthenticatedCryptoTransform transform = null;
+
+ byte[] encrypted = null;
+ byte[] tag = null;
+
+ try {
+ transform = (IAuthenticatedCryptoTransform) algo.CreateEncryptor(K, IV, A, _provider);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ try {
+ encrypted = transform.doFinal(P);
+ tag = transform.getTag();
+
+ assertArrayEquals(E, encrypted);
+ assertArrayEquals(T, tag);
+
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ try {
+ transform = (IAuthenticatedCryptoTransform)algo.CreateDecryptor(K, IV, A, T, _provider);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = transform.doFinal(encrypted);
+ tag = transform.getTag();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(P, decrypted);
+ assertArrayEquals(T, tag);
+ }
+ @Test
+ public void testAes256CbcHmacSha512() {
+ // Arrange: These values are taken from Appendix B of the JWE specification at
+ // https://tools.ietf.org/html/draft-ietf-jose-json-web-encryption-40#appendix-B
+ byte[] K = { (byte)0x00, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08, (byte)0x09, (byte)0x0a, (byte)0x0b, (byte)0x0c, (byte)0x0d, (byte)0x0e, (byte)0x0f,
+ (byte)0x10, (byte)0x11, (byte)0x12, (byte)0x13, (byte)0x14, (byte)0x15, (byte)0x16, (byte)0x17, (byte)0x18, (byte)0x19, (byte)0x1a, (byte)0x1b, (byte)0x1c, (byte)0x1d, (byte)0x1e, (byte)0x1f,
+ (byte)0x20, (byte)0x21, (byte)0x22, (byte)0x23, (byte)0x24, (byte)0x25, (byte)0x26, (byte)0x27, (byte)0x28, (byte)0x29, (byte)0x2a, (byte)0x2b, (byte)0x2c, (byte)0x2d, (byte)0x2e, (byte)0x2f,
+ (byte)0x30, (byte)0x31, (byte)0x32, (byte)0x33, (byte)0x34, (byte)0x35, (byte)0x36, (byte)0x37, (byte)0x38, (byte)0x39, (byte)0x3a, (byte)0x3b, (byte)0x3c, (byte)0x3d, (byte)0x3e, (byte)0x3f };
+ byte[] P = { (byte)0x41, (byte)0x20, (byte)0x63, (byte)0x69, (byte)0x70, (byte)0x68, (byte)0x65, (byte)0x72, (byte)0x20, (byte)0x73, (byte)0x79, (byte)0x73, (byte)0x74, (byte)0x65, (byte)0x6d, (byte)0x20,
+ (byte)0x6d, (byte)0x75, (byte)0x73, (byte)0x74, (byte)0x20, (byte)0x6e, (byte)0x6f, (byte)0x74, (byte)0x20, (byte)0x62, (byte)0x65, (byte)0x20, (byte)0x72, (byte)0x65, (byte)0x71, (byte)0x75,
+ (byte)0x69, (byte)0x72, (byte)0x65, (byte)0x64, (byte)0x20, (byte)0x74, (byte)0x6f, (byte)0x20, (byte)0x62, (byte)0x65, (byte)0x20, (byte)0x73, (byte)0x65, (byte)0x63, (byte)0x72, (byte)0x65,
+ (byte)0x74, (byte)0x2c, (byte)0x20, (byte)0x61, (byte)0x6e, (byte)0x64, (byte)0x20, (byte)0x69, (byte)0x74, (byte)0x20, (byte)0x6d, (byte)0x75, (byte)0x73, (byte)0x74, (byte)0x20, (byte)0x62,
+ (byte)0x65, (byte)0x20, (byte)0x61, (byte)0x62, (byte)0x6c, (byte)0x65, (byte)0x20, (byte)0x74, (byte)0x6f, (byte)0x20, (byte)0x66, (byte)0x61, (byte)0x6c, (byte)0x6c, (byte)0x20, (byte)0x69,
+ (byte)0x6e, (byte)0x74, (byte)0x6f, (byte)0x20, (byte)0x74, (byte)0x68, (byte)0x65, (byte)0x20, (byte)0x68, (byte)0x61, (byte)0x6e, (byte)0x64, (byte)0x73, (byte)0x20, (byte)0x6f, (byte)0x66,
+ (byte)0x20, (byte)0x74, (byte)0x68, (byte)0x65, (byte)0x20, (byte)0x65, (byte)0x6e, (byte)0x65, (byte)0x6d, (byte)0x79, (byte)0x20, (byte)0x77, (byte)0x69, (byte)0x74, (byte)0x68, (byte)0x6f,
+ (byte)0x75, (byte)0x74, (byte)0x20, (byte)0x69, (byte)0x6e, (byte)0x63, (byte)0x6f, (byte)0x6e, (byte)0x76, (byte)0x65, (byte)0x6e, (byte)0x69, (byte)0x65, (byte)0x6e, (byte)0x63, (byte)0x65 };
+ byte[] IV = { (byte)0x1a, (byte)0xf3, (byte)0x8c, (byte)0x2d, (byte)0xc2, (byte)0xb9, (byte)0x6f, (byte)0xfd, (byte)0xd8, (byte)0x66, (byte)0x94, (byte)0x09, (byte)0x23, (byte)0x41, (byte)0xbc, (byte)0x04 };
+ byte[] A = { (byte)0x54, (byte)0x68, (byte)0x65, (byte)0x20, (byte)0x73, (byte)0x65, (byte)0x63, (byte)0x6f, (byte)0x6e, (byte)0x64, (byte)0x20, (byte)0x70, (byte)0x72, (byte)0x69, (byte)0x6e, (byte)0x63,
+ (byte)0x69, (byte)0x70, (byte)0x6c, (byte)0x65, (byte)0x20, (byte)0x6f, (byte)0x66, (byte)0x20, (byte)0x41, (byte)0x75, (byte)0x67, (byte)0x75, (byte)0x73, (byte)0x74, (byte)0x65, (byte)0x20,
+ (byte)0x4b, (byte)0x65, (byte)0x72, (byte)0x63, (byte)0x6b, (byte)0x68, (byte)0x6f, (byte)0x66, (byte)0x66, (byte)0x73 };
+ byte[] E = { (byte)0x4a, (byte)0xff, (byte)0xaa, (byte)0xad, (byte)0xb7, (byte)0x8c, (byte)0x31, (byte)0xc5, (byte)0xda, (byte)0x4b, (byte)0x1b, (byte)0x59, (byte)0x0d, (byte)0x10, (byte)0xff, (byte)0xbd,
+ (byte)0x3d, (byte)0xd8, (byte)0xd5, (byte)0xd3, (byte)0x02, (byte)0x42, (byte)0x35, (byte)0x26, (byte)0x91, (byte)0x2d, (byte)0xa0, (byte)0x37, (byte)0xec, (byte)0xbc, (byte)0xc7, (byte)0xbd,
+ (byte)0x82, (byte)0x2c, (byte)0x30, (byte)0x1d, (byte)0xd6, (byte)0x7c, (byte)0x37, (byte)0x3b, (byte)0xcc, (byte)0xb5, (byte)0x84, (byte)0xad, (byte)0x3e, (byte)0x92, (byte)0x79, (byte)0xc2,
+ (byte)0xe6, (byte)0xd1, (byte)0x2a, (byte)0x13, (byte)0x74, (byte)0xb7, (byte)0x7f, (byte)0x07, (byte)0x75, (byte)0x53, (byte)0xdf, (byte)0x82, (byte)0x94, (byte)0x10, (byte)0x44, (byte)0x6b,
+ (byte)0x36, (byte)0xeb, (byte)0xd9, (byte)0x70, (byte)0x66, (byte)0x29, (byte)0x6a, (byte)0xe6, (byte)0x42, (byte)0x7e, (byte)0xa7, (byte)0x5c, (byte)0x2e, (byte)0x08, (byte)0x46, (byte)0xa1,
+ (byte)0x1a, (byte)0x09, (byte)0xcc, (byte)0xf5, (byte)0x37, (byte)0x0d, (byte)0xc8, (byte)0x0b, (byte)0xfe, (byte)0xcb, (byte)0xad, (byte)0x28, (byte)0xc7, (byte)0x3f, (byte)0x09, (byte)0xb3,
+ (byte)0xa3, (byte)0xb7, (byte)0x5e, (byte)0x66, (byte)0x2a, (byte)0x25, (byte)0x94, (byte)0x41, (byte)0x0a, (byte)0xe4, (byte)0x96, (byte)0xb2, (byte)0xe2, (byte)0xe6, (byte)0x60, (byte)0x9e,
+ (byte)0x31, (byte)0xe6, (byte)0xe0, (byte)0x2c, (byte)0xc8, (byte)0x37, (byte)0xf0, (byte)0x53, (byte)0xd2, (byte)0x1f, (byte)0x37, (byte)0xff, (byte)0x4f, (byte)0x51, (byte)0x95, (byte)0x0b,
+ (byte)0xbe, (byte)0x26, (byte)0x38, (byte)0xd0, (byte)0x9d, (byte)0xd7, (byte)0xa4, (byte)0x93, (byte)0x09, (byte)0x30, (byte)0x80, (byte)0x6d, (byte)0x07, (byte)0x03, (byte)0xb1, (byte)0xf6 };
+ byte[] T = { (byte)0x4d, (byte)0xd3, (byte)0xb4, (byte)0xc0, (byte)0x88, (byte)0xa7, (byte)0xf4, (byte)0x5c, (byte)0x21, (byte)0x68, (byte)0x39, (byte)0x64, (byte)0x5b, (byte)0x20, (byte)0x12, (byte)0xbf,
+ (byte)0x2e, (byte)0x62, (byte)0x69, (byte)0xa8, (byte)0xc5, (byte)0x6a, (byte)0x81, (byte)0x6d, (byte)0xbc, (byte)0x1b, (byte)0x26, (byte)0x77, (byte)0x61, (byte)0x95, (byte)0x5b, (byte)0xc5 };
+
+ Aes256CbcHmacSha512 algo = new Aes256CbcHmacSha512();
+
+ IAuthenticatedCryptoTransform transform = null;
+
+ byte[] encrypted = null;
+ byte[] tag = null;
+
+ try {
+ transform = (IAuthenticatedCryptoTransform) algo.CreateEncryptor(K, IV, A, _provider);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ try {
+ encrypted = transform.doFinal(P);
+ tag = transform.getTag();
+
+ assertArrayEquals(E, encrypted);
+ assertArrayEquals(T, tag);
+
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ try {
+ transform = (IAuthenticatedCryptoTransform)algo.CreateDecryptor(K, IV, A, T, _provider);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = transform.doFinal(encrypted);
+ tag = transform.getTag();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(P, decrypted);
+ assertArrayEquals(T, tag);
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcTest.java b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcTest.java
new file mode 100644
index 000000000000..7b41487ef988
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcTest.java
@@ -0,0 +1,230 @@
+package com.microsoft.azure.keyvault.cryptography.test;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.fail;
+
+import java.security.Provider;
+import java.util.Arrays;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.microsoft.azure.keyvault.cryptography.ICryptoTransform;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Aes128Cbc;
+
+public class AesCbcTest {
+
+ private Provider _provider = null;
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ setProvider(null);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ protected void setProvider(Provider provider) {
+ _provider = provider;
+ }
+
+ @Test
+ public void testAes128CbcOneBlock() {
+ // Note that AES128CBC as implemented in this library uses PKCS7 padding mode where the test
+ // vectors from RFC3602 do not use padding.
+ byte[] CEK = { 0x06, (byte)0xa9, 0x21, 0x40, 0x36, (byte)0xb8, (byte)0xa1, 0x5b, 0x51, 0x2e, 0x03, (byte)0xd5, 0x34, 0x12, 0x00, 0x06 };
+ byte[] PLAIN = "Single block msg".getBytes();
+ byte[] IV = { 0x3d, (byte)0xaf, (byte)0xba, 0x42, (byte)0x9d, (byte)0x9e, (byte)0xb4, 0x30, (byte)0xb4, 0x22, (byte)0xda, (byte)0x80, 0x2c, (byte)0x9f, (byte)0xac, 0x41 };
+ byte[] ED = { (byte)0xe3, 0x53, 0x77, (byte)0x9c, 0x10, 0x79, (byte)0xae, (byte)0xb8, 0x27, 0x08, (byte)0x94, 0x2d, (byte)0xbe, 0x77, 0x18, 0x1a };
+
+ Aes128Cbc algo = new Aes128Cbc();
+ byte[] encrypted = null;
+
+ ICryptoTransform encryptor = null;
+ try {
+ encryptor = algo.CreateEncryptor(CEK, IV, null, _provider);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ try {
+ encrypted = encryptor.doFinal(PLAIN);
+
+ // Assert: we only compare the first 16 bytes as this library uses PKCS7 padding
+ assertArrayEquals(Arrays.copyOfRange(encrypted, 0, 16), ED);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ICryptoTransform decryptor = null;
+ try {
+ decryptor = algo.CreateDecryptor(CEK, IV, null, null, _provider);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = decryptor.doFinal(encrypted);
+
+ // Assert: we only compare the first 16 bytes as this library uses PKCS7 padding
+ assertArrayEquals(Arrays.copyOfRange(decrypted, 0, 16), PLAIN);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testAes128CbcTwoBlock() {
+ // Note that AES128CBC as implemented in this library uses PKCS7 padding mode where the test
+ // vectors do not use padding.
+ byte[] CEK = { (byte)0xc2, (byte)0x86, 0x69, 0x6d, (byte)0x88, 0x7c, (byte)0x9a, (byte)0xa0, 0x61, 0x1b, (byte)0xbb, 0x3e, 0x20, 0x25, (byte)0xa4, 0x5a };
+ byte[] PLAIN = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f };
+ byte[] IV = { 0x56, 0x2e, 0x17, (byte)0x99, 0x6d, 0x09, 0x3d, 0x28, (byte)0xdd, (byte)0xb3, (byte)0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 };
+ byte[] ED = { (byte)0xd2, (byte)0x96, (byte)0xcd, (byte)0x94, (byte)0xc2, (byte)0xcc, (byte)0xcf, (byte)0x8a, 0x3a, (byte)0x86, 0x30, 0x28, (byte)0xb5, (byte)0xe1, (byte)0xdc, 0x0a, 0x75, (byte)0x86, 0x60, 0x2d, 0x25, 0x3c, (byte)0xff, (byte)0xf9, 0x1b, (byte)0x82, 0x66, (byte)0xbe, (byte)0xa6, (byte)0xd6, 0x1a, (byte)0xb1 };
+
+ Aes128Cbc algo = new Aes128Cbc();
+ byte[] encrypted = null;
+
+ ICryptoTransform encryptor = null;
+ try {
+ encryptor = algo.CreateEncryptor(CEK, IV, null, _provider);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ try {
+ encrypted = encryptor.doFinal(PLAIN);
+
+ // Assert: we only compare the first 32 bytes as this library uses PKCS7 padding
+ assertArrayEquals(Arrays.copyOfRange(encrypted, 0, 32), ED);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ICryptoTransform decryptor = null;
+ try {
+ decryptor = algo.CreateDecryptor(CEK, IV, null, null, _provider);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = decryptor.doFinal(encrypted);
+
+ // Assert: we only compare the first 32 bytes as this library uses PKCS7 padding
+ assertArrayEquals(Arrays.copyOfRange(decrypted, 0, 32), PLAIN);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testAes128CbcOneBlock_ExcessKeyMaterial() {
+ // Note that AES128CBC as implemented in this library uses PKCS7 padding mode where the test
+ // vectors from RFC3602 do not use padding.
+ byte[] CEK = { 0x06, (byte)0xa9, 0x21, 0x40, 0x36, (byte)0xb8, (byte)0xa1, 0x5b, 0x51, 0x2e, 0x03, (byte)0xd5, 0x34, 0x12, 0x00, 0x06, (byte)0xc2, (byte)0x86, 0x69, 0x6d, (byte)0x88, 0x7c, (byte)0x9a, (byte)0xa0, 0x61, 0x1b, (byte)0xbb, 0x3e, 0x20, 0x25, (byte)0xa4, 0x5a };
+ byte[] PLAIN = "Single block msg".getBytes();
+ byte[] IV = { 0x3d, (byte)0xaf, (byte)0xba, 0x42, (byte)0x9d, (byte)0x9e, (byte)0xb4, 0x30, (byte)0xb4, 0x22, (byte)0xda, (byte)0x80, 0x2c, (byte)0x9f, (byte)0xac, 0x41 };
+ byte[] ED = { (byte)0xe3, 0x53, 0x77, (byte)0x9c, 0x10, 0x79, (byte)0xae, (byte)0xb8, 0x27, 0x08, (byte)0x94, 0x2d, (byte)0xbe, 0x77, 0x18, 0x1a };
+
+ Aes128Cbc algo = new Aes128Cbc();
+ byte[] encrypted = null;
+
+ ICryptoTransform encryptor = null;
+ try {
+ encryptor = algo.CreateEncryptor(CEK, IV, null, _provider);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ try {
+ encrypted = encryptor.doFinal(PLAIN);
+
+ // Assert: we only compare the first 16 bytes as this library uses PKCS7 padding
+ assertArrayEquals(Arrays.copyOfRange(encrypted, 0, 16),ED);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ICryptoTransform decryptor = null;
+ try {
+ decryptor = algo.CreateDecryptor(CEK, IV, null, null, _provider);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = decryptor.doFinal(encrypted);
+
+ // Assert: we only compare the first 16 bytes as this library uses PKCS7 padding
+ assertArrayEquals(Arrays.copyOfRange(decrypted, 0, 16), PLAIN);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testAes128CbcTwoBlock_ExcessKeyMaterial() {
+ // Note that AES128CBC as implemented in this library uses PKCS7 padding mode where the test
+ // vectors do not use padding.
+ byte[] CEK = { (byte)0xc2, (byte)0x86, 0x69, 0x6d, (byte)0x88, 0x7c, (byte)0x9a, (byte)0xa0, 0x61, 0x1b, (byte)0xbb, 0x3e, 0x20, 0x25, (byte)0xa4, 0x5a, (byte)0xc2, (byte)0x86, 0x69, 0x6d, (byte)0x88, 0x7c, (byte)0x9a, (byte)0xa0, 0x61, 0x1b, (byte)0xbb, 0x3e, 0x20, 0x25, (byte)0xa4, 0x5a };
+ byte[] PLAIN = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f };
+ byte[] IV = { 0x56, 0x2e, 0x17, (byte)0x99, 0x6d, 0x09, 0x3d, 0x28, (byte)0xdd, (byte)0xb3, (byte)0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 };
+ byte[] ED = { (byte)0xd2, (byte)0x96, (byte)0xcd, (byte)0x94, (byte)0xc2, (byte)0xcc, (byte)0xcf, (byte)0x8a, 0x3a, (byte)0x86, 0x30, 0x28, (byte)0xb5, (byte)0xe1, (byte)0xdc, 0x0a, 0x75, (byte)0x86, 0x60, 0x2d, 0x25, 0x3c, (byte)0xff, (byte)0xf9, 0x1b, (byte)0x82, 0x66, (byte)0xbe, (byte)0xa6, (byte)0xd6, 0x1a, (byte)0xb1 };
+
+ Aes128Cbc algo = new Aes128Cbc();
+ byte[] encrypted = null;
+
+ ICryptoTransform encryptor = null;
+ try {
+ encryptor = algo.CreateEncryptor(CEK, IV, null, _provider);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ try {
+ encrypted = encryptor.doFinal(PLAIN);
+
+ // Assert: we only compare the first 32 bytes as this library uses PKCS7 padding
+ assertArrayEquals(Arrays.copyOfRange(encrypted, 0, 32), ED);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ ICryptoTransform decryptor = null;
+ try {
+ decryptor = algo.CreateDecryptor(CEK, IV, null, null, _provider);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = decryptor.doFinal(encrypted);
+
+ // Assert: we only compare the first 32 bytes as this library uses PKCS7 padding
+ assertArrayEquals(Arrays.copyOfRange(decrypted, 0, 32), PLAIN);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesKwBCProviderTest.java b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesKwBCProviderTest.java
new file mode 100644
index 000000000000..480db6f2e896
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesKwBCProviderTest.java
@@ -0,0 +1,34 @@
+/**
+ *
+ * Copyright (c) Microsoft and contributors. All rights reserved.
+ *
+ * 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.keyvault.cryptography.test;
+
+import java.security.Provider;
+import org.junit.Before;
+
+public class AesKwBCProviderTest extends AesKwTest {
+
+ @Before
+ public void setUp() throws Exception {
+ try {
+ super.setProvider((Provider) Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider").newInstance());
+ } catch (Exception ex) {
+ throw new RuntimeException(ex.getMessage());
+ }
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesKwTest.java b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesKwTest.java
new file mode 100644
index 000000000000..e79e5569fe71
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesKwTest.java
@@ -0,0 +1,429 @@
+/**
+ *
+ * Copyright (c) Microsoft and contributors. All rights reserved.
+ *
+ * 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.keyvault.cryptography.test;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.fail;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import javax.crypto.Cipher;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.microsoft.azure.keyvault.cryptography.ICryptoTransform;
+import com.microsoft.azure.keyvault.cryptography.algorithms.AesKw;
+import com.microsoft.azure.keyvault.cryptography.algorithms.AesKw128;
+import com.microsoft.azure.keyvault.cryptography.algorithms.AesKw192;
+import com.microsoft.azure.keyvault.cryptography.algorithms.AesKw256;
+
+public class AesKwTest {
+
+ // Always null for the default provider
+ private Provider _provider = null;
+
+ private static boolean hasUnlimitedCrypto() {
+ try {
+ return Cipher.getMaxAllowedKeyLength("RC5") >= 256;
+ } catch (NoSuchAlgorithmException e) {
+ return false;
+ }
+ }
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ protected void setProvider(Provider provider) {
+ _provider = provider;
+ }
+
+ @Test
+ public void KeyVault_AesKw128() {
+ // Arrange
+ byte[] KEK = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
+ byte[] EK = { 0x1F, (byte) 0xA6, (byte) 0x8B, 0x0A, (byte) 0x81, 0x12, (byte) 0xB4, 0x47, (byte) 0xAE, (byte) 0xF3, 0x4B, (byte) 0xD8, (byte) 0xFB, 0x5A, 0x7B, (byte) 0x82, (byte) 0x9D, 0x3E, (byte) 0x86, 0x23, 0x71, (byte) 0xD2, (byte) 0xCF, (byte) 0xE5 };
+
+ AesKw kw = new AesKw128();
+
+ ICryptoTransform encryptor = null;
+
+ try {
+ encryptor = kw.CreateEncryptor(KEK, _provider);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ byte[] encrypted = null;
+
+ try {
+ encrypted = encryptor.doFinal(CEK);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(EK, encrypted);
+
+ ICryptoTransform decryptor = null;
+
+ try {
+ decryptor = kw.CreateDecryptor(KEK, _provider);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = decryptor.doFinal(EK);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(CEK, decrypted);
+ }
+
+ @Test
+ public void KeyVault_AesKw192() {
+ // Arrange
+ byte[] KEK = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
+ byte[] EK = { (byte) 0x96, 0x77, (byte) 0x8B, 0x25, (byte) 0xAE, 0x6C, (byte) 0xA4, 0x35, (byte) 0xF9, 0x2B, 0x5B, (byte) 0x97, (byte) 0xC0, 0x50, (byte) 0xAE, (byte) 0xD2, 0x46, (byte) 0x8A, (byte) 0xB8, (byte) 0xA1, 0x7A, (byte) 0xD8, 0x4E, 0x5D };
+
+ /*
+ * This test using the default JCE provider depends on whether unlimited security
+ * is installed or not. In the unlimited case, the full test should pass but in
+ * the limited case, it should fail with InvalidKeyException.
+ */
+ boolean unlimited = hasUnlimitedCrypto();
+ AesKw kw = new AesKw192();
+
+ ICryptoTransform encryptor = null;
+
+ try {
+ encryptor = kw.CreateEncryptor(KEK, _provider);
+
+ if (!unlimited) fail("Expected InvalidKeyException");
+ } catch (InvalidKeyException e) {
+ if (unlimited) fail("InvalidKeyException");
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ if (unlimited) {
+ byte[] encrypted = null;
+
+ try {
+ encrypted = encryptor.doFinal(CEK);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(EK, encrypted);
+ }
+
+ ICryptoTransform decryptor = null;
+
+ try {
+ decryptor = kw.CreateDecryptor(KEK, _provider);
+ if (!unlimited) fail("Expected InvalidKeyException");
+ } catch (InvalidKeyException e) {
+ if (unlimited) fail("InvalidKeyException");
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ if (unlimited) {
+ byte[] decrypted = null;
+
+ try {
+ decrypted = decryptor.doFinal(EK);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(CEK, decrypted);
+ }
+ }
+
+ @Test
+ public void KeyVault_AesKw256() {
+ // Arrange
+ byte[] KEK = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
+ byte[] EK = { 0x64, (byte) 0xE8, (byte) 0xC3, (byte) 0xF9, (byte) 0xCE, 0x0F, 0x5B, (byte) 0xA2, 0x63, (byte) 0xE9, 0x77, 0x79, 0x05, (byte) 0x81, (byte) 0x8A, 0x2A, (byte) 0x93, (byte) 0xC8, 0x19, 0x1E, 0x7D, 0x6E, (byte) 0x8A, (byte) 0xE7 };
+
+ /*
+ * This test using the default JCE provider depends on whether unlimited security
+ * is installed or not. In the unlimited case, the full test should pass but in
+ * the limited case, it should fail with InvalidKeyException.
+ */
+ boolean unlimited = hasUnlimitedCrypto();
+ AesKw kw = new AesKw256();
+
+ ICryptoTransform encryptor = null;
+
+ try {
+ encryptor = kw.CreateEncryptor(KEK, _provider);
+ if (!unlimited) fail("Expected InvalidKeyException");
+ } catch (InvalidKeyException e) {
+ if (unlimited) fail("InvalidKeyException");
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ if (unlimited) {
+ byte[] encrypted = null;
+
+ try {
+ encrypted = encryptor.doFinal(CEK);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(EK, encrypted);
+ }
+
+ ICryptoTransform decryptor = null;
+
+ try {
+ decryptor = kw.CreateDecryptor(KEK, _provider);
+
+ if (!unlimited) fail("Expected InvalidKeyException");
+ } catch (InvalidKeyException e) {
+ if (unlimited) fail("InvalidKeyException");
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ if (unlimited) {
+ byte[] decrypted = null;
+
+ try {
+ decrypted = decryptor.doFinal(EK);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(CEK, decrypted);
+ }
+ }
+
+ @Test
+ public void KeyVault_AesKw128_ExcessKeyMaterial() {
+ // Arrange
+ byte[] KEK = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte)0x88, (byte)0x99, (byte)0xAA, (byte)0xBB, (byte)0xCC, (byte)0xDD, (byte)0xEE, (byte)0xFF };
+ byte[] EK = { 0x1F, (byte)0xA6, (byte)0x8B, 0x0A, (byte)0x81, 0x12, (byte)0xB4, 0x47, (byte)0xAE, (byte)0xF3, 0x4B, (byte)0xD8, (byte)0xFB, 0x5A, 0x7B, (byte)0x82, (byte)0x9D, 0x3E, (byte)0x86, 0x23, 0x71, (byte)0xD2, (byte)0xCF, (byte)0xE5 };
+
+ AesKw kw = new AesKw128();
+
+ ICryptoTransform encryptor = null;
+
+ try {
+ encryptor = kw.CreateEncryptor(KEK, _provider);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ byte[] encrypted = null;
+
+ try {
+ encrypted = encryptor.doFinal(CEK);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(EK, encrypted);
+
+ ICryptoTransform decryptor = null;
+
+ try {
+ decryptor = kw.CreateDecryptor(KEK, _provider);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = decryptor.doFinal(EK);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(CEK, decrypted);
+ }
+
+ @Test
+ public void KeyVault_AesKw192_ExcessKeyMaterial() {
+ // Arrange
+ byte[] KEK = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
+ byte[] EK = { (byte) 0x96, 0x77, (byte) 0x8B, 0x25, (byte) 0xAE, 0x6C, (byte) 0xA4, 0x35, (byte) 0xF9, 0x2B, 0x5B, (byte) 0x97, (byte) 0xC0, 0x50, (byte) 0xAE, (byte) 0xD2, 0x46, (byte) 0x8A, (byte) 0xB8, (byte) 0xA1, 0x7A, (byte) 0xD8, 0x4E, 0x5D };
+
+ /*
+ * This test using the default JCE provider depends on whether unlimited security
+ * is installed or not. In the unlimited case, the full test should pass but in
+ * the limited case, it should fail with InvalidKeyException.
+ */
+ boolean unlimited = hasUnlimitedCrypto();
+ AesKw kw = new AesKw192();
+
+ ICryptoTransform encryptor = null;
+
+ try {
+ encryptor = kw.CreateEncryptor(KEK, _provider);
+
+ if (!unlimited) fail("Expected InvalidKeyException");
+ } catch (InvalidKeyException e) {
+ if (unlimited) fail("InvalidKeyException");
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ if (unlimited) {
+ byte[] encrypted = null;
+
+ try {
+ encrypted = encryptor.doFinal(CEK);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(EK, encrypted);
+ }
+
+ ICryptoTransform decryptor = null;
+
+ try {
+ decryptor = kw.CreateDecryptor(KEK, _provider);
+ if (!unlimited) fail("Expected InvalidKeyException");
+ } catch (InvalidKeyException e) {
+ if (unlimited) fail("InvalidKeyException");
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ if (unlimited) {
+ byte[] decrypted = null;
+
+ try {
+ decrypted = decryptor.doFinal(EK);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(CEK, decrypted);
+ }
+ }
+
+ @Test
+ public void KeyVault_AesKw256_ExcessKeyMaterial() {
+ // Arrange
+ byte[] KEK = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
+ byte[] EK = { 0x64, (byte) 0xE8, (byte) 0xC3, (byte) 0xF9, (byte) 0xCE, 0x0F, 0x5B, (byte) 0xA2, 0x63, (byte) 0xE9, 0x77, 0x79, 0x05, (byte) 0x81, (byte) 0x8A, 0x2A, (byte) 0x93, (byte) 0xC8, 0x19, 0x1E, 0x7D, 0x6E, (byte) 0x8A, (byte) 0xE7 };
+
+ /*
+ * This test using the default JCE provider depends on whether unlimited security
+ * is installed or not. In the unlimited case, the full test should pass but in
+ * the limited case, it should fail with InvalidKeyException.
+ */
+ boolean unlimited = hasUnlimitedCrypto();
+ AesKw kw = new AesKw256();
+
+ ICryptoTransform encryptor = null;
+
+ try {
+ encryptor = kw.CreateEncryptor(KEK, _provider);
+ if (!unlimited) fail("Expected InvalidKeyException");
+ } catch (InvalidKeyException e) {
+ if (unlimited) fail("InvalidKeyException");
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ if (unlimited) {
+ byte[] encrypted = null;
+
+ try {
+ encrypted = encryptor.doFinal(CEK);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(EK, encrypted);
+ }
+
+ ICryptoTransform decryptor = null;
+
+ try {
+ decryptor = kw.CreateDecryptor(KEK, _provider);
+
+ if (!unlimited) fail("Expected InvalidKeyException");
+ } catch (InvalidKeyException e) {
+ if (unlimited) fail("InvalidKeyException");
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ if (unlimited) {
+ byte[] decrypted = null;
+
+ try {
+ decrypted = decryptor.doFinal(EK);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(CEK, decrypted);
+ }
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/ECKeyBCProviderTest.java b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/ECKeyBCProviderTest.java
new file mode 100644
index 000000000000..545c0eb1429c
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/ECKeyBCProviderTest.java
@@ -0,0 +1,16 @@
+package com.microsoft.azure.keyvault.cryptography.test;
+
+import java.security.Provider;
+import org.junit.Before;
+
+public class ECKeyBCProviderTest extends ECKeyTest {
+
+ @Before
+ public void setUp() throws Exception {
+ try {
+ super.setProvider((Provider) Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider").newInstance());
+ } catch (Exception ex) {
+ throw new RuntimeException(ex.getMessage());
+ }
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/ECKeyTest.java b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/ECKeyTest.java
new file mode 100644
index 000000000000..748c75f6f159
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/ECKeyTest.java
@@ -0,0 +1,324 @@
+package com.microsoft.azure.keyvault.cryptography.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableMap;
+import com.microsoft.azure.keyvault.cryptography.EcKey;
+import com.microsoft.azure.keyvault.cryptography.test.resources.PemFile;
+import com.microsoft.azure.keyvault.webkey.JsonWebKey;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyCurveName;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyType;
+
+public class ECKeyTest {
+
+ private static Provider _provider = null;
+
+ static byte[] CEK;
+ static KeyFactory FACTORY;
+ static MessageDigest DIGEST_256;
+ static MessageDigest DIGEST_384;
+ static MessageDigest DIGEST_512;
+ static KeyPairGenerator EC_KEY_GENERATOR;
+ static Map CURVE_TO_DIGEST;
+ static List CURVE_LIST;
+
+// To create keys and signatures used in this class with openssl:
+//
+// Create key
+// openssl ecparam -name {curve_name} -genkey > {key_name}.pem
+// openssl pkcs8 -topk8 -nocrypt -in {key_name}.pem -out {key_name}pkcs8.pem
+// openssl ec -in {key_name}pkcs8.pem -pubout -out {key_name}pkcs8pub.pem
+//
+// Sign key
+// openssl dgst -{sha_digest} -sign {key_name}pkcs8.pem -out {signature}
+//
+// Verify key
+// openssl dgst -{sha_digest} -verify {key_name}pkcs8pub.pem -signature {signature}
+
+
+ protected static void setProvider(Provider provider) {
+ _provider = provider;
+ }
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ setProvider(Security.getProvider("SunEC"));
+ EC_KEY_GENERATOR = KeyPairGenerator.getInstance("EC", _provider);
+
+ Path byte_location = Paths.get("src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/byte_array.bin");
+ CEK = Files.readAllBytes(byte_location);
+
+ FACTORY = KeyFactory.getInstance("EC", _provider);
+
+ DIGEST_256 = MessageDigest.getInstance("SHA-256");
+ DIGEST_384 = MessageDigest.getInstance("SHA-384");
+ DIGEST_512 = MessageDigest.getInstance("SHA-512");
+
+ CURVE_TO_DIGEST = ImmutableMap.builder()
+ .put(JsonWebKeyCurveName.P_256, DIGEST_256)
+ .put(JsonWebKeyCurveName.P_384, DIGEST_384)
+ .put(JsonWebKeyCurveName.P_521, DIGEST_512)
+ .put(JsonWebKeyCurveName.P_256K, DIGEST_256)
+ .build();
+ //JsonWebKeyCurveName.SECP256K1)
+ CURVE_LIST = Arrays.asList(JsonWebKeyCurveName.P_256, JsonWebKeyCurveName.P_384, JsonWebKeyCurveName.P_521, JsonWebKeyCurveName.P_256K);
+ }
+
+ @Test
+ public void testCurves() throws Exception {
+ for (JsonWebKeyCurveName crv : CURVE_LIST) {
+ EcKey key = new EcKey("keyId", crv);
+ doSignVerify(key, CURVE_TO_DIGEST.get(crv));
+ }
+ }
+
+ @Test(expected = NoSuchAlgorithmException.class)
+ public void testUnsupportedCurve() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, InstantiationException, IllegalAccessException, ClassNotFoundException {
+ EcKey key = new EcKey("keyId", new JsonWebKeyCurveName("not an algo"));
+ }
+
+ @Test
+ public void testDefaultKey() throws Exception {
+ EcKey key = new EcKey("keyId");
+ doSignVerify(key, DIGEST_256);
+ }
+
+ @Test
+ public void testWithKeyPair() throws Exception {
+ for (JsonWebKeyCurveName crv : CURVE_LIST) {
+ ECGenParameterSpec gps = new ECGenParameterSpec(EcKey.CURVE_TO_SPEC_NAME.get(crv));
+ EC_KEY_GENERATOR.initialize(gps);
+ KeyPair keyPair = EC_KEY_GENERATOR.generateKeyPair();
+
+ final String name = "keyid";
+ EcKey key = new EcKey(name, keyPair);
+ assertEquals(name, key.getKid());
+ assertEquals(crv, key.getCurve());
+ doSignVerify(key, CURVE_TO_DIGEST.get(crv));
+ }
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testWithNotCurveKeyPair() throws Exception {
+ ECGenParameterSpec gps = new ECGenParameterSpec("secp192k1");
+ EC_KEY_GENERATOR.initialize(gps);
+ KeyPair keyPair = EC_KEY_GENERATOR.generateKeyPair();
+
+ final String name = "keyid";
+ EcKey key = new EcKey(name, keyPair);
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testFromJsonWebKeyPublicOnly() throws Exception {
+ ECGenParameterSpec gps = new ECGenParameterSpec(EcKey.P256);
+ EC_KEY_GENERATOR.initialize(gps);
+ KeyPair keyPair = EC_KEY_GENERATOR.generateKeyPair();
+
+ ECPublicKey apub = (ECPublicKey) keyPair.getPublic();
+ ECPoint point = apub.getW();
+
+ JsonWebKey jwk = new JsonWebKey()
+ .withKid("kid")
+ .withCrv(JsonWebKeyCurveName.P_256)
+ .withX(point.getAffineX().toByteArray())
+ .withY(point.getAffineY().toByteArray())
+ .withKty(JsonWebKeyType.EC);
+
+ assertFalse(jwk.hasPrivateKey());
+
+ EcKey newKey = EcKey.fromJsonWebKey(jwk, false);
+ assertEquals("kid", newKey.getKid());
+ doSignVerify(newKey, DIGEST_256);
+ }
+
+ @Test
+ public void testFromJsonWebKey() throws Exception {
+ ECGenParameterSpec gps = new ECGenParameterSpec(EcKey.P384);
+ EC_KEY_GENERATOR.initialize(gps);
+ KeyPair keyPair = EC_KEY_GENERATOR.generateKeyPair();
+
+ ECPublicKey apub = (ECPublicKey) keyPair.getPublic();
+ ECPoint point = apub.getW();
+ ECPrivateKey apriv = (ECPrivateKey) keyPair.getPrivate();
+
+ JsonWebKey jwk = new JsonWebKey()
+ .withKid("kid")
+ .withCrv(JsonWebKeyCurveName.P_384)
+ .withX(point.getAffineX().toByteArray())
+ .withY(point.getAffineY().toByteArray())
+ .withD(apriv.getS().toByteArray())
+ .withKty(JsonWebKeyType.EC);
+
+ assertTrue(jwk.hasPrivateKey());
+
+ EcKey newKey = EcKey.fromJsonWebKey(jwk, true);
+ assertEquals("kid", newKey.getKid());
+ doSignVerify(newKey, DIGEST_384);
+ }
+
+ private static PrivateKey generatePrivateKey(KeyFactory factory, String filename) throws InvalidKeySpecException, FileNotFoundException, IOException {
+ PemFile pemFile = new PemFile(filename);
+ byte[] content = pemFile.getPemObject().getContent();
+ PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content);
+ return factory.generatePrivate(privKeySpec);
+ }
+
+ private static PublicKey generatePublicKey(KeyFactory factory, String filename) throws InvalidKeySpecException, FileNotFoundException, IOException {
+ PemFile pemFile = new PemFile(filename);
+ byte[] content = pemFile.getPemObject().getContent();
+ X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
+ return factory.generatePublic(pubKeySpec);
+ }
+
+ private KeyPair getKeyFromFile(String privateKeyPath, String publicKeyPath) throws InvalidKeySpecException, FileNotFoundException, IOException {
+ PrivateKey priv = generatePrivateKey(FACTORY, privateKeyPath);
+ PublicKey pub = generatePublicKey(FACTORY, publicKeyPath);
+ ECPublicKey apub = (ECPublicKey) pub;
+ ECPrivateKey apriv = (ECPrivateKey) priv;
+
+ KeyPair keyPair = new KeyPair(apub, apriv);
+ return keyPair;
+ }
+
+ private void testFromFile(String keyType, MessageDigest digest) throws Exception {
+ String privateKeyPath = "src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/" + keyType + "keynew.pem";
+ String publicKeyPath = "src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/" + keyType + "keypubnew.pem";
+
+ EcKey newKey = new EcKey("akey", getKeyFromFile(privateKeyPath, publicKeyPath));
+
+ Path signatureLocation = Paths.get("src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/" + keyType + "sig.der");
+ byte[] signature = Files.readAllBytes(signatureLocation);
+
+ doVerify(newKey, digest, signature);
+ }
+
+ @Test
+ public void testCreateSECP256K1Key() throws Exception {
+ ECGenParameterSpec gps = new ECGenParameterSpec("secp256k1");
+ Provider myprov = Security.getProvider("BC");
+ final KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
+
+ generator.initialize(gps);
+ EcKey key = new EcKey("akey", JsonWebKeyCurveName.P_256K);
+ }
+
+ @Test
+ public void testFromP384File() throws Exception {
+ testFromFile("p384", DIGEST_384);
+ }
+
+ @Test
+ public void testFromP521File() throws Exception {
+ testFromFile("p521", DIGEST_512);
+ }
+
+ @Test
+ public void testFromP256File() throws Exception {
+ testFromFile("p256", DIGEST_256);
+ }
+
+ @Test
+ public void testFromSEC256File() throws Exception{
+ testFromFile("secp256", DIGEST_256);
+ }
+
+ @Test
+ public void testToJsonWebKey() throws Exception {
+ ECGenParameterSpec gps = new ECGenParameterSpec(EcKey.P521);
+ EC_KEY_GENERATOR.initialize(gps);
+ KeyPair keyPair = EC_KEY_GENERATOR.generateKeyPair();
+
+ ECPublicKey apub = (ECPublicKey) keyPair.getPublic();
+ ECPoint point = apub.getW();
+ ECPrivateKey apriv = (ECPrivateKey) keyPair.getPrivate();
+
+ JsonWebKey jwk = new JsonWebKey()
+ .withKid("kid")
+ .withCrv(JsonWebKeyCurveName.P_521)
+ .withX(point.getAffineX().toByteArray())
+ .withY(point.getAffineY().toByteArray())
+ .withD(apriv.getS().toByteArray())
+ .withKty(JsonWebKeyType.EC);
+
+ EcKey newKey = new EcKey("kid", keyPair);
+
+ JsonWebKey newJwk = newKey.toJsonWebKey();
+ //set missing parameters
+ newJwk.withKid("kid");
+
+ assertEquals(jwk, newJwk);
+ }
+
+ //Checks validity of verify by
+ //Externally signing a byte_array with openssl
+ //Verifying with SDK
+ private void doVerify(EcKey key, MessageDigest digest, byte[] preGenSignature) throws IOException, NoSuchAlgorithmException, InterruptedException, ExecutionException {
+ byte[] hash = digest.digest(CEK);
+
+ //Use sign and verify to test each other.
+ boolean result = key.verifyAsync(hash, preGenSignature, key.getDefaultSignatureAlgorithm()).get();
+ assertTrue(result);
+
+ //Check that key denies invalid digest.
+ BigInteger bigInt = new BigInteger(hash);
+ BigInteger shiftInt = bigInt.shiftRight(4);
+ byte [] shifted = shiftInt.toByteArray();
+ boolean incorrectResult = key.verifyAsync(shifted, preGenSignature, key.getDefaultSignatureAlgorithm()).get();
+ assertFalse(incorrectResult);
+
+ key.close();
+ }
+
+ private void doSignVerify(EcKey key, MessageDigest digest) throws IOException, NoSuchAlgorithmException, InterruptedException, ExecutionException {
+
+ byte[] hash = digest.digest(CEK);
+
+ //Use sign and verify to test each other.
+ Pair signature = key.signAsync(hash, key.getDefaultSignatureAlgorithm()).get();
+ boolean result = key.verifyAsync(hash, signature.getLeft(), key.getDefaultSignatureAlgorithm()).get();
+ assertTrue(result);
+
+ //Check that key denies invalid digest.
+ BigInteger bigInt = new BigInteger(hash);
+ BigInteger shiftInt = bigInt.shiftRight(4);
+ byte [] shifted = shiftInt.toByteArray();
+ boolean incorrectResult = key.verifyAsync(shifted, signature.getLeft(), key.getDefaultSignatureAlgorithm()).get();
+ assertFalse(incorrectResult);
+
+ key.close();
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyBCProviderTest.java b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyBCProviderTest.java
new file mode 100644
index 000000000000..c9a9c70acaeb
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyBCProviderTest.java
@@ -0,0 +1,16 @@
+package com.microsoft.azure.keyvault.cryptography.test;
+
+import java.security.Provider;
+import org.junit.Before;
+
+public class RsaKeyBCProviderTest extends RsaKeyTest {
+
+ @Before
+ public void setUp() throws Exception {
+ try {
+ super.setProvider((Provider) Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider").newInstance());
+ } catch (Exception ex) {
+ throw new RuntimeException(ex.getMessage());
+ }
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyTest.java b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyTest.java
new file mode 100644
index 000000000000..49449105e90c
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyTest.java
@@ -0,0 +1,183 @@
+package com.microsoft.azure.keyvault.cryptography.test;
+
+import static org.junit.Assert.*;
+
+import java.security.MessageDigest;
+import java.security.Provider;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.lang3.tuple.Triple;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.microsoft.azure.keyvault.cryptography.RsaKey;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Rs256;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Rsa15;
+import com.microsoft.azure.keyvault.cryptography.algorithms.RsaOaep;
+import com.microsoft.azure.keyvault.webkey.JsonWebKey;
+
+public class RsaKeyTest {
+
+ // A Content Encryption Key, or Message. This value is kept consistent with the .NET
+ // unit test cases to enable cross platform testing.
+ static final byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte)0x88, (byte)0x99, (byte)0xAA, (byte)0xBB, (byte)0xCC, (byte)0xDD, (byte)0xEE, (byte)0xFF };
+ static final String CrossPlatformHash = "qPrtarvzXBKksm5A9v6xnXNtkARcg7n5ox9jjTI+aBE=";
+ static final String CrossPlatformSignature = "RaNc+8WcWxplS8I7ynJLSoLJKz+dgBvrZhIGH3VFlTTyzu7b9d+lpaV9IKhzCNBsgSysKhgL7EZwVCOTBZ4m6xvKSXqVFXYaBPyBTD7VoKPMYMW6ai5x6xV5XAMaZPfMkff3Deg/RXcc8xQ28FhYuUa8yly01GySY4Hk55anEvb2wBxSy1UGun/0LE1lYH3C3XEgSry4cEkJHDJl1hp+wB4J/noXOqn5ECGU+/4ehBJOyW1gtUH0/gRe8yXnDH0AXepHRyH8iBHLWlKX1r+1/OrMulqOoi82RZzJlTyEz9X+bsQhllqGF6n3hdLS6toH9o7wUtwYNqSx82JuQT6iMg==";
+
+ private Provider _provider = null;
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ protected void setProvider(Provider provider) {
+ _provider = provider;
+ }
+
+ @Test
+ public void testRsa15() throws Exception {
+
+ RsaKey key = getTestRsaKey();
+
+ // Wrap and Unwrap
+ Pair wrapped = key.wrapKeyAsync(CEK, Rsa15.ALGORITHM_NAME).get();
+ byte[] unwrapped = key.unwrapKeyAsync(wrapped.getLeft(), wrapped.getRight()).get();
+
+ // Assert
+ assertEquals(Rsa15.ALGORITHM_NAME, wrapped.getRight());
+ assertArrayEquals(CEK, unwrapped);
+
+ // Encrypt and Decrypt
+ Triple encrypted = key.encryptAsync(CEK, null, null, Rsa15.ALGORITHM_NAME).get();
+ byte[] decrypted = key.decryptAsync(encrypted.getLeft(), null, null, null, encrypted.getRight()).get();
+
+ // Assert
+ assertEquals(Rsa15.ALGORITHM_NAME, encrypted.getRight());
+ assertArrayEquals(CEK, decrypted);
+
+ key.close();
+ }
+
+ @Test
+ public void testRsaOaep() throws Exception {
+
+ RsaKey key = getTestRsaKey();
+
+ // Wrap and Unwrap
+ Pair wrapped = key.wrapKeyAsync(CEK, RsaOaep.ALGORITHM_NAME).get();
+ byte[] unwrapped = key.unwrapKeyAsync(wrapped.getLeft(), wrapped.getRight()).get();
+
+ // Assert
+ assertEquals(RsaOaep.ALGORITHM_NAME, wrapped.getRight());
+ assertArrayEquals(CEK, unwrapped);
+
+ // Encrypt and Decrypt
+ Triple encrypted = key.encryptAsync(CEK, null, null, RsaOaep.ALGORITHM_NAME).get();
+ byte[] decrypted = key.decryptAsync(encrypted.getLeft(), null, null, null, encrypted.getRight()).get();
+
+ // Assert
+ assertEquals(RsaOaep.ALGORITHM_NAME, encrypted.getRight());
+ assertArrayEquals(CEK, decrypted);
+
+ key.close();
+ }
+
+ @Test
+ public void testDefaultAlgorithm() throws Exception {
+
+ RsaKey key = getTestRsaKey();
+
+ assertEquals(RsaOaep.ALGORITHM_NAME, key.getDefaultEncryptionAlgorithm());
+ assertEquals(RsaOaep.ALGORITHM_NAME, key.getDefaultKeyWrapAlgorithm());
+ assertEquals(Rs256.ALGORITHM_NAME, key.getDefaultSignatureAlgorithm());
+
+ // Wrap and Unwrap
+ Pair wrapped = key.wrapKeyAsync(CEK, key.getDefaultKeyWrapAlgorithm()).get();
+ byte[] unwrapped = key.unwrapKeyAsync(wrapped.getLeft(), wrapped.getRight()).get();
+
+ // Assert
+ assertEquals(RsaOaep.ALGORITHM_NAME, wrapped.getRight());
+ assertArrayEquals(CEK, unwrapped);
+
+ // Encrypt and Decrypt
+ Triple encrypted = key.encryptAsync(CEK, null, null, key.getDefaultEncryptionAlgorithm()).get();
+ byte[] decrypted = key.decryptAsync(encrypted.getLeft(), null, null, null, encrypted.getRight()).get();
+
+ // Assert
+ assertEquals(RsaOaep.ALGORITHM_NAME, encrypted.getRight());
+ assertArrayEquals(CEK, decrypted);
+
+ key.close();
+ }
+
+ @Test
+ public void testSignVerify() throws Exception {
+
+ RsaKey key = getTestRsaKey();
+
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
+ byte[] hash = digest.digest(CEK);
+
+ byte[] crossPlatformHash = Base64.decodeBase64(CrossPlatformHash);
+ byte[] crossPlatformSignature = Base64.decodeBase64(CrossPlatformSignature);
+
+ // Check the hash
+ assertNotNull( hash );
+ assertEquals( 32, hash.length );
+ assertArrayEquals(hash, crossPlatformHash);
+
+ Pair signature = key.signAsync(hash, "RS256").get();
+ boolean result = key.verifyAsync(hash, signature.getLeft(), "RS256").get();
+
+ // Check the signature
+ assertTrue(result);
+ assertArrayEquals(crossPlatformSignature, signature.getLeft());
+
+ // Now prove we can verify the cross platform signature
+ result = key.verifyAsync(hash, Base64.decodeBase64(CrossPlatformSignature), "RS256").get();
+
+ assertTrue(result);
+
+ key.close();
+ }
+
+ @Test
+ public void testToFromJsonWebKey() throws Exception {
+ RsaKey key = getTestRsaKey();
+ JsonWebKey jwk = key.toJsonWebKey();
+ jwk.withKid("new kid");
+ //setting kid
+ RsaKey sameKey = RsaKey.fromJsonWebKey(jwk, true, _provider);
+ JsonWebKey jwkSame = sameKey.toJsonWebKey();
+ jwkSame.withKid("new kid");
+ assertEquals(jwk, jwkSame);
+ }
+
+ private RsaKey getTestRsaKey() throws Exception {
+ String jwkString = "{\"kty\":\"RSA\",\"n\":\"rZ8pnmXkhfmmgNWVVdtNcYy2q0OAcCGIpeFzsN9URqJsiBEiWQfxlUxFTbM4kVWPqjauKt6byvApBGEeMA7Qs8kxwRVP-BD4orXRe9VPgliM92rH0UxQWHmCHUe7G7uUAFPwbiDVhWuFzELxNa6Kljg6Z9DuUKoddmQvlYWj8uSunofCtDi_zzlZKGYTOYJma5IYScHNww1yjLp8-b-Be2UdHbrPkCv6Nuwi6MVIKjPpEeRQgfefRmxDBJQKY3OfydMXZmEwukYXVkUcdIP8XwG2OxnfdRK0oAo0NDebNNVuT89k_3AyZLTr1KbDmx1nnjwa8uB8k-uLtcOC9igbTw\",\"e\":\"AQAB\",\"d\":\"H-z7hy_vVJ9yeZBMtIvt8qpQUK_J51STPwV085otcgud72tPKJXoW2658664ASl9kGwbnLBwb2G3-SEunuGqiNS_PGUB3niob6sFSUMRKsPDsB9HfPoOcCZvwZiWFGRqs6C7vlR1TuJVqRjKJ_ffbf4K51oo6FZPspx7j4AShLAwLUSQ60Ld5QPuxYMYZIMpdVbMVIVHJ26pR4Y18e_0GYmEGnbF5N0HkwqQmfmTiIK5aoGnD3GGgqHeHmWBwh6_WAq90ITLcX_zBeqQUgBSj-Z5v61SroO9Eang36T9mMoYrcPpYwemtAOb4HhQYDj8dCCfbeOcVmvZ9UJKWCX2oQ\",\"dp\":\"HW87UpwPoj3lPI9B9K1hJFeuGgarpakvtHuk1HpZ5hXWFGAJiXoWRV-jvYyjoM2k7RpSxPyuuFFmYHcIxiGFp2ES4HnP0BIhKVa2DyugUxIEcMK53C43Ub4mboJPZTSC3sapKgAmA2ue624sapWmshTPpx9qnUP2Oj3cSMkgMGE\",\"dq\":\"RhwEwb5FYio0GS2tmul8FAYsNH7JDehwI1yUApnTiakhSenFetml4PYyVkKR4csgLZEi3RY6J3R8Tg-36zrZuF7hxhVJn80L5_KETSpfEI3jcrXMVg4SRaMsWLY9Ahxflt2FJgUnHOmWRLmP6_hmaTcxxSACjbyUd_HhwNavD5E\",\"qi\":\"wYPZ4lKIslA1w3FaAzQifnNLABYXXUZ_KAA3a8T8fuxkdE4OP3xIFX7WHhnmBd6uOFiEcGoeq2jNQqDg91rV5661-5muQKcvp4uUsNId5rQw9EZw-kdDcwMtVFTEBfvVuyp83X974xYAHn1Jd8wWohSwrpi1QuH5cQMR5Fm6I1A\",\"p\":\"74Ot7MgxRu4euB31UWnGtrqYPjJmvbjYESS43jfDfo-s62ggV5a39P_YPg6oosgtGHNw0QDxunUOXNu9iriaYPf_imptRk69bKN8Nrl727Y-AaBYdLf1UZuwz8X07FqHAH5ghYpk79djld8QvkUUJLpx6rzcW8BJLTOi46DtzZE\",\"q\":\"uZJu-qenARIt28oj_Jlsk-p_KLnqdczczZfbRDd7XNp6csGLa8R0EyYqUB4xLWELQZsX4tAu9SaAO62tuuEy5wbOAmOVrq2ntoia1mGQSJdoeVq6OqtN300xVnaBc3us0rm8C6-824fEQ1PWXoulXLKcSqBhFT-hQahsYi-kat8\"}";
+ ObjectMapper mapper = new ObjectMapper();
+ JsonWebKey jwk = null;
+
+ jwk = mapper.readValue(jwkString, JsonWebKey.class);
+
+ return new RsaKey("foo", jwk.toRSA(true, _provider) );
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/SymmetricKeyBCProviderTest.java b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/SymmetricKeyBCProviderTest.java
new file mode 100644
index 000000000000..2954df416105
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/SymmetricKeyBCProviderTest.java
@@ -0,0 +1,34 @@
+/**
+ *
+ * Copyright (c) Microsoft and contributors. All rights reserved.
+ *
+ * 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.keyvault.cryptography.test;
+
+import java.security.Provider;
+import org.junit.Before;
+
+public class SymmetricKeyBCProviderTest extends SymmetricKeyTest {
+
+ @Before
+ public void setUp() throws Exception {
+ try {
+ super.setProvider((Provider) Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider").newInstance());
+ } catch (Exception ex) {
+ throw new RuntimeException(ex.getMessage());
+ }
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/SymmetricKeyTest.java b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/SymmetricKeyTest.java
new file mode 100644
index 000000000000..b6d3194cae05
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/SymmetricKeyTest.java
@@ -0,0 +1,592 @@
+/**
+ *
+ * Copyright (c) Microsoft and contributors. All rights reserved.
+ *
+ * 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.keyvault.cryptography.test;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.util.concurrent.ExecutionException;
+
+import javax.crypto.Cipher;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.microsoft.azure.keyvault.cryptography.SymmetricKey;
+
+public class SymmetricKeyTest {
+
+ private Provider _provider = null;
+
+ private static boolean hasUnlimitedCrypto() {
+ try {
+ return Cipher.getMaxAllowedKeyLength("RC5") >= 256;
+ } catch (NoSuchAlgorithmException e) {
+ return false;
+ }
+ }
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ setProvider(null);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ protected void setProvider(Provider provider) {
+ _provider = provider;
+ }
+
+ @Test
+ public void testSymmetricKeyAesKw128() {
+ // Arrange
+ byte[] KEK = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
+ byte[] EK = { 0x1F, (byte) 0xA6, (byte) 0x8B, 0x0A, (byte) 0x81, 0x12, (byte) 0xB4, 0x47, (byte) 0xAE, (byte) 0xF3, 0x4B, (byte) 0xD8, (byte) 0xFB, 0x5A, 0x7B, (byte) 0x82, (byte) 0x9D, 0x3E, (byte) 0x86, 0x23, 0x71, (byte) 0xD2, (byte) 0xCF, (byte) 0xE5 };
+
+ SymmetricKey key = new SymmetricKey("KEK", KEK, _provider);
+
+ byte[] encrypted = null;
+
+ try {
+ encrypted = key.wrapKeyAsync(CEK, "A128KW").get().getLeft();
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+ fail("ExecutionException");
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ // Assert
+ assertArrayEquals(EK, encrypted);
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = key.unwrapKeyAsync(EK, "A128KW").get();
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+ fail("ExecutionException");
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ // Assert
+ assertArrayEquals(CEK, decrypted);
+
+ try {
+ key.close();
+ } catch (IOException e) {
+ fail("Key could not be closed");
+ }
+ }
+
+ @Test
+ public void testSymmetricKeyAesKw192() {
+ // Arrange
+ byte[] KEK = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
+ byte[] EK = { (byte) 0x96, 0x77, (byte) 0x8B, 0x25, (byte) 0xAE, 0x6C, (byte) 0xA4, 0x35, (byte) 0xF9, 0x2B, 0x5B, (byte) 0x97, (byte) 0xC0, 0x50, (byte) 0xAE, (byte) 0xD2, 0x46, (byte) 0x8A, (byte) 0xB8, (byte) 0xA1, 0x7A, (byte) 0xD8, 0x4E, 0x5D };
+
+ boolean unlimited = hasUnlimitedCrypto();
+ SymmetricKey key = new SymmetricKey("KEK", KEK, _provider);
+
+ byte[] encrypted = null;
+
+ try {
+ encrypted = key.wrapKeyAsync(CEK, "A192KW").get().getLeft();
+
+ if (!unlimited) fail("Expected ExecutionException");
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+
+ // In the limited case, the failure should be InvalidKeyException
+ // In the unlimited case, this should not fail
+ if (!unlimited) {
+ Throwable cause = e.getCause();
+ if (cause == null || !(cause instanceof InvalidKeyException)) fail("ExecutionException");
+ } else {
+ fail("ExecutionException");
+ }
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ if (unlimited) {
+ // Assert
+ assertArrayEquals(EK, encrypted);
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = key.unwrapKeyAsync(EK, "A192KW").get();
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+ fail("ExecutionException");
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ // Assert
+ assertArrayEquals(CEK, decrypted);
+ }
+
+ try {
+ key.close();
+ } catch (IOException e) {
+ fail("Key could not be closed");
+ }
+ }
+
+ @Test
+ public void testSymmetricKeyAesKw256() {
+ // Arrange
+ byte[] KEK = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
+ byte[] EK = { 0x64, (byte) 0xE8, (byte) 0xC3, (byte) 0xF9, (byte) 0xCE, 0x0F, 0x5B, (byte) 0xA2, 0x63, (byte) 0xE9, 0x77, 0x79, 0x05, (byte) 0x81, (byte) 0x8A, 0x2A, (byte) 0x93, (byte) 0xC8, 0x19, 0x1E, 0x7D, 0x6E, (byte) 0x8A, (byte) 0xE7 };
+
+ /*
+ * This test using the default JCE provider depends on whether unlimited security
+ * is installed or not. In the unlimited case, the full test should pass but in
+ * the limited case, it should fail with InvalidKeyException.
+ */
+ boolean unlimited = hasUnlimitedCrypto();
+ SymmetricKey key = new SymmetricKey("KEK", KEK, _provider);
+
+ byte[] encrypted = null;
+
+ try {
+ encrypted = key.wrapKeyAsync(CEK, "A256KW").get().getLeft();
+
+ if (!unlimited) fail("Expected ExecutionException");
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+ // In the limited case, the failure should be InvalidKeyException
+ // In the unlimited case, this should not fail
+ if (!unlimited) {
+ Throwable cause = e.getCause();
+ if (cause == null || !(cause instanceof InvalidKeyException)) fail("ExecutionException");
+ } else {
+ fail("ExecutionException");
+ }
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ if (unlimited) {
+ // Assert
+ assertArrayEquals(EK, encrypted);
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = key.unwrapKeyAsync(EK, "A256KW").get();
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+ fail("ExecutionException");
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ // Assert
+ assertArrayEquals(CEK, decrypted);
+ }
+
+ try {
+ key.close();
+ } catch (IOException e) {
+ fail("Key could not be closed");
+ }
+ }
+
+ @Test
+ public void testSymmetricKeyDefaultAlgorithmAesKw128() {
+ // Arrange
+ byte[] KEK = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
+ byte[] EK = { 0x1F, (byte) 0xA6, (byte) 0x8B, 0x0A, (byte) 0x81, 0x12, (byte) 0xB4, 0x47, (byte) 0xAE, (byte) 0xF3, 0x4B, (byte) 0xD8, (byte) 0xFB, 0x5A, 0x7B, (byte) 0x82, (byte) 0x9D, 0x3E, (byte) 0x86, 0x23, 0x71, (byte) 0xD2, (byte) 0xCF, (byte) 0xE5 };
+
+ SymmetricKey key = new SymmetricKey("KEK", KEK, _provider);
+
+ byte[] encrypted = null;
+ String algorithm = null;
+
+ try {
+ Pair result = key.wrapKeyAsync(CEK, null).get();
+ encrypted = result.getLeft();
+ algorithm = result.getRight();
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+ fail("ExecutionException");
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ // Assert
+ assertEquals("A128KW", algorithm);
+ assertArrayEquals(EK, encrypted);
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = key.unwrapKeyAsync(EK, algorithm).get();
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+ fail("ExecutionException");
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ // Assert
+ assertArrayEquals(CEK, decrypted);
+
+ try {
+ key.close();
+ } catch (IOException e) {
+ fail("Key could not be closed");
+ }
+ }
+
+ @Test
+ public void testSymmetricKeyDefaultAlgorithmAesKw192() {
+ // Arrange
+ byte[] KEK = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
+ byte[] EK = { (byte) 0x96, 0x77, (byte) 0x8B, 0x25, (byte) 0xAE, 0x6C, (byte) 0xA4, 0x35, (byte) 0xF9, 0x2B, 0x5B, (byte) 0x97, (byte) 0xC0, 0x50, (byte) 0xAE, (byte) 0xD2, 0x46, (byte) 0x8A, (byte) 0xB8, (byte) 0xA1, 0x7A, (byte) 0xD8, 0x4E, 0x5D };
+
+ /*
+ * This test using the default JCE provider depends on whether unlimited security
+ * is installed or not. In the unlimited case, the full test should pass but in
+ * the limited case, it should fail with InvalidKeyException.
+ */
+ boolean unlimited = hasUnlimitedCrypto();
+ SymmetricKey key = new SymmetricKey("KEK", KEK, _provider);
+
+ byte[] encrypted = null;
+ String algorithm = null;
+
+ try {
+ Pair result = key.wrapKeyAsync(CEK, null).get();
+
+ encrypted = result.getLeft();
+ algorithm = result.getRight();
+
+ if (!unlimited) fail("Expected ExecutionException");
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+ // In the limited case, the failure should be InvalidKeyException
+ // In the unlimited case, this should not fail
+ if (!unlimited) {
+ Throwable cause = e.getCause();
+ if (cause == null || !(cause instanceof InvalidKeyException)) fail("ExecutionException");
+ } else {
+ fail("ExecutionException");
+ }
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ if (unlimited) {
+ // Assert
+ assertEquals( "A192KW", algorithm);
+ assertArrayEquals(EK, encrypted);
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = key.unwrapKeyAsync(EK, algorithm).get();
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+ fail("ExecutionException");
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ // Assert
+ assertArrayEquals(CEK, decrypted);
+ }
+
+ try {
+ key.close();
+ } catch (IOException e) {
+ fail("Key could not be closed");
+ }
+ }
+
+ @Test
+ public void testSymmetricKeyDefaultAlgorithmAesKw256() {
+ // Arrange
+ byte[] KEK = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
+ byte[] EK = { 0x64, (byte) 0xE8, (byte) 0xC3, (byte) 0xF9, (byte) 0xCE, 0x0F, 0x5B, (byte) 0xA2, 0x63, (byte) 0xE9, 0x77, 0x79, 0x05, (byte) 0x81, (byte) 0x8A, 0x2A, (byte) 0x93, (byte) 0xC8, 0x19, 0x1E, 0x7D, 0x6E, (byte) 0x8A, (byte) 0xE7 };
+ /*
+ * This test using the default JCE provider depends on whether unlimited security
+ * is installed or not. In the unlimited case, the full test should pass but in
+ * the limited case, it should fail with InvalidKeyException.
+ */
+ boolean unlimited = hasUnlimitedCrypto();
+ SymmetricKey key = new SymmetricKey("KEK", KEK, _provider);
+
+ byte[] encrypted = null;
+ String algorithm = null;
+
+ try {
+ Pair result = key.wrapKeyAsync(CEK, null).get();
+ encrypted = result.getLeft();
+ algorithm = result.getRight();
+
+ if (!unlimited) fail("Expected ExecutionException");
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+ // In the limited case, the failure should be InvalidKeyException
+ // In the unlimited case, this should not fail
+ if (!unlimited) {
+ Throwable cause = e.getCause();
+ if (cause == null || !(cause instanceof InvalidKeyException)) fail("ExecutionException");
+ } else {
+ fail("ExecutionException");
+ }
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ if (unlimited) {
+ // Assert
+ assertEquals("A256KW", algorithm);
+ assertArrayEquals(EK, encrypted);
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = key.unwrapKeyAsync(EK, algorithm).get();
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+ fail("ExecutionException");
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ // Assert
+ assertArrayEquals(CEK, decrypted);
+ }
+
+ try {
+ key.close();
+ } catch (IOException e) {
+ fail("Key could not be closed");
+ }
+ }
+
+ @Test
+ public void testSymmetricKeyAesKw128_ExcessKeyMaterial() {
+ // Arrange
+ byte[] KEK = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte)0x88, (byte)0x99, (byte)0xAA, (byte)0xBB, (byte)0xCC, (byte)0xDD, (byte)0xEE, (byte)0xFF };
+ byte[] EK = { 0x1F, (byte)0xA6, (byte)0x8B, 0x0A, (byte)0x81, 0x12, (byte)0xB4, 0x47, (byte)0xAE, (byte)0xF3, 0x4B, (byte)0xD8, (byte)0xFB, 0x5A, 0x7B, (byte)0x82, (byte)0x9D, 0x3E, (byte)0x86, 0x23, 0x71, (byte)0xD2, (byte)0xCF, (byte)0xE5 };
+
+ SymmetricKey key = new SymmetricKey("KEK", KEK, _provider);
+
+ byte[] encrypted = null;
+
+ try {
+ encrypted = key.wrapKeyAsync(CEK, "A128KW").get().getLeft();
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+ fail("ExecutionException");
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ // Assert
+ assertArrayEquals(EK, encrypted);
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = key.unwrapKeyAsync(EK, "A128KW").get();
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+ fail("ExecutionException");
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ // Assert
+ assertArrayEquals(CEK, decrypted);
+
+ try {
+ key.close();
+ } catch (IOException e) {
+ fail("Key could not be closed");
+ }
+ }
+
+ @Test
+ public void testSymmetricKeyAesKw192_ExcessKeyMaterial() {
+ // Arrange
+ byte[] KEK = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte)0x88, (byte)0x99, (byte)0xAA, (byte)0xBB, (byte)0xCC, (byte)0xDD, (byte)0xEE, (byte)0xFF };
+ byte[] EK = { (byte)0x96, 0x77, (byte)0x8B, 0x25, (byte)0xAE, 0x6C, (byte)0xA4, 0x35, (byte)0xF9, 0x2B, 0x5B, (byte)0x97, (byte)0xC0, 0x50, (byte)0xAE, (byte)0xD2, 0x46, (byte)0x8A, (byte)0xB8, (byte)0xA1, 0x7A, (byte)0xD8, 0x4E, 0x5D };
+
+ boolean unlimited = hasUnlimitedCrypto();
+ SymmetricKey key = new SymmetricKey("KEK", KEK, _provider);
+
+ byte[] encrypted = null;
+
+ try {
+ encrypted = key.wrapKeyAsync(CEK, "A192KW").get().getLeft();
+
+ if (!unlimited) fail("Expected ExecutionException");
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+
+ // In the limited case, the failure should be InvalidKeyException
+ // In the unlimited case, this should not fail
+ if (!unlimited) {
+ Throwable cause = e.getCause();
+ if (cause == null || !(cause instanceof InvalidKeyException)) fail("ExecutionException");
+ } else {
+ fail("ExecutionException");
+ }
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ if (unlimited) {
+ // Assert
+ assertArrayEquals(EK, encrypted);
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = key.unwrapKeyAsync(EK, "A192KW").get();
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+ fail("ExecutionException");
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ // Assert
+ assertArrayEquals(CEK, decrypted);
+ }
+
+ try {
+ key.close();
+ } catch (IOException e) {
+ fail("Key could not be closed");
+ }
+ }
+
+ @Test
+ public void testSymmetricKeyAesKw256_ExcessKeyMaterial() {
+ // Arrange
+ byte[] KEK = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
+ byte[] EK = { 0x64, (byte)0xE8, (byte)0xC3, (byte)0xF9, (byte)0xCE, 0x0F, 0x5B, (byte)0xA2, 0x63, (byte)0xE9, 0x77, 0x79, 0x05, (byte)0x81, (byte)0x8A, 0x2A, (byte)0x93, (byte)0xC8, 0x19, 0x1E, 0x7D, 0x6E, (byte)0x8A, (byte)0xE7 };
+
+ /*
+ * This test using the default JCE provider depends on whether unlimited security
+ * is installed or not. In the unlimited case, the full test should pass but in
+ * the limited case, it should fail with InvalidKeyException.
+ */
+ boolean unlimited = hasUnlimitedCrypto();
+ SymmetricKey key = new SymmetricKey("KEK", KEK, _provider);
+
+ byte[] encrypted = null;
+
+ try {
+ encrypted = key.wrapKeyAsync(CEK, "A256KW").get().getLeft();
+
+ if (!unlimited) fail("Expected ExecutionException");
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+ // In the limited case, the failure should be InvalidKeyException
+ // In the unlimited case, this should not fail
+ if (!unlimited) {
+ Throwable cause = e.getCause();
+ if (cause == null || !(cause instanceof InvalidKeyException)) fail("ExecutionException");
+ } else {
+ fail("ExecutionException");
+ }
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ if (unlimited) {
+ // Assert
+ assertArrayEquals(EK, encrypted);
+
+ byte[] decrypted = null;
+
+ try {
+ decrypted = key.unwrapKeyAsync(EK, "A256KW").get();
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+ fail("ExecutionException");
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ // Assert
+ assertArrayEquals(CEK, decrypted);
+ }
+
+ try {
+ key.close();
+ } catch (IOException e) {
+ fail("Key could not be closed");
+ }
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/PemFile.java b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/PemFile.java
new file mode 100644
index 000000000000..1064a943d68a
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/PemFile.java
@@ -0,0 +1,27 @@
+package com.microsoft.azure.keyvault.cryptography.test.resources;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import org.bouncycastle.util.io.pem.PemObject;
+import org.bouncycastle.util.io.pem.PemReader;
+
+public class PemFile {
+
+ private PemObject pemObject;
+
+ public PemFile(String filename) throws FileNotFoundException, IOException {
+ PemReader pemReader = new PemReader(new InputStreamReader(new FileInputStream(filename)));
+ try {
+ this.pemObject = pemReader.readPemObject();
+ } finally {
+ pemReader.close();
+ }
+ }
+
+ public PemObject getPemObject() {
+ return pemObject;
+ }
+}
\ No newline at end of file
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/SECP256key.pem b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/SECP256key.pem
new file mode 100644
index 000000000000..9422787ad2e2
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/SECP256key.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BgUrgQQACg==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHQCAQEEIIbmPOGbSMPdQoRmd5CTnkMl5EtyAYG9YF0/cC9/QiOsoAcGBSuBBAAK
+oUQDQgAEcgWYGgCEzF7O2klfOCQJSrIjKZd1InDMUVwbykw5gvbCaL8m2/hSY13o
+X7A1b4PbLn6zK7TAFRqBipA8w2sQ6g==
+-----END EC PRIVATE KEY-----
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/byte_array.bin b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/byte_array.bin
new file mode 100644
index 000000000000..2fdaa8e3b66f
Binary files /dev/null and b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/byte_array.bin differ
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p256key.pem b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p256key.pem
new file mode 100644
index 000000000000..0dc7ae15b09c
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p256key.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BgUrgQQACg==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHQCAQEEICuTXZmGPyKlnpX/NZjNsfRF3V6np91hIN6JGuq3+ml4oAcGBSuBBAAK
+oUQDQgAEB4kcrPPdAiPb0RNPgqik6RbzD4CluCZB/FcqgS8tBOJ3mSjnCNUzlAng
+QQWZu0YZzq2n4QZwa9E1FZc5hBH7nA==
+-----END EC PRIVATE KEY-----
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p256keynew.pem b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p256keynew.pem
new file mode 100644
index 000000000000..fc9d36273a6e
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p256keynew.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgmDtpx1m8G4Wmwo5+
+CuQx27iupfo5nf4CqsfWmMYxFEehRANCAARIcREG1iUacEdriN3Zim6er9nbgSil
+YSYN9tX1+HhLlPr1MXL7nERsSlVSlTptbC+SxGL+2cBcI4dgM7/XPe9Z
+-----END PRIVATE KEY-----
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p256keypubnew.pem b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p256keypubnew.pem
new file mode 100644
index 000000000000..7e245ae14711
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p256keypubnew.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESHERBtYlGnBHa4jd2Ypunq/Z24Eo
+pWEmDfbV9fh4S5T69TFy+5xEbEpVUpU6bWwvksRi/tnAXCOHYDO/1z3vWQ==
+-----END PUBLIC KEY-----
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p256sig.der b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p256sig.der
new file mode 100644
index 000000000000..23f41f2ee364
Binary files /dev/null and b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p256sig.der differ
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p384keynew.pem b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p384keynew.pem
new file mode 100644
index 000000000000..9ec79bdab30e
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p384keynew.pem
@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDC0ooKHLcKqHpTI1Cz2
+AjkFh/DXxz9VaHW6tdRYow3eHRpPyjWzdpK9ThCc2vsVvnqhZANiAATy14M2foWP
+Tbql4vwUhL1JEh0Oy629FNaggH6oGCNNPdtVOWJfRcPvFWdYIcfOotVGHLIl8WLJ
+HnuDUMUbxCJFoWboyPIBzufbiPEvZaAjWjT509d971YJANAwVcYmR4Y=
+-----END PRIVATE KEY-----
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p384keypubnew.pem b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p384keypubnew.pem
new file mode 100644
index 000000000000..44de436df915
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p384keypubnew.pem
@@ -0,0 +1,5 @@
+-----BEGIN PUBLIC KEY-----
+MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8teDNn6Fj026peL8FIS9SRIdDsutvRTW
+oIB+qBgjTT3bVTliX0XD7xVnWCHHzqLVRhyyJfFiyR57g1DFG8QiRaFm6MjyAc7n
+24jxL2WgI1o0+dPXfe9WCQDQMFXGJkeG
+-----END PUBLIC KEY-----
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p384sig.der b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p384sig.der
new file mode 100644
index 000000000000..44e3fc6b3007
Binary files /dev/null and b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p384sig.der differ
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p521keynew.pem b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p521keynew.pem
new file mode 100644
index 000000000000..8a95bdd14d96
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p521keynew.pem
@@ -0,0 +1,8 @@
+-----BEGIN PRIVATE KEY-----
+MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAlTlzXR+eSE1CiFBs
+s139xS1gP1ESKhGeeeohoa0+s2IDlgwz5CZmIOhfHeDqIMiuvt0Da/SdXa8YEdlr
+PfpM9BuhgYkDgYYABAEbJoXHYgVIkmneHp65hog0j3WD7pUaXMwy6HIWCiRU+va9
+1ZN7e8ht4Cor9ME93hiRBFAW1W2unA8AcjIKHhGj1QCq6My/fh4Lur0qgk0DHWj3
+Jlh+hIWAVxLZdkKA2uza01OUN9Ma1VNBoKssZDB7VCGnWUKa6heWDth8hp6X+bLd
+LA==
+-----END PRIVATE KEY-----
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p521keypubnew.pem b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p521keypubnew.pem
new file mode 100644
index 000000000000..da5457b3ff9f
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p521keypubnew.pem
@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBGyaFx2IFSJJp3h6euYaINI91g+6V
+GlzMMuhyFgokVPr2vdWTe3vIbeAqK/TBPd4YkQRQFtVtrpwPAHIyCh4Ro9UAqujM
+v34eC7q9KoJNAx1o9yZYfoSFgFcS2XZCgNrs2tNTlDfTGtVTQaCrLGQwe1Qhp1lC
+muoXlg7YfIael/my3Sw=
+-----END PUBLIC KEY-----
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p521sig.der b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p521sig.der
new file mode 100644
index 000000000000..819d2e33ca2a
Binary files /dev/null and b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/p521sig.der differ
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/secp256keynew.pem b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/secp256keynew.pem
new file mode 100644
index 000000000000..3f68ccd6e32c
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/secp256keynew.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQghuY84ZtIw91ChGZ3kJOe
+QyXkS3IBgb1gXT9wL39CI6yhRANCAARyBZgaAITMXs7aSV84JAlKsiMpl3UicMxR
+XBvKTDmC9sJovybb+FJjXehfsDVvg9sufrMrtMAVGoGKkDzDaxDq
+-----END PRIVATE KEY-----
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/secp256keypubnew.pem b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/secp256keypubnew.pem
new file mode 100644
index 000000000000..4e7cddb68862
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/secp256keypubnew.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEcgWYGgCEzF7O2klfOCQJSrIjKZd1InDM
+UVwbykw5gvbCaL8m2/hSY13oX7A1b4PbLn6zK7TAFRqBipA8w2sQ6g==
+-----END PUBLIC KEY-----
diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/secp256sig.der b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/secp256sig.der
new file mode 100644
index 000000000000..2dc90f98c7cf
Binary files /dev/null and b/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/resources/secp256sig.der differ
diff --git a/keyvault/data-plane/azure-keyvault-extensions/pom.xml b/keyvault/data-plane/azure-keyvault-extensions/pom.xml
new file mode 100644
index 000000000000..6c3af7a2693f
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/pom.xml
@@ -0,0 +1,185 @@
+
+
+ 4.0.0
+
+ com.microsoft.azure
+ azure-keyvault-parent
+ 1.1.2
+ ../pom.xml
+
+
+ azure-keyvault-extensions
+ 1.1.2
+ jar
+
+ Microsoft Azure SDK for Key Vault Extensions
+ This package contains Microsoft Azure Key Vault SDK Extensions.
+ https://github.com/Azure/azure-sdk-for-java
+
+
+
+ The MIT License (MIT)
+ http://opensource.org/licenses/MIT
+ repo
+
+
+
+
+ scm:git:https://github.com/Azure/azure-sdk-for-java
+ scm:git:git@github.com:Azure/azure-sdk-for-java.git
+ HEAD
+
+
+
+ UTF-8
+
+
+
+
+
+ microsoft
+ Microsoft
+
+
+
+
+
+
+
+ com.microsoft.azure
+ azure-keyvault-webkey
+
+
+ com.microsoft.azure
+ azure-keyvault-core
+
+
+ com.microsoft.azure
+ azure-keyvault-cryptography
+
+
+ com.microsoft.azure
+ azure-keyvault
+
+
+
+
+ com.microsoft.azure
+ azure-client-runtime
+
+
+ com.microsoft.azure
+ azure-mgmt-resources
+
+
+
+
+ com.microsoft.rest
+ client-runtime
+
+
+
+
+ com.google.guava
+ guava
+
+
+ org.apache.commons
+ commons-lang3
+
+
+ commons-codec
+ commons-codec
+
+
+
+
+
+
+ com.microsoft.azure
+ azure-mgmt-resources
+ 1.3.1-SNAPSHOT
+ test-jar
+ test
+
+
+ com.microsoft.azure
+ adal4j
+ test
+
+
+ com.microsoft.azure
+ azure
+ test
+
+
+
+
+ junit
+ junit
+ test
+
+
+ org.bouncycastle
+ bcprov-jdk15on
+ test
+
+
+ org.mockito
+ mockito-core
+ 1.10.19
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.0.2
+
+
+
+ true
+ true
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+ 1.12
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.1
+
+ 1.7
+ 1.7
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 2.8
+
+ *.implementation.*;*.utils.*;com.microsoft.schemas._2003._10.serialization;*.blob.core.storage
+ /**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */]]>
+
+
+
+
+
diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/AggregateKeyResolver.java b/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/AggregateKeyResolver.java
new file mode 100644
index 000000000000..8ce09dde16ae
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/AggregateKeyResolver.java
@@ -0,0 +1,142 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.extensions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import com.google.common.util.concurrent.AbstractFuture;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.microsoft.azure.keyvault.core.IKey;
+import com.microsoft.azure.keyvault.core.IKeyResolver;
+
+/**
+ * The collection of key resolvers that would iterate on a key id to resolve to {@link IKey}.
+ */
+public class AggregateKeyResolver implements IKeyResolver {
+
+ /**
+ * Future key class that resolves a key id after the async result is available.
+ */
+ class FutureKey extends AbstractFuture {
+
+ private final String kid;
+
+ private boolean isCancelled = false;
+ private boolean isDone = false;
+ private IKey result = null;
+
+ FutureKey(String kid) {
+ this.kid = kid;
+ }
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+
+ // mark cancelled
+ isCancelled = true;
+
+ return isCancelled;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return isCancelled;
+ }
+
+ @Override
+ public boolean isDone() {
+
+ // always true
+ return isDone;
+ }
+
+ @Override
+ public IKey get() throws InterruptedException, ExecutionException {
+
+ // throw if cancelled
+ if (isCancelled) {
+ throw new InterruptedException();
+ }
+
+ synchronized (resolvers) {
+ for (IKeyResolver resolver : resolvers) {
+ Future futureKey = resolver.resolveKeyAsync(kid);
+
+ result = futureKey.get();
+
+ if (result != null) {
+ break;
+ }
+ }
+ }
+
+ // Mark done
+ isDone = true;
+
+ return result;
+ }
+
+ @Override
+ public IKey get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+
+ // throw if cancelled
+ if (isCancelled) {
+ throw new InterruptedException();
+ }
+
+ synchronized (resolvers) {
+ for (IKeyResolver resolver : resolvers) {
+ Future futureKey = resolver.resolveKeyAsync(kid);
+
+ result = futureKey.get(timeout, unit);
+
+ if (result != null) {
+ break;
+ }
+ }
+ }
+
+ // Mark done
+ isDone = true;
+
+ return result;
+ }
+ }
+
+ private final List resolvers;
+
+ /**
+ * Constructor.
+ */
+ public AggregateKeyResolver() {
+
+ resolvers = Collections.synchronizedList(new ArrayList());
+ }
+
+ /**
+ * Adds a key resolver to the collection of key resolvers.
+ * @param resolver the key resolver
+ */
+ public void add(IKeyResolver resolver) {
+
+ synchronized (resolvers) {
+ resolvers.add(resolver);
+ }
+ }
+
+ @Override
+ public ListenableFuture resolveKeyAsync(String kid) {
+ return new FutureKey(kid);
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/CachingKeyResolver.java b/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/CachingKeyResolver.java
new file mode 100644
index 000000000000..62bca3fabfdb
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/CachingKeyResolver.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.extensions;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.microsoft.azure.keyvault.KeyIdentifier;
+import com.microsoft.azure.keyvault.core.IKey;
+import com.microsoft.azure.keyvault.core.IKeyResolver;
+
+/**
+ * The key resolver that caches the key after resolving to {@link IKey}.
+ */
+public class CachingKeyResolver implements IKeyResolver {
+
+ private final IKeyResolver keyResolver;
+ private final LoadingCache> cache;
+
+ /**
+ * Constructor.
+ * @param capacity the cache size
+ * @param keyResolver the key resolver
+ */
+ public CachingKeyResolver(int capacity, final IKeyResolver keyResolver) {
+ this.keyResolver = keyResolver;
+ cache = CacheBuilder.newBuilder().maximumSize(capacity)
+ .build(new CacheLoader>() {
+
+ @Override
+ public ListenableFuture load(String kid) {
+ return keyResolver.resolveKeyAsync(kid);
+ }
+ });
+ }
+
+ @Override
+ public ListenableFuture resolveKeyAsync(String kid) {
+ KeyIdentifier keyIdentifier = new KeyIdentifier(kid);
+ if (keyIdentifier.version() == null) {
+ final ListenableFuture key = keyResolver.resolveKeyAsync(kid);
+ key.addListener(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ cache.put(key.get().getKid(), key);
+ } catch (Exception e) {
+ // Key caching will occur on first read
+ }
+ }
+ },
+ MoreExecutors.directExecutor()
+ );
+ return key;
+ } else {
+ return cache.getUnchecked(kid);
+ }
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKey.java b/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKey.java
new file mode 100644
index 000000000000..bfb58a8a7b8a
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKey.java
@@ -0,0 +1,234 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+package com.microsoft.azure.keyvault.extensions;
+
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+
+import com.google.common.util.concurrent.MoreExecutors;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.lang3.tuple.Triple;
+
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.microsoft.azure.keyvault.KeyVaultClient;
+import com.microsoft.azure.keyvault.core.IKey;
+import com.microsoft.azure.keyvault.cryptography.RsaKey;
+import com.microsoft.azure.keyvault.webkey.JsonWebKey;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyEncryptionAlgorithm;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeySignatureAlgorithm;
+import com.microsoft.azure.keyvault.models.KeyBundle;
+import com.microsoft.azure.keyvault.models.KeyOperationResult;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyType;
+
+/**
+ * The key vault key that performs cryptography operations.
+ */
+public class KeyVaultKey implements IKey {
+
+ /**
+ * Transforms the result of decrypt operation to byte array.
+ */
+ class DecryptResultTransform implements Function {
+
+ DecryptResultTransform() {
+ super();
+ }
+
+ @Override
+ public byte[] apply(KeyOperationResult result) {
+ return result.result();
+ }
+ }
+
+ /**
+ * Transforms the result of sign operation to byte array and algorithm pair.
+ */
+ class SignResultTransform implements Function> {
+
+ private final String algorithm;
+
+ SignResultTransform(String algorithm) {
+ super();
+ this.algorithm = algorithm;
+ }
+
+ @Override
+ public Pair apply(KeyOperationResult input) {
+
+ return Pair.of(input.result(), algorithm);
+ }
+ }
+
+ private final KeyVaultClient client;
+ private IKey implementation;
+
+ protected KeyVaultKey(KeyVaultClient client, KeyBundle keyBundle) {
+
+ if (client == null) {
+ throw new IllegalArgumentException("client");
+ }
+
+ if (keyBundle == null) {
+ throw new IllegalArgumentException("keyBundle");
+ }
+
+ JsonWebKey key = keyBundle.key();
+
+ if (key == null) {
+ throw new IllegalArgumentException("keyBundle must contain a key");
+ }
+
+ if (key.kty().equals(JsonWebKeyType.RSA)) {
+ // The private key is not available for KeyVault keys
+ implementation = new RsaKey(key.kid(), key.toRSA(false));
+ } else if (key.kty().equals(JsonWebKeyType.RSA_HSM)) {
+ // The private key is not available for KeyVault keys
+ implementation = new RsaKey(key.kid(), key.toRSA(false));
+ }
+
+ if (implementation == null) {
+ throw new IllegalArgumentException(String.format("The key type %s is not supported", key.kty()));
+ }
+
+ this.client = client;
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (implementation != null) {
+ implementation.close();
+ }
+ }
+
+ @Override
+ public String getDefaultEncryptionAlgorithm() {
+ if (implementation == null) {
+ return null;
+ }
+
+ return implementation.getDefaultEncryptionAlgorithm();
+ }
+
+ @Override
+ public String getDefaultKeyWrapAlgorithm() {
+
+ if (implementation == null) {
+ return null;
+ }
+
+ return implementation.getDefaultKeyWrapAlgorithm();
+ }
+
+ @Override
+ public String getDefaultSignatureAlgorithm() {
+
+ if (implementation == null) {
+ return null;
+ }
+
+ return implementation.getDefaultSignatureAlgorithm();
+ }
+
+ @Override
+ public String getKid() {
+
+ if (implementation == null) {
+ return null;
+ }
+
+ return implementation.getKid();
+ }
+
+ @Override
+ public ListenableFuture decryptAsync(byte[] ciphertext, byte[] iv, byte[] authenticationData, byte[] authenticationTag, String algorithm) {
+
+ if (implementation == null) {
+ return null;
+ }
+
+ if (Strings.isNullOrWhiteSpace(algorithm)) {
+ algorithm = getDefaultEncryptionAlgorithm();
+ }
+
+ // Never local
+ ListenableFuture futureCall =
+ client.decryptAsync(
+ implementation.getKid(),
+ new JsonWebKeyEncryptionAlgorithm(algorithm),
+ ciphertext,
+ null);
+ return Futures.transform(futureCall, new DecryptResultTransform(), MoreExecutors.directExecutor());
+ }
+
+ @Override
+ public ListenableFuture> encryptAsync(byte[] plaintext, byte[] iv, byte[] authenticationData, String algorithm) throws NoSuchAlgorithmException {
+ if (implementation == null) {
+ return null;
+ }
+
+ return implementation.encryptAsync(plaintext, iv, authenticationData, algorithm);
+ }
+
+ @Override
+ public ListenableFuture> wrapKeyAsync(byte[] plaintext, String algorithm) throws NoSuchAlgorithmException {
+ if (implementation == null) {
+ return null;
+ }
+
+ return implementation.wrapKeyAsync(plaintext, algorithm);
+ }
+
+ @Override
+ public ListenableFuture unwrapKeyAsync(byte[] ciphertext, String algorithm) {
+ if (implementation == null) {
+ return null;
+ }
+
+ if (Strings.isNullOrWhiteSpace(algorithm)) {
+ algorithm = getDefaultKeyWrapAlgorithm();
+ }
+
+ // Never local
+ ListenableFuture futureCall =
+ client.unwrapKeyAsync(
+ implementation.getKid(),
+ new JsonWebKeyEncryptionAlgorithm(algorithm),
+ ciphertext,
+ null);
+ return Futures.transform(futureCall, new DecryptResultTransform(), MoreExecutors.directExecutor());
+ }
+
+ @Override
+ public ListenableFuture> signAsync(byte[] digest, String algorithm) throws NoSuchAlgorithmException {
+ if (implementation == null) {
+ return null;
+ }
+
+ if (Strings.isNullOrWhiteSpace(algorithm)) {
+ algorithm = getDefaultSignatureAlgorithm();
+ }
+
+ // Never local
+ ListenableFuture futureCall =
+ client.signAsync(
+ implementation.getKid(),
+ new JsonWebKeySignatureAlgorithm(algorithm),
+ digest,
+ null);
+ return Futures.transform(futureCall, new SignResultTransform(algorithm), MoreExecutors.directExecutor());
+ }
+
+ @Override
+ public ListenableFuture verifyAsync(byte[] digest, byte[] signature, String algorithm) throws NoSuchAlgorithmException {
+ if (implementation == null) {
+ return null;
+ }
+
+ return implementation.verifyAsync(digest, signature, algorithm);
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKeyResolver.java b/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKeyResolver.java
new file mode 100644
index 000000000000..3e8cc130cf7d
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKeyResolver.java
@@ -0,0 +1,124 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.extensions;
+
+import java.security.Provider;
+
+import com.google.common.util.concurrent.MoreExecutors;
+import org.apache.commons.codec.binary.Base64;
+
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.microsoft.azure.keyvault.KeyIdentifier;
+import com.microsoft.azure.keyvault.KeyVaultClient;
+import com.microsoft.azure.keyvault.SecretIdentifier;
+import com.microsoft.azure.keyvault.core.IKey;
+import com.microsoft.azure.keyvault.core.IKeyResolver;
+import com.microsoft.azure.keyvault.cryptography.SymmetricKey;
+import com.microsoft.azure.keyvault.models.KeyBundle;
+import com.microsoft.azure.keyvault.models.SecretBundle;
+
+/**
+ * The key resolver class that handles resolving key id to type {@link IKey}
+ * to be used for cryptography operations.
+ */
+public class KeyVaultKeyResolver implements IKeyResolver {
+
+ static final Base64 BASE64 = new Base64(-1, null, true);
+
+ /**
+ * Transforms {@link KeyBundle} to {@link IKey}.
+ */
+ class FutureKeyFromKey implements Function {
+
+ protected FutureKeyFromKey() {
+ super();
+ }
+
+ @Override
+ public IKey apply(KeyBundle keyBundle) {
+
+ if (keyBundle != null) {
+ return new KeyVaultKey(client, keyBundle);
+ }
+
+ return null;
+ }
+ }
+
+ /**
+ * Transforms {@link SecretBundle} to {@link IKey}.
+ */
+ class FutureKeyFromSecret implements Function {
+
+ protected FutureKeyFromSecret() {
+ super();
+ }
+
+ @Override
+ public IKey apply(SecretBundle secretBundle) {
+
+ if (secretBundle != null && secretBundle.contentType().equalsIgnoreCase("application/octet-stream")) {
+ byte[] keyBytes = BASE64.decode(secretBundle.value());
+
+ if (keyBytes != null) {
+ return new SymmetricKey(secretBundle.id(), keyBytes, provider);
+ }
+ }
+
+ return null;
+ }
+ }
+
+ private final KeyVaultClient client;
+ private final Provider provider;
+
+ /**
+ * Constructor.
+ * @param client the key vault client
+ */
+ public KeyVaultKeyResolver(KeyVaultClient client) {
+ this.client = client;
+ this.provider = null;
+ }
+
+ /**
+ * Constructor.
+ * @param client the key vault client
+ * @param provider the java security provider
+ */
+ public KeyVaultKeyResolver(KeyVaultClient client, Provider provider) {
+ this.client = client;
+ this.provider = provider;
+ }
+
+ private ListenableFuture resolveKeyFromSecretAsync(String kid) {
+
+ ListenableFuture futureCall = client.getSecretAsync(kid, null);
+ return Futures.transform(futureCall, new FutureKeyFromSecret(), MoreExecutors.directExecutor());
+ }
+
+ private ListenableFuture resolveKeyFromKeyAsync(String kid) {
+
+ ListenableFuture futureCall = client.getKeyAsync(kid, null);
+ return Futures.transform(futureCall, new FutureKeyFromKey(), MoreExecutors.directExecutor());
+ }
+
+ @Override
+ public ListenableFuture resolveKeyAsync(String kid) {
+
+ if (KeyIdentifier.isKeyIdentifier(kid)) {
+ return resolveKeyFromKeyAsync(kid);
+ } else if (SecretIdentifier.isSecretIdentifier(kid)) {
+ return resolveKeyFromSecretAsync(kid);
+ }
+
+ return Futures.immediateFuture(null);
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/Strings.java b/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/Strings.java
new file mode 100644
index 000000000000..5d5fe934de6b
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/Strings.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.extensions;
+
+/**
+ * String handlers.
+ */
+public class Strings {
+
+ /**
+ * Determines whether the parameter string is either null or empty.
+ * @param arg the string to verify
+ * @return true if the string is empty or null and false otherwise.
+ */
+ public static boolean isNullOrEmpty(String arg) {
+
+ if (arg == null || arg.length() == 0) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Determines whether the parameter string is null, empty or whitespace.
+ * @param arg the string to verify
+ * @return true if the string is empty, contains only whitespace or is null and false otherwise
+ */
+ public static boolean isNullOrWhiteSpace(String arg) {
+
+ if (Strings.isNullOrEmpty(arg) || arg.trim().isEmpty()) {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/package.html b/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/package.html
new file mode 100644
index 000000000000..12edd05fd0ba
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/package.html
@@ -0,0 +1,5 @@
+
+
+This package contains the Azure Key Vault Extension classes.
+
+
diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/CachingKeyResolverTest.java b/keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/CachingKeyResolverTest.java
new file mode 100644
index 000000000000..39e15a594185
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/CachingKeyResolverTest.java
@@ -0,0 +1,151 @@
+/**
+ *
+ * Copyright (c) Microsoft and contributors. All rights reserved.
+ *
+ * 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.keyvault.extensions.test;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.UncheckedExecutionException;
+import com.microsoft.azure.keyvault.core.IKey;
+import com.microsoft.azure.keyvault.core.IKeyResolver;
+import com.microsoft.azure.keyvault.extensions.CachingKeyResolver;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.concurrent.Executor;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+public class CachingKeyResolverTest {
+
+ @SuppressWarnings("unchecked")
+ final ListenableFuture ikeyAsync = mock(ListenableFuture.class);
+ final static String keyId = "https://test.vault.azure.net/keys/keyID/version";
+ final static String keyId2 = "https://test.vault.azure.net/keys/keyID2/version";
+ final static String keyId3 = "https://test.vault.azure.net/keys/keyID3/version";
+ final static String newerKeyId3 = "https://test.vault.azure.net/keys/keyID3/version2";
+ final static String unversionnedKeyId3 = "https://test.vault.azure.net/keys/keyID3";
+
+
+ /*
+ * Tests the capacity limit of CachingKeyResolver by adding more keys
+ * than the cache limit and verifying that least recently used entity is evicted.
+ */
+ @Test
+ public void KeyVault_CapacityLimitOfCachingKeyResolver()
+ {
+ IKeyResolver mockedKeyResolver = mock(IKeyResolver.class);
+ CachingKeyResolver resolver = new CachingKeyResolver(2, mockedKeyResolver);
+
+ when(mockedKeyResolver.resolveKeyAsync(keyId)).thenReturn(ikeyAsync);
+ when(mockedKeyResolver.resolveKeyAsync(keyId2)).thenReturn(ikeyAsync);
+ when(mockedKeyResolver.resolveKeyAsync(keyId3)).thenReturn(ikeyAsync);
+
+ resolver.resolveKeyAsync(keyId);
+ resolver.resolveKeyAsync(keyId2);
+ resolver.resolveKeyAsync(keyId3);
+
+ resolver.resolveKeyAsync(keyId2);
+ resolver.resolveKeyAsync(keyId3);
+ resolver.resolveKeyAsync(keyId);
+ resolver.resolveKeyAsync(keyId3);
+
+ verify(mockedKeyResolver, times(1)).resolveKeyAsync(keyId2);
+ verify(mockedKeyResolver, times(1)).resolveKeyAsync(keyId3);
+ verify(mockedKeyResolver, times(2)).resolveKeyAsync(keyId);
+ }
+
+ /*
+ * Tests the behavior of CachingKeyResolver when resolving key throws
+ * and validate that the failed entity is not added to the cache.
+ */
+ @Test
+ public void KeyVault_CachingKeyResolverThrows()
+ {
+ IKeyResolver mockedKeyResolver = mock(IKeyResolver.class);
+ CachingKeyResolver resolver = new CachingKeyResolver(10, mockedKeyResolver);
+
+ // First throw exception and for the second call return a value
+ when(mockedKeyResolver.resolveKeyAsync(keyId))
+ .thenThrow(new RuntimeException("test"))
+ .thenReturn(ikeyAsync);
+
+ try {
+ resolver.resolveKeyAsync(keyId);
+ fail("Should have thrown an exception.");
+ }
+ catch (UncheckedExecutionException e) {
+ assertTrue("RuntimeException is expected.", e.getCause() instanceof RuntimeException);
+ }
+
+ resolver.resolveKeyAsync(keyId);
+ resolver.resolveKeyAsync(keyId);
+
+ verify(mockedKeyResolver, times(2)).resolveKeyAsync(keyId);
+ }
+
+ /*
+ * Tests that CachingKeyResolver does not cache unversionned keys,
+ * but does cache the result versionned key
+ */
+ @Test
+ public void KeyVault_CachingUnversionnedKey() throws Exception {
+ IKeyResolver mockedKeyResolver = mock(IKeyResolver.class);
+ CachingKeyResolver resolver = new CachingKeyResolver(2, mockedKeyResolver);
+
+ IKey key = mock(IKey.class);
+
+ when(mockedKeyResolver.resolveKeyAsync(unversionnedKeyId3)).thenReturn(ikeyAsync);
+ when(ikeyAsync.get()).thenReturn(key);
+ doAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
+ invocationOnMock.getArgumentAt(0, Runnable.class).run();
+ return null;
+ }
+ }).when(ikeyAsync).addListener(any(Runnable.class), any(Executor.class));
+ when(key.getKid()).thenReturn(keyId3);
+
+ /*
+ * First resolve unversionned key
+ */
+ ListenableFuture result = resolver.resolveKeyAsync(unversionnedKeyId3);
+ assertEquals(result.get().getKid(), keyId3);
+ verify(mockedKeyResolver, times(1)).resolveKeyAsync(unversionnedKeyId3);
+ verify(mockedKeyResolver, times(0)).resolveKeyAsync(keyId3);
+
+ /*
+ * Second resolve unversionned key, but the result should be a newer key
+ */
+ when(key.getKid()).thenReturn(newerKeyId3);
+ result = resolver.resolveKeyAsync(unversionnedKeyId3);
+ assertEquals(result.get().getKid(), newerKeyId3);
+ verify(mockedKeyResolver, times(2)).resolveKeyAsync(unversionnedKeyId3);
+ verify(mockedKeyResolver, times(0)).resolveKeyAsync(keyId3);
+ verify(mockedKeyResolver, times(0)).resolveKeyAsync(newerKeyId3);
+
+ /*
+ * Check that versionned keys were added to the cache, and do not get resolved again
+ */
+ resolver.resolveKeyAsync(keyId3);
+ resolver.resolveKeyAsync(newerKeyId3);
+ verify(mockedKeyResolver, times(0)).resolveKeyAsync(keyId3);
+ verify(mockedKeyResolver, times(0)).resolveKeyAsync(newerKeyId3);
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultClientIntegrationTestBase.java b/keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultClientIntegrationTestBase.java
new file mode 100644
index 000000000000..2e17e5e4bc9c
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultClientIntegrationTestBase.java
@@ -0,0 +1,382 @@
+package com.microsoft.azure.keyvault.extensions.test;
+
+import com.microsoft.aad.adal4j.AuthenticationContext;
+import com.microsoft.aad.adal4j.AuthenticationResult;
+import com.microsoft.aad.adal4j.ClientCredential;
+import com.microsoft.azure.AzureResponseBuilder;
+import com.microsoft.azure.credentials.ApplicationTokenCredentials;
+import com.microsoft.azure.keyvault.KeyVaultClient;
+import com.microsoft.azure.keyvault.authentication.KeyVaultCredentials;
+import com.microsoft.azure.keyvault.models.Attributes;
+import com.microsoft.azure.keyvault.models.DeletedCertificateBundle;
+import com.microsoft.azure.keyvault.models.DeletedKeyBundle;
+import com.microsoft.azure.keyvault.models.DeletedSecretBundle;
+import com.microsoft.azure.management.resources.core.AzureTestCredentials;
+import com.microsoft.azure.management.resources.core.InterceptorManager;
+import com.microsoft.azure.management.resources.core.TestBase;
+import com.microsoft.azure.management.resources.fluentcore.utils.ProviderRegistrationInterceptor;
+import com.microsoft.azure.management.resources.fluentcore.utils.ResourceManagerThrottlingInterceptor;
+import com.microsoft.azure.management.resources.fluentcore.utils.SdkContext;
+import com.microsoft.azure.serializer.AzureJacksonAdapter;
+import com.microsoft.rest.LogLevel;
+import com.microsoft.rest.RestClient;
+import com.microsoft.rest.ServiceClient;
+import com.microsoft.rest.credentials.ServiceClientCredentials;
+import com.microsoft.rest.interceptors.LoggingInterceptor;
+import org.junit.*;
+import org.junit.rules.TestName;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.Properties;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+public class KeyVaultClientIntegrationTestBase {
+
+ private static TestBase.TestMode testMode = null;
+ private PrintStream out;
+
+ protected enum RunCondition {
+ MOCK_ONLY, LIVE_ONLY, BOTH
+ }
+
+ protected static KeyVaultClient keyVaultClient;
+
+ protected final static String ZERO_SUBSCRIPTION = "00000000-0000-0000-0000-000000000000";
+ protected final static String ZERO_TENANT = "00000000-0000-0000-0000-000000000000";
+ private static final String PLAYBACK_URI_BASE = "http://localhost:";
+ protected static String playbackUri = null;
+
+ private final RunCondition runCondition;
+
+ protected KeyVaultClientIntegrationTestBase() {
+ this(RunCondition.BOTH);
+ }
+
+ protected KeyVaultClientIntegrationTestBase(RunCondition runCondition) {
+ this.runCondition = runCondition;
+ }
+
+ /**
+ * Primary vault URI, used for keys and secrets tests.
+ */
+ public static String getVaultUri() {
+ return getLiveVaultUri1();
+ }
+
+ /**
+ * Secondary vault URI, used to verify ability to transparently authenticate
+ * against a different resource.
+ */
+ public static String getSecondaryVaultUri() {
+ return getLiveVaultUri2();
+ }
+
+ private static String getLiveVaultUri1() {
+ return getenvOrDefault("keyvault.vaulturi", "https://javasdktestvault.vault.azure.net");
+ }
+
+ private static String getLiveVaultUri2() {
+ return getenvOrDefault("keyvault.vaulturi.alt", "https://javasdktestvault2.vault.azure.net");
+ }
+
+ private static String getenvOrDefault(String varName, String defValue) {
+ String value = System.getenv(varName);
+ return value != null ? value : defValue;
+ }
+
+ protected static void compareAttributes(Attributes expectedAttributes, Attributes actualAttribute) {
+ if (expectedAttributes != null) {
+ Assert.assertEquals(expectedAttributes.enabled(), actualAttribute.enabled());
+ Assert.assertEquals(expectedAttributes.expires(), actualAttribute.expires());
+ Assert.assertEquals(expectedAttributes.notBefore(), actualAttribute.notBefore());
+ }
+ }
+
+ private static AuthenticationResult getAccessToken(String authorization, String resource) throws Exception {
+
+ String clientId = System.getenv("arm.clientid");
+
+ if (clientId == null) {
+ throw new Exception("Please inform arm.clientid in the environment settings.");
+ }
+
+ String clientKey = System.getenv("arm.clientkey");
+ String username = System.getenv("arm.username");
+ String password = System.getenv("arm.password");
+
+ AuthenticationResult result = null;
+ ExecutorService service = null;
+ try {
+ service = Executors.newFixedThreadPool(1);
+ AuthenticationContext context = new AuthenticationContext(authorization, false, service);
+
+ Future future = null;
+
+ if (clientKey != null && password == null) {
+ ClientCredential credentials = new ClientCredential(clientId, clientKey);
+ future = context.acquireToken(resource, credentials, null);
+ }
+
+ if (password != null && clientKey == null) {
+ future = context.acquireToken(resource, clientId, username, password, null);
+ }
+
+ if (future == null) {
+ throw new Exception(
+ "Missing or ambiguous credentials - please inform exactly one of arm.clientkey or arm.password in the environment settings.");
+ }
+
+ result = future.get();
+ } finally {
+ service.shutdown();
+ }
+
+ if (result == null) {
+ throw new RuntimeException("authentication result was null");
+ }
+ return result;
+ }
+
+ private static ServiceClientCredentials createTestCredentials() throws Exception {
+ return new KeyVaultCredentials() {
+
+ @Override
+ public String doAuthenticate(String authorization, String resource, String scope) {
+ try {
+
+ if (isRecordMode()) {
+ AuthenticationResult authResult = getAccessToken(authorization, resource);
+ return authResult.getAccessToken();
+ } else {
+ return "";
+ }
+
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ };
+ }
+
+ protected void initializeClients(RestClient restClient, String s, String s1) throws IOException {
+ try {
+ RestClient restClientWithTimeout = buildRestClient(new RestClient.Builder()
+ .withBaseUrl("https://{vaultBaseUrl}").withSerializerAdapter(new AzureJacksonAdapter())
+ .withResponseBuilderFactory(new AzureResponseBuilder.Factory())
+ .withCredentials(createTestCredentials()).withLogLevel(LogLevel.BODY_AND_HEADERS)
+ .withNetworkInterceptor(interceptorManager.initInterceptor()));
+ createTestCredentials();
+ keyVaultClient = new KeyVaultClient(restClientWithTimeout);
+
+ // keyVaultClient = new KeyVaultClient(restClient);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static String generateRandomResourceName(String prefix, int maxLen) {
+ return SdkContext.randomResourceName(prefix, maxLen);
+ }
+
+
+ private String shouldCancelTest(boolean isPlaybackMode) {
+ // Determine whether to run the test based on the condition the test has been
+ // configured with
+ switch (this.runCondition) {
+ case MOCK_ONLY:
+ return (!isPlaybackMode) ? "Test configured to run only as mocked, not live." : null;
+ case LIVE_ONLY:
+ return (isPlaybackMode) ? "Test configured to run only as live, not mocked." : null;
+ default:
+ return null;
+ }
+ }
+
+ private static void initTestMode() throws IOException {
+ String azureTestMode = System.getenv("AZURE_TEST_MODE");
+ if (azureTestMode != null) {
+ if (azureTestMode.equalsIgnoreCase("Record")) {
+ testMode = TestBase.TestMode.RECORD;
+ } else if (azureTestMode.equalsIgnoreCase("Playback")) {
+ testMode = TestBase.TestMode.PLAYBACK;
+ } else {
+ throw new IOException("Unknown AZURE_TEST_MODE: " + azureTestMode);
+ }
+ } else {
+ // System.out.print("Environment variable 'AZURE_TEST_MODE' has not been set
+ // yet. Using 'Playback' mode.");
+ testMode = TestBase.TestMode.PLAYBACK;
+ }
+ }
+
+ private static void initPlaybackUri() throws IOException {
+ if (isPlaybackMode()) {
+ Properties mavenProps = new Properties();
+ InputStream in = TestBase.class.getResourceAsStream("/maven.properties");
+ if (in == null) {
+ throw new IOException(
+ "The file \"maven.properties\" has not been generated yet. Please execute \"mvn compile\" to generate the file.");
+ }
+ mavenProps.load(in);
+ String port = mavenProps.getProperty("playbackServerPort");
+ playbackUri = PLAYBACK_URI_BASE + port;
+ } else {
+ playbackUri = PLAYBACK_URI_BASE + "1234";
+ }
+ }
+
+ public static boolean isPlaybackMode() {
+ if (testMode == null)
+ try {
+ initTestMode();
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException("Can't init test mode.");
+ }
+ return testMode == TestBase.TestMode.PLAYBACK;
+ }
+
+ public static boolean isRecordMode() {
+ return !isPlaybackMode();
+ }
+
+ private static void printThreadInfo(String what) {
+ long id = Thread.currentThread().getId();
+ String name = Thread.currentThread().getName();
+ System.out.println(String.format("\n***\n*** [%s:%s] - %s\n***\n", name, id, what));
+ }
+
+ @Rule
+ public TestName testName = new TestName();
+
+ protected InterceptorManager interceptorManager = null;
+
+ @BeforeClass
+ public static void beforeClass() throws IOException {
+ printThreadInfo("beforeclass");
+ initTestMode();
+ initPlaybackUri();
+ }
+
+ @Before
+ public void beforeMethod() throws Exception {
+ printThreadInfo(String.format("%s: %s", "beforeTest", testName.getMethodName()));
+ final String skipMessage = shouldCancelTest(isPlaybackMode());
+ Assume.assumeTrue(skipMessage, skipMessage == null);
+
+ interceptorManager = InterceptorManager.create(testName.getMethodName(), testMode);
+
+ RestClient restClient;
+ String defaultSubscription;
+ ServiceClientCredentials credentials = createTestCredentials();
+
+ if (isRecordMode()) {
+
+ restClient = buildRestClient(new RestClient.Builder().withBaseUrl("https://{vaultBaseUrl}")
+ .withSerializerAdapter(new AzureJacksonAdapter())
+ .withResponseBuilderFactory(new AzureResponseBuilder.Factory()).withCredentials(credentials)
+ .withLogLevel(LogLevel.NONE)
+ .withNetworkInterceptor(new LoggingInterceptor(LogLevel.BODY_AND_HEADERS))
+ .withNetworkInterceptor(interceptorManager.initInterceptor())
+ .withInterceptor(new ResourceManagerThrottlingInterceptor()));
+
+ interceptorManager.addTextReplacementRule("https://management.azure.com/", playbackUri + "/");
+ interceptorManager.addTextReplacementRule("https://graph.windows.net/", playbackUri + "/");
+
+ keyVaultClient = new KeyVaultClient(restClient);
+ } else { // is Playback Mode
+
+ restClient = buildRestClient(new RestClient.Builder().withBaseUrl(playbackUri + "/")
+ .withSerializerAdapter(new AzureJacksonAdapter())
+ .withResponseBuilderFactory(new AzureResponseBuilder.Factory()).withCredentials(credentials)
+ .withLogLevel(LogLevel.NONE)
+ .withNetworkInterceptor(new LoggingInterceptor(LogLevel.BODY_AND_HEADERS))
+ .withNetworkInterceptor(interceptorManager.initInterceptor())
+ .withInterceptor(new ResourceManagerThrottlingInterceptor()));
+ defaultSubscription = ZERO_SUBSCRIPTION;
+
+ out = System.out;
+ System.setOut(new PrintStream(new OutputStream() {
+ public void write(int b) {
+ // DO NOTHING
+ }
+ }));
+
+ keyVaultClient = new KeyVaultClient(restClient);
+ }
+
+ }
+
+ protected static DeletedCertificateBundle pollOnCertificateDeletion(String vaultBaseUrl, String certificateName)
+ throws Exception {
+ int pendingPollCount = 0;
+ while (pendingPollCount < 21) {
+ DeletedCertificateBundle certificateBundle = keyVaultClient.getDeletedCertificate(vaultBaseUrl,
+ certificateName);
+ if (certificateBundle == null) {
+ if (isRecordMode()) {
+ Thread.sleep(10000);
+ }
+ pendingPollCount += 1;
+ continue;
+ } else {
+ return certificateBundle;
+ }
+ }
+ throw new Exception("Deleting certificate delayed");
+ }
+
+ protected static DeletedKeyBundle pollOnKeyDeletion(String vaultBaseUrl, String certificateName) throws Exception {
+ int pendingPollCount = 0;
+ while (pendingPollCount < 21) {
+ DeletedKeyBundle deletedKeyBundle = keyVaultClient.getDeletedKey(vaultBaseUrl, certificateName);
+ if (deletedKeyBundle == null) {
+ if (isRecordMode()) {
+ Thread.sleep(10000);
+ }
+ pendingPollCount += 1;
+ continue;
+ } else {
+ return deletedKeyBundle;
+ }
+ }
+ throw new Exception("Deleting key delayed");
+ }
+
+ protected static DeletedSecretBundle pollOnSecretDeletion(String vaultBaseUrl, String secretName) throws Exception {
+ int pendingPollCount = 0;
+ while (pendingPollCount < 50) {
+ DeletedSecretBundle deletedSecretBundle = keyVaultClient.getDeletedSecret(vaultBaseUrl, secretName);
+ if (deletedSecretBundle == null) {
+ if (isRecordMode()) {
+ Thread.sleep(10000);
+ }
+ pendingPollCount += 1;
+ continue;
+ } else {
+ return deletedSecretBundle;
+ }
+ }
+ throw new Exception("Deleting secret delayed");
+ }
+
+
+ @After
+ public void afterMethod() throws IOException {
+ if (shouldCancelTest(isPlaybackMode()) != null) {
+ return;
+ }
+
+ interceptorManager.finalizeInterceptor();
+ }
+
+ protected RestClient buildRestClient(RestClient.Builder builder) {
+ return builder.build();
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultKeyResolverBCProviderTest.java b/keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultKeyResolverBCProviderTest.java
new file mode 100644
index 000000000000..767ba1615544
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultKeyResolverBCProviderTest.java
@@ -0,0 +1,308 @@
+//
+//Copyright © Microsoft Corporation, All Rights Reserved
+//
+//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
+//
+//THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
+//OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
+//ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A
+//PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT.
+//
+//See the Apache License, Version 2.0 for the specific language
+//governing permissions and limitations under the License.
+
+package com.microsoft.azure.keyvault.extensions.test;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.fail;
+
+import java.security.Provider;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import org.apache.commons.codec.binary.Base64;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.microsoft.azure.keyvault.core.IKey;
+import com.microsoft.azure.keyvault.extensions.KeyVaultKeyResolver;
+import com.microsoft.azure.keyvault.models.KeyBundle;
+import com.microsoft.azure.keyvault.models.SecretBundle;
+import com.microsoft.azure.keyvault.requests.CreateKeyRequest;
+import com.microsoft.azure.keyvault.requests.SetSecretRequest;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyType;
+
+public class KeyVaultKeyResolverBCProviderTest extends KeyVaultClientIntegrationTestBase {
+
+ private Provider _provider = null;
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ try {
+ _provider = (Provider) Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider").newInstance();
+ } catch (ClassNotFoundException ex) {
+ throw new RuntimeException(ex.getMessage());
+ } catch (IllegalAccessException ex) {
+ throw new RuntimeException(ex.getMessage());
+ } catch (InstantiationException ex) {
+ throw new RuntimeException(ex.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ private static final String KEY_NAME = "JavaExtensionKey";
+ private static final String SECRET_NAME = "JavaExtensionSecret";
+
+ private static final Base64 _base64 = new Base64(-1, null, true);
+
+ @Test
+ public void KeyVault_KeyVaultKeyResolver_Key_KeyVaultKeyResolverBCProviderTest() throws InterruptedException, ExecutionException
+ {
+ String TEST_KEY_NAME = KEY_NAME + "1";
+ try {
+ // Create a key on a vault.
+ CreateKeyRequest request = new CreateKeyRequest.Builder(getVaultUri(), TEST_KEY_NAME, JsonWebKeyType.RSA).build();
+ KeyBundle bundle = keyVaultClient.createKey(request);
+
+ if ( bundle != null )
+ {
+ try
+ {
+ // ctor with client
+ KeyVaultKeyResolver resolver = new KeyVaultKeyResolver( keyVaultClient, _provider );
+
+ Future baseKeyFuture = resolver.resolveKeyAsync( bundle.keyIdentifier().baseIdentifier() );
+ Future versionKeyFuture = resolver.resolveKeyAsync( bundle.keyIdentifier().identifier() );
+
+ IKey baseKey = baseKeyFuture.get();
+ IKey versionKey = versionKeyFuture.get();
+
+ Assert.assertEquals( baseKey.getKid(), versionKey.getKid() );
+ }
+ finally
+ {
+ // Delete the key
+ keyVaultClient.deleteKey( getVaultUri(), TEST_KEY_NAME );
+ pollOnKeyDeletion( getVaultUri(), TEST_KEY_NAME );
+ keyVaultClient.purgeDeletedKey( getVaultUri(), TEST_KEY_NAME);
+
+ }
+ }
+ }
+ catch ( Exception ex )
+ {
+ Assert.fail(ex.getMessage());
+ }
+ }
+
+ /*
+ * Test resolving a key from a 128bit secret encoded as base64 in a vault using various KeyVaultKeyResolver constructors.
+ */
+ @Test
+ public void KeyVault_KeyVaultKeyResolver_Secret128Base64_KeyVaultKeyResolverBCProviderTest() throws InterruptedException, ExecutionException
+ {
+ // Arrange
+ byte[] keyBytes = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
+ byte[] EK = { 0x1F, (byte) 0xA6, (byte) 0x8B, 0x0A, (byte) 0x81, 0x12, (byte) 0xB4, 0x47, (byte) 0xAE, (byte) 0xF3, 0x4B, (byte) 0xD8, (byte) 0xFB, 0x5A, 0x7B, (byte) 0x82, (byte) 0x9D, 0x3E, (byte) 0x86, 0x23, 0x71, (byte) 0xD2, (byte) 0xCF, (byte) 0xE5 };
+
+ String TEST_SECRET_NAME = SECRET_NAME + "1";
+ try {
+
+ SetSecretRequest request = new SetSecretRequest.Builder(getVaultUri(), TEST_SECRET_NAME, _base64.encodeAsString(keyBytes)).withContentType("application/octet-stream").build();
+ SecretBundle secretBundle = keyVaultClient.setSecret( request );
+
+ if ( secretBundle != null )
+ {
+ try {
+ // ctor with client
+ KeyVaultKeyResolver resolver = new KeyVaultKeyResolver( keyVaultClient );
+
+ IKey baseKey = resolver.resolveKeyAsync( secretBundle.secretIdentifier().baseIdentifier() ).get();
+ IKey versionKey = resolver.resolveKeyAsync( secretBundle.secretIdentifier().identifier() ).get();
+
+ // Check for correct key identifiers
+ Assert.assertEquals( baseKey.getKid(), versionKey.getKid() );
+
+ // Ensure key operations give the expected results
+ byte[] encrypted = null;
+
+ try {
+ encrypted = baseKey.wrapKeyAsync(CEK, "A128KW").get().getLeft();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(EK, encrypted);
+
+ try {
+ encrypted = versionKey.wrapKeyAsync(CEK, "A128KW").get().getLeft();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(EK, encrypted);
+ }
+ finally
+ {
+ // Delete the secret
+ keyVaultClient.deleteSecret( getVaultUri(), TEST_SECRET_NAME );
+ pollOnSecretDeletion( getVaultUri(), TEST_SECRET_NAME );
+ keyVaultClient.purgeDeletedSecret( getVaultUri(), TEST_SECRET_NAME );
+
+ }
+ }
+ }
+ catch ( Exception ex ) {
+ Assert.fail(ex.getMessage());
+ }
+ }
+
+ /*
+ * Test resolving a key from a 128bit secret encoded as base64 in a vault using various KeyVaultKeyResolver constructors.
+ */
+ @Test
+ public void KeyVault_KeyVaultKeyResolver_Secret192Base64_KeyVaultKeyResolverBCProviderTest() throws InterruptedException, ExecutionException
+ {
+ // Arrange
+ byte[] keyBytes = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
+ byte[] EK = { (byte) 0x96, 0x77, (byte) 0x8B, 0x25, (byte) 0xAE, 0x6C, (byte) 0xA4, 0x35, (byte) 0xF9, 0x2B, 0x5B, (byte) 0x97, (byte) 0xC0, 0x50, (byte) 0xAE, (byte) 0xD2, 0x46, (byte) 0x8A, (byte) 0xB8, (byte) 0xA1, 0x7A, (byte) 0xD8, 0x4E, 0x5D };
+
+ String TEST_SECRET_NAME = SECRET_NAME + "2";
+ try {
+ SetSecretRequest request = new SetSecretRequest.Builder(getVaultUri(), TEST_SECRET_NAME, _base64.encodeAsString(keyBytes)).withContentType("application/octet-stream").build();
+ SecretBundle secretBundle = keyVaultClient.setSecret( request );
+
+ if ( secretBundle != null )
+ {
+ try
+ {
+ // ctor with client
+ KeyVaultKeyResolver resolver = new KeyVaultKeyResolver( keyVaultClient, _provider );
+
+ IKey baseKey = resolver.resolveKeyAsync( secretBundle.secretIdentifier().baseIdentifier() ).get();
+ IKey versionKey = resolver.resolveKeyAsync( secretBundle.secretIdentifier().identifier() ).get();
+
+ // Check for correct key identifiers
+ Assert.assertEquals( baseKey.getKid(), versionKey.getKid() );
+
+ // Ensure key operations give the expected results
+ byte[] encrypted = null;
+
+ try {
+ encrypted = baseKey.wrapKeyAsync(CEK, "A192KW").get().getLeft();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(EK, encrypted);
+
+ try {
+ encrypted = versionKey.wrapKeyAsync(CEK, "A192KW").get().getLeft();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(EK, encrypted);
+ }
+ finally
+ {
+ // Delete the key
+ keyVaultClient.deleteSecret( getVaultUri(), TEST_SECRET_NAME );
+ pollOnSecretDeletion( getVaultUri(), TEST_SECRET_NAME );
+ keyVaultClient.purgeDeletedSecret( getVaultUri(), TEST_SECRET_NAME);
+ }
+ }
+ } catch (Exception ex) {
+ Assert.fail(ex.getMessage());
+ }
+ }
+
+ /*
+ * Test resolving a key from a 256bit secret encoded as base64 in a vault using various KeyVaultKeyResolver constructors.
+ */
+ @Test
+ public void KeyVault_KeyVaultKeyResolver_Secret256Base64_KeyVaultKeyResolverBCProviderTest() throws InterruptedException, ExecutionException
+ {
+ // Arrange
+ byte[] keyBytes = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
+ byte[] EK = { 0x64, (byte) 0xE8, (byte) 0xC3, (byte) 0xF9, (byte) 0xCE, 0x0F, 0x5B, (byte) 0xA2, 0x63, (byte) 0xE9, 0x77, 0x79, 0x05, (byte) 0x81, (byte) 0x8A, 0x2A, (byte) 0x93, (byte) 0xC8, 0x19, 0x1E, 0x7D, 0x6E, (byte) 0x8A, (byte) 0xE7 };
+
+ String TEST_SECRET_NAME = SECRET_NAME + "3";
+
+ try {
+ SetSecretRequest request = new SetSecretRequest.Builder(getVaultUri(), TEST_SECRET_NAME, _base64.encodeAsString(keyBytes)).withContentType("application/octet-stream").build();
+ SecretBundle secretBundle = keyVaultClient.setSecret( request );
+
+ if ( secretBundle != null )
+ {
+ try
+ {
+ // ctor with client
+ KeyVaultKeyResolver resolver = new KeyVaultKeyResolver( keyVaultClient, _provider );
+
+ IKey baseKey = resolver.resolveKeyAsync( secretBundle.secretIdentifier().baseIdentifier() ).get();
+ IKey versionKey = resolver.resolveKeyAsync( secretBundle.secretIdentifier().identifier() ).get();
+
+ // Check for correct key identifiers
+ Assert.assertEquals( baseKey.getKid(), versionKey.getKid() );
+
+ // Ensure key operations give the expected results
+ byte[] encrypted = null;
+
+ try {
+ encrypted = baseKey.wrapKeyAsync(CEK, "A256KW").get().getLeft();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(EK, encrypted);
+
+ try {
+ encrypted = versionKey.wrapKeyAsync(CEK, "A256KW").get().getLeft();
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(EK, encrypted);
+ }
+ finally
+ {
+ // Delete the key
+ keyVaultClient.deleteSecret( getVaultUri(), TEST_SECRET_NAME );
+ pollOnSecretDeletion( getVaultUri(), TEST_SECRET_NAME );
+ keyVaultClient.purgeDeletedSecret( getVaultUri(), TEST_SECRET_NAME );
+ }
+ }
+ } catch ( Exception ex ) {
+ fail(ex.getMessage());
+ }
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultKeyResolverDefaultProviderTest.java b/keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultKeyResolverDefaultProviderTest.java
new file mode 100644
index 000000000000..2df4c05fef71
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultKeyResolverDefaultProviderTest.java
@@ -0,0 +1,332 @@
+package com.microsoft.azure.keyvault.extensions.test;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.fail;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.concurrent.ExecutionException;
+import javax.crypto.Cipher;
+
+import org.apache.commons.codec.binary.Base64;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.microsoft.azure.keyvault.core.IKey;
+import com.microsoft.azure.keyvault.extensions.KeyVaultKeyResolver;
+import com.microsoft.azure.keyvault.models.KeyBundle;
+import com.microsoft.azure.keyvault.models.SecretBundle;
+import com.microsoft.azure.keyvault.requests.CreateKeyRequest;
+import com.microsoft.azure.keyvault.requests.SetSecretRequest;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyType;
+
+//
+//Copyright © Microsoft Corporation, All Rights Reserved
+//
+//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
+//
+//THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
+//OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
+//ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A
+//PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT.
+//
+//See the Apache License, Version 2.0 for the specific language
+//governing permissions and limitations under the License.
+
+public class KeyVaultKeyResolverDefaultProviderTest extends KeyVaultClientIntegrationTestBase {
+
+ private static boolean hasUnlimitedCrypto() {
+ try {
+ return Cipher.getMaxAllowedKeyLength("RC5") >= 256;
+ } catch (NoSuchAlgorithmException e) {
+ return false;
+ }
+ }
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ private static final boolean _unlimited = hasUnlimitedCrypto();
+
+
+ private static final String KEY_NAME = "JavaExtensionKey";
+ private static final String SECRET_NAME = "JavaExtensionSecret";
+
+ private static final Base64 _base64 = new Base64(-1, null, true);
+
+ @Test
+ public void KeyVault_KeyVaultKeyResolver_Key_KeyVaultKeyResolverDefaultProviderTest() throws InterruptedException, ExecutionException
+ {
+ String TEST_KEY_NAME = KEY_NAME + "1";
+ try {
+ // Create a key on a vault.
+ CreateKeyRequest request = new CreateKeyRequest.Builder(getVaultUri(), TEST_KEY_NAME, JsonWebKeyType.RSA).build();
+ KeyBundle keyBundle = keyVaultClient.createKey(request);
+
+ try
+ {
+ // ctor with client
+ final KeyVaultKeyResolver resolver = new KeyVaultKeyResolver( keyVaultClient );
+
+ IKey baseKey = resolver.resolveKeyAsync( keyBundle.keyIdentifier().baseIdentifier() ).get();
+ IKey versionKey = resolver.resolveKeyAsync( keyBundle.keyIdentifier().identifier() ).get();
+
+ Assert.assertEquals( baseKey.getKid(), versionKey.getKid() );
+ }
+ finally
+ {
+ // Delete the key
+ keyVaultClient.deleteKey( getVaultUri(), TEST_KEY_NAME );
+ pollOnKeyDeletion( getVaultUri(), TEST_KEY_NAME );
+ keyVaultClient.purgeDeletedKey( getVaultUri(), TEST_KEY_NAME );
+ }
+ } catch(Exception ex) {
+ fail(ex.getMessage());
+ }
+ }
+
+ /*
+ * Test resolving a key from a 128bit secret encoded as base64 in a vault using various KeyVaultKeyResolver constructors.
+ */
+ @Test
+ public void KeyVault_KeyVaultKeyResolver_Secret128Base64_KeyVaultKeyResolverDefaultProviderTest() throws InterruptedException, ExecutionException
+ {
+ // Arrange
+ byte[] keyBytes = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
+ byte[] EK = { 0x1F, (byte) 0xA6, (byte) 0x8B, 0x0A, (byte) 0x81, 0x12, (byte) 0xB4, 0x47, (byte) 0xAE, (byte) 0xF3, 0x4B, (byte) 0xD8, (byte) 0xFB, 0x5A, 0x7B, (byte) 0x82, (byte) 0x9D, 0x3E, (byte) 0x86, 0x23, 0x71, (byte) 0xD2, (byte) 0xCF, (byte) 0xE5 };
+
+ String TEST_SECRET_NAME = SECRET_NAME + "1";
+
+ try {
+ SetSecretRequest request = new SetSecretRequest.Builder(getVaultUri(), TEST_SECRET_NAME, _base64.encodeAsString(keyBytes)).withContentType("application/octet-stream").build();
+ SecretBundle secretBundle = keyVaultClient.setSecret(request);
+
+ if ( secretBundle != null )
+ {
+ try
+ {
+ // ctor with client
+ KeyVaultKeyResolver resolver = new KeyVaultKeyResolver( keyVaultClient );
+
+ IKey baseKey = resolver.resolveKeyAsync( secretBundle.secretIdentifier().baseIdentifier() ).get();
+ IKey versionKey = resolver.resolveKeyAsync( secretBundle.secretIdentifier().identifier() ).get();
+
+ // Check for correct key identifiers
+ Assert.assertEquals( baseKey.getKid(), versionKey.getKid() );
+
+ // Ensure key operations give the expected results
+ byte[] encrypted = null;
+
+ try {
+ encrypted = baseKey.wrapKeyAsync(CEK, "A128KW").get().getLeft();
+ } catch ( Exception ex ) {
+ fail(ex.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(EK, encrypted);
+
+ try {
+ encrypted = versionKey.wrapKeyAsync(CEK, "A128KW").get().getLeft();
+ } catch ( Exception ex ) {
+ fail(ex.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(EK, encrypted);
+ }
+ finally
+ {
+ // Delete the key
+ keyVaultClient.deleteSecret( getVaultUri(), TEST_SECRET_NAME );
+ pollOnSecretDeletion( getVaultUri(), TEST_SECRET_NAME );
+ keyVaultClient.purgeDeletedSecret( getVaultUri(), TEST_SECRET_NAME );
+ }
+ }
+ } catch ( Exception ex ) {
+ fail(ex.getMessage());
+ }
+ }
+
+ /*
+ * Test resolving a key from a 128bit secret encoded as base64 in a vault using various KeyVaultKeyResolver constructors.
+ */
+ @Test
+ public void KeyVault_KeyVaultKeyResolver_Secret192Base64_KeyVaultKeyResolverDefaultProviderTest() throws InterruptedException, ExecutionException
+ {
+ // Arrange
+ byte[] keyBytes = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
+ byte[] EK = { (byte) 0x96, 0x77, (byte) 0x8B, 0x25, (byte) 0xAE, 0x6C, (byte) 0xA4, 0x35, (byte) 0xF9, 0x2B, 0x5B, (byte) 0x97, (byte) 0xC0, 0x50, (byte) 0xAE, (byte) 0xD2, 0x46, (byte) 0x8A, (byte) 0xB8, (byte) 0xA1, 0x7A, (byte) 0xD8, 0x4E, 0x5D };
+
+ String TEST_SECRET_NAME = SECRET_NAME + "2";
+
+ try {
+ SetSecretRequest request = new SetSecretRequest.Builder(getVaultUri(), TEST_SECRET_NAME, _base64.encodeAsString(keyBytes)).withContentType("application/octet-stream").build();
+ SecretBundle secretBundle = keyVaultClient.setSecret( request );
+
+ if ( secretBundle != null )
+ {
+ try
+ {
+ // ctor with client
+ KeyVaultKeyResolver resolver = new KeyVaultKeyResolver( keyVaultClient );
+
+ IKey baseKey = resolver.resolveKeyAsync( secretBundle.secretIdentifier().baseIdentifier() ).get();
+ IKey versionKey = resolver.resolveKeyAsync( secretBundle.secretIdentifier().identifier() ).get();
+
+ // Check for correct key identifiers
+ Assert.assertEquals( baseKey.getKid(), versionKey.getKid() );
+
+ // Ensure key operations give the expected results
+ byte[] encrypted = null;
+
+ try {
+ encrypted = baseKey.wrapKeyAsync(CEK, "A192KW").get().getLeft();
+
+ if (!_unlimited) fail("Expected ExecutionException");
+ } catch (ExecutionException e) {
+ // In the limited case, the failure should be InvalidKeyException
+ // In the unlimited case, this should not fail
+ if (!_unlimited) {
+ Throwable cause = e.getCause();
+ if (cause == null || !(cause instanceof InvalidKeyException)) fail("ExecutionException");
+ } else {
+ fail("ExecutionException");
+ }
+ } catch ( Exception ex ) {
+ fail(ex.getMessage());
+ }
+
+ if ( _unlimited ) {
+ // Assert
+ assertArrayEquals(EK, encrypted);
+
+ try {
+ encrypted = versionKey.wrapKeyAsync(CEK, "A192KW").get().getLeft();
+ } catch ( Exception ex ) {
+ fail(ex.getMessage());
+ }
+
+ // Assert
+ assertArrayEquals(EK, encrypted);
+ }
+ }
+ finally
+ {
+ // Delete the key
+ keyVaultClient.deleteSecret( getVaultUri(), TEST_SECRET_NAME );
+ pollOnSecretDeletion( getVaultUri(), TEST_SECRET_NAME );
+ keyVaultClient.purgeDeletedSecret( getVaultUri(), TEST_SECRET_NAME );
+ }
+ }
+ } catch ( Exception ex ) {
+ fail(ex.getMessage());
+ }
+ }
+
+ /*
+ * Test resolving a key from a 256bit secret encoded as base64 in a vault using various KeyVaultKeyResolver constructors.
+ */
+ @Test
+ public void KeyVault_KeyVaultKeyResolver_Secret256Base64_KeyVaultKeyResolverDefaultProviderTest() throws InterruptedException, ExecutionException
+ {
+ // Arrange
+ byte[] keyBytes = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };
+ byte[] CEK = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, (byte) 0x88, (byte) 0x99, (byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF };
+ byte[] EK = { 0x64, (byte) 0xE8, (byte) 0xC3, (byte) 0xF9, (byte) 0xCE, 0x0F, 0x5B, (byte) 0xA2, 0x63, (byte) 0xE9, 0x77, 0x79, 0x05, (byte) 0x81, (byte) 0x8A, 0x2A, (byte) 0x93, (byte) 0xC8, 0x19, 0x1E, 0x7D, 0x6E, (byte) 0x8A, (byte) 0xE7 };
+
+ String TEST_SECRET_NAME = SECRET_NAME + "3";
+
+ try {
+ SetSecretRequest request = new SetSecretRequest.Builder(getVaultUri(), TEST_SECRET_NAME, _base64.encodeAsString(keyBytes)).withContentType("application/octet-stream").build();
+ SecretBundle secretBundle = keyVaultClient.setSecret( request );
+
+ if ( secretBundle != null )
+ {
+ try
+ {
+ // ctor with client
+ KeyVaultKeyResolver resolver = new KeyVaultKeyResolver( keyVaultClient );
+
+ IKey baseKey = resolver.resolveKeyAsync( secretBundle.secretIdentifier().baseIdentifier() ).get();
+ IKey versionKey = resolver.resolveKeyAsync( secretBundle.secretIdentifier().identifier() ).get();
+
+ // Check for correct key identifiers
+ Assert.assertEquals( baseKey.getKid(), versionKey.getKid() );
+
+ // Ensure key operations give the expected results
+ byte[] encrypted = null;
+
+ try {
+ encrypted = baseKey.wrapKeyAsync(CEK, "A256KW").get().getLeft();
+
+ if (!_unlimited) fail("Expected ExecutionException");
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+ // In the limited case, the failure should be InvalidKeyException
+ // In the unlimited case, this should not fail
+ if (!_unlimited) {
+ Throwable cause = e.getCause();
+ if (cause == null || !(cause instanceof InvalidKeyException)) fail("ExecutionException");
+ } else {
+ fail("ExecutionException");
+ }
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ if ( _unlimited ) {
+ // Assert
+ assertArrayEquals(EK, encrypted);
+
+ try {
+ encrypted = versionKey.wrapKeyAsync(CEK, "A256KW").get().getLeft();
+ } catch (InterruptedException e) {
+ fail("InterrupedException");
+ } catch (ExecutionException e) {
+ fail("ExecutionException");
+ } catch (NoSuchAlgorithmException e) {
+ fail("NoSuchAlgorithmException");
+ }
+
+ // Assert
+ assertArrayEquals(EK, encrypted);
+ }
+ }
+ finally
+ {
+ // Delete the key
+ keyVaultClient.deleteSecret( getVaultUri(), TEST_SECRET_NAME );
+ pollOnSecretDeletion( getVaultUri(), TEST_SECRET_NAME );
+ keyVaultClient.purgeDeletedSecret( getVaultUri(), TEST_SECRET_NAME );
+ }
+ }
+ } catch ( Exception ex ) {
+ fail(ex.getMessage());
+ }
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Key.json b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Key.json
new file mode 100644
index 000000000000..4ec8238186e3
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Key.json
@@ -0,0 +1,212 @@
+{
+ "networkCallRecords" : [ {
+ "Method" : "POST",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey/create?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:09 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "67881604-5362-4a60-985e-05c14eb0c784",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "POST",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey/create?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:10 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "661",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "73672cfe-a45c-451c-b4d0-6d0ec4e7bc18",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : "{\"key\":{\"kid\":\"https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey/86cee9e27d734d5692f8c0401575675e\",\"kty\":\"RSA\",\"key_ops\":[\"encrypt\",\"decrypt\",\"sign\",\"verify\",\"wrapKey\",\"unwrapKey\"],\"n\":\"sWFPRfq-Z2JFEF_8HZ9j2CwVKHKhOT-3F9tq-R7nwDfZ965Nx4cAkPeQVRd79MiCFs2WS3ar4sWSd2_w35WLwICC0gH650QtczcXX2I5xYOkWLIbokRtQG1WdS5DVdWlSQUewewfbvlUp1Huh5qVeZoYja_Pgboi8k5QsCZt44R9mKX_1BeANZQnzQlvX7klyihF44D7d2lflWa5RZ1bV0S50hS1acnmBnN7pHNwBwhD-XreCJHHe_LlWZg7GwcErPeHNVMCQrJ3_pMGjQVqC8H_HrU745ZVcbiZJP34bX8lixZrtPEKIoK-WLsJM3m7a83G6jc-EIi26VAoukq5iw\",\"e\":\"AQAB\"},\"attributes\":{\"enabled\":true,\"created\":1509124270,\"updated\":1509124270,\"recoveryLevel\":\"Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey/?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:10 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "63ec4b4a-16d7-4348-aae9-0239ac709e0d",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey/?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:10 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "661",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "f37808cf-bd0c-4719-b51b-96f6c94edbe5",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : "{\"key\":{\"kid\":\"https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey/86cee9e27d734d5692f8c0401575675e\",\"kty\":\"RSA\",\"key_ops\":[\"encrypt\",\"decrypt\",\"sign\",\"verify\",\"wrapKey\",\"unwrapKey\"],\"n\":\"sWFPRfq-Z2JFEF_8HZ9j2CwVKHKhOT-3F9tq-R7nwDfZ965Nx4cAkPeQVRd79MiCFs2WS3ar4sWSd2_w35WLwICC0gH650QtczcXX2I5xYOkWLIbokRtQG1WdS5DVdWlSQUewewfbvlUp1Huh5qVeZoYja_Pgboi8k5QsCZt44R9mKX_1BeANZQnzQlvX7klyihF44D7d2lflWa5RZ1bV0S50hS1acnmBnN7pHNwBwhD-XreCJHHe_LlWZg7GwcErPeHNVMCQrJ3_pMGjQVqC8H_HrU745ZVcbiZJP34bX8lixZrtPEKIoK-WLsJM3m7a83G6jc-EIi26VAoukq5iw\",\"e\":\"AQAB\"},\"attributes\":{\"enabled\":true,\"created\":1509124270,\"updated\":1509124270,\"recoveryLevel\":\"Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey/86cee9e27d734d5692f8c0401575675e?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:10 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "2d1edf82-321d-45b2-810a-50e2f2e2b8dd",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey/86cee9e27d734d5692f8c0401575675e?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:10 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "661",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "adff96dc-ddec-4cca-9364-7837426b7eb2",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : "{\"key\":{\"kid\":\"https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey/86cee9e27d734d5692f8c0401575675e\",\"kty\":\"RSA\",\"key_ops\":[\"encrypt\",\"decrypt\",\"sign\",\"verify\",\"wrapKey\",\"unwrapKey\"],\"n\":\"sWFPRfq-Z2JFEF_8HZ9j2CwVKHKhOT-3F9tq-R7nwDfZ965Nx4cAkPeQVRd79MiCFs2WS3ar4sWSd2_w35WLwICC0gH650QtczcXX2I5xYOkWLIbokRtQG1WdS5DVdWlSQUewewfbvlUp1Huh5qVeZoYja_Pgboi8k5QsCZt44R9mKX_1BeANZQnzQlvX7klyihF44D7d2lflWa5RZ1bV0S50hS1acnmBnN7pHNwBwhD-XreCJHHe_LlWZg7GwcErPeHNVMCQrJ3_pMGjQVqC8H_HrU745ZVcbiZJP34bX8lixZrtPEKIoK-WLsJM3m7a83G6jc-EIi26VAoukq5iw\",\"e\":\"AQAB\"},\"attributes\":{\"enabled\":true,\"created\":1509124270,\"updated\":1509124270,\"recoveryLevel\":\"Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:10 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "d1fc532a-d2c0-4ac8-add0-199d3b59cea0",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:10 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "661",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "ba7ee61b-0773-48e5-a158-c16b8115a397",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : "{\"key\":{\"kid\":\"https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey/86cee9e27d734d5692f8c0401575675e\",\"kty\":\"RSA\",\"key_ops\":[\"encrypt\",\"decrypt\",\"sign\",\"verify\",\"wrapKey\",\"unwrapKey\"],\"n\":\"sWFPRfq-Z2JFEF_8HZ9j2CwVKHKhOT-3F9tq-R7nwDfZ965Nx4cAkPeQVRd79MiCFs2WS3ar4sWSd2_w35WLwICC0gH650QtczcXX2I5xYOkWLIbokRtQG1WdS5DVdWlSQUewewfbvlUp1Huh5qVeZoYja_Pgboi8k5QsCZt44R9mKX_1BeANZQnzQlvX7klyihF44D7d2lflWa5RZ1bV0S50hS1acnmBnN7pHNwBwhD-XreCJHHe_LlWZg7GwcErPeHNVMCQrJ3_pMGjQVqC8H_HrU745ZVcbiZJP34bX8lixZrtPEKIoK-WLsJM3m7a83G6jc-EIi26VAoukq5iw\",\"e\":\"AQAB\"},\"attributes\":{\"enabled\":true,\"created\":1509124270,\"updated\":1509124270,\"recoveryLevel\":\"Purgeable\"}}"
+ }
+ } ],
+ "variables" : [ ]
+}
\ No newline at end of file
diff --git a/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Key_KeyVaultKeyResolverBCProviderTest.json b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Key_KeyVaultKeyResolverBCProviderTest.json
new file mode 100644
index 000000000000..7411b42e22e3
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Key_KeyVaultKeyResolverBCProviderTest.json
@@ -0,0 +1,245 @@
+{
+ "networkCallRecords" : [ {
+ "Method" : "POST",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1/create?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:25 GMT",
+ "content-length" : "0",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "b33299d5-0d84-429a-9863-9f71fa653e33",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "POST",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1/create?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:26 GMT",
+ "content-length" : "674",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "3c394856-1f18-486b-8a72-a0e1da379be6",
+ "Body" : "{\"key\":{\"kid\":\"https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1/dccd6ba8014a4ae39ac2f122499c6eca\",\"kty\":\"RSA\",\"key_ops\":[\"encrypt\",\"decrypt\",\"sign\",\"verify\",\"wrapKey\",\"unwrapKey\"],\"n\":\"j1Yl305qd5uKultZ9jitFjj2NaVvElwBOk2qQGX0YeCncznmfAqk5QgwqwgUhDWKt2Ojutud3n-Ptuw8pJ4zY2je119omDo_7X3R1CBD13vqAhReNFLbZuF-pFXCPR0xRz0tQpX8kQeV4Rq5IxMR6id1XoxX7isjbBZmwSesH7inRqkM3vWSkqZkNF0V02g6YUzDajmudzH1zppPlBLXkymECXQOA_GA2LImAaBk35YSDYgeXbCqtCdkCaV4PsyPEmBTis5xM30KDrTxviVCJltM9fut6s8dJstammi4wHodZe0ZNkBu-cCKvX9DbPAvymdG3NFD5ss-nCMWSWcQUQ\",\"e\":\"AQAB\"},\"attributes\":{\"enabled\":true,\"created\":1529962946,\"updated\":1529962946,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1/?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:28 GMT",
+ "content-length" : "674",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "5954b38a-0273-42bf-9517-e511ccf15578",
+ "Body" : "{\"key\":{\"kid\":\"https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1/dccd6ba8014a4ae39ac2f122499c6eca\",\"kty\":\"RSA\",\"key_ops\":[\"encrypt\",\"decrypt\",\"sign\",\"verify\",\"wrapKey\",\"unwrapKey\"],\"n\":\"j1Yl305qd5uKultZ9jitFjj2NaVvElwBOk2qQGX0YeCncznmfAqk5QgwqwgUhDWKt2Ojutud3n-Ptuw8pJ4zY2je119omDo_7X3R1CBD13vqAhReNFLbZuF-pFXCPR0xRz0tQpX8kQeV4Rq5IxMR6id1XoxX7isjbBZmwSesH7inRqkM3vWSkqZkNF0V02g6YUzDajmudzH1zppPlBLXkymECXQOA_GA2LImAaBk35YSDYgeXbCqtCdkCaV4PsyPEmBTis5xM30KDrTxviVCJltM9fut6s8dJstammi4wHodZe0ZNkBu-cCKvX9DbPAvymdG3NFD5ss-nCMWSWcQUQ\",\"e\":\"AQAB\"},\"attributes\":{\"enabled\":true,\"created\":1529962946,\"updated\":1529962946,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1/dccd6ba8014a4ae39ac2f122499c6eca?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:30 GMT",
+ "content-length" : "674",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "0e9d2a1b-1251-403d-8471-87cbb685789c",
+ "Body" : "{\"key\":{\"kid\":\"https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1/dccd6ba8014a4ae39ac2f122499c6eca\",\"kty\":\"RSA\",\"key_ops\":[\"encrypt\",\"decrypt\",\"sign\",\"verify\",\"wrapKey\",\"unwrapKey\"],\"n\":\"j1Yl305qd5uKultZ9jitFjj2NaVvElwBOk2qQGX0YeCncznmfAqk5QgwqwgUhDWKt2Ojutud3n-Ptuw8pJ4zY2je119omDo_7X3R1CBD13vqAhReNFLbZuF-pFXCPR0xRz0tQpX8kQeV4Rq5IxMR6id1XoxX7isjbBZmwSesH7inRqkM3vWSkqZkNF0V02g6YUzDajmudzH1zppPlBLXkymECXQOA_GA2LImAaBk35YSDYgeXbCqtCdkCaV4PsyPEmBTis5xM30KDrTxviVCJltM9fut6s8dJstammi4wHodZe0ZNkBu-cCKvX9DbPAvymdG3NFD5ss-nCMWSWcQUQ\",\"e\":\"AQAB\"},\"attributes\":{\"enabled\":true,\"created\":1529962946,\"updated\":1529962946,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:31 GMT",
+ "content-length" : "823",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "5e445b91-1dbb-4c2c-9236-7020164618cc",
+ "Body" : "{\"recoveryId\":\"https://tifchen-keyvault-fancy.vault.azure.net/deletedkeys/JavaExtensionKey1\",\"deletedDate\":1529962951,\"scheduledPurgeDate\":1537738951,\"key\":{\"kid\":\"https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1/dccd6ba8014a4ae39ac2f122499c6eca\",\"kty\":\"RSA\",\"key_ops\":[\"encrypt\",\"decrypt\",\"sign\",\"verify\",\"wrapKey\",\"unwrapKey\"],\"n\":\"j1Yl305qd5uKultZ9jitFjj2NaVvElwBOk2qQGX0YeCncznmfAqk5QgwqwgUhDWKt2Ojutud3n-Ptuw8pJ4zY2je119omDo_7X3R1CBD13vqAhReNFLbZuF-pFXCPR0xRz0tQpX8kQeV4Rq5IxMR6id1XoxX7isjbBZmwSesH7inRqkM3vWSkqZkNF0V02g6YUzDajmudzH1zppPlBLXkymECXQOA_GA2LImAaBk35YSDYgeXbCqtCdkCaV4PsyPEmBTis5xM30KDrTxviVCJltM9fut6s8dJstammi4wHodZe0ZNkBu-cCKvX9DbPAvymdG3NFD5ss-nCMWSWcQUQ\",\"e\":\"AQAB\"},\"attributes\":{\"enabled\":true,\"created\":1529962946,\"updated\":1529962946,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedkeys/JavaExtensionKey1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:33 GMT",
+ "content-length" : "85",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "404",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "e51c8e1d-2212-4e90-9fea-5c6f8b20d9be",
+ "Body" : "{\"error\":{\"code\":\"KeyNotFound\",\"message\":\"Deleted Key not found: JavaExtensionKey1\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedkeys/JavaExtensionKey1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:44 GMT",
+ "content-length" : "85",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "404",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "5078e4f6-465d-4cb9-ad74-4915df6d855c",
+ "Body" : "{\"error\":{\"code\":\"KeyNotFound\",\"message\":\"Deleted Key not found: JavaExtensionKey1\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedkeys/JavaExtensionKey1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:57 GMT",
+ "content-length" : "823",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "4dc4c494-f0b4-4fe1-8917-cd31d45ff7ff",
+ "Body" : "{\"recoveryId\":\"https://tifchen-keyvault-fancy.vault.azure.net/deletedkeys/JavaExtensionKey1\",\"deletedDate\":1529962951,\"scheduledPurgeDate\":1537738951,\"key\":{\"kid\":\"https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1/dccd6ba8014a4ae39ac2f122499c6eca\",\"kty\":\"RSA\",\"key_ops\":[\"encrypt\",\"decrypt\",\"sign\",\"verify\",\"wrapKey\",\"unwrapKey\"],\"n\":\"j1Yl305qd5uKultZ9jitFjj2NaVvElwBOk2qQGX0YeCncznmfAqk5QgwqwgUhDWKt2Ojutud3n-Ptuw8pJ4zY2je119omDo_7X3R1CBD13vqAhReNFLbZuF-pFXCPR0xRz0tQpX8kQeV4Rq5IxMR6id1XoxX7isjbBZmwSesH7inRqkM3vWSkqZkNF0V02g6YUzDajmudzH1zppPlBLXkymECXQOA_GA2LImAaBk35YSDYgeXbCqtCdkCaV4PsyPEmBTis5xM30KDrTxviVCJltM9fut6s8dJstammi4wHodZe0ZNkBu-cCKvX9DbPAvymdG3NFD5ss-nCMWSWcQUQ\",\"e\":\"AQAB\"},\"attributes\":{\"enabled\":true,\"created\":1529962946,\"updated\":1529962946,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedkeys/JavaExtensionKey1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:58 GMT",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "204",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "8ad5c8a9-cf11-4427-818d-efaa3f2bad05",
+ "Body" : ""
+ }
+ } ],
+ "variables" : [ ]
+}
\ No newline at end of file
diff --git a/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Key_KeyVaultKeyResolverDefaultProviderTest.json b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Key_KeyVaultKeyResolverDefaultProviderTest.json
new file mode 100644
index 000000000000..ffc9a930ff70
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Key_KeyVaultKeyResolverDefaultProviderTest.json
@@ -0,0 +1,218 @@
+{
+ "networkCallRecords" : [ {
+ "Method" : "POST",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1/create?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:22:14 GMT",
+ "content-length" : "0",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "c045ccf2-263b-4be5-bb45-cf61cdf8d191",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "POST",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1/create?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:22:16 GMT",
+ "content-length" : "674",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "3ab77773-2743-4cd4-b573-aa2acbfd05a1",
+ "Body" : "{\"key\":{\"kid\":\"https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1/93d42ad97a7842eb8925c5b4dfbea76e\",\"kty\":\"RSA\",\"key_ops\":[\"encrypt\",\"decrypt\",\"sign\",\"verify\",\"wrapKey\",\"unwrapKey\"],\"n\":\"0l9rjWJoKf-BnGB78pt1q_Qt43e2oEM2wE0zG8VqczMsD6H72iL_RcQZUwgIyJAZAinJQ9cUqbwz21C20rACtaPEi99uVv0cYQUnQK66F8frCrPTH_H2B2mLFk4DJs442FW3GcMt5i8kozs-Kc532g-DSTNPdz2of-MDVtF0wG0bk6V1s0Gs6tRd087goZUCre8eYUC_wc1jsivhN4z9teyHqqJQi7-3jO_PBiaBsc3NaitVMuwg797QOjMO84eO3PQnkYeCA6Jb10SThFMgbH5JXtRZOegptyrzYxPRzyah7OfVsiqHsgLMtJ9LnhLpXtc9nSXlaf20II7MP-7SUw\",\"e\":\"AQAB\"},\"attributes\":{\"enabled\":true,\"created\":1529961736,\"updated\":1529961736,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1/?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:22:18 GMT",
+ "content-length" : "674",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "acbca651-c8ab-47e8-bb2f-04d4d2f1eab5",
+ "Body" : "{\"key\":{\"kid\":\"https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1/93d42ad97a7842eb8925c5b4dfbea76e\",\"kty\":\"RSA\",\"key_ops\":[\"encrypt\",\"decrypt\",\"sign\",\"verify\",\"wrapKey\",\"unwrapKey\"],\"n\":\"0l9rjWJoKf-BnGB78pt1q_Qt43e2oEM2wE0zG8VqczMsD6H72iL_RcQZUwgIyJAZAinJQ9cUqbwz21C20rACtaPEi99uVv0cYQUnQK66F8frCrPTH_H2B2mLFk4DJs442FW3GcMt5i8kozs-Kc532g-DSTNPdz2of-MDVtF0wG0bk6V1s0Gs6tRd087goZUCre8eYUC_wc1jsivhN4z9teyHqqJQi7-3jO_PBiaBsc3NaitVMuwg797QOjMO84eO3PQnkYeCA6Jb10SThFMgbH5JXtRZOegptyrzYxPRzyah7OfVsiqHsgLMtJ9LnhLpXtc9nSXlaf20II7MP-7SUw\",\"e\":\"AQAB\"},\"attributes\":{\"enabled\":true,\"created\":1529961736,\"updated\":1529961736,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1/93d42ad97a7842eb8925c5b4dfbea76e?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:22:19 GMT",
+ "content-length" : "674",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "34697143-5109-4df3-b36e-e8488d0a729f",
+ "Body" : "{\"key\":{\"kid\":\"https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1/93d42ad97a7842eb8925c5b4dfbea76e\",\"kty\":\"RSA\",\"key_ops\":[\"encrypt\",\"decrypt\",\"sign\",\"verify\",\"wrapKey\",\"unwrapKey\"],\"n\":\"0l9rjWJoKf-BnGB78pt1q_Qt43e2oEM2wE0zG8VqczMsD6H72iL_RcQZUwgIyJAZAinJQ9cUqbwz21C20rACtaPEi99uVv0cYQUnQK66F8frCrPTH_H2B2mLFk4DJs442FW3GcMt5i8kozs-Kc532g-DSTNPdz2of-MDVtF0wG0bk6V1s0Gs6tRd087goZUCre8eYUC_wc1jsivhN4z9teyHqqJQi7-3jO_PBiaBsc3NaitVMuwg797QOjMO84eO3PQnkYeCA6Jb10SThFMgbH5JXtRZOegptyrzYxPRzyah7OfVsiqHsgLMtJ9LnhLpXtc9nSXlaf20II7MP-7SUw\",\"e\":\"AQAB\"},\"attributes\":{\"enabled\":true,\"created\":1529961736,\"updated\":1529961736,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:22:19 GMT",
+ "content-length" : "823",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "85fbccc4-89ce-44e2-b631-fc0742d93f56",
+ "Body" : "{\"recoveryId\":\"https://tifchen-keyvault-fancy.vault.azure.net/deletedkeys/JavaExtensionKey1\",\"deletedDate\":1529961739,\"scheduledPurgeDate\":1537737739,\"key\":{\"kid\":\"https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1/93d42ad97a7842eb8925c5b4dfbea76e\",\"kty\":\"RSA\",\"key_ops\":[\"encrypt\",\"decrypt\",\"sign\",\"verify\",\"wrapKey\",\"unwrapKey\"],\"n\":\"0l9rjWJoKf-BnGB78pt1q_Qt43e2oEM2wE0zG8VqczMsD6H72iL_RcQZUwgIyJAZAinJQ9cUqbwz21C20rACtaPEi99uVv0cYQUnQK66F8frCrPTH_H2B2mLFk4DJs442FW3GcMt5i8kozs-Kc532g-DSTNPdz2of-MDVtF0wG0bk6V1s0Gs6tRd087goZUCre8eYUC_wc1jsivhN4z9teyHqqJQi7-3jO_PBiaBsc3NaitVMuwg797QOjMO84eO3PQnkYeCA6Jb10SThFMgbH5JXtRZOegptyrzYxPRzyah7OfVsiqHsgLMtJ9LnhLpXtc9nSXlaf20II7MP-7SUw\",\"e\":\"AQAB\"},\"attributes\":{\"enabled\":true,\"created\":1529961736,\"updated\":1529961736,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedkeys/JavaExtensionKey1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:22:23 GMT",
+ "content-length" : "85",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "404",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "3e663752-1ab5-4824-bb3c-51c46afb30e2",
+ "Body" : "{\"error\":{\"code\":\"KeyNotFound\",\"message\":\"Deleted Key not found: JavaExtensionKey1\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedkeys/JavaExtensionKey1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:22:34 GMT",
+ "content-length" : "823",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "3460e39b-9e11-4133-9477-ce4c7e92410f",
+ "Body" : "{\"recoveryId\":\"https://tifchen-keyvault-fancy.vault.azure.net/deletedkeys/JavaExtensionKey1\",\"deletedDate\":1529961739,\"scheduledPurgeDate\":1537737739,\"key\":{\"kid\":\"https://tifchen-keyvault-fancy.vault.azure.net/keys/JavaExtensionKey1/93d42ad97a7842eb8925c5b4dfbea76e\",\"kty\":\"RSA\",\"key_ops\":[\"encrypt\",\"decrypt\",\"sign\",\"verify\",\"wrapKey\",\"unwrapKey\"],\"n\":\"0l9rjWJoKf-BnGB78pt1q_Qt43e2oEM2wE0zG8VqczMsD6H72iL_RcQZUwgIyJAZAinJQ9cUqbwz21C20rACtaPEi99uVv0cYQUnQK66F8frCrPTH_H2B2mLFk4DJs442FW3GcMt5i8kozs-Kc532g-DSTNPdz2of-MDVtF0wG0bk6V1s0Gs6tRd087goZUCre8eYUC_wc1jsivhN4z9teyHqqJQi7-3jO_PBiaBsc3NaitVMuwg797QOjMO84eO3PQnkYeCA6Jb10SThFMgbH5JXtRZOegptyrzYxPRzyah7OfVsiqHsgLMtJ9LnhLpXtc9nSXlaf20II7MP-7SUw\",\"e\":\"AQAB\"},\"attributes\":{\"enabled\":true,\"created\":1529961736,\"updated\":1529961736,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedkeys/JavaExtensionKey1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:22:35 GMT",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "204",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "4418fde5-e9e7-457a-81af-b33c2acb6c31",
+ "Body" : ""
+ }
+ } ],
+ "variables" : [ ]
+}
\ No newline at end of file
diff --git a/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret128Base64.json b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret128Base64.json
new file mode 100644
index 000000000000..3f97ae80723a
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret128Base64.json
@@ -0,0 +1,212 @@
+{
+ "networkCallRecords" : [ {
+ "Method" : "PUT",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:08 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "7cd993cf-216d-42c4-bb36-7278729d55f9",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "PUT",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:09 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "290",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "d89cdda4-741f-46a8-ae27-db93aa1d5909",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODw\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/73d86a48b2a94f868276007ba620b305\",\"attributes\":{\"enabled\":true,\"created\":1509124269,\"updated\":1509124269,\"recoveryLevel\":\"Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:09 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "3e7ea916-39bf-46b1-8c00-886f309b5e20",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:09 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "290",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "f3e1aacd-ce5e-4b1e-8df1-1406a8d61e1d",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODw\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/73d86a48b2a94f868276007ba620b305\",\"attributes\":{\"enabled\":true,\"created\":1509124269,\"updated\":1509124269,\"recoveryLevel\":\"Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/73d86a48b2a94f868276007ba620b305?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:09 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "8674d079-9a74-4b5a-9d85-86c887731e29",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/73d86a48b2a94f868276007ba620b305?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:09 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "290",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "387f9ad1-c6f0-4c7f-bda0-2a591d9c5004",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODw\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/73d86a48b2a94f868276007ba620b305\",\"attributes\":{\"enabled\":true,\"created\":1509124269,\"updated\":1509124269,\"recoveryLevel\":\"Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:09 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "d3544617-f562-43d7-a381-e91e810626db",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:09 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "257",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "19c91fd9-0c20-4bf9-aa82-02252bdb6913",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : "{\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/73d86a48b2a94f868276007ba620b305\",\"attributes\":{\"enabled\":true,\"created\":1509124269,\"updated\":1509124269,\"recoveryLevel\":\"Purgeable\"}}"
+ }
+ } ],
+ "variables" : [ ]
+}
\ No newline at end of file
diff --git a/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret128Base64_KeyVaultKeyResolverBCProviderTest.json b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret128Base64_KeyVaultKeyResolverBCProviderTest.json
new file mode 100644
index 000000000000..bc2d373201e3
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret128Base64_KeyVaultKeyResolverBCProviderTest.json
@@ -0,0 +1,218 @@
+{
+ "networkCallRecords" : [ {
+ "Method" : "PUT",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:41:41 GMT",
+ "content-length" : "0",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "54df7778-3be6-4420-8ed0-892b94f7f1a4",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "PUT",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:41:43 GMT",
+ "content-length" : "303",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "e6e6b826-232a-4f1f-9ced-d766c5f40563",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODw\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1/b1bdfdb663494a2f8a7594d4aca309f5\",\"attributes\":{\"enabled\":true,\"created\":1529962903,\"updated\":1529962903,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1/?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:41:44 GMT",
+ "content-length" : "303",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "9397cc6f-3fd4-4e7e-8ac3-cbd6510fb284",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODw\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1/b1bdfdb663494a2f8a7594d4aca309f5\",\"attributes\":{\"enabled\":true,\"created\":1529962903,\"updated\":1529962903,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1/b1bdfdb663494a2f8a7594d4aca309f5?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:41:45 GMT",
+ "content-length" : "303",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "49169fdc-b7f6-4dde-8775-9cff28e9903f",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODw\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1/b1bdfdb663494a2f8a7594d4aca309f5\",\"attributes\":{\"enabled\":true,\"created\":1529962903,\"updated\":1529962903,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:41:47 GMT",
+ "content-length" : "425",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "6b11c66b-440d-4582-8f3f-36fce9aba79a",
+ "Body" : "{\"recoveryId\":\"https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret1\",\"deletedDate\":1529962907,\"scheduledPurgeDate\":1537738907,\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1/b1bdfdb663494a2f8a7594d4aca309f5\",\"attributes\":{\"enabled\":true,\"created\":1529962903,\"updated\":1529962903,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:41:47 GMT",
+ "content-length" : "94",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "404",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "27dd6357-1025-4c6f-95f1-3aa5f4382dc2",
+ "Body" : "{\"error\":{\"code\":\"SecretNotFound\",\"message\":\"Deleted Secret not found: JavaExtensionSecret1\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:00 GMT",
+ "content-length" : "425",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "c4842b6d-1abf-440c-8953-d97b5d77ee0e",
+ "Body" : "{\"recoveryId\":\"https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret1\",\"deletedDate\":1529962907,\"scheduledPurgeDate\":1537738907,\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1/b1bdfdb663494a2f8a7594d4aca309f5\",\"attributes\":{\"enabled\":true,\"created\":1529962903,\"updated\":1529962903,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:01 GMT",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "204",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "dc6e5859-4d2c-4a67-896b-421e70026551",
+ "Body" : ""
+ }
+ } ],
+ "variables" : [ ]
+}
\ No newline at end of file
diff --git a/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret128Base64_KeyVaultKeyResolverDefaultProviderTest.json b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret128Base64_KeyVaultKeyResolverDefaultProviderTest.json
new file mode 100644
index 000000000000..c21eda2f67ab
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret128Base64_KeyVaultKeyResolverDefaultProviderTest.json
@@ -0,0 +1,245 @@
+{
+ "networkCallRecords" : [ {
+ "Method" : "PUT",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:21:05 GMT",
+ "content-length" : "0",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "cb1b7f7f-72ee-4642-bec1-b5c8030f042b",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "PUT",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:21:08 GMT",
+ "content-length" : "303",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "8b6bc90f-8930-48e2-96b8-c9a176eed228",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODw\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1/3660edafb1a04204876ed246a3c4514b\",\"attributes\":{\"enabled\":true,\"created\":1529961668,\"updated\":1529961668,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1/?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:21:09 GMT",
+ "content-length" : "303",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "71739e44-356f-4d91-8fd9-8082cac85d19",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODw\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1/3660edafb1a04204876ed246a3c4514b\",\"attributes\":{\"enabled\":true,\"created\":1529961668,\"updated\":1529961668,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1/3660edafb1a04204876ed246a3c4514b?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:21:11 GMT",
+ "content-length" : "303",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "5d62591d-66f3-4be9-b5e5-652a410a299e",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODw\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1/3660edafb1a04204876ed246a3c4514b\",\"attributes\":{\"enabled\":true,\"created\":1529961668,\"updated\":1529961668,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:21:11 GMT",
+ "content-length" : "425",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "b59f0561-bb57-4a4a-8ad4-a4e69d598e76",
+ "Body" : "{\"recoveryId\":\"https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret1\",\"deletedDate\":1529961672,\"scheduledPurgeDate\":1537737672,\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1/3660edafb1a04204876ed246a3c4514b\",\"attributes\":{\"enabled\":true,\"created\":1529961668,\"updated\":1529961668,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:21:12 GMT",
+ "content-length" : "94",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "404",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "1cfffd8b-acd9-476b-8fcb-e639fbf2b078",
+ "Body" : "{\"error\":{\"code\":\"SecretNotFound\",\"message\":\"Deleted Secret not found: JavaExtensionSecret1\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:21:23 GMT",
+ "content-length" : "94",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "404",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "73497dde-2cbb-4188-bb39-2258e4c7e8cb",
+ "Body" : "{\"error\":{\"code\":\"SecretNotFound\",\"message\":\"Deleted Secret not found: JavaExtensionSecret1\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:21:34 GMT",
+ "content-length" : "425",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "5f1232e2-0b99-4ff7-b511-5ea1ee435f7a",
+ "Body" : "{\"recoveryId\":\"https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret1\",\"deletedDate\":1529961672,\"scheduledPurgeDate\":1537737672,\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret1/3660edafb1a04204876ed246a3c4514b\",\"attributes\":{\"enabled\":true,\"created\":1529961668,\"updated\":1529961668,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret1?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:21:37 GMT",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "204",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "019bf790-a06b-454f-8d4c-ddf2f872e943",
+ "Body" : ""
+ }
+ } ],
+ "variables" : [ ]
+}
\ No newline at end of file
diff --git a/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret192Base64.json b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret192Base64.json
new file mode 100644
index 000000000000..3998032740d8
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret192Base64.json
@@ -0,0 +1,212 @@
+{
+ "networkCallRecords" : [ {
+ "Method" : "PUT",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:07 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "8a2b2e25-e12b-47cb-88d1-93bddfdfb2ef",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "PUT",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:07 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "300",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "05a49818-7459-4e4f-8dc0-c15b39aa3ead",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYX\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/2a5319a6aa9442399660ee6cc582445f\",\"attributes\":{\"enabled\":true,\"created\":1509124267,\"updated\":1509124267,\"recoveryLevel\":\"Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:07 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "ce06104c-1b88-43b0-bcc7-5a92e244c82b",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:07 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "300",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "1ef7c500-e316-4169-a5e4-d787c3a38c52",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYX\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/2a5319a6aa9442399660ee6cc582445f\",\"attributes\":{\"enabled\":true,\"created\":1509124267,\"updated\":1509124267,\"recoveryLevel\":\"Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/2a5319a6aa9442399660ee6cc582445f?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:07 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "fdaa3373-8eb8-412c-ba72-def52a428462",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/2a5319a6aa9442399660ee6cc582445f?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:07 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "300",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "a4d06428-6bc2-4573-89bf-a5c477cd0d43",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYX\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/2a5319a6aa9442399660ee6cc582445f\",\"attributes\":{\"enabled\":true,\"created\":1509124267,\"updated\":1509124267,\"recoveryLevel\":\"Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:07 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "32f2e4da-f924-4adb-ac86-f621f0029704",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:08 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "257",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "c7b2e8ab-8bcd-413f-ac30-04fdaec0a052",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : "{\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/2a5319a6aa9442399660ee6cc582445f\",\"attributes\":{\"enabled\":true,\"created\":1509124267,\"updated\":1509124267,\"recoveryLevel\":\"Purgeable\"}}"
+ }
+ } ],
+ "variables" : [ ]
+}
\ No newline at end of file
diff --git a/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret192Base64_KeyVaultKeyResolverBCProviderTest.json b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret192Base64_KeyVaultKeyResolverBCProviderTest.json
new file mode 100644
index 000000000000..e01e72a4754f
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret192Base64_KeyVaultKeyResolverBCProviderTest.json
@@ -0,0 +1,218 @@
+{
+ "networkCallRecords" : [ {
+ "Method" : "PUT",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:58 GMT",
+ "content-length" : "0",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "d4374be8-8f6e-431d-a2f7-43d4a14b21fe",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "PUT",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:59 GMT",
+ "content-length" : "313",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "d47caae8-b82d-4fd0-9aa3-a8adb80b91e9",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYX\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2/b501f89c350e430a81d4efd59c372c91\",\"attributes\":{\"enabled\":true,\"created\":1529962979,\"updated\":1529962979,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2/?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:43:00 GMT",
+ "content-length" : "313",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "9ec8c543-5875-4cf7-a7fd-2fe9af5066b2",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYX\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2/b501f89c350e430a81d4efd59c372c91\",\"attributes\":{\"enabled\":true,\"created\":1529962979,\"updated\":1529962979,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2/b501f89c350e430a81d4efd59c372c91?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:43:03 GMT",
+ "content-length" : "313",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "2b0bbedb-6a9f-4dc3-8306-e56019c8f97c",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYX\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2/b501f89c350e430a81d4efd59c372c91\",\"attributes\":{\"enabled\":true,\"created\":1529962979,\"updated\":1529962979,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:43:04 GMT",
+ "content-length" : "425",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "4380c7a1-1a69-4987-90c9-2b92567d7f8a",
+ "Body" : "{\"recoveryId\":\"https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret2\",\"deletedDate\":1529962984,\"scheduledPurgeDate\":1537738984,\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2/b501f89c350e430a81d4efd59c372c91\",\"attributes\":{\"enabled\":true,\"created\":1529962979,\"updated\":1529962979,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret2?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:43:05 GMT",
+ "content-length" : "94",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "404",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "bccc94ad-d3d1-41d3-90b5-3a2af1c299e5",
+ "Body" : "{\"error\":{\"code\":\"SecretNotFound\",\"message\":\"Deleted Secret not found: JavaExtensionSecret2\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret2?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:43:20 GMT",
+ "content-length" : "425",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "705f16af-2a5b-45e9-96c4-db3dc60016d8",
+ "Body" : "{\"recoveryId\":\"https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret2\",\"deletedDate\":1529962984,\"scheduledPurgeDate\":1537738984,\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2/b501f89c350e430a81d4efd59c372c91\",\"attributes\":{\"enabled\":true,\"created\":1529962979,\"updated\":1529962979,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret2?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:43:21 GMT",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "204",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "b65c2739-f027-4e75-ac8c-f78f8b7c87c3",
+ "Body" : ""
+ }
+ } ],
+ "variables" : [ ]
+}
\ No newline at end of file
diff --git a/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret192Base64_KeyVaultKeyResolverDefaultProviderTest.json b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret192Base64_KeyVaultKeyResolverDefaultProviderTest.json
new file mode 100644
index 000000000000..e5c6aed12a21
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret192Base64_KeyVaultKeyResolverDefaultProviderTest.json
@@ -0,0 +1,218 @@
+{
+ "networkCallRecords" : [ {
+ "Method" : "PUT",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:20:36 GMT",
+ "content-length" : "0",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "62cb3197-e61c-44fb-87a2-b1fcaa0260ed",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "PUT",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:20:40 GMT",
+ "content-length" : "313",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "b5a08ae9-bf3b-46b5-b715-9b20356f7307",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYX\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2/034d5deab8164ffc97ca154f0cd9466e\",\"attributes\":{\"enabled\":true,\"created\":1529961640,\"updated\":1529961640,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2/?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:20:41 GMT",
+ "content-length" : "313",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "291803e2-3257-4d43-a855-ffae71542940",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYX\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2/034d5deab8164ffc97ca154f0cd9466e\",\"attributes\":{\"enabled\":true,\"created\":1529961640,\"updated\":1529961640,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2/034d5deab8164ffc97ca154f0cd9466e?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:20:46 GMT",
+ "content-length" : "313",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "efde48d1-b1bb-4abb-9eff-2a18105d3dae",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYX\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2/034d5deab8164ffc97ca154f0cd9466e\",\"attributes\":{\"enabled\":true,\"created\":1529961640,\"updated\":1529961640,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:20:48 GMT",
+ "content-length" : "425",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "4557a962-740d-4221-9ff5-8f0fa90ae5e5",
+ "Body" : "{\"recoveryId\":\"https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret2\",\"deletedDate\":1529961648,\"scheduledPurgeDate\":1537737648,\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2/034d5deab8164ffc97ca154f0cd9466e\",\"attributes\":{\"enabled\":true,\"created\":1529961640,\"updated\":1529961640,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret2?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:20:50 GMT",
+ "content-length" : "94",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "404",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "d901c334-4cbf-4c39-8706-e7f79ed78e3b",
+ "Body" : "{\"error\":{\"code\":\"SecretNotFound\",\"message\":\"Deleted Secret not found: JavaExtensionSecret2\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret2?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:21:03 GMT",
+ "content-length" : "425",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "b1c9446f-bffa-4028-abe0-e29d6bdadbae",
+ "Body" : "{\"recoveryId\":\"https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret2\",\"deletedDate\":1529961648,\"scheduledPurgeDate\":1537737648,\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret2/034d5deab8164ffc97ca154f0cd9466e\",\"attributes\":{\"enabled\":true,\"created\":1529961640,\"updated\":1529961640,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret2?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:21:04 GMT",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "204",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "c1f5b6ab-e133-4215-956a-2da4f3be09df",
+ "Body" : ""
+ }
+ } ],
+ "variables" : [ ]
+}
\ No newline at end of file
diff --git a/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret256Base64.json b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret256Base64.json
new file mode 100644
index 000000000000..2c09335ae047
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret256Base64.json
@@ -0,0 +1,212 @@
+{
+ "networkCallRecords" : [ {
+ "Method" : "PUT",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:06 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "ed9f4eec-eb23-4128-9ccd-bf0c6312c3d0",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "PUT",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:06 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "311",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "428d5d1f-e6fc-485e-b15b-2747466d15ee",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/a741d540b987426c9649ef1bde017488\",\"attributes\":{\"enabled\":true,\"created\":1509124267,\"updated\":1509124267,\"recoveryLevel\":\"Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:06 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "fc6c54e3-fe73-4d31-b84e-e0fca26050d9",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:06 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "311",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "2edc5dd1-a1bb-4995-b64e-52b370e0c427",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/a741d540b987426c9649ef1bde017488\",\"attributes\":{\"enabled\":true,\"created\":1509124267,\"updated\":1509124267,\"recoveryLevel\":\"Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/a741d540b987426c9649ef1bde017488?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:06 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "7952e0ca-99de-4839-9248-d307d6b102b5",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/a741d540b987426c9649ef1bde017488?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:07 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "311",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "59a41bdd-badd-4f3c-8cd5-783d92f538c1",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/a741d540b987426c9649ef1bde017488\",\"attributes\":{\"enabled\":true,\"created\":1509124267,\"updated\":1509124267,\"recoveryLevel\":\"Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:07 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "b7933819-6a71-47ac-bd2d-713c714e965e",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret?api-version=2016-10-01",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null (KeyVaultClientBase, 2016-10-01)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 27 Oct 2017 17:11:07 GMT",
+ "server" : "Microsoft-IIS/8.5",
+ "content-length" : "257",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-request-id" : "5f590fab-7878-4b51-ac84-e5f3d72e5a69",
+ "x-ms-keyvault-service-version" : "1.0.0.826",
+ "Body" : "{\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret/a741d540b987426c9649ef1bde017488\",\"attributes\":{\"enabled\":true,\"created\":1509124267,\"updated\":1509124267,\"recoveryLevel\":\"Purgeable\"}}"
+ }
+ } ],
+ "variables" : [ ]
+}
\ No newline at end of file
diff --git a/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret256Base64_KeyVaultKeyResolverBCProviderTest.json b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret256Base64_KeyVaultKeyResolverBCProviderTest.json
new file mode 100644
index 000000000000..af284b3c04fc
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret256Base64_KeyVaultKeyResolverBCProviderTest.json
@@ -0,0 +1,218 @@
+{
+ "networkCallRecords" : [ {
+ "Method" : "PUT",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:01 GMT",
+ "content-length" : "0",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "cc5bd3d4-d3ff-4453-a20e-fa49e582a84b",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "PUT",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:03 GMT",
+ "content-length" : "324",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "2a72c49e-5d14-4e46-97fc-62dacb0c9c0f",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3/a94886eb8ad64bef8af8e1fcc0d820ab\",\"attributes\":{\"enabled\":true,\"created\":1529962923,\"updated\":1529962923,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3/?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:06 GMT",
+ "content-length" : "324",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "2277fd77-1acd-4735-84b8-b6ef097c6ac2",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3/a94886eb8ad64bef8af8e1fcc0d820ab\",\"attributes\":{\"enabled\":true,\"created\":1529962923,\"updated\":1529962923,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3/a94886eb8ad64bef8af8e1fcc0d820ab?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:07 GMT",
+ "content-length" : "324",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "d44518f5-ccf1-4e88-9586-4038c1fb1cf4",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3/a94886eb8ad64bef8af8e1fcc0d820ab\",\"attributes\":{\"enabled\":true,\"created\":1529962923,\"updated\":1529962923,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:09 GMT",
+ "content-length" : "425",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "f6e3b359-848e-4cc5-9143-12a6389e9808",
+ "Body" : "{\"recoveryId\":\"https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret3\",\"deletedDate\":1529962929,\"scheduledPurgeDate\":1537738929,\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3/a94886eb8ad64bef8af8e1fcc0d820ab\",\"attributes\":{\"enabled\":true,\"created\":1529962923,\"updated\":1529962923,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret3?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:10 GMT",
+ "content-length" : "94",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "404",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "b391ff5b-fef8-4053-a422-fdbd2f41f7a9",
+ "Body" : "{\"error\":{\"code\":\"SecretNotFound\",\"message\":\"Deleted Secret not found: JavaExtensionSecret3\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret3?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:22 GMT",
+ "content-length" : "425",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "0384cc96-00ef-4404-8de0-04b72ca1b14c",
+ "Body" : "{\"recoveryId\":\"https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret3\",\"deletedDate\":1529962929,\"scheduledPurgeDate\":1537738929,\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3/a94886eb8ad64bef8af8e1fcc0d820ab\",\"attributes\":{\"enabled\":true,\"created\":1529962923,\"updated\":1529962923,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret3?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:42:24 GMT",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "204",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "4212235d-b2eb-4f99-ae79-703da82c16a3",
+ "Body" : ""
+ }
+ } ],
+ "variables" : [ ]
+}
\ No newline at end of file
diff --git a/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret256Base64_KeyVaultKeyResolverDefaultProviderTest.json b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret256Base64_KeyVaultKeyResolverDefaultProviderTest.json
new file mode 100644
index 000000000000..449913aab844
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-extensions/target/test-classes/session-records/KeyVault_KeyVaultKeyResolver_Secret256Base64_KeyVaultKeyResolverDefaultProviderTest.json
@@ -0,0 +1,245 @@
+{
+ "networkCallRecords" : [ {
+ "Method" : "PUT",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:21:37 GMT",
+ "content-length" : "0",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "www-authenticate" : "Bearer authorization=\"https://login.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47\", resource=\"https://vault.azure.net\"",
+ "retry-after" : "0",
+ "StatusCode" : "401",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "515fc45a-5154-4def-bd38-7f5e7e225274",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "PUT",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:21:40 GMT",
+ "content-length" : "324",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "fe666844-bbff-4583-aee4-61d597f7e0f7",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3/ea1deb0012b24eb89a924fe1783751be\",\"attributes\":{\"enabled\":true,\"created\":1529961701,\"updated\":1529961701,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3/?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:21:44 GMT",
+ "content-length" : "324",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "abd49cc7-f213-4c39-984a-8625ead28a4a",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3/ea1deb0012b24eb89a924fe1783751be\",\"attributes\":{\"enabled\":true,\"created\":1529961701,\"updated\":1529961701,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3/ea1deb0012b24eb89a924fe1783751be?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:21:46 GMT",
+ "content-length" : "324",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "53d069d3-6c2f-4fc8-b0e6-fbdbaacbad4b",
+ "Body" : "{\"value\":\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8\",\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3/ea1deb0012b24eb89a924fe1783751be\",\"attributes\":{\"enabled\":true,\"created\":1529961701,\"updated\":1529961701,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:21:47 GMT",
+ "content-length" : "425",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "d406910f-3266-45f2-9913-aa22d4c0ebc2",
+ "Body" : "{\"recoveryId\":\"https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret3\",\"deletedDate\":1529961708,\"scheduledPurgeDate\":1537737708,\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3/ea1deb0012b24eb89a924fe1783751be\",\"attributes\":{\"enabled\":true,\"created\":1529961701,\"updated\":1529961701,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret3?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:21:48 GMT",
+ "content-length" : "94",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "404",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "15c519bc-78e5-40a5-bb8e-de82a9e8416d",
+ "Body" : "{\"error\":{\"code\":\"SecretNotFound\",\"message\":\"Deleted Secret not found: JavaExtensionSecret3\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret3?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:21:59 GMT",
+ "content-length" : "94",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "404",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "9575069d-5da9-492f-bbec-d7e66a695f25",
+ "Body" : "{\"error\":{\"code\":\"SecretNotFound\",\"message\":\"Deleted Secret not found: JavaExtensionSecret3\"}}"
+ }
+ }, {
+ "Method" : "GET",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret3?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:22:11 GMT",
+ "content-length" : "425",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "200",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "content-type" : "application/json; charset=utf-8",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "c3cda06a-f5e3-4ab9-8ac8-7659c73a8c0c",
+ "Body" : "{\"recoveryId\":\"https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret3\",\"deletedDate\":1529961708,\"scheduledPurgeDate\":1537737708,\"contentType\":\"application/octet-stream\",\"id\":\"https://tifchen-keyvault-fancy.vault.azure.net/secrets/JavaExtensionSecret3/ea1deb0012b24eb89a924fe1783751be\",\"attributes\":{\"enabled\":true,\"created\":1529961701,\"updated\":1529961701,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "DELETE",
+ "Uri" : "https://tifchen-keyvault-fancy.vault.azure.net/deletedsecrets/JavaExtensionSecret3?api-version=7.0",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Mon, 25 Jun 2018 21:22:14 GMT",
+ "server" : "Microsoft-IIS/10.0",
+ "expires" : "-1",
+ "x-aspnet-version" : "4.0.30319",
+ "retry-after" : "0",
+ "StatusCode" : "204",
+ "pragma" : "no-cache",
+ "strict-transport-security" : "max-age=31536000;includeSubDomains",
+ "x-content-type-options" : "nosniff",
+ "x-powered-by" : "ASP.NET",
+ "x-ms-keyvault-network-info" : "addr=167.220.1.18;act_addr_fam=InterNetwork;",
+ "x-ms-keyvault-region" : "West US",
+ "cache-control" : "no-cache",
+ "x-ms-keyvault-service-version" : "1.0.0.849",
+ "x-ms-request-id" : "5ea866f5-7130-48ca-b495-8eed855098eb",
+ "Body" : ""
+ }
+ } ],
+ "variables" : [ ]
+}
\ No newline at end of file
diff --git a/keyvault/data-plane/azure-keyvault-webkey/pom.xml b/keyvault/data-plane/azure-keyvault-webkey/pom.xml
new file mode 100644
index 000000000000..19c30eeed8a0
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-webkey/pom.xml
@@ -0,0 +1,128 @@
+
+
+ 4.0.0
+
+ com.microsoft.azure
+ azure-keyvault-parent
+ 1.1.2
+ ../pom.xml
+
+
+ azure-keyvault-webkey
+ 1.1.2
+ jar
+
+ Microsoft Azure SDK for Key Vault WebKey
+ This package contains Microsoft Azure Key Vault WebKey library.
+ https://github.com/Azure/azure-sdk-for-java
+
+
+
+ The MIT License (MIT)
+ http://opensource.org/licenses/MIT
+ repo
+
+
+
+
+ scm:git:https://github.com/Azure/azure-sdk-for-java
+ scm:git:git@github.com:Azure/azure-sdk-for-java.git
+ HEAD
+
+
+
+ UTF-8
+
+
+
+
+
+ microsoft
+ Microsoft
+
+
+
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+
+
+
+
+ commons-codec
+ commons-codec
+
+
+ com.google.guava
+ guava
+
+
+
+
+ junit
+ junit
+ test
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.0.2
+
+
+
+ true
+ true
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+ 1.12
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.1
+
+ 1.7
+ 1.7
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 2.8
+
+ com.microsoft.schemas._2003._10.serialization;
+ /**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */]]>
+
+
+
+
+
diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/Base64UrlJsonDeserializer.java b/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/Base64UrlJsonDeserializer.java
new file mode 100644
index 000000000000..f36de8c23bca
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/Base64UrlJsonDeserializer.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.webkey;
+
+import java.io.IOException;
+
+import org.apache.commons.codec.binary.Base64;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+
+/**
+ * The base64 URL JSON deserializer.
+ */
+public class Base64UrlJsonDeserializer extends JsonDeserializer {
+
+ static final Base64 BASE64 = new Base64(-1, null, true);
+
+ @Override
+ public byte[] deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
+ String text = jp.getText();
+ if (text != null) {
+ return BASE64.decode(text);
+ }
+ return null;
+ }
+
+}
\ No newline at end of file
diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/Base64UrlJsonSerializer.java b/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/Base64UrlJsonSerializer.java
new file mode 100644
index 000000000000..c4b56b7d5a3a
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/Base64UrlJsonSerializer.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.webkey;
+
+import java.io.IOException;
+
+import org.apache.commons.codec.binary.Base64;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+/**
+ * The base64 URL JSON serializer.
+ */
+public class Base64UrlJsonSerializer extends JsonSerializer {
+
+ static final Base64 BASE64 = new Base64(-1, null, true);
+
+ @Override
+ public void serialize(byte[] value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
+ String text;
+ if (value == null) {
+ text = null;
+ } else if (value.length == 0) {
+ text = "";
+ } else {
+ text = BASE64.encodeAsString(value);
+ }
+ jgen.writeString(text);
+ }
+
+}
\ No newline at end of file
diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKey.java b/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKey.java
new file mode 100644
index 000000000000..c7d317a07028
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKey.java
@@ -0,0 +1,1203 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.webkey;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.EllipticCurve;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * As of http://tools.ietf.org/html/draft-ietf-jose-json-web-key-18.
+ */
+@JsonAutoDetect(getterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY, setterVisibility = JsonAutoDetect.Visibility.PUBLIC_ONLY)
+public class JsonWebKey {
+
+ /**
+ * Key Identifier.
+ */
+ @JsonProperty(value = "kid")
+ private String kid;
+
+ /**
+ * JsonWebKey key type (kty). Possible values include: 'EC', 'EC-HSM', 'RSA',
+ * 'RSA-HSM', 'oct'.
+ */
+ @JsonProperty(value = "kty")
+ private JsonWebKeyType kty;
+
+ /**
+ * The keyOps property.
+ */
+ @JsonProperty(value = "key_ops")
+ private List keyOps;
+
+ /**
+ * RSA modulus.
+ */
+ @JsonProperty(value = "n")
+ private byte[] n;
+
+ /**
+ * RSA public exponent.
+ */
+ @JsonProperty(value = "e")
+ private byte[] e;
+
+ /**
+ * RSA private exponent, or the D component of an EC private key.
+ */
+ @JsonProperty(value = "d")
+ private byte[] d;
+
+ /**
+ * RSA Private Key Parameter.
+ */
+ @JsonProperty(value = "dp")
+ private byte[] dp;
+
+ /**
+ * RSA Private Key Parameter.
+ */
+ @JsonProperty(value = "dq")
+ private byte[] dq;
+
+ /**
+ * RSA Private Key Parameter.
+ */
+ @JsonProperty(value = "qi")
+ private byte[] qi;
+
+ /**
+ * RSA secret prime.
+ */
+ @JsonProperty(value = "p")
+ private byte[] p;
+
+ /**
+ * RSA secret prime, with p & q.
+ */
+ @JsonProperty(value = "q")
+ private byte[] q;
+
+ /**
+ * Symmetric key.
+ */
+ @JsonProperty(value = "k")
+ private byte[] k;
+
+ /**
+ * HSM Token, used with Bring Your Own Key.
+ */
+ @JsonProperty(value = "key_hsm")
+ private byte[] t;
+
+ /**
+ * Elliptic curve name. For valid values, see JsonWebKeyCurveName. Possible
+ * values include: 'P-256', 'P-384', 'P-521', 'SECP256K1'.
+ */
+ @JsonProperty(value = "crv")
+ private JsonWebKeyCurveName crv;
+
+ /**
+ * X component of an EC public key.
+ */
+ @JsonProperty(value = "x")
+ private byte[] x;
+
+ /**
+ * Y component of an EC public key.
+ */
+ @JsonProperty(value = "y")
+ private byte[] y;
+
+ /**
+ * Get the kid value.
+ *
+ * @return the kid value
+ */
+ @JsonProperty("kid")
+ public String kid() {
+ return this.kid;
+ }
+
+ /**
+ * Set the key identifier value.
+ *
+ * @param kid
+ * the kid value to set
+ * @return the JsonWebKey object itself.
+ */
+ public JsonWebKey withKid(String kid) {
+ this.kid = kid;
+ return this;
+ }
+
+ /**
+ * Get the kty value.
+ *
+ * @return the kty value
+ */
+ @JsonProperty("kty")
+ public JsonWebKeyType kty() {
+ return this.kty;
+ }
+
+ /**
+ * Set the key type value.
+ *
+ * @param kty
+ * the key type
+ * @return the JsonWebKey object itself.
+ */
+ public JsonWebKey withKty(JsonWebKeyType kty) {
+ this.kty = kty;
+ return this;
+ }
+
+ /**
+ * Get the keyOps value.
+ *
+ * @return the keyOps value
+ */
+ @JsonProperty("key_ops")
+ public List keyOps() {
+ return this.keyOps;
+ }
+
+ /**
+ * Set the keyOps value.
+ *
+ * @param keyOps
+ * the keyOps value to set
+ * @return the JsonWebKey object itself.
+ */
+ public JsonWebKey withKeyOps(List keyOps) {
+ this.keyOps = keyOps;
+ return this;
+ }
+
+ /**
+ * Get the n value.
+ *
+ * @return the n value
+ */
+ @JsonProperty("n")
+ @JsonSerialize(using = Base64UrlJsonSerializer.class)
+ @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
+ public byte[] n() {
+ return this.n;
+ }
+
+ /**
+ * Set the n value.
+ *
+ * @param n
+ * the n value to set
+ * @return the JsonWebKey object itself.
+ */
+ public JsonWebKey withN(byte[] n) {
+ this.n = n;
+ return this;
+ }
+
+ /**
+ * Get the e value.
+ *
+ * @return the e value
+ */
+ @JsonProperty("e")
+ @JsonSerialize(using = Base64UrlJsonSerializer.class)
+ @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
+ public byte[] e() {
+ return this.e;
+ }
+
+ /**
+ * Set the e value.
+ *
+ * @param e
+ * the e value to set
+ * @return the JsonWebKey object itself.
+ */
+ public JsonWebKey withE(byte[] e) {
+ this.e = e;
+ return this;
+ }
+
+ /**
+ * Get the d value.
+ *
+ * @return the d value
+ */
+ @JsonProperty("d")
+ @JsonSerialize(using = Base64UrlJsonSerializer.class)
+ @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
+ public byte[] d() {
+ return this.d;
+ }
+
+ /**
+ * Set the d value.
+ *
+ * @param d
+ * the d value to set
+ * @return the JsonWebKey object itself.
+ */
+ public JsonWebKey withD(byte[] d) {
+ this.d = d;
+ return this;
+ }
+
+ /**
+ * Get the RSA Private Key Parameter value.
+ *
+ * @return the RSA Private Key Parameter value.
+ */
+ @JsonProperty("dp")
+ @JsonSerialize(using = Base64UrlJsonSerializer.class)
+ @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
+ public byte[] dp() {
+ return this.dp;
+ }
+
+ /**
+ * Set RSA Private Key Parameter value.
+ *
+ * @param dp
+ * the RSA Private Key Parameter value to set.
+ * @return the JsonWebKey object itself.
+ */
+ public JsonWebKey withDp(byte[] dp) {
+ this.dp = dp;
+ return this;
+ }
+
+ /**
+ * Get the RSA Private Key Parameter value.
+ *
+ * @return the RSA Private Key Parameter value.
+ */
+ @JsonProperty("dq")
+ @JsonSerialize(using = Base64UrlJsonSerializer.class)
+ @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
+ public byte[] dq() {
+ return this.dq;
+ }
+
+ /**
+ * Set RSA Private Key Parameter value .
+ *
+ * @param dq
+ * the RSA Private Key Parameter value to set.
+ * @return the JsonWebKey object itself.
+ */
+ public JsonWebKey withDq(byte[] dq) {
+ this.dq = dq;
+ return this;
+ }
+
+ /**
+ * Get the RSA Private Key Parameter value.
+ *
+ * @return the RSA Private Key Parameter value.
+ */
+ @JsonProperty("qi")
+ @JsonSerialize(using = Base64UrlJsonSerializer.class)
+ @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
+ public byte[] qi() {
+ return this.qi;
+ }
+
+ /**
+ * Set RSA Private Key Parameter value.
+ *
+ * @param qi
+ * the RSA Private Key Parameter value to set.
+ * @return the JsonWebKey object itself.
+ */
+ public JsonWebKey withQi(byte[] qi) {
+ this.qi = qi;
+ return this;
+ }
+
+ /**
+ * Get the RSA secret prime value.
+ *
+ * @return the RSA secret prime value.
+ */
+ @JsonProperty("p")
+ @JsonSerialize(using = Base64UrlJsonSerializer.class)
+ @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
+ public byte[] p() {
+ return this.p;
+ }
+
+ /**
+ * Set the RSA secret prime value.
+ *
+ * @param p
+ * the RSA secret prime value.
+ * @return the JsonWebKey object itself.
+ */
+ public JsonWebKey withP(byte[] p) {
+ this.p = p;
+ return this;
+ }
+
+ /**
+ * Get RSA secret prime, with p < q value.
+ *
+ * @return the RSA secret prime, with p < q value.
+ */
+ @JsonProperty("q")
+ @JsonSerialize(using = Base64UrlJsonSerializer.class)
+ @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
+ public byte[] q() {
+ return this.q;
+ }
+
+ /**
+ * Set the RSA secret prime, with p < q value.
+ *
+ * @param q
+ * the the RSA secret prime, with p < q value to be set.
+ * @return the JsonWebKey object itself.
+ */
+ public JsonWebKey withQ(byte[] q) {
+ this.q = q;
+ return this;
+ }
+
+ /**
+ * Get Symmetric key value.
+ *
+ * @return the symmetric key value.
+ */
+ @JsonProperty("k")
+ @JsonSerialize(using = Base64UrlJsonSerializer.class)
+ @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
+ public byte[] k() {
+ return this.k;
+ }
+
+ /**
+ * Set the Symmetric key value.
+ *
+ * @param k
+ * the symmetric key value to set.
+ * @return the JsonWebKey object itself.
+ */
+ public JsonWebKey withK(byte[] k) {
+ this.k = k;
+ return this;
+ }
+
+ /**
+ * Get HSM Token value, used with Bring Your Own Key.
+ *
+ * @return HSM Token, used with Bring Your Own Key.
+ */
+ @JsonProperty("key_hsm")
+ @JsonSerialize(using = Base64UrlJsonSerializer.class)
+ @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
+ public byte[] t() {
+ return this.t;
+ }
+
+ /**
+ * Set HSM Token value, used with Bring Your Own Key.
+ *
+ * @param t
+ * HSM Token value to set, used with Bring Your Own Key
+ * @return the JsonWebKey object itself.
+ */
+ public JsonWebKey withT(byte[] t) {
+ this.t = t;
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ ObjectMapper mapper = new ObjectMapper();
+ try {
+ return mapper.writeValueAsString(this);
+ } catch (JsonGenerationException e) {
+ throw new IllegalStateException(e);
+ } catch (JsonMappingException e) {
+ throw new IllegalStateException(e);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Get the crv value.
+ *
+ * @return the crv value
+ */
+ @JsonProperty("crv")
+ public JsonWebKeyCurveName crv() {
+ return this.crv;
+ }
+
+ /**
+ * Set the crv value.
+ *
+ * @param crv
+ * the crv value to set
+ * @return the JsonWebKey object itself.
+ */
+ public JsonWebKey withCrv(JsonWebKeyCurveName crv) {
+ this.crv = crv;
+ return this;
+ }
+
+ /**
+ * Get the x value.
+ *
+ * @return the x value
+ */
+ @JsonProperty("x")
+ @JsonSerialize(using = Base64UrlJsonSerializer.class)
+ @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
+ public byte[] x() {
+ return this.x;
+ }
+
+ /**
+ * Set the x value.
+ *
+ * @param x
+ * the x value to set
+ * @return the JsonWebKey object itself.
+ */
+ public JsonWebKey withX(byte[] x) {
+ this.x = x;
+ return this;
+ }
+
+ /**
+ * Get the y value.
+ *
+ * @return the y value
+ */
+ @JsonProperty("y")
+ @JsonSerialize(using = Base64UrlJsonSerializer.class)
+ @JsonDeserialize(using = Base64UrlJsonDeserializer.class)
+ public byte[] y() {
+ return this.y;
+ }
+
+ /**
+ * Set the y value.
+ *
+ * @param y
+ * the y value to set
+ * @return the JsonWebKey object itself.
+ */
+ public JsonWebKey withY(byte[] y) {
+ this.y = y;
+ return this;
+ }
+
+ /**
+ * Get the RSA public key spec value.
+ *
+ * @return the RSA public key spec value
+ */
+ private RSAPublicKeySpec getRSAPublicKeySpec() {
+
+ return new RSAPublicKeySpec(toBigInteger(n), toBigInteger(e));
+ }
+
+ /**
+ * Get the RSA private key spec value.
+ *
+ * @return the RSA private key spec value
+ */
+ private RSAPrivateKeySpec getRSAPrivateKeySpec() {
+
+ return new RSAPrivateCrtKeySpec(toBigInteger(n), toBigInteger(e), toBigInteger(d), toBigInteger(p),
+ toBigInteger(q), toBigInteger(dp), toBigInteger(dq), toBigInteger(qi));
+ }
+
+ /**
+ * Get the RSA public key value.
+ *
+ * @param provider
+ * the Java security provider.
+ * @return the RSA public key value
+ */
+ private PublicKey getRSAPublicKey(Provider provider) {
+
+ try {
+ RSAPublicKeySpec publicKeySpec = getRSAPublicKeySpec();
+ KeyFactory factory = provider != null ? KeyFactory.getInstance("RSA", provider)
+ : KeyFactory.getInstance("RSA");
+
+ return factory.generatePublic(publicKeySpec);
+ } catch (GeneralSecurityException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Get the RSA private key value.
+ *
+ * @param provider
+ * the Java security provider.
+ * @return the RSA private key value
+ */
+ private PrivateKey getRSAPrivateKey(Provider provider) {
+
+ try {
+ RSAPrivateKeySpec privateKeySpec = getRSAPrivateKeySpec();
+ KeyFactory factory = provider != null ? KeyFactory.getInstance("RSA", provider)
+ : KeyFactory.getInstance("RSA");
+
+ return factory.generatePrivate(privateKeySpec);
+ } catch (GeneralSecurityException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private static PublicKey getECPublicKey(ECPoint ecPoint, ECParameterSpec curveSpec, Provider provider) {
+ // Create public key spec with given point
+ try {
+ ECPublicKeySpec pubSpec = new ECPublicKeySpec(ecPoint, curveSpec);
+ KeyFactory kf = provider != null ? KeyFactory.getInstance("EC", provider)
+ : KeyFactory.getInstance("EC", "SunEC");
+ return (ECPublicKey) kf.generatePublic(pubSpec);
+ } catch (GeneralSecurityException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private static PrivateKey getECPrivateKey(byte[] d, ECParameterSpec curveSpec, Provider provider) {
+ try {
+ ECPrivateKeySpec priSpec = new ECPrivateKeySpec(new BigInteger(1, d), curveSpec);
+ KeyFactory kf = provider != null ? KeyFactory.getInstance("EC", provider)
+ : KeyFactory.getInstance("EC", "SunEC");
+ return (ECPrivateKey) kf.generatePrivate(priSpec);
+ } catch (GeneralSecurityException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Verifies if the key is an RSA key.
+ */
+ private void checkRSACompatible() {
+ if (!JsonWebKeyType.RSA.equals(kty) && !JsonWebKeyType.RSA_HSM.equals(kty)) {
+ throw new UnsupportedOperationException("Not an RSA key");
+ }
+ }
+
+ private static byte[] toByteArray(BigInteger n) {
+ byte[] result = n.toByteArray();
+ if (result[0] == 0) {
+ // The leading zero is used to let the number positive. Since RSA
+ // parameters are always positive, we remove it.
+ return Arrays.copyOfRange(result, 1, result.length);
+ }
+ return result;
+ }
+
+ private static BigInteger toBigInteger(byte[] b) {
+ if (b[0] < 0) {
+ // RSA parameters are always positive numbers, so if the first byte
+ // is negative, we need to add a leading zero
+ // to make the entire BigInteger positive.
+ byte[] temp = new byte[1 + b.length];
+ System.arraycopy(b, 0, temp, 1, b.length);
+ b = temp;
+ }
+ return new BigInteger(b);
+ }
+
+ /**
+ * Converts RSA key pair to JSON web key.
+ *
+ * @param keyPair
+ * RSA key pair
+ * @return the JSON web key, converted from RSA key pair.
+ */
+ public static JsonWebKey fromRSA(KeyPair keyPair) {
+
+ RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) keyPair.getPrivate();
+ JsonWebKey key = null;
+
+ if (privateKey != null) {
+
+ key = new JsonWebKey().withKty(JsonWebKeyType.RSA).withN(toByteArray(privateKey.getModulus()))
+ .withE(toByteArray(privateKey.getPublicExponent()))
+ .withD(toByteArray(privateKey.getPrivateExponent())).withP(toByteArray(privateKey.getPrimeP()))
+ .withQ(toByteArray(privateKey.getPrimeQ())).withDp(toByteArray(privateKey.getPrimeExponentP()))
+ .withDq(toByteArray(privateKey.getPrimeExponentQ()))
+ .withQi(toByteArray(privateKey.getCrtCoefficient()));
+ } else {
+
+ RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
+
+ key = new JsonWebKey().withKty(JsonWebKeyType.RSA).withN(toByteArray(publicKey.getModulus()))
+ .withE(toByteArray(publicKey.getPublicExponent())).withD(null).withP(null).withQ(null).withDp(null)
+ .withDq(null).withQi(null);
+ }
+
+ return key;
+ }
+
+ /**
+ * Converts JSON web key to RSA key pair.
+ *
+ * @return RSA key pair
+ */
+ public KeyPair toRSA() {
+ return this.toRSA(false);
+ }
+
+ /**
+ * Converts JSON web key to RSA key pair and include the private key if set to
+ * true.
+ *
+ * @param includePrivateParameters
+ * true if the RSA key pair should include the private key. False
+ * otherwise.
+ * @return RSA key pair
+ */
+ public KeyPair toRSA(boolean includePrivateParameters) {
+ return toRSA(includePrivateParameters, null);
+ }
+
+ /**
+ * Converts JSON web key to RSA key pair and include the private key if set to
+ * true.
+ *
+ * @param provider
+ * the Java security provider.
+ * @param includePrivateParameters
+ * true if the RSA key pair should include the private key. False
+ * otherwise.
+ * @return RSA key pair
+ */
+ public KeyPair toRSA(boolean includePrivateParameters, Provider provider) {
+
+ // Must be RSA
+ checkRSACompatible();
+
+ if (includePrivateParameters) {
+ return new KeyPair(getRSAPublicKey(provider), getRSAPrivateKey(provider));
+ } else {
+ return new KeyPair(getRSAPublicKey(provider), null);
+ }
+ }
+
+ /**
+ * Converts JSON web key to EC key pair and include the private key if set to
+ * true.
+ *
+ * @return EC key pair
+ */
+ public KeyPair toEC() {
+ return toEC(false, null);
+ }
+
+ /**
+ * Converts JSON web key to EC key pair and include the private key if set to
+ * true.
+ *
+ * @param includePrivateParameters
+ * true if the EC key pair should include the private key. False
+ * otherwise.
+ * @return EC key pair
+ */
+ public KeyPair toEC(boolean includePrivateParameters) {
+ return toEC(includePrivateParameters, null);
+ }
+
+ /**
+ * Converts JSON web key to EC key pair and include the private key if set to
+ * true.
+ *
+ * @param includePrivateParameters
+ * true if the EC key pair should include the private key. False
+ * otherwise.
+ * @param provider
+ * Java security provider
+ * @return EC key pair
+ */
+ public KeyPair toEC(boolean includePrivateParameters, Provider provider) {
+
+ if (provider == null) {
+ // Our default provider for this class
+ provider = Security.getProvider("SunEC");
+ }
+
+ if (!JsonWebKeyType.EC.equals(kty) && !JsonWebKeyType.EC_HSM.equals(kty)) {
+ throw new IllegalArgumentException("Not an EC key.");
+ }
+
+ try {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", provider);
+
+ ECGenParameterSpec gps = new ECGenParameterSpec(CURVE_TO_SPEC_NAME.get(crv));
+ kpg.initialize(gps);
+
+ // Generate dummy keypair to get parameter spec.
+ KeyPair apair = kpg.generateKeyPair();
+ ECPublicKey apub = (ECPublicKey) apair.getPublic();
+ ECParameterSpec aspec = apub.getParams();
+
+ ECPoint ecPoint = new ECPoint(new BigInteger(1, x), new BigInteger(1, y));
+
+ KeyPair realKeyPair;
+
+ if (includePrivateParameters) {
+ realKeyPair = new KeyPair(getECPublicKey(ecPoint, aspec, provider),
+ getECPrivateKey(d, aspec, provider));
+ } else {
+ realKeyPair = new KeyPair(getECPublicKey(ecPoint, aspec, provider), null);
+ }
+
+ return realKeyPair;
+ } catch (GeneralSecurityException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Converts EC key pair to JSON web key.
+ *
+ * @param keyPair
+ * EC key pair
+ * @param provider
+ * Java security provider
+ * @return the JSON web key, converted from EC key pair.
+ */
+ public static JsonWebKey fromEC(KeyPair keyPair, Provider provider) {
+
+ ECPublicKey apub = (ECPublicKey) keyPair.getPublic();
+ ECPoint point = apub.getW();
+ ECPrivateKey apriv = (ECPrivateKey) keyPair.getPrivate();
+
+ if (apriv != null) {
+ return new JsonWebKey().withKty(JsonWebKeyType.EC).withCrv(getCurveFromKeyPair(keyPair, provider))
+ .withX(point.getAffineX().toByteArray()).withY(point.getAffineY().toByteArray())
+ .withD(apriv.getS().toByteArray()).withKty(JsonWebKeyType.EC);
+ } else {
+ return new JsonWebKey().withKty(JsonWebKeyType.EC).withCrv(getCurveFromKeyPair(keyPair, provider))
+ .withX(point.getAffineX().toByteArray()).withY(point.getAffineY().toByteArray())
+ .withKty(JsonWebKeyType.EC);
+ }
+ }
+
+ // Matches the curve of the keyPair to supported curves.
+ private static JsonWebKeyCurveName getCurveFromKeyPair(KeyPair keyPair, Provider provider) {
+
+ try {
+ ECPublicKey key = (ECPublicKey) keyPair.getPublic();
+ ECParameterSpec spec = key.getParams();
+ EllipticCurve crv = spec.getCurve();
+
+ List curveList = Arrays.asList(JsonWebKeyCurveName.P_256, JsonWebKeyCurveName.P_384,
+ JsonWebKeyCurveName.P_521, JsonWebKeyCurveName.P_256K);
+
+ for (JsonWebKeyCurveName curve : curveList) {
+ ECGenParameterSpec gps = new ECGenParameterSpec(CURVE_TO_SPEC_NAME.get(curve));
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", provider);
+ kpg.initialize(gps);
+
+ // Generate dummy keypair to get parameter spec.
+ KeyPair apair = kpg.generateKeyPair();
+ ECPublicKey apub = (ECPublicKey) apair.getPublic();
+ ECParameterSpec aspec = apub.getParams();
+ EllipticCurve acurve = aspec.getCurve();
+
+ // Matches the parameter spec
+ if (acurve.equals(crv)) {
+ return curve;
+ }
+ }
+
+ // Did not find a supported curve.
+ throw new NoSuchAlgorithmException("Curve not supported.");
+ } catch (GeneralSecurityException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Converts AES key to JSON web key.
+ *
+ * @param secretKey
+ * AES key
+ * @return the JSON web key, converted from AES key.
+ */
+ public static JsonWebKey fromAes(SecretKey secretKey) {
+ if (secretKey == null) {
+ return null;
+ }
+
+ return new JsonWebKey().withK(secretKey.getEncoded()).withKty(JsonWebKeyType.OCT);
+ }
+
+ /**
+ * Converts JSON web key to AES key.
+ *
+ * @return AES key
+ */
+ public SecretKey toAes() {
+ if (k == null) {
+ return null;
+ }
+
+ SecretKey secretKey = new SecretKeySpec(k, "AES");
+ return secretKey;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof JsonWebKey) {
+ return this.equals((JsonWebKey) obj);
+ }
+ return super.equals(obj);
+ }
+
+ /**
+ * Indicates whether some other {@link JsonWebKey} is "equal to" this one.
+ *
+ * @param jwk
+ * the other {@link JsonWebKey} to compare with.
+ * @return true if this {@link JsonWebKey} is the same as the jwk argument;
+ * false otherwise.
+ */
+ public boolean equals(JsonWebKey jwk) {
+ if (jwk == null) {
+ return false;
+ }
+
+ if (!Objects.equal(kid, jwk.kid)) {
+ return false;
+ }
+
+ if (!Objects.equal(kty, jwk.kty)) {
+ return false;
+ }
+
+ if (!Objects.equal(keyOps, jwk.keyOps)) {
+ return false;
+ }
+
+ if (!Objects.equal(crv, jwk.crv)) {
+ return false;
+ }
+
+ if (!Arrays.equals(k, jwk.k)) {
+ return false;
+ }
+
+ // Public parameters
+ if (!Arrays.equals(n, jwk.n)) {
+ return false;
+ }
+ if (!Arrays.equals(e, jwk.e)) {
+ return false;
+ }
+
+ // Private parameters
+ if (!Arrays.equals(d, jwk.d)) {
+ return false;
+ }
+ if (!Arrays.equals(dp, jwk.dp)) {
+ return false;
+ }
+ if (!Arrays.equals(dq, jwk.dq)) {
+ return false;
+ }
+ if (!Arrays.equals(qi, jwk.qi)) {
+ return false;
+ }
+ if (!Arrays.equals(p, jwk.p)) {
+ return false;
+ }
+ if (!Arrays.equals(q, jwk.q)) {
+ return false;
+ }
+ if (!Arrays.equals(x, jwk.x)) {
+ return false;
+ }
+ if (!Arrays.equals(y, jwk.y)) {
+ return false;
+ }
+
+ // HSM token
+ if (!Arrays.equals(t, jwk.t)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Verifies whether the {@link JsonWebKey} has private key.
+ *
+ * @return true if the {@link JsonWebKey} has private key; false otherwise.
+ */
+ public boolean hasPrivateKey() {
+
+ if (JsonWebKeyType.OCT.equals(kty)) {
+ return k != null;
+ }
+
+ else if (JsonWebKeyType.RSA.equals(kty) || JsonWebKeyType.RSA_HSM.equals(kty)) {
+ return (d != null && dp != null && dq != null && qi != null && p != null && q != null);
+ }
+
+ else if (JsonWebKeyType.EC.equals(kty) || JsonWebKeyType.EC_HSM.equals(kty)) {
+ return (d != null);
+ }
+
+ return false;
+ }
+
+ /**
+ * Verifies whether the {@link JsonWebKey} is valid.
+ *
+ * @return true if the {@link JsonWebKey} is valid; false otherwise.
+ */
+ @JsonIgnore
+ public boolean isValid() {
+ if (kty == null) {
+ return false;
+ }
+
+ if (keyOps != null) {
+ final Set set = new HashSet(JsonWebKeyOperation.ALL_OPERATIONS);
+ for (int i = 0; i < keyOps.size(); i++) {
+ if (!set.contains(keyOps.get(i))) {
+ return false;
+ }
+ }
+ }
+
+ if (JsonWebKeyType.OCT.equals(kty)) {
+ return isValidOctet();
+ }
+
+ else if (JsonWebKeyType.RSA.equals(kty)) {
+ return isValidRsa();
+ }
+
+ else if (JsonWebKeyType.RSA_HSM.equals(kty)) {
+ return isValidRsaHsm();
+ }
+
+ else if (JsonWebKeyType.EC.equals(kty)) {
+ return isValidEc();
+ }
+
+ else if (JsonWebKeyType.EC_HSM.equals(kty)) {
+ return isValidEcHsm();
+ }
+
+ return false;
+ }
+
+ private boolean isValidOctet() {
+ if (k != null) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isValidRsa() {
+ if (n == null || e == null) {
+ return false;
+ }
+
+ return hasPrivateKey() || (d == null && dp == null && dq == null && qi == null && p == null && q == null);
+ }
+
+ private boolean isValidRsaHsm() {
+ // MAY have public key parameters
+ if ((n == null && e != null) || (n != null && e == null)) {
+ return false;
+ }
+
+ // no private key
+ if (hasPrivateKey()) {
+ return false;
+ }
+
+ // MUST have ( T || ( N && E ) )
+ boolean tokenParameters = t != null;
+ boolean publicParameters = (n != null && e != null);
+
+ if (tokenParameters && publicParameters) {
+ return false;
+ }
+
+ return (tokenParameters || publicParameters);
+ }
+
+ private boolean isValidEc() {
+ boolean ecPointParameters = (x != null && y != null);
+ if (!ecPointParameters || crv == null) {
+ return false;
+ }
+
+ return hasPrivateKey() || (d == null);
+ }
+
+ private boolean isValidEcHsm() {
+ // MAY have public key parameters
+ boolean ecPointParameters = (x != null && y != null);
+ if ((ecPointParameters && crv == null) || (!ecPointParameters && crv != null)) {
+ return false;
+ }
+
+ // no private key
+ if (hasPrivateKey()) {
+ return false;
+ }
+
+ // MUST have (T || (ecPointParameters && crv))
+ boolean publicParameters = (ecPointParameters && crv != null);
+ boolean tokenParameters = t != null;
+
+ if (tokenParameters && publicParameters) {
+ return false;
+ }
+
+ return (tokenParameters || publicParameters);
+ }
+
+ /**
+ * Clear key materials.
+ */
+ public void clearMemory() {
+ zeroArray(k);
+ k = null;
+ zeroArray(n);
+ n = null;
+ zeroArray(e);
+ e = null;
+ zeroArray(d);
+ d = null;
+ zeroArray(dp);
+ dp = null;
+ zeroArray(dq);
+ dq = null;
+ zeroArray(qi);
+ qi = null;
+ zeroArray(p);
+ p = null;
+ zeroArray(q);
+ q = null;
+ zeroArray(t);
+ t = null;
+ zeroArray(x);
+ x = null;
+ zeroArray(y);
+ y = null;
+ }
+
+ private static void zeroArray(byte[] bytes) {
+ if (bytes != null) {
+ Arrays.fill(bytes, (byte) 0);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ int hashCode = 48313; // setting it to a random prime number
+ if (kid != null) {
+ hashCode += kid.hashCode();
+ }
+
+ if (JsonWebKeyType.OCT.equals(kty)) {
+ hashCode += hashCode(k);
+ }
+
+ else if (JsonWebKeyType.RSA.equals(kty)) {
+ hashCode += hashCode(n);
+ }
+
+ else if (JsonWebKeyType.EC.equals(kty)) {
+ hashCode += hashCode(x);
+ hashCode += hashCode(y);
+ hashCode += crv.hashCode();
+ }
+
+ else if (JsonWebKeyType.RSA_HSM.equals(kty) || JsonWebKeyType.EC_HSM.equals(kty)) {
+ hashCode += hashCode(t);
+ }
+
+ return hashCode;
+ }
+
+ private static int hashCode(byte[] obj) {
+ int hashCode = 0;
+
+ if (obj == null || obj.length == 0) {
+ return 0;
+ }
+
+ for (int i = 0; i < obj.length; i++) {
+ hashCode = (hashCode << 3) | (hashCode >> 29) ^ obj[i];
+ }
+ return hashCode;
+ }
+
+ private static final Map CURVE_TO_SPEC_NAME = ImmutableMap
+ .builder().put(JsonWebKeyCurveName.P_256, "secp256r1")
+ .put(JsonWebKeyCurveName.P_384, "secp384r1").put(JsonWebKeyCurveName.P_521, "secp521r1")
+ .put(JsonWebKeyCurveName.P_256K, "secp256k1").build();
+}
\ No newline at end of file
diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyCurveName.java b/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyCurveName.java
new file mode 100644
index 000000000000..b12aa57ece5f
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyCurveName.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ *
+ * Code generated by Microsoft (R) AutoRest Code Generator.
+ */
+
+package com.microsoft.azure.keyvault.webkey;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+
+/**
+ * Defines values for JsonWebKeyCurveName.
+ */
+public final class JsonWebKeyCurveName {
+ /** Static value P-256 for JsonWebKeyCurveName. */
+ public static final JsonWebKeyCurveName P_256 = new JsonWebKeyCurveName("P-256");
+
+ /** Static value P-384 for JsonWebKeyCurveName. */
+ public static final JsonWebKeyCurveName P_384 = new JsonWebKeyCurveName("P-384");
+
+ /** Static value P-521 for JsonWebKeyCurveName. */
+ public static final JsonWebKeyCurveName P_521 = new JsonWebKeyCurveName("P-521");
+
+ /** Static value SECP256K1 for JsonWebKeyCurveName. */
+ public static final JsonWebKeyCurveName P_256K = new JsonWebKeyCurveName("P-256K");
+
+ private String value;
+
+ /**
+ * Creates a custom value for JsonWebKeyCurveName.
+ * @param value the custom value
+ */
+ public JsonWebKeyCurveName(String value) {
+ this.value = value;
+ }
+
+ @JsonValue
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof JsonWebKeyCurveName)) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ JsonWebKeyCurveName rhs = (JsonWebKeyCurveName) obj;
+ if (value == null) {
+ return rhs.value == null;
+ } else {
+ return value.equals(rhs.value);
+ }
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyEncryptionAlgorithm.java b/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyEncryptionAlgorithm.java
new file mode 100644
index 000000000000..6631fb4a2dac
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyEncryptionAlgorithm.java
@@ -0,0 +1,73 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.webkey;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+
+/**
+ * Defines values for JsonWebKeyEncryptionAlgorithm.
+ */
+public final class JsonWebKeyEncryptionAlgorithm {
+
+ /** Static value RSA-OAEP for JsonWebKeyEncryptionAlgorithm. */
+ public static final JsonWebKeyEncryptionAlgorithm RSA_OAEP = new JsonWebKeyEncryptionAlgorithm("RSA-OAEP");
+
+ /** Static value RSA-OAEP-256 for JsonWebKeyEncryptionAlgorithm. */
+ public static final JsonWebKeyEncryptionAlgorithm RSA_OAEP_256 = new JsonWebKeyEncryptionAlgorithm("RSA-OAEP-256");
+
+ /** Static value RSA1_5 for JsonWebKeyEncryptionAlgorithm. */
+ public static final JsonWebKeyEncryptionAlgorithm RSA1_5 = new JsonWebKeyEncryptionAlgorithm("RSA1_5");
+
+ private String value;
+
+ /**
+ * Creates a custom value for JsonWebKeyEncryptionAlgorithm.
+ *
+ * @param value
+ * the custom value
+ */
+ public JsonWebKeyEncryptionAlgorithm(String value) {
+ this.value = value;
+ }
+
+ @JsonValue
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof JsonWebKeyEncryptionAlgorithm)) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ JsonWebKeyEncryptionAlgorithm rhs = (JsonWebKeyEncryptionAlgorithm) obj;
+ if (value == null) {
+ return rhs.value == null;
+ } else {
+ return value.equals(rhs.value);
+ }
+ }
+
+ /**
+ * All the JWK encryption algorithms.
+ */
+ public static final List ALL_ALGORITHMS = Collections
+ .unmodifiableList(Arrays.asList(RSA_OAEP, RSA1_5, RSA_OAEP_256));
+}
diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyOperation.java b/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyOperation.java
new file mode 100644
index 000000000000..9dbb9d30fce6
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyOperation.java
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.webkey;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+
+/**
+ * Defines values for JsonWebKeyOperation.
+ */
+public final class JsonWebKeyOperation {
+ /** Static value encrypt for JsonWebKeyOperation. */
+ public static final JsonWebKeyOperation ENCRYPT = new JsonWebKeyOperation("encrypt");
+
+ /** Static value decrypt for JsonWebKeyOperation. */
+ public static final JsonWebKeyOperation DECRYPT = new JsonWebKeyOperation("decrypt");
+
+ /** Static value sign for JsonWebKeyOperation. */
+ public static final JsonWebKeyOperation SIGN = new JsonWebKeyOperation("sign");
+
+ /** Static value verify for JsonWebKeyOperation. */
+ public static final JsonWebKeyOperation VERIFY = new JsonWebKeyOperation("verify");
+
+ /** Static value wrapKey for JsonWebKeyOperation. */
+ public static final JsonWebKeyOperation WRAP_KEY = new JsonWebKeyOperation("wrapKey");
+
+ /** Static value unwrapKey for JsonWebKeyOperation. */
+ public static final JsonWebKeyOperation UNWRAP_KEY = new JsonWebKeyOperation("unwrapKey");
+
+ private String value;
+
+ /**
+ * Creates a custom value for JsonWebKeyOperation.
+ * @param value the custom value
+ */
+ public JsonWebKeyOperation(String value) {
+ this.value = value;
+ }
+
+ @JsonValue
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof JsonWebKeyOperation)) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ JsonWebKeyOperation rhs = (JsonWebKeyOperation) obj;
+ if (value == null) {
+ return rhs.value == null;
+ } else {
+ return value.equals(rhs.value);
+ }
+ }
+
+ /**
+ * All the JWK operations.
+ */
+ public static final List ALL_OPERATIONS =
+ Collections.unmodifiableList(Arrays.asList(ENCRYPT, DECRYPT, SIGN, VERIFY, WRAP_KEY, UNWRAP_KEY));
+}
diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeySignatureAlgorithm.java b/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeySignatureAlgorithm.java
new file mode 100644
index 000000000000..7075d00a1f97
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeySignatureAlgorithm.java
@@ -0,0 +1,93 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ **/
+
+package com.microsoft.azure.keyvault.webkey;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+
+/**
+ * Defines values for JsonWebKeySignatureAlgorithm.
+ */
+public final class JsonWebKeySignatureAlgorithm {
+
+ /** Static value PS256 for JsonWebKeySignatureAlgorithm. */
+ public static final JsonWebKeySignatureAlgorithm PS256 = new JsonWebKeySignatureAlgorithm("PS256");
+
+ /** Static value PS384 for JsonWebKeySignatureAlgorithm. */
+ public static final JsonWebKeySignatureAlgorithm PS384 = new JsonWebKeySignatureAlgorithm("PS384");
+
+ /** Static value PS512 for JsonWebKeySignatureAlgorithm. */
+ public static final JsonWebKeySignatureAlgorithm PS512 = new JsonWebKeySignatureAlgorithm("PS512");
+
+ /** Static value RS256 for JsonWebKeySignatureAlgorithm. */
+ public static final JsonWebKeySignatureAlgorithm RS256 = new JsonWebKeySignatureAlgorithm("RS256");
+
+ /** Static value RS384 for JsonWebKeySignatureAlgorithm. */
+ public static final JsonWebKeySignatureAlgorithm RS384 = new JsonWebKeySignatureAlgorithm("RS384");
+
+ /** Static value RS512 for JsonWebKeySignatureAlgorithm. */
+ public static final JsonWebKeySignatureAlgorithm RS512 = new JsonWebKeySignatureAlgorithm("RS512");
+
+ /** Static value RSNULL for JsonWebKeySignatureAlgorithm. */
+ public static final JsonWebKeySignatureAlgorithm RSNULL = new JsonWebKeySignatureAlgorithm("RSNULL");
+ /** Static value ES256 for JsonWebKeySignatureAlgorithm. */
+ public static final JsonWebKeySignatureAlgorithm ES256 = new JsonWebKeySignatureAlgorithm("ES256");
+ /** Static value ES384 for JsonWebKeySignatureAlgorithm. */
+ public static final JsonWebKeySignatureAlgorithm ES384 = new JsonWebKeySignatureAlgorithm("ES384");
+ /** Static value ES512 for JsonWebKeySignatureAlgorithm. */
+ public static final JsonWebKeySignatureAlgorithm ES512 = new JsonWebKeySignatureAlgorithm("ES512");
+ /** Static value ECDSA256 for JsonWebKeySignatureAlgorithm. */
+ public static final JsonWebKeySignatureAlgorithm ES256K = new JsonWebKeySignatureAlgorithm("ES256K");
+
+ private String value;
+
+ /**
+ * Creates a custom value for JsonWebKeySignatureAlgorithm.
+ *
+ * @param value
+ * the custom value
+ */
+ public JsonWebKeySignatureAlgorithm(String value) {
+ this.value = value;
+ }
+
+ @JsonValue
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof JsonWebKeySignatureAlgorithm)) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ JsonWebKeySignatureAlgorithm rhs = (JsonWebKeySignatureAlgorithm) obj;
+ if (value == null) {
+ return rhs.value == null;
+ } else {
+ return value.equals(rhs.value);
+ }
+ }
+
+ /**
+ * All the JWK signature algorithms.
+ */
+ public static final List ALL_ALGORITHMS = Collections.unmodifiableList(
+ Arrays.asList(RS256, RS384, RS512, RSNULL, PS256, PS384, PS512, ES256, ES384, ES512, ES256K));
+}
diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyType.java b/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyType.java
new file mode 100644
index 000000000000..dc5a7355bcc8
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyType.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault.webkey;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+
+/**
+ * Defines values for JsonWebKeyType.
+ */
+public final class JsonWebKeyType {
+ /** Static value EC for JsonWebKeyType. */
+ public static final JsonWebKeyType EC = new JsonWebKeyType("EC");
+ /** Static value EC-HSM for JsonWebKeyType. */
+ public static final JsonWebKeyType EC_HSM = new JsonWebKeyType("EC-HSM");
+
+ /** Static value RSA for JsonWebKeyType. */
+ public static final JsonWebKeyType RSA = new JsonWebKeyType("RSA");
+
+ /** Static value RSA-HSM for JsonWebKeyType. */
+ public static final JsonWebKeyType RSA_HSM = new JsonWebKeyType("RSA-HSM");
+
+ /** Static value oct for JsonWebKeyType. */
+ public static final JsonWebKeyType OCT = new JsonWebKeyType("oct");
+
+ private String value;
+
+ /**
+ * Creates a custom value for JsonWebKeyType.
+ * @param value the custom value
+ */
+ public JsonWebKeyType(String value) {
+ this.value = value;
+ }
+
+ @JsonValue
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof JsonWebKeyType)) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ JsonWebKeyType rhs = (JsonWebKeyType) obj;
+ if (value == null) {
+ return rhs.value == null;
+ } else {
+ return value.equals(rhs.value);
+ }
+ }
+
+ /**
+ * All the JWK key types.
+ */
+ public static final List ALL_TYPES =
+ Collections.unmodifiableList(Arrays.asList(EC, RSA, RSA_HSM, OCT, EC_HSM));
+}
diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/package-info.java b/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/package-info.java
new file mode 100644
index 000000000000..6768bb504520
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/package-info.java
@@ -0,0 +1,8 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for
+// license information.
+
+/**
+ * This package contains the classes for key vault JSON web key.
+ */
+package com.microsoft.azure.keyvault.webkey;
diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/AesValidationTests.java b/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/AesValidationTests.java
new file mode 100644
index 000000000000..3d1ed2b07c77
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/AesValidationTests.java
@@ -0,0 +1,92 @@
+package com.microsoft.azure.keyvault.webkey.test;
+
+import java.util.Arrays;
+import java.util.Random;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.microsoft.azure.keyvault.webkey.JsonWebKey;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyOperation;
+
+public class AesValidationTests {
+ private static final String TRANSFORMATION = "AES";
+
+ @Test
+ public void aesKeyValidation() throws Exception {
+ KeyGenerator keyGen = KeyGenerator.getInstance(TRANSFORMATION);
+ keyGen.init(256);
+
+ SecretKey skey = keyGen.generateKey();
+ JsonWebKey key = serializeDeserialize(skey);
+ Assert.assertTrue(key.hasPrivateKey());
+ Assert.assertTrue(key.isValid());
+
+ SecretKey secretKey = key.toAes();
+ encryptDecrypt(secretKey);
+
+ // Compare equal JSON web keys
+ JsonWebKey sameKey = JsonWebKey.fromAes(skey);
+ Assert.assertEquals(key, key);
+ Assert.assertEquals(key, sameKey);
+ Assert.assertEquals(key.hashCode(), sameKey.hashCode());
+ }
+
+ @Test
+ public void invalidKeyOps() throws Exception {
+ JsonWebKey key = getAes();
+ key.withKeyOps(Arrays.asList(JsonWebKeyOperation.ENCRYPT, new JsonWebKeyOperation("foo")));
+ Assert.assertFalse(key.isValid());
+ }
+
+ @Test
+ public void octHashCode() throws Exception {
+ JsonWebKey key = getAes();
+
+ // Compare hash codes for unequal JWK that would not map to the same hash
+ Assert.assertNotEquals(key.hashCode(), new JsonWebKey().withK(key.k()).hashCode());
+ Assert.assertNotEquals(key.hashCode(), new JsonWebKey().withKty(key.kty()).hashCode());
+
+ // Compare hash codes for unequal JWK that would map to the same hash
+ Assert.assertEquals(key.hashCode(), new JsonWebKey().withK(key.k()).withKty(key.kty()).hashCode());
+ }
+
+ private static JsonWebKey getAes() throws Exception {
+ KeyGenerator keyGen = KeyGenerator.getInstance(TRANSFORMATION);
+ keyGen.init(256);
+
+ SecretKey skey = keyGen.generateKey();
+ return JsonWebKey.fromAes(skey);
+ }
+
+ private static JsonWebKey serializeDeserialize(SecretKey skey) throws Exception {
+ JsonWebKey webKey = JsonWebKey.fromAes(skey);
+ String serializedKey = webKey.toString();
+ ObjectMapper mapper = new ObjectMapper();
+ return mapper.readValue(serializedKey, JsonWebKey.class);
+ }
+
+ private static void encryptDecrypt(SecretKey key) throws Exception {
+ byte[] plaintext = new byte[10];
+ new Random().nextBytes(plaintext);
+ byte[] cipherText = encrypt(key, plaintext);
+ Assert.assertArrayEquals(decrypt(key, cipherText), plaintext);
+ }
+
+ private static byte[] encrypt(SecretKey key, byte[] plaintext) throws Exception {
+ Cipher cipher = Cipher.getInstance(TRANSFORMATION);
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ return cipher.doFinal(plaintext);
+ }
+
+ private static byte[] decrypt(SecretKey key, byte[] ciphertext) throws Exception {
+ Cipher cipher = Cipher.getInstance(TRANSFORMATION);
+ cipher.init(Cipher.DECRYPT_MODE, key);
+ return cipher.doFinal(ciphertext);
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/ClearMemoryTests.java b/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/ClearMemoryTests.java
new file mode 100644
index 000000000000..f28801584059
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/ClearMemoryTests.java
@@ -0,0 +1,56 @@
+package com.microsoft.azure.keyvault.webkey.test;
+
+import java.util.Random;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.microsoft.azure.keyvault.webkey.JsonWebKey;
+
+public class ClearMemoryTests {
+
+ @Test
+ public void clearMemory()
+ {
+ JsonWebKey key = new JsonWebKey()
+ .withD(getRandomByte())
+ .withDp(getRandomByte())
+ .withDq(getRandomByte())
+ .withE(getRandomByte())
+ .withK(getRandomByte())
+ .withN(getRandomByte())
+ .withP(getRandomByte())
+ .withQ(getRandomByte())
+ .withQi(getRandomByte())
+ .withT(getRandomByte());
+ key.clearMemory();
+ Assert.assertNull(key.d());
+ Assert.assertNull(key.dp());
+ Assert.assertNull(key.dq());
+ Assert.assertNull(key.e());
+ Assert.assertNull(key.k());
+ Assert.assertNull(key.n());
+ Assert.assertNull(key.p());
+ Assert.assertNull(key.q());
+ Assert.assertNull(key.qi());
+ Assert.assertNull(key.t());
+
+ // Compare it with a newly created JsonWebKey with no properties set.
+ JsonWebKey key2 = new JsonWebKey();
+ Assert.assertTrue(key2.equals(key));
+ }
+
+ @Test
+ public void clearNullMemory()
+ {
+ JsonWebKey key = new JsonWebKey();
+ key.clearMemory();
+ }
+
+ private static byte[] getRandomByte() {
+ byte[] bytes = new byte[10];
+ new Random().nextBytes(bytes);
+ return bytes;
+ }
+
+}
diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/EcHsmValidationTests.java b/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/EcHsmValidationTests.java
new file mode 100644
index 000000000000..0175b2164d69
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/EcHsmValidationTests.java
@@ -0,0 +1,47 @@
+package com.microsoft.azure.keyvault.webkey.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyCurveName;
+import com.microsoft.azure.keyvault.webkey.JsonWebKey;
+
+
+public class EcHsmValidationTests {
+
+ String keyWithoutT = "{\"kid\":\"key_id\",\"kty\":\"EC-HSM\",\"key_ops\":null,\"n\":null,\"e\":null,\"d\":null,\"dp\":null,\"dq\":null,\"qi\":null,\"p\":null,\"q\":null,\"k\":null,\"key_hsm\":null,\"crv\":\"P-256\",\"x\":\"KyjF795jLyVIgswKSQInEGYHNBKSKyPgNojEgYlldMI\",\"y\":\"AIl_ca1ZIKbJ5YGdgGr_7HySldI2aWeBaOImZEYIMpVe\"}";
+ String keyWithT = "{\"kid\":\"key_id\",\"kty\":\"EC-HSM\",\"key_ops\":null,\"key_hsm\":\"T-TOKEN\"}";
+
+ @Test
+ public void ecHsmValidation() throws Exception {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonWebKey keyNoT = mapper.readValue(keyWithoutT, JsonWebKey.class);
+ JsonWebKey keyT = mapper.readValue(keyWithT, JsonWebKey.class);
+
+ Assert.assertTrue(keyNoT.isValid());
+ Assert.assertFalse(keyNoT.hasPrivateKey());
+
+ Assert.assertTrue(keyT.isValid());
+ Assert.assertFalse(keyT.hasPrivateKey());
+ }
+
+ @Test
+ public void ecHsmHashCode() throws Exception {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonWebKey keyNoT = mapper.readValue(keyWithoutT, JsonWebKey.class);
+ JsonWebKey keyT = mapper.readValue(keyWithT, JsonWebKey.class);
+
+ Assert.assertNotEquals(keyT.hashCode(), keyNoT.hashCode());
+
+ // Compare hash codes for unequal JWK that would not map to the same hash
+ Assert.assertNotEquals(keyT.hashCode(), new JsonWebKey().withKid(keyT.kid()).withT(keyT.t()).hashCode());
+ Assert.assertNotEquals(keyT.hashCode(), new JsonWebKey().withKid(keyT.kid()).withKty(keyT.kty()).hashCode());
+ Assert.assertNotEquals(keyNoT.hashCode(), new JsonWebKey().hashCode());
+
+ // Compare hash codes for unequal JWK that would map to the same hash
+ Assert.assertEquals(keyT.hashCode(),
+ new JsonWebKey().withKid(keyT.kid()).withKty(keyT.kty()).withT(keyT.t()).hashCode());
+ Assert.assertEquals(keyNoT.hashCode(), new JsonWebKey().withKid(keyT.kid()).hashCode());
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/EcValidationTests.java b/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/EcValidationTests.java
new file mode 100644
index 000000000000..a2f341dc1c05
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/EcValidationTests.java
@@ -0,0 +1,115 @@
+package com.microsoft.azure.keyvault.webkey.test;
+
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.Map;
+import java.util.Random;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.ImmutableMap;
+import com.microsoft.azure.keyvault.webkey.JsonWebKey;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyCurveName;
+
+
+public class EcValidationTests {
+
+ @Test
+ public void ecPublicKeyValidation() throws Exception {
+
+ for (String keyStr : keys.values()) {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonWebKey key = mapper.readValue(keyStr, JsonWebKey.class);
+ Assert.assertTrue(key.hasPrivateKey());
+ Assert.assertTrue(key.isValid());
+
+ KeyPair keyPair = key.toEC();
+ validateEcKey(keyPair, key);
+ Assert.assertNull(keyPair.getPrivate());
+
+ // Compare equal JSON web keys
+ JsonWebKey sameKey = mapper.readValue(keyStr, JsonWebKey.class);
+ Assert.assertEquals(key, key);
+ Assert.assertEquals(key, sameKey);
+ Assert.assertEquals(key.hashCode(), sameKey.hashCode());
+ }
+ }
+
+ @Test
+ public void ecPrivateKeyValidation() throws Exception {
+ for (String keyStr : keys.values()) {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonWebKey key = mapper.readValue(keyStr, JsonWebKey.class);
+ KeyPair keyPairWithPrivate = key.toEC(true);
+ validateEcKey(keyPairWithPrivate, key);
+ signVerify(keyPairWithPrivate.getPublic(), keyPairWithPrivate.getPrivate(), key.crv());
+ }
+ }
+
+ private static void validateEcKey(KeyPair keyPair, JsonWebKey key) throws Exception {
+ JsonWebKey jsonWebKey = JsonWebKey.fromEC(keyPair, Security.getProvider("SunEC"));
+ boolean includePrivateKey = keyPair.getPrivate() != null;
+ KeyPair keyPair2 = jsonWebKey.toEC(includePrivateKey);
+
+ Assert.assertTrue(includePrivateKey == jsonWebKey.hasPrivateKey());
+
+ PublicKey publicKey = keyPair2.getPublic();
+ PrivateKey privateKey = keyPair2.getPrivate();
+
+ if(includePrivateKey) {
+
+ // set the missing properties to compare the keys
+ jsonWebKey.withKid(new String(key.kid()));
+ Assert.assertNotNull(privateKey);
+ Assert.assertEquals(jsonWebKey, key);
+ Assert.assertEquals(key.hashCode(), jsonWebKey.hashCode());
+ signVerify(publicKey, privateKey, jsonWebKey.crv());
+ }
+ }
+
+ private static void signVerify(PublicKey publicKey, PrivateKey privateKey, JsonWebKeyCurveName curve) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException {
+ Signature signature = Signature.getInstance(CURVE_TO_SIGNATURE.get(curve), Security.getProvider("SunEC"));
+ signature.initSign(privateKey);
+ MessageDigest digest = MessageDigest.getInstance(algorithm.get(curve));
+ byte[] plaintext = new byte[10];
+ new Random().nextBytes(plaintext);
+ byte[] hash = digest.digest(plaintext);
+ signature.update(hash);
+ byte[] signed_hash = signature.sign();
+
+ signature.initVerify(publicKey);
+ signature.update(hash);
+ Assert.assertTrue(signature.verify(signed_hash));
+
+ }
+
+ static Map algorithm = ImmutableMap.builder()
+ .put(JsonWebKeyCurveName.P_256, "SHA-256")
+ .put(JsonWebKeyCurveName.P_384, "SHA-384")
+ .put(JsonWebKeyCurveName.P_521, "SHA-512")
+ .put(JsonWebKeyCurveName.P_256K, "SHA-256")
+ .build();
+
+ Map keys = ImmutableMap.builder()
+ .put(256, "{\"kid\":\"key_id\",\"kty\":\"EC\",\"key_ops\":null,\"n\":null,\"e\":null,\"d\":\"AM_iqldq9VSqlf9v3w7lren4pJvZTG81v6_V5ZBLP7ZI\",\"dp\":null,\"dq\":null,\"qi\":null,\"p\":null,\"q\":null,\"k\":null,\"key_hsm\":null,\"crv\":\"P-256\",\"x\":\"KyjF795jLyVIgswKSQInEGYHNBKSKyPgNojEgYlldMI\",\"y\":\"AIl_ca1ZIKbJ5YGdgGr_7HySldI2aWeBaOImZEYIMpVe\"}")
+ .put(384, "{\"kid\":\"key_id\",\"kty\":\"EC\",\"key_ops\":null,\"n\":null,\"e\":null,\"d\":\"AJEYT00mAfa-_uJ8S9ob0-9uZbPEr56CFebUQW9O-jZQBrtrMSPeqVbjJvTVlzOwbg\",\"dp\":null,\"dq\":null,\"qi\":null,\"p\":null,\"q\":null,\"k\":null,\"key_hsm\":null,\"crv\":\"P-384\",\"x\":\"AKOdkhxTtVkLtaslZIOPQGnsdKRT2xo3Ynk-bnAVvTCf3iGrTpRiMxUmyq_tvzBLEg\",\"y\":\"QoHux2O2XGMh8w7a5sWwskAyCR0g3Lj7kPGuvnDq_bQ_-_VoTvsGMAe9MFexv68I\"}")
+ .put(521, "{\"kid\":\"key_id\",\"kty\":\"EC\",\"key_ops\":null,\"n\":null,\"e\":null,\"d\":\"AVW7TFJVOJ8jY5PqK0nnKyVYQwhkBEGKt0nhSZTS5io7U32dR7xZle77Gq6SpjrdFVa32jvGWgchlSguV3WKy3sj\",\"dp\":null,\"dq\":null,\"qi\":null,\"p\":null,\"q\":null,\"k\":null,\"key_hsm\":null,\"crv\":\"P-521\",\"x\":\"AIDmImOrJNKOjOGp7wD8Dzi_uz-00E7cs8iN5SwBkzBXktyRrLDFS_SMwVdnIWpLcdJQn5sTGDS121DhjQA2i2dO\",\"y\":\"AWRoeIfIoRoEx8V9ijjwaco3V6vUPUYvKMKxtCPvm8iwhB7pZAI7-mODSfkb3rZo3gxuWoM3G7L66FttUlKSLK4w\"}")
+ .put(265, "{\"kid\":\"key_id\",\"kty\":\"EC\",\"key_ops\":null,\"n\":null,\"e\":null,\"d\":\"YKv22AkpwBpKUcDodNhKhvI-bRpiWqoN8l0kNCo-Mds\",\"dp\":null,\"dq\":null,\"qi\":null,\"p\":null,\"q\":null,\"k\":null,\"key_hsm\":null,\"crv\":\"P-256K\",\"x\":\"Yw9Sln8gYf_oiFY1anQm0V_WwsRaCIcEccfbhu5hSJo\",\"y\":\"AJq3JT2YldszaohHaS7LkngPWS9y0yAn7HhHb5p0IUDS\"}")
+ .build();
+
+ public static final Map CURVE_TO_SIGNATURE = ImmutableMap.builder()
+ .put(JsonWebKeyCurveName.P_256, "SHA256withECDSA")
+ .put(JsonWebKeyCurveName.P_384, "SHA384withECDSA")
+ .put(JsonWebKeyCurveName.P_521, "SHA512withECDSA")
+ .put(JsonWebKeyCurveName.P_256K, "NONEwithECDSA")
+ .build();
+}
diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/RsaHsmValidationTests.java b/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/RsaHsmValidationTests.java
new file mode 100644
index 000000000000..fd960ee23a8c
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/RsaHsmValidationTests.java
@@ -0,0 +1,46 @@
+package com.microsoft.azure.keyvault.webkey.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.microsoft.azure.keyvault.webkey.JsonWebKey;
+
+
+public class RsaHsmValidationTests {
+
+ String keyWithoutT = "{\"kid\":\"key_id\",\"kty\":\"RSA-HSM\",\"key_ops\":[\"encrypt\",\"decrypt\"],\"n\":\"1_6ZtP288hEkKML-L6nFyZh1PD1rmAgwbbwjEvTSDK_008BYWhjp_6ULy9BhWtRIytNkPkm9gzaBTrCpp-vyDXPGa836Htp-w8u5JmxoUZchJh576m3m-8ZYWTmZSAp5SpruyKAmLSxPJHEWPXQntnmuTMjb9HBT9Ltrwc0ZDk-jsMLYunDJrNmrRUxQgb0zQ_Tl5fJjj8j-0KVx2RXtbfWFvf5fRdBYyP3m0aUpoopQPwtXszD2LcSKMJ_TnmnvMWr8MOA5aRlBaGdBk7zBgRafvDPam3Q2AvFA9mfcAVncpfZ3JFm73VARw6MofXtRqOHtZ7y4oNbY95xXwU2r6w\",\"e\":\"AQAB\"}";
+ String keyWithT = "{\"kid\":\"key_id\",\"kty\":\"RSA-HSM\",\"key_ops\":[\"encrypt\",\"decrypt\"],\"key_hsm\":\"T-TOKEN\"}";
+
+ @Test
+ public void rsaHsmValidation() throws Exception {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonWebKey keyNoT = mapper.readValue(keyWithoutT, JsonWebKey.class);
+ JsonWebKey keyT = mapper.readValue(keyWithT, JsonWebKey.class);
+
+ Assert.assertTrue(keyNoT.isValid());
+ Assert.assertFalse(keyNoT.hasPrivateKey());
+
+ Assert.assertTrue(keyT.isValid());
+ Assert.assertFalse(keyT.hasPrivateKey());
+ }
+
+ @Test
+ public void rsaHsmHashCode() throws Exception {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonWebKey keyNoT = mapper.readValue(keyWithoutT, JsonWebKey.class);
+ JsonWebKey keyT = mapper.readValue(keyWithT, JsonWebKey.class);
+
+ Assert.assertNotEquals(keyT.hashCode(), keyNoT.hashCode());
+
+ // Compare hash codes for unequal JWK that would not map to the same hash
+ Assert.assertNotEquals(keyT.hashCode(), new JsonWebKey().withKid(keyT.kid()).withT(keyT.t()).hashCode());
+ Assert.assertNotEquals(keyT.hashCode(), new JsonWebKey().withKid(keyT.kid()).withKty(keyT.kty()).hashCode());
+ Assert.assertNotEquals(keyNoT.hashCode(), new JsonWebKey().hashCode());
+
+ // Compare hash codes for unequal JWK that would map to the same hash
+ Assert.assertEquals(keyT.hashCode(),
+ new JsonWebKey().withKid(keyT.kid()).withKty(keyT.kty()).withT(keyT.t()).hashCode());
+ Assert.assertEquals(keyNoT.hashCode(), new JsonWebKey().withKid(keyT.kid()).hashCode());
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/RsaValidationTests.java b/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/RsaValidationTests.java
new file mode 100644
index 000000000000..cb5bcb3de228
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/RsaValidationTests.java
@@ -0,0 +1,126 @@
+package com.microsoft.azure.keyvault.webkey.test;
+
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.Random;
+
+import javax.crypto.Cipher;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.ImmutableMap;
+import com.microsoft.azure.keyvault.webkey.JsonWebKey;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyOperation;
+
+public class RsaValidationTests {
+
+ private static final String TRANSFORMATION = "RSA/ECB/PKCS1Padding";
+
+ @Test
+ public void rsaPublicKeyValidation() throws Exception {
+ for(String keyStr : keys.values())
+ {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonWebKey key = mapper.readValue(keyStr, JsonWebKey.class);
+ Assert.assertTrue(key.hasPrivateKey());
+ Assert.assertTrue(key.isValid());
+
+ KeyPair keyPair = key.toRSA();
+ validateRsaKey(keyPair, key);
+ Assert.assertNull(keyPair.getPrivate());
+
+ // Compare equal JSON web keys
+ JsonWebKey sameKey = mapper.readValue(keyStr, JsonWebKey.class);
+ Assert.assertEquals(key, key);
+ Assert.assertEquals(key, sameKey);
+ Assert.assertEquals(key.hashCode(), sameKey.hashCode());
+ }
+ }
+
+ @Test
+ public void rsaPrivateKeyValidation() throws Exception {
+ for(String keyStr : keys.values())
+ {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonWebKey key = mapper.readValue(keyStr, JsonWebKey.class);
+
+ KeyPair keyPairWithPrivate = key.toRSA(true);
+ validateRsaKey(keyPairWithPrivate, key);
+ encryptDecrypt(keyPairWithPrivate.getPublic(), keyPairWithPrivate.getPrivate());
+ }
+ }
+
+ @Test
+ public void rsaHashCode() throws Exception {
+
+ String keyStr = (String) keys.values().toArray()[0];
+ ObjectMapper mapper = new ObjectMapper();
+ JsonWebKey key = mapper.readValue(keyStr, JsonWebKey.class);
+
+ // Compare hash codes for unequal JWK that would not map to the same hash
+ Assert.assertNotEquals(key.hashCode(), new JsonWebKey().withKid(key.kid()).withN(key.n()).hashCode());
+ Assert.assertNotEquals(key.hashCode(), new JsonWebKey().withKid(key.kid()).withKty(key.kty()).hashCode());
+ Assert.assertNotEquals(key.hashCode(), new JsonWebKey().withKid(key.kid()).withT(key.t()).hashCode());
+
+ // Compare hash codes for unequal JWK that would map to the same hash
+ Assert.assertEquals(key.hashCode(),
+ new JsonWebKey().withN(key.n()).withKty(key.kty()).withKid(key.kid()).hashCode());
+ }
+
+ private static void encryptDecrypt(PublicKey publicKey, PrivateKey privateKey) throws Exception {
+ byte[] plaintext = new byte[10];
+ new Random().nextBytes(plaintext);
+ byte[] cipherText = encrypt(publicKey, plaintext);
+ if(privateKey != null) {
+ Assert.assertArrayEquals(decrypt(privateKey, cipherText), plaintext);
+ }
+ }
+
+ private static byte[] encrypt(PublicKey key, byte[] plaintext) throws Exception {
+ Cipher cipher = Cipher.getInstance(TRANSFORMATION);
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ return cipher.doFinal(plaintext);
+ }
+
+ private static byte[] decrypt(PrivateKey key, byte[] ciphertext) throws Exception {
+ Cipher cipher = Cipher.getInstance(TRANSFORMATION);
+ cipher.init(Cipher.DECRYPT_MODE, key);
+ return cipher.doFinal(ciphertext);
+ }
+
+ private static void validateRsaKey(KeyPair keyPair, JsonWebKey key) throws Exception {
+ JsonWebKey jsonWebKey = JsonWebKey.fromRSA(keyPair);
+ boolean includePrivateKey = keyPair.getPrivate() != null;
+ KeyPair keyPair2 = jsonWebKey.toRSA(includePrivateKey);
+
+ Assert.assertTrue(includePrivateKey == jsonWebKey.hasPrivateKey());
+
+ PublicKey publicKey = keyPair2.getPublic();
+ PrivateKey privateKey = keyPair2.getPrivate();
+
+ if(includePrivateKey) {
+ Assert.assertNotNull(privateKey);
+
+ // set the missing properties to compare the keys
+ jsonWebKey.withKeyOps(new ArrayList(key.keyOps()));
+ jsonWebKey.withKid(new String(key.kid()));
+ Assert.assertEquals(jsonWebKey, key);
+ Assert.assertEquals(key.hashCode(), jsonWebKey.hashCode());
+ }
+
+ encryptDecrypt(publicKey, privateKey);
+ }
+
+ Map keys = ImmutableMap.builder()
+ .put(512, "{\"kty\":\"RSA\",\"n\":\"uOXIpiH9L0h_byTuP3fcMvKbfS85eTKvxW2skw4oIU2TM3ceFvlDwDK4gKHl4qE4z18bz0qrv9ElstOrT96piQ\",\"e\":\"AQAB\",\"d\":\"And2KMA5uQ1r9MwuvZCODi0D2lcFvz7oBbenyxqmuhTYfdGcuGE9FZg5V6ZcNwBK_eYGZqSwL1Gh2EmzG6AxwQ\",\"dp\":\"CEh8kzQnCRK97NKQeV_wGgWsLYlmgis7Cms85_DIqwE\",\"dq\":\"TAi0G0iE5pvMpiEN2y189hjSRSqE6Unc1lXaE3hcnWE\",\"qi\":\"2HhNqW3QBv1R_iEpu44KVMQs0DdnY5oWp1lH6hgPhXU\",\"p\":\"5BblSoMJmO5Afa-urQFzFpBfACt1175NMUs4tHUYEkE\",\"q\":\"z4Xdf_FU-51wTkW5mFJ6QoDK-GrkMXSdct9hdW26NUk\",\"key_ops\":[\"wrapKey\",\"unwrapKey\",\"encrypt\",\"decrypt\",\"sign\",\"verify\"],\"kid\":\"key_id\"}")
+ .put(1024, "{\"kty\":\"RSA\",\"n\":\"zicSNMeAUYwp6V6UQlJ8gW04o6O4ZJBIefsLnV6-to1YkzgDu6vDBWb83DcDgB2x63W-ZVK23F4dcJcULu1VM-jX83Sfg0b_ZrugiiXCnZ4iidLNcY5QOS1dSHjfI1eWH6QdLPSIE3sHk-BILrIXqoyIJH-LFxzMu--4bDlej2M\",\"e\":\"AQAB\",\"d\":\"A4h7F2YT6bhG2TXcJ9OiFQj6LFPLmG2gnSnGssiQHDDWXWLB-mvT-9O4CBr2ETJxFvsw0cVV8CqGXQrTaodGxOuCGNmYoczodvlhUBJyMBxAI2or5eZUF9jRiECvigoxNVWKsqWxypvq_X1pMfQbh9ot7F6KOJAEg6wlLTc-fIE\",\"dp\":\"v2JbDaZfi3OCCLMtNMjOxfNsBOPb1IqerGux4IR17fLIzG6JlcyaR4uasILdjE4VufqnppZ6FIlFCZUiyIP0GQ\",\"dq\":\"m6NTbNOxN2qnont_qttyqg6WvOA6zWK55-ZnX8hShmlv0ySgtw1PfOWso3wpRMHAujTOfUSeI14DgOLHLNkKtQ\",\"qi\":\"HOcBZfyxW1dSnghCvdTuKL3jLSww6k_v0jhYET32gyKe8od7uxP7w0dXZ8al4zQ3xGxrip9y7jJi0pjG-Z4uGw\",\"p\":\"6dlyTUBrwxLyLbr0X3yqmNu3VrHSt2zbW8jueZFWXPELlbuQ6EKrHoR39BM8MSjFN5PfZbsBhcqNBkqhitj6xw\",\"q\":\"4a4DOrnZt4423myMKmhgDINvIdNmLCHG0aE8UWcSPKO6RFhzHX46NJSoOuk9gvccMKEXOpcJC6P8b8ypN-OKhQ\",\"key_ops\":[\"wrapKey\",\"unwrapKey\",\"encrypt\",\"decrypt\",\"sign\",\"verify\"],\"kid\":\"key_id\"}")
+ .put(2048, "{\"kty\":\"RSA\",\"n\":\"rZ8pnmXkhfmmgNWVVdtNcYy2q0OAcCGIpeFzsN9URqJsiBEiWQfxlUxFTbM4kVWPqjauKt6byvApBGEeMA7Qs8kxwRVP-BD4orXRe9VPgliM92rH0UxQWHmCHUe7G7uUAFPwbiDVhWuFzELxNa6Kljg6Z9DuUKoddmQvlYWj8uSunofCtDi_zzlZKGYTOYJma5IYScHNww1yjLp8-b-Be2UdHbrPkCv6Nuwi6MVIKjPpEeRQgfefRmxDBJQKY3OfydMXZmEwukYXVkUcdIP8XwG2OxnfdRK0oAo0NDebNNVuT89k_3AyZLTr1KbDmx1nnjwa8uB8k-uLtcOC9igbTw\",\"e\":\"AQAB\",\"d\":\"H-z7hy_vVJ9yeZBMtIvt8qpQUK_J51STPwV085otcgud72tPKJXoW2658664ASl9kGwbnLBwb2G3-SEunuGqiNS_PGUB3niob6sFSUMRKsPDsB9HfPoOcCZvwZiWFGRqs6C7vlR1TuJVqRjKJ_ffbf4K51oo6FZPspx7j4AShLAwLUSQ60Ld5QPuxYMYZIMpdVbMVIVHJ26pR4Y18e_0GYmEGnbF5N0HkwqQmfmTiIK5aoGnD3GGgqHeHmWBwh6_WAq90ITLcX_zBeqQUgBSj-Z5v61SroO9Eang36T9mMoYrcPpYwemtAOb4HhQYDj8dCCfbeOcVmvZ9UJKWCX2oQ\",\"dp\":\"HW87UpwPoj3lPI9B9K1hJFeuGgarpakvtHuk1HpZ5hXWFGAJiXoWRV-jvYyjoM2k7RpSxPyuuFFmYHcIxiGFp2ES4HnP0BIhKVa2DyugUxIEcMK53C43Ub4mboJPZTSC3sapKgAmA2ue624sapWmshTPpx9qnUP2Oj3cSMkgMGE\",\"dq\":\"RhwEwb5FYio0GS2tmul8FAYsNH7JDehwI1yUApnTiakhSenFetml4PYyVkKR4csgLZEi3RY6J3R8Tg-36zrZuF7hxhVJn80L5_KETSpfEI3jcrXMVg4SRaMsWLY9Ahxflt2FJgUnHOmWRLmP6_hmaTcxxSACjbyUd_HhwNavD5E\",\"qi\":\"wYPZ4lKIslA1w3FaAzQifnNLABYXXUZ_KAA3a8T8fuxkdE4OP3xIFX7WHhnmBd6uOFiEcGoeq2jNQqDg91rV5661-5muQKcvp4uUsNId5rQw9EZw-kdDcwMtVFTEBfvVuyp83X974xYAHn1Jd8wWohSwrpi1QuH5cQMR5Fm6I1A\",\"p\":\"74Ot7MgxRu4euB31UWnGtrqYPjJmvbjYESS43jfDfo-s62ggV5a39P_YPg6oosgtGHNw0QDxunUOXNu9iriaYPf_imptRk69bKN8Nrl727Y-AaBYdLf1UZuwz8X07FqHAH5ghYpk79djld8QvkUUJLpx6rzcW8BJLTOi46DtzZE\",\"q\":\"uZJu-qenARIt28oj_Jlsk-p_KLnqdczczZfbRDd7XNp6csGLa8R0EyYqUB4xLWELQZsX4tAu9SaAO62tuuEy5wbOAmOVrq2ntoia1mGQSJdoeVq6OqtN300xVnaBc3us0rm8C6-824fEQ1PWXoulXLKcSqBhFT-hQahsYi-kat8\",\"key_ops\":[\"wrapKey\",\"unwrapKey\",\"encrypt\",\"decrypt\",\"sign\",\"verify\"],\"kid\":\"key_id\"}")
+ .put(3072, "{\"kty\":\"RSA\",\"n\":\"03u6K67VN18OzIRZdvCC8F9iOVojF-0kk03JQ7rfwumQMqgxLYOmLkrqLcyJV69XYt32LeEesuwuz_zJbQo9gg4T1pnKJSb-l5xoH1rfnihdc9PyMAH___d_zv3Zg9vdusg668eO1oqS5DtAe517suzwhcMIyCsFNx4aBxCDiPlEwzYISwMQHylt-4d6mbFsqJoGK14WqxTOyv0mLoeeDPs9gmQulGbyjYdZJgqjeRBMuHpXgjs_eMwHuqYmWr-jmbRMzBJpKoAgAJkDxkJzJ7wdf4Bq9HrutVspXqw9ZWh4ImIq65Rm5Mx3JDlUNdlYB0jMyDHpuwAZfr8shACty2d5bvlMnk7aYKngCbX2ZSm6BFInA4mz1eey9Iz8uxnfyEjwaYJCFRDy44P_8aymW4tsLoLYgWnF9NodxcLVbhJjBqsipYiUbvW6PUUB4SVtql4yI3EEcZsFFVAVOnms1sXGXK8vm9V9KU1RSWqF268jMD8s-QHg3a1WmooX6sw5\",\"e\":\"AQAB\",\"d\":\"WKU3m6DcmamcK-jcEUluMTBiHTUlmZ1a4-3Ki7vUmEBLo5gxiOjyatwW_dyKwzjpkbUFQCTpN8ldM-w7SBvvPUkGUsFC5MDMHaO_V0lBi2tTBL6V-T6VXmcRaSOpnaY28liErhkHS_Fo8gbOGCKiW5UKmp7uWu0BciGJemWXJP6LLqJC5qJhixZUFgcrQioHKELrjBkTumFt7tMewokxHDLhjPrONYFTcTSHDzWNYS0OY5NQg_OuvsUTBk8nq4lA2GSQqXyM-B2gbwG6pLSwccwu0x3Fd8qurxg6TSGQAjh69Iyb9ZwiHMsx3XLV95Jmqc0rcEbCzLZUBxX3daGjshw3Yd3pzEXqM8Mz-58p835VPhSMlZB_yvtP72o2QiKybhq1ob5Ygt7hqlqe08K5StN2rzJJoFkwivhfC3_KDX7XSLEK9PzqPaTOkkJu7y7tJgi6aC6Fq-X3fgeLy20LsBKV_SF4Zd323IZ713iGJFJo0f4mDUXfQmU3wrILk40L\",\"dp\":\"V5SlApD1a0ng5XrzEmOV2EVKVLcS7Z2j1WYLVa4BMxSsi8zJal_v8nllEN8ylDTWKCZt6Dg3fcHtOWKYGe7e2fBMwSsKcjPI2aFVHjI18ZMbC1m6eHWK81zlTQ-ZhgiRMXQvsRCX6Qt8PPvqfV4j-YILYfgJbQ_DRYEfJzq9JCQjFwGUiSoZvOBl9jQMM1u4NmOnvodwf8Jk4Oi1DC65U-CjOC7D07eDPNv74Pog6h6x3u7Z9S-ITvP1NX4h0_ot\",\"dq\":\"rg2IrHzp59w8nZbtd4NDk_stRB8xT6T2pxpH3LhNhEbLrmy0sF4Xemm8frlgRWeEn9dUV2nzveorEJF57bZ3cclEqBGtD72y_IRPZTPgDcYhc9l4xKJkJJuA3yWcQ6eHZHjLAZHi9PszYvFiUx1veHU2S_f7aGKjO14n05wb9r-YUmIKt7AVwK94HksflvNIREa867E2OL1lIJiX3azkyMgTnSHvi0bwgdIGp6uPdDwVW_qvvUmlFinDWflgq58\",\"qi\":\"Dw0f0UwU2KN98stNeuk2UVtG-GyKjCxSSYocGBlShsXzxeLn2faLSkkqhUVicW4o2PmedPDpxanDW2Gl7osamaPb25CodPS3JJxeHWrJ6hGBfKqvJnysZ-0zL8wVzwuNLc3VL-jlCudFfGK03MBapA9h3qjAFFhHZRgLH8y64MimARfh2gLldZ0FgNF9zB4yxmVzvpOng4XRJGzSBKdf9QbuL60Tia2rWR7QU2GtbrXlp4KiNZspZuzmBLZPaa82\",\"p\":\"3lnk-l3lG3ahUzPzhInjwTJEDRrAt0YMhpLmO444TNs0MD__RxRQO8EAhLGCuKaNJmKOg-D5-Fup34KBAcFKw1vCh06PNxoIbHmcY1KwrlA3M_47pK74sK532429sM2N0JH9ti4QjtcD85__THeS6I5g8x8xdSH6sm6ubOiUWUQ96fN10pDv-9D7PuoHGEGlndvsRE0GwWmBIjCnIbxXN4kQsE5YXbrY_WTdPXxwTb8F6Cqc2WXIuhZLlSqd8NjD\",\"q\":\"83zNQcd3dTEpO-j6e7hHeKYghVBhIViD6bXDzD3IX--maTnllGMD-xxHNzOURwl_VzwWo1Al_QQSKDMeEnNDXhSU50qbdhdyVDyRXQuR2Fb9hN5SACX-SiPgfs-2buJVZh8JD-VFSI7ou6eMQ9h-uIGnhoxH3vCs7dJgy-mHGPsvqTypaIo3LHGfM21z8h0yqgyYwaanv5UllaustjvRFId_2oWqNtrn6q410s9W5-6Q6xqkrW2m_lUffu7ViRdT\",\"key_ops\":[\"wrapKey\",\"unwrapKey\",\"encrypt\",\"decrypt\",\"sign\",\"verify\"],\"kid\":\"key_id\"}")
+ .put(4096, "{\"kty\":\"RSA\",\"n\":\"mmpRerSZYY4Xx_s89Qn3NMAmJOW0TXtddwjdTedA2CITP_BQW9Q6K7ZEKcAk5W8KwfvAYEIDkWN0iKtoSiBmTJxgCqpDI2MO1D_JJXFP6Tovbtgj1FJ8Ai90w04wmxoCdS9mFC2tE51qUWO7frJpTGrZqVAB8UMH031c3pUPzWedGRvKwj7J-Awtg_IoByaK-qoyRlwfqm8WpHjg6R6Fn1aJY3Fp62l1F3XGayUgqoJmg0_YzYxKpz9WDqIJo15sbyQEpTG6kRybD8T5O8908JU2d3KPp7GOKDNpai5wdaK50QyvaU3BtvKI35IaK367FSVPEZPEoAGgUBCoLXx8N16XHVgjspSMV6NnjBEoehr4xU3nw4cZ-09yZSXJv5FGKmg4pkJGCHQwUfA3XlWNZSPYIgBByyjpMe6gJt_RDBhkkYGVddkwn4HPlMIk3Gi9wzMLuVcLNVeq5k4Us3YsaXdSPI6LSfoosu7mi8qm2JMYlFzbB9_FaxJWqgHlTRSiXX0XNuHPMJoBHtKwh_7VXxiosim8EvszF_Is1ttF77l5lC198slQ5zsZ2XM90Ln9UV04kAyI1jEegDiW37uVSikt-VKyVKSZg5lgmp16CevLnqD2g_YD6fJMmbU4QmeVELhZeQc7Z_XGH7lM1bSeiAJ0dKlDKDURnA0h2LQfquM\",\"e\":\"AQAB\",\"d\":\"D_CvEz5WzGihW9Y7p1qtV5deWKtoaXc1YXcGIWdLR68nfY-OkWw0dRQOWqD92LwVyDX3g02ilfzw_WAfFp0xnPGnmHJAbAQVy83_MwuiIYQNfCEj0bnnbfJS2LaBngFEBQTXl3hU8ulqcuxwtoDZuIxvMQ3pUBaIqvRjWeGEDW2Hch1vA45ScHYRXMWVYZJBAToAkUgr8f7LFOoa4vXGUCSGxOqNnJejrBWkXfsp3BrfVOmGipwo42BOae71lRUc7HwzXo-Q9YSWcpJK3Y8U60umoRNacQfgkkB8aVGnRP1_YRfbeRYQdpT4PDFrh4Hq83aJKwSuD4vGGNMfXqgIdSWhREajFDN653gDIIrt1BPh-snE9HIr0QWJmGQTlKTFfXMEoHx6mxJgUmzZSdQ9BkfCYyInpevh2piUrdpoAEEBapYyTmEHetutMm6cpPd4EK7-yHf3f1k1Rx-HIkiN-pLPiy6x6sRS-272pRNJUjEyRr7QIxgv2rVmQpFd3HZIsmTA9e5HnEH88pbwzqckWeA8nCpe6vr9uJ5MkIMaZq1Exw2bL8TjezbQdRvFm6eO25ECBE_YRuTm72hWfkn1Aocz5_RrSvW6gjwXpgTB6ScNyDrrmo9Kz8DQA7uvRvwhS48fceGGqEt_02qtj_FY1e8Q-XLVsPz-oafqbrTPI0E\",\"dp\":\"D9PGN8qEoUjBFIDKfuilcKwpU25pLnGsgnlzXxORZYB2T1y_DzHVXoSFkcOcFfn2L-AWFSUQmFlt37ULSoSTi2J5KzeydzXfkz4CauzqyEEyv1Uu_FBM6ZDb14ZkYoS8B_vWx7ow99fopwwObs5LH9vtGmiAJczVTNuwUQd_8uRXsWdoy2Ku8XLmNBaxvpXjzbs3ooKIw450PWB1qk455OrQ0k2dqrbY5VlOjgBEk317yCamGbPy2AgC4EnXnAZ0qJ5gN-mJNbjBCjkS0MImMWphJCrXkKMxl1OURKW_ujb7B5EGXcTmJuFxu8uE6_SxDrhmbCfdrwnfVdQXIGyGsw\",\"dq\":\"xEmqiGWKIuuyMX3wElvw2E_qJfuJ58lyAqQOYrM8ROsk4iaV9yc9G57pHsLRdiCYYrYDoisi96LdJ6kScAcS8j5TAuAdHq2riI0MOd-lZr6I4S_3pnjO3SuHYmCoFagnpIo7QM9-l2ZguDrfCjs7PtQZqMWSg-ncHYrHDsbynhe9GPdes01u4XZ3Y2xoYBDJX2iCXVNKJBUeYwlLd01p4eE1O_UkI8GdxQDMOr0ifOjWa9HtmY13Q8yvWoDtA4UX9Ec83mB3F2RWi4b-0C1pxSifCzeo4VZ0uOZ_aR4ZKfx7npWseE6F-Ue2vPx3qnfZQAkXaqJPsR15ZU0ZtJqAEQ\",\"qi\":\"fzpgNvwBpXBjLkqVkKnGD20kTR1lnMfXKJHk_iGE3UY7FVRSGXiUWpRWo-Gh0Lq8jJVXddX3looqv-v_9uKHja2JkHToWSkJajRznFHvz1pMfs7d3Nr4puumuNxJC1rgktnOIK4eikNxxHJ5Rs6TeQOwWxRbmywMiEeUQAwVvgaaF91g8FmNUE4C2BCpav-1fKkr_ydo1j4AgcSaCcKuywPBvp2Fznf4UcND_1vyZVKhSBbqbu6ql8vb9zEo3E8AKsrn9REji0BnA5kHk1Ps7GiQcMSCdazwBq1kw3DYD5Mt4CuyOdg6Btg-MVDXLLS0Dw0VEvcPhi7ypUlpl0RWcQ\",\"p\":\"uFaIjld13k5EkpQtTJ6zw9Zq5QJwaVBu1RiyXTdji8ysU6rxk07HAsUt049BuKqFv2jdKVDsdL25WkIao93hstdl8Kl_7XQX491_1np1hW-NvapNUYo5UUn-SeT4zseoIu8n-GarEAI00U8Xj2M4pewd82zlCQHTCXZiwbWGF2XMfPqvpYhFtEoMyJUf8z6qCvcZgp-neJJNbLgesspHke8--GwYN-QjrUynkmUGZ14BQdnLsmNLeaWY7A92sLSOFYVK8XnXSzOUld2P5JCgTenS5Na5UpuaY1K8od8rci3TE23Gtma5VhqBiPOFgPXmlkpkBe1uRn84iV5avYQfdw\",\"q\":\"1nHaNzR3mE6cyzPqsqNxT_FDDzMXHCmxW8cO_9GzmFBW6MhNArPEIV9BFAo-NRjDKMYKPin67MlyiLCMN-TWTayeNeuvw_WYwKfI_t9xuyf1nsW-TsNoK4n2d0kwoB5OEH9pAtQKv9rSZl4WULePldJBF4lPBhQb0lmRu-HB_SRskZe8CdDcm-gjwLhoP76gstWN5PNzgrPTpxBC6tHdWD-ZbkzIGWzCjxNHAnJkUAEsy3FVllCtO4pMVXz3zupaVzmDlUQ34weWXqkA-C7QgUPNoCD_M7PTNJKQpnTwlgk1Jvn8v4FDrpmYvv5l8B9swMPtlIi9xADuuEg8gO5i9Q\",\"key_ops\":[\"wrapKey\",\"unwrapKey\",\"encrypt\",\"decrypt\",\"sign\",\"verify\"],\"kid\":\"key_id\"}")
+ .build();
+}
diff --git a/keyvault/data-plane/azure-keyvault/.gitignore b/keyvault/data-plane/azure-keyvault/.gitignore
new file mode 100644
index 000000000000..b83d22266ac8
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/keyvault/data-plane/azure-keyvault/pom.xml b/keyvault/data-plane/azure-keyvault/pom.xml
new file mode 100644
index 000000000000..b6da877337b1
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault/pom.xml
@@ -0,0 +1,270 @@
+
+
+ 4.0.0
+
+ com.microsoft.azure
+ azure-keyvault-parent
+ 1.1.2
+ ../pom.xml
+
+
+ azure-keyvault
+ 1.1.2
+ jar
+
+ Microsoft Azure SDK for Key Vault
+ This package contains Microsoft Azure Key Vault SDK.
+ https://github.com/Azure/azure-sdk-for-java
+
+
+
+ The MIT License (MIT)
+ http://opensource.org/licenses/MIT
+ repo
+
+
+
+
+ scm:git:https://github.com/Azure/azure-sdk-for-java
+ scm:git:git@github.com:Azure/azure-sdk-for-java.git
+ HEAD
+
+
+
+ UTF-8
+
+ playback
+
+
+
+
+ microsoft
+ Microsoft
+
+
+
+
+
+ ossrh
+ Sonatype Snapshots
+ https://oss.sonatype.org/content/repositories/snapshots/
+ default
+
+ true
+ always
+
+
+
+
+
+
+
+
+ com.microsoft.azure
+ azure-keyvault-cryptography
+
+
+ com.microsoft.azure
+ azure-keyvault-webkey
+
+
+
+
+ com.microsoft.azure
+ azure-client-runtime
+
+
+
+
+ com.microsoft.rest
+ client-runtime
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+
+
+
+
+ commons-codec
+ commons-codec
+
+
+ com.google.guava
+ guava
+
+
+ org.apache.commons
+ commons-lang3
+
+
+ joda-time
+ joda-time
+ 2.1
+
+
+ com.squareup.retrofit2
+ retrofit
+ 2.4.0
+
+
+ com.squareup.okhttp3
+ okhttp
+ 3.10.0
+
+
+ com.squareup.okio
+ okio
+ 1.14.0
+
+
+ io.reactivex
+ rxjava
+
+
+
+
+
+ com.microsoft.azure
+ azure-mgmt-storage
+ 1.3.0
+ test
+
+
+ com.microsoft.azure
+ azure-mgmt-graph-rbac
+ 1.3.0
+ test
+
+
+ com.microsoft.azure
+ azure-mgmt-resources
+ test
+
+
+ com.microsoft.azure
+ azure-mgmt-keyvault
+ test
+
+
+ com.microsoft.azure
+ azure-keyvault
+
+
+
+
+ com.microsoft.azure
+ azure-mgmt-resources
+ 1.3.1-SNAPSHOT
+ test-jar
+ test
+
+
+ com.microsoft.azure
+ adal4j
+ test
+
+
+ com.microsoft.azure
+ azure-storage
+ 4.4.0
+ test
+
+
+
+
+ com.google.code.gson
+ gson
+ 2.2.4
+ test
+
+
+ com.microsoft.azure
+ azure-client-authentication
+ [1.1.0,2.0.0)
+ test
+
+
+ junit
+ junit
+ test
+
+
+
+
+
+
+
+
+ org.eclipse.jetty
+ jetty-maven-plugin
+ 9.2.22.v20170606
+
+ ../jetty.xml,../jetty-http.xml
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.0.2
+
+
+
+ true
+ true
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+ 1.12
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.1
+
+ 1.7
+ 1.7
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+ 2.22.0
+
+
+ ${basedir}/azure-keyvault/target/azure-keyvault-${project.version}.jar
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 2.8
+
+ com.microsoft.schemas._2003._10.serialization;
+ /**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */]]>
+
+
+
+
+
diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/CertificateIdentifier.java b/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/CertificateIdentifier.java
new file mode 100644
index 000000000000..3d89362feb2f
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/CertificateIdentifier.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault;
+
+/**
+ * The certificate identifier.
+ */
+public final class CertificateIdentifier extends ObjectIdentifier {
+
+ /**
+ * Verify whether the identifier is for certificate.
+ * @param identifier the certificate identifier
+ * @return true if the identifier is the certificate identifier. False otherwise.
+ */
+ public static boolean isCertificateIdentifier(String identifier) {
+ return ObjectIdentifier.isObjectIdentifier("certificates", identifier);
+ }
+
+ /**
+ * Constructor.
+ * @param vault The vault url
+ * @param name the certificate name
+ */
+ public CertificateIdentifier(String vault, String name) {
+ this(vault, name, "");
+ }
+
+ /**
+ * Constructor.
+ * @param vault the vault url
+ * @param name the certificate name
+ * @param version the certificate version
+ */
+ public CertificateIdentifier(String vault, String name, String version) {
+ super(vault, "certificates", name, version);
+ }
+
+ /**
+ * Constructor.
+ * @param identifier the certificate identifier
+ */
+ public CertificateIdentifier(String identifier) {
+ super("certificates", identifier);
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/CertificateOperationIdentifier.java b/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/CertificateOperationIdentifier.java
new file mode 100644
index 000000000000..df6144064947
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/CertificateOperationIdentifier.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+/**
+ * The certificate operation identifier.
+ */
+public final class CertificateOperationIdentifier extends ObjectIdentifier {
+
+ /**
+ * Verifies whether the identifier belongs to a key vault certificate operation.
+ * @param identifier the key vault certificate operation identifier.
+ * @return true if the identifier belongs to a key vault certificate operation. False otherwise.
+ */
+ public static boolean isCertificateOperationIdentifier(String identifier) {
+ identifier = verifyNonEmpty(identifier, "identifier");
+
+ URI baseUri;
+ try {
+ baseUri = new URI(identifier);
+ } catch (URISyntaxException e) {
+ return false;
+ }
+
+ // Path is of the form "/certificates/[name]/pending"
+ String[] segments = baseUri.getPath().split("/");
+ if (segments.length != 4) {
+ return false;
+ }
+
+ if (!(segments[1]).equals("certificates")) {
+ return false;
+ }
+
+ if (!(segments[3]).equals("pending")) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Constructor.
+ * @param vault the vault url
+ * @param name the name of certificate
+ * @param version the certificate version
+ */
+ public CertificateOperationIdentifier(String vault, String name, String version) {
+ super(vault, "certificates", name, "pending");
+ }
+
+ /**
+ * Constructor.
+ * @param identifier the key vault certificate operation identifier.
+ */
+ public CertificateOperationIdentifier(String identifier) {
+ super("certificates", identifier);
+ if (!version().equals("pending")) {
+ throw new IllegalArgumentException(
+ String.format("Invalid CertificateOperationIdentifier: {0}", identifier));
+ }
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/IssuerIdentifier.java b/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/IssuerIdentifier.java
new file mode 100644
index 000000000000..71c88d9d9ee9
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/IssuerIdentifier.java
@@ -0,0 +1,106 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.InvalidParameterException;
+
+/**
+ * The issuer identifier.
+ */
+public final class IssuerIdentifier extends ObjectIdentifier {
+
+ /**
+ * Verifies whether the identifier belongs to a key vault issuer.
+ * @param identifier the key vault issuer identifier.
+ * @return true if the identifier belongs to a key vault issuer. False otherwise.
+ */
+ public static boolean isIssuerIdentifier(String identifier) {
+ identifier = verifyNonEmpty(identifier, "identifier");
+
+ URI baseUri;
+ try {
+ baseUri = new URI(identifier);
+ } catch (URISyntaxException e) {
+ return false;
+ }
+
+ String[] segments = baseUri.getPath().split("/");
+ if (segments.length != 4 || segments[1] != "certificates" || segments[2] != "issuers") {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Constructor.
+ * @param vault the vault url.
+ * @param name the name of issuer.
+ */
+ public IssuerIdentifier(String vault, String name) {
+ vault = verifyNonEmpty(vault, "vault");
+
+ name = verifyNonEmpty(name, "name");
+
+ URI baseUri;
+ try {
+ baseUri = new URI(vault);
+ } catch (URISyntaxException e) {
+ throw new InvalidParameterException(String.format("Invalid ObjectIdentifier: %s. Not a valid URI", vault));
+ }
+
+ this.name = name;
+ this.version = null;
+ this.vault = String.format("%s://%s", baseUri.getScheme(), getFullAuthority(baseUri));
+
+ baseIdentifier = String.format("%s/%s/%s", this.vault, "certificates/issuers", this.name);
+ identifier = baseIdentifier;
+ }
+
+ /**
+ * Constructor.
+ * @param identifier the key vault issuer identifier.
+ */
+ public IssuerIdentifier(String identifier) {
+
+ identifier = verifyNonEmpty(identifier, "identifier");
+
+ URI baseUri;
+ try {
+ baseUri = new URI(identifier);
+ } catch (URISyntaxException e) {
+ throw new InvalidParameterException(
+ String.format("Invalid ObjectIdentifier: %s. Not a valid URI", identifier));
+ }
+
+ // Path is of the form "/collection/name[/version]"
+ String[] segments = baseUri.getPath().split("/");
+ if (segments.length != 4) {
+ throw new InvalidParameterException(String
+ .format("Invalid ObjectIdentifier: %s. Bad number of segments: %d", identifier, segments.length));
+ }
+
+ if (!segments[1].equals("certificates")) {
+ throw new InvalidParameterException(
+ String.format("Invalid ObjectIdentifier: %s. Segment [1] should be '%s', found '%s'", identifier,
+ "certificates", segments[1]));
+ }
+ if (!segments[2].equals("issuers")) {
+ throw new InvalidParameterException(
+ String.format("Invalid ObjectIdentifier: %s. Segment [2] should be '%s', found '%s'", identifier,
+ "issuers", segments[2]));
+ }
+
+ name = segments[3];
+ version = "";
+ vault = String.format("%s://%s", baseUri.getScheme(), getFullAuthority(baseUri));
+ baseIdentifier = String.format("%s/%s/%s", vault, "certificates/issuers", name);
+ this.identifier = baseIdentifier;
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyIdentifier.java b/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyIdentifier.java
new file mode 100644
index 000000000000..493f4097df55
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyIdentifier.java
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault;
+
+/**
+ * The Key Vault key identifier.
+ */
+public final class KeyIdentifier extends ObjectIdentifier {
+
+ /**
+ * Verifies whether the identifier belongs to a key vault key.
+ * @param identifier the key vault key identifier.
+ * @return true if the identifier belongs to a key vault key. False otherwise.
+ */
+ public static boolean isKeyIdentifier(String identifier) {
+ return ObjectIdentifier.isObjectIdentifier("keys", identifier);
+ }
+
+ /**
+ * Constructor.
+ * @param vault the vault url.
+ * @param name the name of key.
+ */
+ public KeyIdentifier(String vault, String name) {
+ this(vault, name, "");
+ }
+
+ /**
+ * Constructor.
+ * @param vault the vault url.
+ * @param name the name of key.
+ * @param version the key version.
+ */
+ public KeyIdentifier(String vault, String name, String version) {
+ super(vault, "keys", name, version);
+ }
+
+ /**
+ * Constructor.
+ * @param identifier the key vault key identifier.
+ */
+ public KeyIdentifier(String identifier) {
+ super("keys", identifier);
+ }
+}
diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClient.java b/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClient.java
new file mode 100644
index 000000000000..58e8bd36ba57
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClient.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.microsoft.azure.keyvault;
+
+import com.microsoft.azure.keyvault.implementation.KeyVaultClientCustomImpl;
+import com.microsoft.rest.RestClient;
+import com.microsoft.rest.credentials.ServiceClientCredentials;
+
+/**
+ * Class for Key Vault Client.
+ *
+ */
+public final class KeyVaultClient extends KeyVaultClientCustomImpl implements KeyVaultClientCustom {
+
+ /**
+ * Initializes an instance of KeyVaultClient client.
+ *
+ * @param credentials the management credentials for Azure
+ */
+ public KeyVaultClient(ServiceClientCredentials credentials) {
+ super(credentials);
+ initializeService();
+ }
+ /**
+ * Initializes an instance of KeyVaultClient client.
+ *
+ * @param restClient the REST client to connect to Azure.
+ */
+ public KeyVaultClient(RestClient restClient) {
+ super(restClient);
+ initializeService();
+ }
+
+
+}
\ No newline at end of file
diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClientBase.java b/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClientBase.java
new file mode 100644
index 000000000000..72f475261b73
--- /dev/null
+++ b/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClientBase.java
@@ -0,0 +1,6124 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ *
+ * Code generated by Microsoft (R) AutoRest Code Generator.
+ */
+
+package com.microsoft.azure.keyvault;
+
+import java.util.List;
+import java.util.Map;
+
+import com.microsoft.azure.AzureClient;
+import com.microsoft.azure.ListOperationCallback;
+import com.microsoft.azure.Page;
+import com.microsoft.azure.PagedList;
+import com.microsoft.azure.keyvault.models.BackupCertificateResult;
+import com.microsoft.azure.keyvault.models.BackupKeyResult;
+import com.microsoft.azure.keyvault.models.BackupSecretResult;
+import com.microsoft.azure.keyvault.models.BackupStorageResult;
+import com.microsoft.azure.keyvault.models.CertificateAttributes;
+import com.microsoft.azure.keyvault.models.CertificateBundle;
+import com.microsoft.azure.keyvault.models.CertificateIssuerItem;
+import com.microsoft.azure.keyvault.models.CertificateItem;
+import com.microsoft.azure.keyvault.models.CertificateOperation;
+import com.microsoft.azure.keyvault.models.CertificatePolicy;
+import com.microsoft.azure.keyvault.models.Contacts;
+import com.microsoft.azure.keyvault.models.DeletedCertificateBundle;
+import com.microsoft.azure.keyvault.models.DeletedCertificateItem;
+import com.microsoft.azure.keyvault.models.DeletedKeyBundle;
+import com.microsoft.azure.keyvault.models.DeletedKeyItem;
+import com.microsoft.azure.keyvault.models.DeletedSasDefinitionBundle;
+import com.microsoft.azure.keyvault.models.DeletedSasDefinitionItem;
+import com.microsoft.azure.keyvault.models.DeletedSecretBundle;
+import com.microsoft.azure.keyvault.models.DeletedSecretItem;
+import com.microsoft.azure.keyvault.models.DeletedStorageAccountItem;
+import com.microsoft.azure.keyvault.models.DeletedStorageBundle;
+import com.microsoft.azure.keyvault.models.IssuerAttributes;
+import com.microsoft.azure.keyvault.models.IssuerBundle;
+import com.microsoft.azure.keyvault.models.IssuerCredentials;
+import com.microsoft.azure.keyvault.models.JsonWebKeyCurveName;
+import com.microsoft.azure.keyvault.models.KeyAttributes;
+import com.microsoft.azure.keyvault.models.KeyBundle;
+import com.microsoft.azure.keyvault.models.KeyItem;
+import com.microsoft.azure.keyvault.models.KeyOperationResult;
+import com.microsoft.azure.keyvault.models.KeyVaultErrorException;
+import com.microsoft.azure.keyvault.models.KeyVerifyResult;
+import com.microsoft.azure.keyvault.models.OrganizationDetails;
+import com.microsoft.azure.keyvault.models.SasDefinitionAttributes;
+import com.microsoft.azure.keyvault.models.SasDefinitionBundle;
+import com.microsoft.azure.keyvault.models.SasDefinitionItem;
+import com.microsoft.azure.keyvault.models.SasTokenType;
+import com.microsoft.azure.keyvault.models.SecretAttributes;
+import com.microsoft.azure.keyvault.models.SecretBundle;
+import com.microsoft.azure.keyvault.models.SecretItem;
+import com.microsoft.azure.keyvault.models.StorageAccountAttributes;
+import com.microsoft.azure.keyvault.models.StorageAccountItem;
+import com.microsoft.azure.keyvault.models.StorageBundle;
+import com.microsoft.azure.keyvault.webkey.JsonWebKey;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyEncryptionAlgorithm;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyOperation;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeySignatureAlgorithm;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyType;
+import com.microsoft.rest.RestClient;
+import com.microsoft.rest.ServiceCallback;
+import com.microsoft.rest.ServiceFuture;
+import com.microsoft.rest.ServiceResponse;
+
+import rx.Observable;
+
+/**
+ * The interface for KeyVaultClientBase class.
+ */
+public interface KeyVaultClientBase {
+ /**
+ * Gets the REST client.
+ *
+ * @return the {@link RestClient} object.
+ */
+ RestClient restClient();
+
+ /**
+ * Gets the {@link AzureClient} used for long running operations.
+ * @return the azure client;
+ */
+ AzureClient getAzureClient();
+
+ /**
+ * Gets the User-Agent header for the client.
+ *
+ * @return the user agent string.
+ */
+ String userAgent();
+
+ /**
+ * Gets Client API version..
+ *
+ * @return the apiVersion value.
+ */
+ String apiVersion();
+
+ /**
+ * Gets Gets or sets the preferred language for the response..
+ *
+ * @return the acceptLanguage value.
+ */
+ String acceptLanguage();
+
+ /**
+ * Sets Gets or sets the preferred language for the response..
+ *
+ * @param acceptLanguage the acceptLanguage value.
+ * @return the service client itself
+ */
+ KeyVaultClientBase withAcceptLanguage(String acceptLanguage);
+
+ /**
+ * Gets Gets or sets the retry timeout in seconds for Long Running Operations. Default value is 30..
+ *
+ * @return the longRunningOperationRetryTimeout value.
+ */
+ int longRunningOperationRetryTimeout();
+
+ /**
+ * Sets Gets or sets the retry timeout in seconds for Long Running Operations. Default value is 30..
+ *
+ * @param longRunningOperationRetryTimeout the longRunningOperationRetryTimeout value.
+ * @return the service client itself
+ */
+ KeyVaultClientBase withLongRunningOperationRetryTimeout(int longRunningOperationRetryTimeout);
+
+ /**
+ * Gets When set to true a unique x-ms-client-request-id value is generated and included in each request. Default is true..
+ *
+ * @return the generateClientRequestId value.
+ */
+ boolean generateClientRequestId();
+
+ /**
+ * Sets When set to true a unique x-ms-client-request-id value is generated and included in each request. Default is true..
+ *
+ * @param generateClientRequestId the generateClientRequestId value.
+ * @return the service client itself
+ */
+ KeyVaultClientBase withGenerateClientRequestId(boolean generateClientRequestId);
+
+ /**
+ * Creates a new key, stores it, then returns key parameters and attributes to the client.
+ * The create key operation can be used to create any key type in Azure Key Vault. If the named key already exists, Azure Key Vault creates a new version of the key. It requires the keys/create permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name for the new key. The system will generate the version name for the new key.
+ * @param kty The type of key to create. For valid values, see JsonWebKeyType. Possible values include: 'EC', 'EC-HSM', 'RSA', 'RSA-HSM', 'oct'
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the KeyBundle object if successful.
+ */
+ KeyBundle createKey(String vaultBaseUrl, String keyName, JsonWebKeyType kty);
+
+ /**
+ * Creates a new key, stores it, then returns key parameters and attributes to the client.
+ * The create key operation can be used to create any key type in Azure Key Vault. If the named key already exists, Azure Key Vault creates a new version of the key. It requires the keys/create permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name for the new key. The system will generate the version name for the new key.
+ * @param kty The type of key to create. For valid values, see JsonWebKeyType. Possible values include: 'EC', 'EC-HSM', 'RSA', 'RSA-HSM', 'oct'
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture createKeyAsync(String vaultBaseUrl, String keyName, JsonWebKeyType kty, final ServiceCallback serviceCallback);
+
+ /**
+ * Creates a new key, stores it, then returns key parameters and attributes to the client.
+ * The create key operation can be used to create any key type in Azure Key Vault. If the named key already exists, Azure Key Vault creates a new version of the key. It requires the keys/create permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name for the new key. The system will generate the version name for the new key.
+ * @param kty The type of key to create. For valid values, see JsonWebKeyType. Possible values include: 'EC', 'EC-HSM', 'RSA', 'RSA-HSM', 'oct'
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyBundle object
+ */
+ Observable createKeyAsync(String vaultBaseUrl, String keyName, JsonWebKeyType kty);
+
+ /**
+ * Creates a new key, stores it, then returns key parameters and attributes to the client.
+ * The create key operation can be used to create any key type in Azure Key Vault. If the named key already exists, Azure Key Vault creates a new version of the key. It requires the keys/create permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name for the new key. The system will generate the version name for the new key.
+ * @param kty The type of key to create. For valid values, see JsonWebKeyType. Possible values include: 'EC', 'EC-HSM', 'RSA', 'RSA-HSM', 'oct'
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyBundle object
+ */
+ Observable> createKeyWithServiceResponseAsync(String vaultBaseUrl, String keyName, JsonWebKeyType kty);
+ /**
+ * Creates a new key, stores it, then returns key parameters and attributes to the client.
+ * The create key operation can be used to create any key type in Azure Key Vault. If the named key already exists, Azure Key Vault creates a new version of the key. It requires the keys/create permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name for the new key. The system will generate the version name for the new key.
+ * @param kty The type of key to create. For valid values, see JsonWebKeyType. Possible values include: 'EC', 'EC-HSM', 'RSA', 'RSA-HSM', 'oct'
+ * @param keySize The key size in bits. For example: 2048, 3072, or 4096 for RSA.
+ * @param keyOps the List<JsonWebKeyOperation> value
+ * @param keyAttributes the KeyAttributes value
+ * @param tags Application specific metadata in the form of key-value pairs.
+ * @param curve Elliptic curve name. For valid values, see JsonWebKeyCurveName. Possible values include: 'P-256', 'P-384', 'P-521', 'P-256K'
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the KeyBundle object if successful.
+ */
+ KeyBundle createKey(String vaultBaseUrl, String keyName, JsonWebKeyType kty, Integer keySize, List keyOps, KeyAttributes keyAttributes, Map tags, JsonWebKeyCurveName curve);
+
+ /**
+ * Creates a new key, stores it, then returns key parameters and attributes to the client.
+ * The create key operation can be used to create any key type in Azure Key Vault. If the named key already exists, Azure Key Vault creates a new version of the key. It requires the keys/create permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name for the new key. The system will generate the version name for the new key.
+ * @param kty The type of key to create. For valid values, see JsonWebKeyType. Possible values include: 'EC', 'EC-HSM', 'RSA', 'RSA-HSM', 'oct'
+ * @param keySize The key size in bits. For example: 2048, 3072, or 4096 for RSA.
+ * @param keyOps the List<JsonWebKeyOperation> value
+ * @param keyAttributes the KeyAttributes value
+ * @param tags Application specific metadata in the form of key-value pairs.
+ * @param curve Elliptic curve name. For valid values, see JsonWebKeyCurveName. Possible values include: 'P-256', 'P-384', 'P-521', 'P-256K'
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture createKeyAsync(String vaultBaseUrl, String keyName, JsonWebKeyType kty, Integer keySize, List keyOps, KeyAttributes keyAttributes, Map tags, JsonWebKeyCurveName curve, final ServiceCallback serviceCallback);
+
+ /**
+ * Creates a new key, stores it, then returns key parameters and attributes to the client.
+ * The create key operation can be used to create any key type in Azure Key Vault. If the named key already exists, Azure Key Vault creates a new version of the key. It requires the keys/create permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name for the new key. The system will generate the version name for the new key.
+ * @param kty The type of key to create. For valid values, see JsonWebKeyType. Possible values include: 'EC', 'EC-HSM', 'RSA', 'RSA-HSM', 'oct'
+ * @param keySize The key size in bits. For example: 2048, 3072, or 4096 for RSA.
+ * @param keyOps the List<JsonWebKeyOperation> value
+ * @param keyAttributes the KeyAttributes value
+ * @param tags Application specific metadata in the form of key-value pairs.
+ * @param curve Elliptic curve name. For valid values, see JsonWebKeyCurveName. Possible values include: 'P-256', 'P-384', 'P-521', 'P-256K'
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyBundle object
+ */
+ Observable createKeyAsync(String vaultBaseUrl, String keyName, JsonWebKeyType kty, Integer keySize, List keyOps, KeyAttributes keyAttributes, Map tags, JsonWebKeyCurveName curve);
+
+ /**
+ * Creates a new key, stores it, then returns key parameters and attributes to the client.
+ * The create key operation can be used to create any key type in Azure Key Vault. If the named key already exists, Azure Key Vault creates a new version of the key. It requires the keys/create permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name for the new key. The system will generate the version name for the new key.
+ * @param kty The type of key to create. For valid values, see JsonWebKeyType. Possible values include: 'EC', 'EC-HSM', 'RSA', 'RSA-HSM', 'oct'
+ * @param keySize The key size in bits. For example: 2048, 3072, or 4096 for RSA.
+ * @param keyOps the List<JsonWebKeyOperation> value
+ * @param keyAttributes the KeyAttributes value
+ * @param tags Application specific metadata in the form of key-value pairs.
+ * @param curve Elliptic curve name. For valid values, see JsonWebKeyCurveName. Possible values include: 'P-256', 'P-384', 'P-521', 'P-256K'
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyBundle object
+ */
+ Observable> createKeyWithServiceResponseAsync(String vaultBaseUrl, String keyName, JsonWebKeyType kty, Integer keySize, List keyOps, KeyAttributes keyAttributes, Map tags, JsonWebKeyCurveName curve);
+
+ /**
+ * Imports an externally created key, stores it, and returns key parameters and attributes to the client.
+ * The import key operation may be used to import any key type into an Azure Key Vault. If the named key already exists, Azure Key Vault creates a new version of the key. This operation requires the keys/import permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName Name for the imported key.
+ * @param key The Json web key
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the KeyBundle object if successful.
+ */
+ KeyBundle importKey(String vaultBaseUrl, String keyName, JsonWebKey key);
+
+ /**
+ * Imports an externally created key, stores it, and returns key parameters and attributes to the client.
+ * The import key operation may be used to import any key type into an Azure Key Vault. If the named key already exists, Azure Key Vault creates a new version of the key. This operation requires the keys/import permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName Name for the imported key.
+ * @param key The Json web key
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture importKeyAsync(String vaultBaseUrl, String keyName, JsonWebKey key, final ServiceCallback serviceCallback);
+
+ /**
+ * Imports an externally created key, stores it, and returns key parameters and attributes to the client.
+ * The import key operation may be used to import any key type into an Azure Key Vault. If the named key already exists, Azure Key Vault creates a new version of the key. This operation requires the keys/import permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName Name for the imported key.
+ * @param key The Json web key
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyBundle object
+ */
+ Observable importKeyAsync(String vaultBaseUrl, String keyName, JsonWebKey key);
+
+ /**
+ * Imports an externally created key, stores it, and returns key parameters and attributes to the client.
+ * The import key operation may be used to import any key type into an Azure Key Vault. If the named key already exists, Azure Key Vault creates a new version of the key. This operation requires the keys/import permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName Name for the imported key.
+ * @param key The Json web key
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyBundle object
+ */
+ Observable> importKeyWithServiceResponseAsync(String vaultBaseUrl, String keyName, JsonWebKey key);
+ /**
+ * Imports an externally created key, stores it, and returns key parameters and attributes to the client.
+ * The import key operation may be used to import any key type into an Azure Key Vault. If the named key already exists, Azure Key Vault creates a new version of the key. This operation requires the keys/import permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName Name for the imported key.
+ * @param key The Json web key
+ * @param hsm Whether to import as a hardware key (HSM) or software key.
+ * @param keyAttributes The key management attributes.
+ * @param tags Application specific metadata in the form of key-value pairs.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the KeyBundle object if successful.
+ */
+ KeyBundle importKey(String vaultBaseUrl, String keyName, JsonWebKey key, Boolean hsm, KeyAttributes keyAttributes, Map tags);
+
+ /**
+ * Imports an externally created key, stores it, and returns key parameters and attributes to the client.
+ * The import key operation may be used to import any key type into an Azure Key Vault. If the named key already exists, Azure Key Vault creates a new version of the key. This operation requires the keys/import permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName Name for the imported key.
+ * @param key The Json web key
+ * @param hsm Whether to import as a hardware key (HSM) or software key.
+ * @param keyAttributes The key management attributes.
+ * @param tags Application specific metadata in the form of key-value pairs.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture importKeyAsync(String vaultBaseUrl, String keyName, JsonWebKey key, Boolean hsm, KeyAttributes keyAttributes, Map tags, final ServiceCallback serviceCallback);
+
+ /**
+ * Imports an externally created key, stores it, and returns key parameters and attributes to the client.
+ * The import key operation may be used to import any key type into an Azure Key Vault. If the named key already exists, Azure Key Vault creates a new version of the key. This operation requires the keys/import permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName Name for the imported key.
+ * @param key The Json web key
+ * @param hsm Whether to import as a hardware key (HSM) or software key.
+ * @param keyAttributes The key management attributes.
+ * @param tags Application specific metadata in the form of key-value pairs.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyBundle object
+ */
+ Observable importKeyAsync(String vaultBaseUrl, String keyName, JsonWebKey key, Boolean hsm, KeyAttributes keyAttributes, Map tags);
+
+ /**
+ * Imports an externally created key, stores it, and returns key parameters and attributes to the client.
+ * The import key operation may be used to import any key type into an Azure Key Vault. If the named key already exists, Azure Key Vault creates a new version of the key. This operation requires the keys/import permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName Name for the imported key.
+ * @param key The Json web key
+ * @param hsm Whether to import as a hardware key (HSM) or software key.
+ * @param keyAttributes The key management attributes.
+ * @param tags Application specific metadata in the form of key-value pairs.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyBundle object
+ */
+ Observable> importKeyWithServiceResponseAsync(String vaultBaseUrl, String keyName, JsonWebKey key, Boolean hsm, KeyAttributes keyAttributes, Map tags);
+
+ /**
+ * Deletes a key of any type from storage in Azure Key Vault.
+ * The delete key operation cannot be used to remove individual versions of a key. This operation removes the cryptographic material associated with the key, which means the key is not usable for Sign/Verify, Wrap/Unwrap or Encrypt/Decrypt operations. This operation requires the keys/delete permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key to delete.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the DeletedKeyBundle object if successful.
+ */
+ DeletedKeyBundle deleteKey(String vaultBaseUrl, String keyName);
+
+ /**
+ * Deletes a key of any type from storage in Azure Key Vault.
+ * The delete key operation cannot be used to remove individual versions of a key. This operation removes the cryptographic material associated with the key, which means the key is not usable for Sign/Verify, Wrap/Unwrap or Encrypt/Decrypt operations. This operation requires the keys/delete permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key to delete.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture deleteKeyAsync(String vaultBaseUrl, String keyName, final ServiceCallback serviceCallback);
+
+ /**
+ * Deletes a key of any type from storage in Azure Key Vault.
+ * The delete key operation cannot be used to remove individual versions of a key. This operation removes the cryptographic material associated with the key, which means the key is not usable for Sign/Verify, Wrap/Unwrap or Encrypt/Decrypt operations. This operation requires the keys/delete permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key to delete.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the DeletedKeyBundle object
+ */
+ Observable deleteKeyAsync(String vaultBaseUrl, String keyName);
+
+ /**
+ * Deletes a key of any type from storage in Azure Key Vault.
+ * The delete key operation cannot be used to remove individual versions of a key. This operation removes the cryptographic material associated with the key, which means the key is not usable for Sign/Verify, Wrap/Unwrap or Encrypt/Decrypt operations. This operation requires the keys/delete permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key to delete.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the DeletedKeyBundle object
+ */
+ Observable> deleteKeyWithServiceResponseAsync(String vaultBaseUrl, String keyName);
+
+ /**
+ * The update key operation changes specified attributes of a stored key and can be applied to any key type and key version stored in Azure Key Vault.
+ * In order to perform this operation, the key must already exist in the Key Vault. Note: The cryptographic material of a key itself cannot be changed. This operation requires the keys/update permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of key to update.
+ * @param keyVersion The version of the key to update.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the KeyBundle object if successful.
+ */
+ KeyBundle updateKey(String vaultBaseUrl, String keyName, String keyVersion);
+
+ /**
+ * The update key operation changes specified attributes of a stored key and can be applied to any key type and key version stored in Azure Key Vault.
+ * In order to perform this operation, the key must already exist in the Key Vault. Note: The cryptographic material of a key itself cannot be changed. This operation requires the keys/update permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of key to update.
+ * @param keyVersion The version of the key to update.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture updateKeyAsync(String vaultBaseUrl, String keyName, String keyVersion, final ServiceCallback serviceCallback);
+
+ /**
+ * The update key operation changes specified attributes of a stored key and can be applied to any key type and key version stored in Azure Key Vault.
+ * In order to perform this operation, the key must already exist in the Key Vault. Note: The cryptographic material of a key itself cannot be changed. This operation requires the keys/update permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of key to update.
+ * @param keyVersion The version of the key to update.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyBundle object
+ */
+ Observable updateKeyAsync(String vaultBaseUrl, String keyName, String keyVersion);
+
+ /**
+ * The update key operation changes specified attributes of a stored key and can be applied to any key type and key version stored in Azure Key Vault.
+ * In order to perform this operation, the key must already exist in the Key Vault. Note: The cryptographic material of a key itself cannot be changed. This operation requires the keys/update permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of key to update.
+ * @param keyVersion The version of the key to update.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyBundle object
+ */
+ Observable> updateKeyWithServiceResponseAsync(String vaultBaseUrl, String keyName, String keyVersion);
+ /**
+ * The update key operation changes specified attributes of a stored key and can be applied to any key type and key version stored in Azure Key Vault.
+ * In order to perform this operation, the key must already exist in the Key Vault. Note: The cryptographic material of a key itself cannot be changed. This operation requires the keys/update permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of key to update.
+ * @param keyVersion The version of the key to update.
+ * @param keyOps Json web key operations. For more information on possible key operations, see JsonWebKeyOperation.
+ * @param keyAttributes the KeyAttributes value
+ * @param tags Application specific metadata in the form of key-value pairs.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the KeyBundle object if successful.
+ */
+ KeyBundle updateKey(String vaultBaseUrl, String keyName, String keyVersion, List keyOps, KeyAttributes keyAttributes, Map tags);
+
+ /**
+ * The update key operation changes specified attributes of a stored key and can be applied to any key type and key version stored in Azure Key Vault.
+ * In order to perform this operation, the key must already exist in the Key Vault. Note: The cryptographic material of a key itself cannot be changed. This operation requires the keys/update permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of key to update.
+ * @param keyVersion The version of the key to update.
+ * @param keyOps Json web key operations. For more information on possible key operations, see JsonWebKeyOperation.
+ * @param keyAttributes the KeyAttributes value
+ * @param tags Application specific metadata in the form of key-value pairs.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture updateKeyAsync(String vaultBaseUrl, String keyName, String keyVersion, List keyOps, KeyAttributes keyAttributes, Map tags, final ServiceCallback serviceCallback);
+
+ /**
+ * The update key operation changes specified attributes of a stored key and can be applied to any key type and key version stored in Azure Key Vault.
+ * In order to perform this operation, the key must already exist in the Key Vault. Note: The cryptographic material of a key itself cannot be changed. This operation requires the keys/update permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of key to update.
+ * @param keyVersion The version of the key to update.
+ * @param keyOps Json web key operations. For more information on possible key operations, see JsonWebKeyOperation.
+ * @param keyAttributes the KeyAttributes value
+ * @param tags Application specific metadata in the form of key-value pairs.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyBundle object
+ */
+ Observable updateKeyAsync(String vaultBaseUrl, String keyName, String keyVersion, List keyOps, KeyAttributes keyAttributes, Map tags);
+
+ /**
+ * The update key operation changes specified attributes of a stored key and can be applied to any key type and key version stored in Azure Key Vault.
+ * In order to perform this operation, the key must already exist in the Key Vault. Note: The cryptographic material of a key itself cannot be changed. This operation requires the keys/update permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of key to update.
+ * @param keyVersion The version of the key to update.
+ * @param keyOps Json web key operations. For more information on possible key operations, see JsonWebKeyOperation.
+ * @param keyAttributes the KeyAttributes value
+ * @param tags Application specific metadata in the form of key-value pairs.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyBundle object
+ */
+ Observable> updateKeyWithServiceResponseAsync(String vaultBaseUrl, String keyName, String keyVersion, List keyOps, KeyAttributes keyAttributes, Map tags);
+
+ /**
+ * Gets the public part of a stored key.
+ * The get key operation is applicable to all key types. If the requested key is symmetric, then no key material is released in the response. This operation requires the keys/get permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key to get.
+ * @param keyVersion Adding the version parameter retrieves a specific version of a key.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the KeyBundle object if successful.
+ */
+ KeyBundle getKey(String vaultBaseUrl, String keyName, String keyVersion);
+
+ /**
+ * Gets the public part of a stored key.
+ * The get key operation is applicable to all key types. If the requested key is symmetric, then no key material is released in the response. This operation requires the keys/get permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key to get.
+ * @param keyVersion Adding the version parameter retrieves a specific version of a key.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture getKeyAsync(String vaultBaseUrl, String keyName, String keyVersion, final ServiceCallback serviceCallback);
+
+ /**
+ * Gets the public part of a stored key.
+ * The get key operation is applicable to all key types. If the requested key is symmetric, then no key material is released in the response. This operation requires the keys/get permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key to get.
+ * @param keyVersion Adding the version parameter retrieves a specific version of a key.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyBundle object
+ */
+ Observable getKeyAsync(String vaultBaseUrl, String keyName, String keyVersion);
+
+ /**
+ * Gets the public part of a stored key.
+ * The get key operation is applicable to all key types. If the requested key is symmetric, then no key material is released in the response. This operation requires the keys/get permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key to get.
+ * @param keyVersion Adding the version parameter retrieves a specific version of a key.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyBundle object
+ */
+ Observable> getKeyWithServiceResponseAsync(String vaultBaseUrl, String keyName, String keyVersion);
+
+ /**
+ * Retrieves a list of individual key versions with the same key name.
+ * The full key identifier, attributes, and tags are provided in the response. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the PagedList<KeyItem> object if successful.
+ */
+ PagedList getKeyVersions(final String vaultBaseUrl, final String keyName);
+
+ /**
+ * Retrieves a list of individual key versions with the same key name.
+ * The full key identifier, attributes, and tags are provided in the response. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture> getKeyVersionsAsync(final String vaultBaseUrl, final String keyName, final ListOperationCallback serviceCallback);
+
+ /**
+ * Retrieves a list of individual key versions with the same key name.
+ * The full key identifier, attributes, and tags are provided in the response. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the PagedList<KeyItem> object
+ */
+ Observable> getKeyVersionsAsync(final String vaultBaseUrl, final String keyName);
+
+ /**
+ * Retrieves a list of individual key versions with the same key name.
+ * The full key identifier, attributes, and tags are provided in the response. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the PagedList<KeyItem> object
+ */
+ Observable>> getKeyVersionsWithServiceResponseAsync(final String vaultBaseUrl, final String keyName);
+ /**
+ * Retrieves a list of individual key versions with the same key name.
+ * The full key identifier, attributes, and tags are provided in the response. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param maxresults Maximum number of results to return in a page. If not specified the service will return up to 25 results.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the PagedList<KeyItem> object if successful.
+ */
+ PagedList getKeyVersions(final String vaultBaseUrl, final String keyName, final Integer maxresults);
+
+ /**
+ * Retrieves a list of individual key versions with the same key name.
+ * The full key identifier, attributes, and tags are provided in the response. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param maxresults Maximum number of results to return in a page. If not specified the service will return up to 25 results.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture> getKeyVersionsAsync(final String vaultBaseUrl, final String keyName, final Integer maxresults, final ListOperationCallback serviceCallback);
+
+ /**
+ * Retrieves a list of individual key versions with the same key name.
+ * The full key identifier, attributes, and tags are provided in the response. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param maxresults Maximum number of results to return in a page. If not specified the service will return up to 25 results.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the PagedList<KeyItem> object
+ */
+ Observable> getKeyVersionsAsync(final String vaultBaseUrl, final String keyName, final Integer maxresults);
+
+ /**
+ * Retrieves a list of individual key versions with the same key name.
+ * The full key identifier, attributes, and tags are provided in the response. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param maxresults Maximum number of results to return in a page. If not specified the service will return up to 25 results.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the PagedList<KeyItem> object
+ */
+ Observable>> getKeyVersionsWithServiceResponseAsync(final String vaultBaseUrl, final String keyName, final Integer maxresults);
+
+ /**
+ * List keys in the specified vault.
+ * Retrieves a list of the keys in the Key Vault as JSON Web Key structures that contain the public part of a stored key. The LIST operation is applicable to all key types, however only the base key identifier, attributes, and tags are provided in the response. Individual versions of a key are not listed in the response. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the PagedList<KeyItem> object if successful.
+ */
+ PagedList getKeys(final String vaultBaseUrl);
+
+ /**
+ * List keys in the specified vault.
+ * Retrieves a list of the keys in the Key Vault as JSON Web Key structures that contain the public part of a stored key. The LIST operation is applicable to all key types, however only the base key identifier, attributes, and tags are provided in the response. Individual versions of a key are not listed in the response. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture> getKeysAsync(final String vaultBaseUrl, final ListOperationCallback serviceCallback);
+
+ /**
+ * List keys in the specified vault.
+ * Retrieves a list of the keys in the Key Vault as JSON Web Key structures that contain the public part of a stored key. The LIST operation is applicable to all key types, however only the base key identifier, attributes, and tags are provided in the response. Individual versions of a key are not listed in the response. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the PagedList<KeyItem> object
+ */
+ Observable> getKeysAsync(final String vaultBaseUrl);
+
+ /**
+ * List keys in the specified vault.
+ * Retrieves a list of the keys in the Key Vault as JSON Web Key structures that contain the public part of a stored key. The LIST operation is applicable to all key types, however only the base key identifier, attributes, and tags are provided in the response. Individual versions of a key are not listed in the response. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the PagedList<KeyItem> object
+ */
+ Observable>> getKeysWithServiceResponseAsync(final String vaultBaseUrl);
+ /**
+ * List keys in the specified vault.
+ * Retrieves a list of the keys in the Key Vault as JSON Web Key structures that contain the public part of a stored key. The LIST operation is applicable to all key types, however only the base key identifier, attributes, and tags are provided in the response. Individual versions of a key are not listed in the response. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param maxresults Maximum number of results to return in a page. If not specified the service will return up to 25 results.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the PagedList<KeyItem> object if successful.
+ */
+ PagedList getKeys(final String vaultBaseUrl, final Integer maxresults);
+
+ /**
+ * List keys in the specified vault.
+ * Retrieves a list of the keys in the Key Vault as JSON Web Key structures that contain the public part of a stored key. The LIST operation is applicable to all key types, however only the base key identifier, attributes, and tags are provided in the response. Individual versions of a key are not listed in the response. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param maxresults Maximum number of results to return in a page. If not specified the service will return up to 25 results.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture> getKeysAsync(final String vaultBaseUrl, final Integer maxresults, final ListOperationCallback serviceCallback);
+
+ /**
+ * List keys in the specified vault.
+ * Retrieves a list of the keys in the Key Vault as JSON Web Key structures that contain the public part of a stored key. The LIST operation is applicable to all key types, however only the base key identifier, attributes, and tags are provided in the response. Individual versions of a key are not listed in the response. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param maxresults Maximum number of results to return in a page. If not specified the service will return up to 25 results.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the PagedList<KeyItem> object
+ */
+ Observable> getKeysAsync(final String vaultBaseUrl, final Integer maxresults);
+
+ /**
+ * List keys in the specified vault.
+ * Retrieves a list of the keys in the Key Vault as JSON Web Key structures that contain the public part of a stored key. The LIST operation is applicable to all key types, however only the base key identifier, attributes, and tags are provided in the response. Individual versions of a key are not listed in the response. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param maxresults Maximum number of results to return in a page. If not specified the service will return up to 25 results.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the PagedList<KeyItem> object
+ */
+ Observable>> getKeysWithServiceResponseAsync(final String vaultBaseUrl, final Integer maxresults);
+
+ /**
+ * Requests that a backup of the specified key be downloaded to the client.
+ * The Key Backup operation exports a key from Azure Key Vault in a protected form. Note that this operation does NOT return key material in a form that can be used outside the Azure Key Vault system, the returned key material is either protected to a Azure Key Vault HSM or to Azure Key Vault itself. The intent of this operation is to allow a client to GENERATE a key in one Azure Key Vault instance, BACKUP the key, and then RESTORE it into another Azure Key Vault instance. The BACKUP operation may be used to export, in protected form, any key type from Azure Key Vault. Individual versions of a key cannot be backed up. BACKUP / RESTORE can be performed within geographical boundaries only; meaning that a BACKUP from one geographical area cannot be restored to another geographical area. For example, a backup from the US geographical area cannot be restored in an EU geographical area. This operation requires the key/backup permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the BackupKeyResult object if successful.
+ */
+ BackupKeyResult backupKey(String vaultBaseUrl, String keyName);
+
+ /**
+ * Requests that a backup of the specified key be downloaded to the client.
+ * The Key Backup operation exports a key from Azure Key Vault in a protected form. Note that this operation does NOT return key material in a form that can be used outside the Azure Key Vault system, the returned key material is either protected to a Azure Key Vault HSM or to Azure Key Vault itself. The intent of this operation is to allow a client to GENERATE a key in one Azure Key Vault instance, BACKUP the key, and then RESTORE it into another Azure Key Vault instance. The BACKUP operation may be used to export, in protected form, any key type from Azure Key Vault. Individual versions of a key cannot be backed up. BACKUP / RESTORE can be performed within geographical boundaries only; meaning that a BACKUP from one geographical area cannot be restored to another geographical area. For example, a backup from the US geographical area cannot be restored in an EU geographical area. This operation requires the key/backup permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture backupKeyAsync(String vaultBaseUrl, String keyName, final ServiceCallback serviceCallback);
+
+ /**
+ * Requests that a backup of the specified key be downloaded to the client.
+ * The Key Backup operation exports a key from Azure Key Vault in a protected form. Note that this operation does NOT return key material in a form that can be used outside the Azure Key Vault system, the returned key material is either protected to a Azure Key Vault HSM or to Azure Key Vault itself. The intent of this operation is to allow a client to GENERATE a key in one Azure Key Vault instance, BACKUP the key, and then RESTORE it into another Azure Key Vault instance. The BACKUP operation may be used to export, in protected form, any key type from Azure Key Vault. Individual versions of a key cannot be backed up. BACKUP / RESTORE can be performed within geographical boundaries only; meaning that a BACKUP from one geographical area cannot be restored to another geographical area. For example, a backup from the US geographical area cannot be restored in an EU geographical area. This operation requires the key/backup permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the BackupKeyResult object
+ */
+ Observable backupKeyAsync(String vaultBaseUrl, String keyName);
+
+ /**
+ * Requests that a backup of the specified key be downloaded to the client.
+ * The Key Backup operation exports a key from Azure Key Vault in a protected form. Note that this operation does NOT return key material in a form that can be used outside the Azure Key Vault system, the returned key material is either protected to a Azure Key Vault HSM or to Azure Key Vault itself. The intent of this operation is to allow a client to GENERATE a key in one Azure Key Vault instance, BACKUP the key, and then RESTORE it into another Azure Key Vault instance. The BACKUP operation may be used to export, in protected form, any key type from Azure Key Vault. Individual versions of a key cannot be backed up. BACKUP / RESTORE can be performed within geographical boundaries only; meaning that a BACKUP from one geographical area cannot be restored to another geographical area. For example, a backup from the US geographical area cannot be restored in an EU geographical area. This operation requires the key/backup permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the BackupKeyResult object
+ */
+ Observable> backupKeyWithServiceResponseAsync(String vaultBaseUrl, String keyName);
+
+ /**
+ * Restores a backed up key to a vault.
+ * Imports a previously backed up key into Azure Key Vault, restoring the key, its key identifier, attributes and access control policies. The RESTORE operation may be used to import a previously backed up key. Individual versions of a key cannot be restored. The key is restored in its entirety with the same key name as it had when it was backed up. If the key name is not available in the target Key Vault, the RESTORE operation will be rejected. While the key name is retained during restore, the final key identifier will change if the key is restored to a different vault. Restore will restore all versions and preserve version identifiers. The RESTORE operation is subject to security constraints: The target Key Vault must be owned by the same Microsoft Azure Subscription as the source Key Vault The user must have RESTORE permission in the target Key Vault. This operation requires the keys/restore permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyBundleBackup The backup blob associated with a key bundle.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the KeyBundle object if successful.
+ */
+ KeyBundle restoreKey(String vaultBaseUrl, byte[] keyBundleBackup);
+
+ /**
+ * Restores a backed up key to a vault.
+ * Imports a previously backed up key into Azure Key Vault, restoring the key, its key identifier, attributes and access control policies. The RESTORE operation may be used to import a previously backed up key. Individual versions of a key cannot be restored. The key is restored in its entirety with the same key name as it had when it was backed up. If the key name is not available in the target Key Vault, the RESTORE operation will be rejected. While the key name is retained during restore, the final key identifier will change if the key is restored to a different vault. Restore will restore all versions and preserve version identifiers. The RESTORE operation is subject to security constraints: The target Key Vault must be owned by the same Microsoft Azure Subscription as the source Key Vault The user must have RESTORE permission in the target Key Vault. This operation requires the keys/restore permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyBundleBackup The backup blob associated with a key bundle.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture restoreKeyAsync(String vaultBaseUrl, byte[] keyBundleBackup, final ServiceCallback serviceCallback);
+
+ /**
+ * Restores a backed up key to a vault.
+ * Imports a previously backed up key into Azure Key Vault, restoring the key, its key identifier, attributes and access control policies. The RESTORE operation may be used to import a previously backed up key. Individual versions of a key cannot be restored. The key is restored in its entirety with the same key name as it had when it was backed up. If the key name is not available in the target Key Vault, the RESTORE operation will be rejected. While the key name is retained during restore, the final key identifier will change if the key is restored to a different vault. Restore will restore all versions and preserve version identifiers. The RESTORE operation is subject to security constraints: The target Key Vault must be owned by the same Microsoft Azure Subscription as the source Key Vault The user must have RESTORE permission in the target Key Vault. This operation requires the keys/restore permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyBundleBackup The backup blob associated with a key bundle.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyBundle object
+ */
+ Observable restoreKeyAsync(String vaultBaseUrl, byte[] keyBundleBackup);
+
+ /**
+ * Restores a backed up key to a vault.
+ * Imports a previously backed up key into Azure Key Vault, restoring the key, its key identifier, attributes and access control policies. The RESTORE operation may be used to import a previously backed up key. Individual versions of a key cannot be restored. The key is restored in its entirety with the same key name as it had when it was backed up. If the key name is not available in the target Key Vault, the RESTORE operation will be rejected. While the key name is retained during restore, the final key identifier will change if the key is restored to a different vault. Restore will restore all versions and preserve version identifiers. The RESTORE operation is subject to security constraints: The target Key Vault must be owned by the same Microsoft Azure Subscription as the source Key Vault The user must have RESTORE permission in the target Key Vault. This operation requires the keys/restore permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyBundleBackup The backup blob associated with a key bundle.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyBundle object
+ */
+ Observable> restoreKeyWithServiceResponseAsync(String vaultBaseUrl, byte[] keyBundleBackup);
+
+ /**
+ * Encrypts an arbitrary sequence of bytes using an encryption key that is stored in a key vault.
+ * The ENCRYPT operation encrypts an arbitrary sequence of bytes using an encryption key that is stored in Azure Key Vault. Note that the ENCRYPT operation only supports a single block of data, the size of which is dependent on the target key and the encryption algorithm to be used. The ENCRYPT operation is only strictly necessary for symmetric keys stored in Azure Key Vault since protection with an asymmetric key can be performed using public portion of the key. This operation is supported for asymmetric keys as a convenience for callers that have a key-reference but do not have access to the public key material. This operation requires the keys/encypt permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm algorithm identifier. Possible values include: 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5'
+ * @param value the Base64Url value
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the KeyOperationResult object if successful.
+ */
+ KeyOperationResult encrypt(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeyEncryptionAlgorithm algorithm, byte[] value);
+
+ /**
+ * Encrypts an arbitrary sequence of bytes using an encryption key that is stored in a key vault.
+ * The ENCRYPT operation encrypts an arbitrary sequence of bytes using an encryption key that is stored in Azure Key Vault. Note that the ENCRYPT operation only supports a single block of data, the size of which is dependent on the target key and the encryption algorithm to be used. The ENCRYPT operation is only strictly necessary for symmetric keys stored in Azure Key Vault since protection with an asymmetric key can be performed using public portion of the key. This operation is supported for asymmetric keys as a convenience for callers that have a key-reference but do not have access to the public key material. This operation requires the keys/encypt permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm algorithm identifier. Possible values include: 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5'
+ * @param value the Base64Url value
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture encryptAsync(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeyEncryptionAlgorithm algorithm, byte[] value, final ServiceCallback serviceCallback);
+
+ /**
+ * Encrypts an arbitrary sequence of bytes using an encryption key that is stored in a key vault.
+ * The ENCRYPT operation encrypts an arbitrary sequence of bytes using an encryption key that is stored in Azure Key Vault. Note that the ENCRYPT operation only supports a single block of data, the size of which is dependent on the target key and the encryption algorithm to be used. The ENCRYPT operation is only strictly necessary for symmetric keys stored in Azure Key Vault since protection with an asymmetric key can be performed using public portion of the key. This operation is supported for asymmetric keys as a convenience for callers that have a key-reference but do not have access to the public key material. This operation requires the keys/encypt permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm algorithm identifier. Possible values include: 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5'
+ * @param value the Base64Url value
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyOperationResult object
+ */
+ Observable encryptAsync(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeyEncryptionAlgorithm algorithm, byte[] value);
+
+ /**
+ * Encrypts an arbitrary sequence of bytes using an encryption key that is stored in a key vault.
+ * The ENCRYPT operation encrypts an arbitrary sequence of bytes using an encryption key that is stored in Azure Key Vault. Note that the ENCRYPT operation only supports a single block of data, the size of which is dependent on the target key and the encryption algorithm to be used. The ENCRYPT operation is only strictly necessary for symmetric keys stored in Azure Key Vault since protection with an asymmetric key can be performed using public portion of the key. This operation is supported for asymmetric keys as a convenience for callers that have a key-reference but do not have access to the public key material. This operation requires the keys/encypt permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm algorithm identifier. Possible values include: 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5'
+ * @param value the Base64Url value
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyOperationResult object
+ */
+ Observable> encryptWithServiceResponseAsync(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeyEncryptionAlgorithm algorithm, byte[] value);
+
+ /**
+ * Decrypts a single block of encrypted data.
+ * The DECRYPT operation decrypts a well-formed block of ciphertext using the target encryption key and specified algorithm. This operation is the reverse of the ENCRYPT operation; only a single block of data may be decrypted, the size of this block is dependent on the target key and the algorithm to be used. The DECRYPT operation applies to asymmetric and symmetric keys stored in Azure Key Vault since it uses the private portion of the key. This operation requires the keys/decrypt permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm algorithm identifier. Possible values include: 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5'
+ * @param value the Base64Url value
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the KeyOperationResult object if successful.
+ */
+ KeyOperationResult decrypt(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeyEncryptionAlgorithm algorithm, byte[] value);
+
+ /**
+ * Decrypts a single block of encrypted data.
+ * The DECRYPT operation decrypts a well-formed block of ciphertext using the target encryption key and specified algorithm. This operation is the reverse of the ENCRYPT operation; only a single block of data may be decrypted, the size of this block is dependent on the target key and the algorithm to be used. The DECRYPT operation applies to asymmetric and symmetric keys stored in Azure Key Vault since it uses the private portion of the key. This operation requires the keys/decrypt permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm algorithm identifier. Possible values include: 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5'
+ * @param value the Base64Url value
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture decryptAsync(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeyEncryptionAlgorithm algorithm, byte[] value, final ServiceCallback serviceCallback);
+
+ /**
+ * Decrypts a single block of encrypted data.
+ * The DECRYPT operation decrypts a well-formed block of ciphertext using the target encryption key and specified algorithm. This operation is the reverse of the ENCRYPT operation; only a single block of data may be decrypted, the size of this block is dependent on the target key and the algorithm to be used. The DECRYPT operation applies to asymmetric and symmetric keys stored in Azure Key Vault since it uses the private portion of the key. This operation requires the keys/decrypt permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm algorithm identifier. Possible values include: 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5'
+ * @param value the Base64Url value
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyOperationResult object
+ */
+ Observable decryptAsync(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeyEncryptionAlgorithm algorithm, byte[] value);
+
+ /**
+ * Decrypts a single block of encrypted data.
+ * The DECRYPT operation decrypts a well-formed block of ciphertext using the target encryption key and specified algorithm. This operation is the reverse of the ENCRYPT operation; only a single block of data may be decrypted, the size of this block is dependent on the target key and the algorithm to be used. The DECRYPT operation applies to asymmetric and symmetric keys stored in Azure Key Vault since it uses the private portion of the key. This operation requires the keys/decrypt permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm algorithm identifier. Possible values include: 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5'
+ * @param value the Base64Url value
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyOperationResult object
+ */
+ Observable> decryptWithServiceResponseAsync(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeyEncryptionAlgorithm algorithm, byte[] value);
+
+ /**
+ * Creates a signature from a digest using the specified key.
+ * The SIGN operation is applicable to asymmetric and symmetric keys stored in Azure Key Vault since this operation uses the private portion of the key. This operation requires the keys/sign permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm The signing/verification algorithm identifier. For more information on possible algorithm types, see JsonWebKeySignatureAlgorithm. Possible values include: 'PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512', 'RSNULL', 'ES256', 'ES384', 'ES512', 'ES256K'
+ * @param value the Base64Url value
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the KeyOperationResult object if successful.
+ */
+ KeyOperationResult sign(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeySignatureAlgorithm algorithm, byte[] value);
+
+ /**
+ * Creates a signature from a digest using the specified key.
+ * The SIGN operation is applicable to asymmetric and symmetric keys stored in Azure Key Vault since this operation uses the private portion of the key. This operation requires the keys/sign permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm The signing/verification algorithm identifier. For more information on possible algorithm types, see JsonWebKeySignatureAlgorithm. Possible values include: 'PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512', 'RSNULL', 'ES256', 'ES384', 'ES512', 'ES256K'
+ * @param value the Base64Url value
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture signAsync(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeySignatureAlgorithm algorithm, byte[] value, final ServiceCallback serviceCallback);
+
+ /**
+ * Creates a signature from a digest using the specified key.
+ * The SIGN operation is applicable to asymmetric and symmetric keys stored in Azure Key Vault since this operation uses the private portion of the key. This operation requires the keys/sign permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm The signing/verification algorithm identifier. For more information on possible algorithm types, see JsonWebKeySignatureAlgorithm. Possible values include: 'PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512', 'RSNULL', 'ES256', 'ES384', 'ES512', 'ES256K'
+ * @param value the Base64Url value
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyOperationResult object
+ */
+ Observable signAsync(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeySignatureAlgorithm algorithm, byte[] value);
+
+ /**
+ * Creates a signature from a digest using the specified key.
+ * The SIGN operation is applicable to asymmetric and symmetric keys stored in Azure Key Vault since this operation uses the private portion of the key. This operation requires the keys/sign permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm The signing/verification algorithm identifier. For more information on possible algorithm types, see JsonWebKeySignatureAlgorithm. Possible values include: 'PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512', 'RSNULL', 'ES256', 'ES384', 'ES512', 'ES256K'
+ * @param value the Base64Url value
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyOperationResult object
+ */
+ Observable> signWithServiceResponseAsync(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeySignatureAlgorithm algorithm, byte[] value);
+
+ /**
+ * Verifies a signature using a specified key.
+ * The VERIFY operation is applicable to symmetric keys stored in Azure Key Vault. VERIFY is not strictly necessary for asymmetric keys stored in Azure Key Vault since signature verification can be performed using the public portion of the key but this operation is supported as a convenience for callers that only have a key-reference and not the public portion of the key. This operation requires the keys/verify permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm The signing/verification algorithm. For more information on possible algorithm types, see JsonWebKeySignatureAlgorithm. Possible values include: 'PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512', 'RSNULL', 'ES256', 'ES384', 'ES512', 'ES256K'
+ * @param digest The digest used for signing.
+ * @param signature The signature to be verified.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the KeyVerifyResult object if successful.
+ */
+ KeyVerifyResult verify(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeySignatureAlgorithm algorithm, byte[] digest, byte[] signature);
+
+ /**
+ * Verifies a signature using a specified key.
+ * The VERIFY operation is applicable to symmetric keys stored in Azure Key Vault. VERIFY is not strictly necessary for asymmetric keys stored in Azure Key Vault since signature verification can be performed using the public portion of the key but this operation is supported as a convenience for callers that only have a key-reference and not the public portion of the key. This operation requires the keys/verify permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm The signing/verification algorithm. For more information on possible algorithm types, see JsonWebKeySignatureAlgorithm. Possible values include: 'PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512', 'RSNULL', 'ES256', 'ES384', 'ES512', 'ES256K'
+ * @param digest The digest used for signing.
+ * @param signature The signature to be verified.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture verifyAsync(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeySignatureAlgorithm algorithm, byte[] digest, byte[] signature, final ServiceCallback serviceCallback);
+
+ /**
+ * Verifies a signature using a specified key.
+ * The VERIFY operation is applicable to symmetric keys stored in Azure Key Vault. VERIFY is not strictly necessary for asymmetric keys stored in Azure Key Vault since signature verification can be performed using the public portion of the key but this operation is supported as a convenience for callers that only have a key-reference and not the public portion of the key. This operation requires the keys/verify permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm The signing/verification algorithm. For more information on possible algorithm types, see JsonWebKeySignatureAlgorithm. Possible values include: 'PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512', 'RSNULL', 'ES256', 'ES384', 'ES512', 'ES256K'
+ * @param digest The digest used for signing.
+ * @param signature The signature to be verified.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyVerifyResult object
+ */
+ Observable verifyAsync(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeySignatureAlgorithm algorithm, byte[] digest, byte[] signature);
+
+ /**
+ * Verifies a signature using a specified key.
+ * The VERIFY operation is applicable to symmetric keys stored in Azure Key Vault. VERIFY is not strictly necessary for asymmetric keys stored in Azure Key Vault since signature verification can be performed using the public portion of the key but this operation is supported as a convenience for callers that only have a key-reference and not the public portion of the key. This operation requires the keys/verify permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm The signing/verification algorithm. For more information on possible algorithm types, see JsonWebKeySignatureAlgorithm. Possible values include: 'PS256', 'PS384', 'PS512', 'RS256', 'RS384', 'RS512', 'RSNULL', 'ES256', 'ES384', 'ES512', 'ES256K'
+ * @param digest The digest used for signing.
+ * @param signature The signature to be verified.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyVerifyResult object
+ */
+ Observable> verifyWithServiceResponseAsync(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeySignatureAlgorithm algorithm, byte[] digest, byte[] signature);
+
+ /**
+ * Wraps a symmetric key using a specified key.
+ * The WRAP operation supports encryption of a symmetric key using a key encryption key that has previously been stored in an Azure Key Vault. The WRAP operation is only strictly necessary for symmetric keys stored in Azure Key Vault since protection with an asymmetric key can be performed using the public portion of the key. This operation is supported for asymmetric keys as a convenience for callers that have a key-reference but do not have access to the public key material. This operation requires the keys/wrapKey permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm algorithm identifier. Possible values include: 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5'
+ * @param value the Base64Url value
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the KeyOperationResult object if successful.
+ */
+ KeyOperationResult wrapKey(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeyEncryptionAlgorithm algorithm, byte[] value);
+
+ /**
+ * Wraps a symmetric key using a specified key.
+ * The WRAP operation supports encryption of a symmetric key using a key encryption key that has previously been stored in an Azure Key Vault. The WRAP operation is only strictly necessary for symmetric keys stored in Azure Key Vault since protection with an asymmetric key can be performed using the public portion of the key. This operation is supported for asymmetric keys as a convenience for callers that have a key-reference but do not have access to the public key material. This operation requires the keys/wrapKey permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm algorithm identifier. Possible values include: 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5'
+ * @param value the Base64Url value
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture wrapKeyAsync(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeyEncryptionAlgorithm algorithm, byte[] value, final ServiceCallback serviceCallback);
+
+ /**
+ * Wraps a symmetric key using a specified key.
+ * The WRAP operation supports encryption of a symmetric key using a key encryption key that has previously been stored in an Azure Key Vault. The WRAP operation is only strictly necessary for symmetric keys stored in Azure Key Vault since protection with an asymmetric key can be performed using the public portion of the key. This operation is supported for asymmetric keys as a convenience for callers that have a key-reference but do not have access to the public key material. This operation requires the keys/wrapKey permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm algorithm identifier. Possible values include: 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5'
+ * @param value the Base64Url value
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyOperationResult object
+ */
+ Observable wrapKeyAsync(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeyEncryptionAlgorithm algorithm, byte[] value);
+
+ /**
+ * Wraps a symmetric key using a specified key.
+ * The WRAP operation supports encryption of a symmetric key using a key encryption key that has previously been stored in an Azure Key Vault. The WRAP operation is only strictly necessary for symmetric keys stored in Azure Key Vault since protection with an asymmetric key can be performed using the public portion of the key. This operation is supported for asymmetric keys as a convenience for callers that have a key-reference but do not have access to the public key material. This operation requires the keys/wrapKey permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm algorithm identifier. Possible values include: 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5'
+ * @param value the Base64Url value
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyOperationResult object
+ */
+ Observable> wrapKeyWithServiceResponseAsync(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeyEncryptionAlgorithm algorithm, byte[] value);
+
+ /**
+ * Unwraps a symmetric key using the specified key that was initially used for wrapping that key.
+ * The UNWRAP operation supports decryption of a symmetric key using the target key encryption key. This operation is the reverse of the WRAP operation. The UNWRAP operation applies to asymmetric and symmetric keys stored in Azure Key Vault since it uses the private portion of the key. This operation requires the keys/unwrapKey permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm algorithm identifier. Possible values include: 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5'
+ * @param value the Base64Url value
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the KeyOperationResult object if successful.
+ */
+ KeyOperationResult unwrapKey(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeyEncryptionAlgorithm algorithm, byte[] value);
+
+ /**
+ * Unwraps a symmetric key using the specified key that was initially used for wrapping that key.
+ * The UNWRAP operation supports decryption of a symmetric key using the target key encryption key. This operation is the reverse of the WRAP operation. The UNWRAP operation applies to asymmetric and symmetric keys stored in Azure Key Vault since it uses the private portion of the key. This operation requires the keys/unwrapKey permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm algorithm identifier. Possible values include: 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5'
+ * @param value the Base64Url value
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture unwrapKeyAsync(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeyEncryptionAlgorithm algorithm, byte[] value, final ServiceCallback serviceCallback);
+
+ /**
+ * Unwraps a symmetric key using the specified key that was initially used for wrapping that key.
+ * The UNWRAP operation supports decryption of a symmetric key using the target key encryption key. This operation is the reverse of the WRAP operation. The UNWRAP operation applies to asymmetric and symmetric keys stored in Azure Key Vault since it uses the private portion of the key. This operation requires the keys/unwrapKey permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm algorithm identifier. Possible values include: 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5'
+ * @param value the Base64Url value
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyOperationResult object
+ */
+ Observable unwrapKeyAsync(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeyEncryptionAlgorithm algorithm, byte[] value);
+
+ /**
+ * Unwraps a symmetric key using the specified key that was initially used for wrapping that key.
+ * The UNWRAP operation supports decryption of a symmetric key using the target key encryption key. This operation is the reverse of the WRAP operation. The UNWRAP operation applies to asymmetric and symmetric keys stored in Azure Key Vault since it uses the private portion of the key. This operation requires the keys/unwrapKey permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param keyVersion The version of the key.
+ * @param algorithm algorithm identifier. Possible values include: 'RSA-OAEP', 'RSA-OAEP-256', 'RSA1_5'
+ * @param value the Base64Url value
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyOperationResult object
+ */
+ Observable> unwrapKeyWithServiceResponseAsync(String vaultBaseUrl, String keyName, String keyVersion, JsonWebKeyEncryptionAlgorithm algorithm, byte[] value);
+
+ /**
+ * Lists the deleted keys in the specified vault.
+ * Retrieves a list of the keys in the Key Vault as JSON Web Key structures that contain the public part of a deleted key. This operation includes deletion-specific information. The Get Deleted Keys operation is applicable for vaults enabled for soft-delete. While the operation can be invoked on any vault, it will return an error if invoked on a non soft-delete enabled vault. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the PagedList<DeletedKeyItem> object if successful.
+ */
+ PagedList getDeletedKeys(final String vaultBaseUrl);
+
+ /**
+ * Lists the deleted keys in the specified vault.
+ * Retrieves a list of the keys in the Key Vault as JSON Web Key structures that contain the public part of a deleted key. This operation includes deletion-specific information. The Get Deleted Keys operation is applicable for vaults enabled for soft-delete. While the operation can be invoked on any vault, it will return an error if invoked on a non soft-delete enabled vault. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture> getDeletedKeysAsync(final String vaultBaseUrl, final ListOperationCallback serviceCallback);
+
+ /**
+ * Lists the deleted keys in the specified vault.
+ * Retrieves a list of the keys in the Key Vault as JSON Web Key structures that contain the public part of a deleted key. This operation includes deletion-specific information. The Get Deleted Keys operation is applicable for vaults enabled for soft-delete. While the operation can be invoked on any vault, it will return an error if invoked on a non soft-delete enabled vault. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the PagedList<DeletedKeyItem> object
+ */
+ Observable> getDeletedKeysAsync(final String vaultBaseUrl);
+
+ /**
+ * Lists the deleted keys in the specified vault.
+ * Retrieves a list of the keys in the Key Vault as JSON Web Key structures that contain the public part of a deleted key. This operation includes deletion-specific information. The Get Deleted Keys operation is applicable for vaults enabled for soft-delete. While the operation can be invoked on any vault, it will return an error if invoked on a non soft-delete enabled vault. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the PagedList<DeletedKeyItem> object
+ */
+ Observable>> getDeletedKeysWithServiceResponseAsync(final String vaultBaseUrl);
+ /**
+ * Lists the deleted keys in the specified vault.
+ * Retrieves a list of the keys in the Key Vault as JSON Web Key structures that contain the public part of a deleted key. This operation includes deletion-specific information. The Get Deleted Keys operation is applicable for vaults enabled for soft-delete. While the operation can be invoked on any vault, it will return an error if invoked on a non soft-delete enabled vault. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param maxresults Maximum number of results to return in a page. If not specified the service will return up to 25 results.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the PagedList<DeletedKeyItem> object if successful.
+ */
+ PagedList getDeletedKeys(final String vaultBaseUrl, final Integer maxresults);
+
+ /**
+ * Lists the deleted keys in the specified vault.
+ * Retrieves a list of the keys in the Key Vault as JSON Web Key structures that contain the public part of a deleted key. This operation includes deletion-specific information. The Get Deleted Keys operation is applicable for vaults enabled for soft-delete. While the operation can be invoked on any vault, it will return an error if invoked on a non soft-delete enabled vault. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param maxresults Maximum number of results to return in a page. If not specified the service will return up to 25 results.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture> getDeletedKeysAsync(final String vaultBaseUrl, final Integer maxresults, final ListOperationCallback serviceCallback);
+
+ /**
+ * Lists the deleted keys in the specified vault.
+ * Retrieves a list of the keys in the Key Vault as JSON Web Key structures that contain the public part of a deleted key. This operation includes deletion-specific information. The Get Deleted Keys operation is applicable for vaults enabled for soft-delete. While the operation can be invoked on any vault, it will return an error if invoked on a non soft-delete enabled vault. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param maxresults Maximum number of results to return in a page. If not specified the service will return up to 25 results.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the PagedList<DeletedKeyItem> object
+ */
+ Observable> getDeletedKeysAsync(final String vaultBaseUrl, final Integer maxresults);
+
+ /**
+ * Lists the deleted keys in the specified vault.
+ * Retrieves a list of the keys in the Key Vault as JSON Web Key structures that contain the public part of a deleted key. This operation includes deletion-specific information. The Get Deleted Keys operation is applicable for vaults enabled for soft-delete. While the operation can be invoked on any vault, it will return an error if invoked on a non soft-delete enabled vault. This operation requires the keys/list permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param maxresults Maximum number of results to return in a page. If not specified the service will return up to 25 results.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the PagedList<DeletedKeyItem> object
+ */
+ Observable>> getDeletedKeysWithServiceResponseAsync(final String vaultBaseUrl, final Integer maxresults);
+
+ /**
+ * Gets the public part of a deleted key.
+ * The Get Deleted Key operation is applicable for soft-delete enabled vaults. While the operation can be invoked on any vault, it will return an error if invoked on a non soft-delete enabled vault. This operation requires the keys/get permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the DeletedKeyBundle object if successful.
+ */
+ DeletedKeyBundle getDeletedKey(String vaultBaseUrl, String keyName);
+
+ /**
+ * Gets the public part of a deleted key.
+ * The Get Deleted Key operation is applicable for soft-delete enabled vaults. While the operation can be invoked on any vault, it will return an error if invoked on a non soft-delete enabled vault. This operation requires the keys/get permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture getDeletedKeyAsync(String vaultBaseUrl, String keyName, final ServiceCallback serviceCallback);
+
+ /**
+ * Gets the public part of a deleted key.
+ * The Get Deleted Key operation is applicable for soft-delete enabled vaults. While the operation can be invoked on any vault, it will return an error if invoked on a non soft-delete enabled vault. This operation requires the keys/get permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the DeletedKeyBundle object
+ */
+ Observable getDeletedKeyAsync(String vaultBaseUrl, String keyName);
+
+ /**
+ * Gets the public part of a deleted key.
+ * The Get Deleted Key operation is applicable for soft-delete enabled vaults. While the operation can be invoked on any vault, it will return an error if invoked on a non soft-delete enabled vault. This operation requires the keys/get permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the DeletedKeyBundle object
+ */
+ Observable> getDeletedKeyWithServiceResponseAsync(String vaultBaseUrl, String keyName);
+
+ /**
+ * Permanently deletes the specified key.
+ * The Purge Deleted Key operation is applicable for soft-delete enabled vaults. While the operation can be invoked on any vault, it will return an error if invoked on a non soft-delete enabled vault. This operation requires the keys/purge permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ */
+ void purgeDeletedKey(String vaultBaseUrl, String keyName);
+
+ /**
+ * Permanently deletes the specified key.
+ * The Purge Deleted Key operation is applicable for soft-delete enabled vaults. While the operation can be invoked on any vault, it will return an error if invoked on a non soft-delete enabled vault. This operation requires the keys/purge permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture purgeDeletedKeyAsync(String vaultBaseUrl, String keyName, final ServiceCallback serviceCallback);
+
+ /**
+ * Permanently deletes the specified key.
+ * The Purge Deleted Key operation is applicable for soft-delete enabled vaults. While the operation can be invoked on any vault, it will return an error if invoked on a non soft-delete enabled vault. This operation requires the keys/purge permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceResponse} object if successful.
+ */
+ Observable purgeDeletedKeyAsync(String vaultBaseUrl, String keyName);
+
+ /**
+ * Permanently deletes the specified key.
+ * The Purge Deleted Key operation is applicable for soft-delete enabled vaults. While the operation can be invoked on any vault, it will return an error if invoked on a non soft-delete enabled vault. This operation requires the keys/purge permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the key
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceResponse} object if successful.
+ */
+ Observable> purgeDeletedKeyWithServiceResponseAsync(String vaultBaseUrl, String keyName);
+
+ /**
+ * Recovers the deleted key to its latest version.
+ * The Recover Deleted Key operation is applicable for deleted keys in soft-delete enabled vaults. It recovers the deleted key back to its latest version under /keys. An attempt to recover an non-deleted key will return an error. Consider this the inverse of the delete operation on soft-delete enabled vaults. This operation requires the keys/recover permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the deleted key.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the KeyBundle object if successful.
+ */
+ KeyBundle recoverDeletedKey(String vaultBaseUrl, String keyName);
+
+ /**
+ * Recovers the deleted key to its latest version.
+ * The Recover Deleted Key operation is applicable for deleted keys in soft-delete enabled vaults. It recovers the deleted key back to its latest version under /keys. An attempt to recover an non-deleted key will return an error. Consider this the inverse of the delete operation on soft-delete enabled vaults. This operation requires the keys/recover permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the deleted key.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture recoverDeletedKeyAsync(String vaultBaseUrl, String keyName, final ServiceCallback serviceCallback);
+
+ /**
+ * Recovers the deleted key to its latest version.
+ * The Recover Deleted Key operation is applicable for deleted keys in soft-delete enabled vaults. It recovers the deleted key back to its latest version under /keys. An attempt to recover an non-deleted key will return an error. Consider this the inverse of the delete operation on soft-delete enabled vaults. This operation requires the keys/recover permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the deleted key.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyBundle object
+ */
+ Observable recoverDeletedKeyAsync(String vaultBaseUrl, String keyName);
+
+ /**
+ * Recovers the deleted key to its latest version.
+ * The Recover Deleted Key operation is applicable for deleted keys in soft-delete enabled vaults. It recovers the deleted key back to its latest version under /keys. An attempt to recover an non-deleted key will return an error. Consider this the inverse of the delete operation on soft-delete enabled vaults. This operation requires the keys/recover permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param keyName The name of the deleted key.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the KeyBundle object
+ */
+ Observable> recoverDeletedKeyWithServiceResponseAsync(String vaultBaseUrl, String keyName);
+
+ /**
+ * Sets a secret in a specified key vault.
+ * The SET operation adds a secret to the Azure Key Vault. If the named secret already exists, Azure Key Vault creates a new version of that secret. This operation requires the secrets/set permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param secretName The name of the secret.
+ * @param value The value of the secret.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the SecretBundle object if successful.
+ */
+ SecretBundle setSecret(String vaultBaseUrl, String secretName, String value);
+
+ /**
+ * Sets a secret in a specified key vault.
+ * The SET operation adds a secret to the Azure Key Vault. If the named secret already exists, Azure Key Vault creates a new version of that secret. This operation requires the secrets/set permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param secretName The name of the secret.
+ * @param value The value of the secret.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture setSecretAsync(String vaultBaseUrl, String secretName, String value, final ServiceCallback serviceCallback);
+
+ /**
+ * Sets a secret in a specified key vault.
+ * The SET operation adds a secret to the Azure Key Vault. If the named secret already exists, Azure Key Vault creates a new version of that secret. This operation requires the secrets/set permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param secretName The name of the secret.
+ * @param value The value of the secret.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the SecretBundle object
+ */
+ Observable setSecretAsync(String vaultBaseUrl, String secretName, String value);
+
+ /**
+ * Sets a secret in a specified key vault.
+ * The SET operation adds a secret to the Azure Key Vault. If the named secret already exists, Azure Key Vault creates a new version of that secret. This operation requires the secrets/set permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param secretName The name of the secret.
+ * @param value The value of the secret.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the SecretBundle object
+ */
+ Observable> setSecretWithServiceResponseAsync(String vaultBaseUrl, String secretName, String value);
+ /**
+ * Sets a secret in a specified key vault.
+ * The SET operation adds a secret to the Azure Key Vault. If the named secret already exists, Azure Key Vault creates a new version of that secret. This operation requires the secrets/set permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param secretName The name of the secret.
+ * @param value The value of the secret.
+ * @param tags Application specific metadata in the form of key-value pairs.
+ * @param contentType Type of the secret value such as a password.
+ * @param secretAttributes The secret management attributes.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the SecretBundle object if successful.
+ */
+ SecretBundle setSecret(String vaultBaseUrl, String secretName, String value, Map tags, String contentType, SecretAttributes secretAttributes);
+
+ /**
+ * Sets a secret in a specified key vault.
+ * The SET operation adds a secret to the Azure Key Vault. If the named secret already exists, Azure Key Vault creates a new version of that secret. This operation requires the secrets/set permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param secretName The name of the secret.
+ * @param value The value of the secret.
+ * @param tags Application specific metadata in the form of key-value pairs.
+ * @param contentType Type of the secret value such as a password.
+ * @param secretAttributes The secret management attributes.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture setSecretAsync(String vaultBaseUrl, String secretName, String value, Map tags, String contentType, SecretAttributes secretAttributes, final ServiceCallback serviceCallback);
+
+ /**
+ * Sets a secret in a specified key vault.
+ * The SET operation adds a secret to the Azure Key Vault. If the named secret already exists, Azure Key Vault creates a new version of that secret. This operation requires the secrets/set permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param secretName The name of the secret.
+ * @param value The value of the secret.
+ * @param tags Application specific metadata in the form of key-value pairs.
+ * @param contentType Type of the secret value such as a password.
+ * @param secretAttributes The secret management attributes.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the SecretBundle object
+ */
+ Observable setSecretAsync(String vaultBaseUrl, String secretName, String value, Map tags, String contentType, SecretAttributes secretAttributes);
+
+ /**
+ * Sets a secret in a specified key vault.
+ * The SET operation adds a secret to the Azure Key Vault. If the named secret already exists, Azure Key Vault creates a new version of that secret. This operation requires the secrets/set permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param secretName The name of the secret.
+ * @param value The value of the secret.
+ * @param tags Application specific metadata in the form of key-value pairs.
+ * @param contentType Type of the secret value such as a password.
+ * @param secretAttributes The secret management attributes.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the SecretBundle object
+ */
+ Observable> setSecretWithServiceResponseAsync(String vaultBaseUrl, String secretName, String value, Map tags, String contentType, SecretAttributes secretAttributes);
+
+ /**
+ * Deletes a secret from a specified key vault.
+ * The DELETE operation applies to any secret stored in Azure Key Vault. DELETE cannot be applied to an individual version of a secret. This operation requires the secrets/delete permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param secretName The name of the secret.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @throws KeyVaultErrorException thrown if the request is rejected by server
+ * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent
+ * @return the DeletedSecretBundle object if successful.
+ */
+ DeletedSecretBundle deleteSecret(String vaultBaseUrl, String secretName);
+
+ /**
+ * Deletes a secret from a specified key vault.
+ * The DELETE operation applies to any secret stored in Azure Key Vault. DELETE cannot be applied to an individual version of a secret. This operation requires the secrets/delete permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param secretName The name of the secret.
+ * @param serviceCallback the async ServiceCallback to handle successful and failed responses.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the {@link ServiceFuture} object
+ */
+ ServiceFuture deleteSecretAsync(String vaultBaseUrl, String secretName, final ServiceCallback serviceCallback);
+
+ /**
+ * Deletes a secret from a specified key vault.
+ * The DELETE operation applies to any secret stored in Azure Key Vault. DELETE cannot be applied to an individual version of a secret. This operation requires the secrets/delete permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param secretName The name of the secret.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the DeletedSecretBundle object
+ */
+ Observable deleteSecretAsync(String vaultBaseUrl, String secretName);
+
+ /**
+ * Deletes a secret from a specified key vault.
+ * The DELETE operation applies to any secret stored in Azure Key Vault. DELETE cannot be applied to an individual version of a secret. This operation requires the secrets/delete permission.
+ *
+ * @param vaultBaseUrl The vault name, for example https://myvault.vault.azure.net.
+ * @param secretName The name of the secret.
+ * @throws IllegalArgumentException thrown if parameters fail the validation
+ * @return the observable to the DeletedSecretBundle object
+ */
+ Observable