diff --git a/azure-keyvault-cryptography/pom.xml b/azure-keyvault-cryptography/pom.xml
index eae8042..6901103 100644
--- a/azure-keyvault-cryptography/pom.xml
+++ b/azure-keyvault-cryptography/pom.xml
@@ -4,12 +4,12 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
-
- com.microsoft.azure
- azure-keyvault-parent
- 1.1-beta-1
- ../pom.xml
-
+
+ com.microsoft.azure
+ azure-keyvault-parent
+ 1.1-beta-1
+ ../pom.xml
+
azure-keyvault-cryptography
jar
@@ -39,39 +39,27 @@
true
-
-
-
- junit
- junit
- test
-
-
- org.bouncycastle
- bcprov-jdk15on
- test
- 1.59
-
-
- com.microsoft.azure
- azure-keyvault-webkey
- 1.1-beta-1
-
-
- com.microsoft.azure
- azure-keyvault-core
- 1.0.0
+
+
+ org.bouncycastle
+ bcprov-jdk15on
+ test
+ 1.59
- com.microsoft.rest
- client-runtime
- 1.3.0
+ com.microsoft.azure
+ azure-keyvault-webkey
+ 1.1-beta-1
com.microsoft.azure
- azure-client-authentication
- 1.3.0
+ azure-keyvault-core
+ 1.0.0
+
+
+ junit
+ junit
+ test
-
-
+
diff --git a/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AlgorithmResolver.java b/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AlgorithmResolver.java
index 7727041..31bf10e 100644
--- a/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AlgorithmResolver.java
+++ b/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AlgorithmResolver.java
@@ -22,9 +22,14 @@
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.Ps256;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Ps384;
+import com.microsoft.azure.keyvault.cryptography.algorithms.Ps512;
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.cryptography.algorithms.RsaesOaep256;
+import com.microsoft.azure.keyvault.cryptography.algorithms.PsBase;
public class AlgorithmResolver {
@@ -45,8 +50,13 @@ public class AlgorithmResolver {
Default.put(Rsa15.ALGORITHM_NAME, new Rsa15());
Default.put(RsaOaep.ALGORITHM_NAME, new RsaOaep());
+ Default.put(RsaesOaep256.ALGORITHM_NAME, new RsaesOaep256());
Default.put( Rs256.ALGORITHM_NAME, new Rs256() );
+ Default.put( Ps256.ALGORITHM_NAME, new Ps256());
+ Default.put( Ps384.ALGORITHM_NAME, new Ps384());
+ Default.put( Ps512.ALGORITHM_NAME, new Ps512());
+
// Default.put( RsNull.ALGORITHM_NAME, new RsNull() );
Default.put(Ecdsa256.ALGORITHM_NAME, new Ecdsa256());
diff --git a/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/RsaKey.java b/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/RsaKey.java
index c0ae1b5..6f39ccd 100644
--- a/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/RsaKey.java
+++ b/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/RsaKey.java
@@ -22,6 +22,7 @@
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.cryptography.algorithms.RsaSignature;
import com.microsoft.azure.keyvault.webkey.JsonWebKey;
public class RsaKey implements IKey {
@@ -346,12 +347,12 @@ public ListenableFuture> signAsync(final byte[] digest, fin
throw new NoSuchAlgorithmException(algorithm);
}
- Rs256 algo = (Rs256)baseAlgorithm;
+ RsaSignature algo = (RsaSignature) baseAlgorithm;
ISignatureTransform signer = algo.createSignatureTransform(_keyPair);
try {
- return Futures.immediateFuture(Pair.of(signer.sign(digest), Rs256.ALGORITHM_NAME));
+ return Futures.immediateFuture(Pair.of(signer.sign(digest), algorithm));
} catch (Exception e) {
return Futures.immediateFailedFuture(e);
}
@@ -376,7 +377,7 @@ public ListenableFuture verifyAsync(final byte[] digest, final byte[] s
throw new NoSuchAlgorithmException(algorithm);
}
- Rs256 algo = (Rs256)baseAlgorithm;
+ RsaSignature algo = (RsaSignature) baseAlgorithm;
ISignatureTransform signer = algo.createSignatureTransform(_keyPair);
diff --git a/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ps256.java b/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ps256.java
new file mode 100644
index 0000000..3b4ea50
--- /dev/null
+++ b/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ps256.java
@@ -0,0 +1,21 @@
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+import java.security.KeyPair;
+
+import com.microsoft.azure.keyvault.cryptography.ISignatureTransform;
+
+public class Ps256 extends PsBase {
+
+ public final static String ALGORITHM_NAME = "PS256";
+ public final static String DIGEST_HASH_NAME = "SHA-256";
+
+ public Ps256() {
+ super(ALGORITHM_NAME);
+ }
+
+ @Override
+ public ISignatureTransform createSignatureTransform(KeyPair keyPair) {
+ return createSignatureTransform(keyPair, DIGEST_HASH_NAME);
+ }
+
+}
diff --git a/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ps384.java b/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ps384.java
new file mode 100644
index 0000000..7017d3b
--- /dev/null
+++ b/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ps384.java
@@ -0,0 +1,21 @@
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+import java.security.KeyPair;
+
+import com.microsoft.azure.keyvault.cryptography.ISignatureTransform;
+
+public class Ps384 extends PsBase {
+
+ public final static String ALGORITHM_NAME = "PS384";
+ public final static String DIGEST_HASH_NAME = "SHA-384";
+
+ public Ps384() {
+ super(ALGORITHM_NAME);
+ }
+
+ @Override
+ public ISignatureTransform createSignatureTransform(KeyPair keyPair) {
+ return createSignatureTransform(keyPair, DIGEST_HASH_NAME);
+ }
+
+}
diff --git a/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ps512.java b/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ps512.java
new file mode 100644
index 0000000..02b8591
--- /dev/null
+++ b/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ps512.java
@@ -0,0 +1,19 @@
+package com.microsoft.azure.keyvault.cryptography.algorithms;
+
+import java.security.KeyPair;
+
+import com.microsoft.azure.keyvault.cryptography.ISignatureTransform;
+
+public class Ps512 extends PsBase {
+ public final static String ALGORITHM_NAME = "PS512";
+ public final static String DIGEST_HASH_NAME = "SHA-512";
+
+ public Ps512() {
+ super(ALGORITHM_NAME);
+ }
+
+ @Override
+ public ISignatureTransform createSignatureTransform(KeyPair keyPair) {
+ return createSignatureTransform(keyPair, DIGEST_HASH_NAME);
+ }
+}
diff --git a/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/PsBase.java b/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/PsBase.java
new file mode 100644
index 0000000..3ca44c3
--- /dev/null
+++ b/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/PsBase.java
@@ -0,0 +1,97 @@
+/**
+ * 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.security.spec.PSSParameterSpec;
+import java.util.Arrays;
+import java.util.zip.DataFormatException;
+import java.security.Signature;
+
+import com.microsoft.azure.keyvault.cryptography.ByteExtensions;
+import com.microsoft.azure.keyvault.cryptography.ISignatureTransform;
+
+/**
+ *
+ */
+public abstract class PsBase extends RsaSignature {
+
+ protected PsBase(String name) {
+ super(name);
+ }
+
+ class PsBaseSignatureTransform implements ISignatureTransform {
+
+ private final KeyPair _keyPair;
+ private final int _emLen;
+ private final int _modBits;
+ private final String _digestName;
+
+ PsBaseSignatureTransform(KeyPair keyPair, String digestName) {
+ _keyPair = keyPair;
+ BigInteger modulus = ((RSAPublicKey) _keyPair.getPublic()).getModulus();
+ _emLen = getOctetLength(modulus.bitLength());
+ _modBits = ((RSAPublicKey) _keyPair.getPublic()).getModulus().bitLength();
+ _digestName = digestName;
+ }
+
+ @Override
+ public byte[] sign(byte[] digest) throws NoSuchAlgorithmException {
+
+ if (_keyPair.getPrivate() == null) {
+ throw new IllegalArgumentException("Keypair must have private key to for signing.");
+ }
+
+ // Construct the encoded message
+ // Apply the EMSA-PSS encoding operation (Section
+ // 9.1.1) to the message M to produce an encoded message EM of length
+ // \ceil ((modBits - 1)/8) octets such that the bit length of the
+ // integer OS2IP (EM) (see Section 4.2) is at most modBits - 1, where
+ // modBits is the length in bits of the RSA modulus n:
+ MessageDigest messageDigest = MessageDigest.getInstance(_digestName);
+ byte[] EM = EMSA_PSS_ENCODE_HASH(digest, _modBits - 1, messageDigest);
+
+ // Convert to integer message
+ BigInteger m = OS2IP(EM);
+
+ // RSASP1(s)
+ m = RSASP1((RSAPrivateKey) _keyPair.getPrivate(), m);
+
+ // Convert to octet sequence
+ return I2OSP(m, _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);
+
+ MessageDigest messageDigest = MessageDigest.getInstance(_digestName);
+ return EMSA_PSS_VERIFY(digest, EM, _modBits, messageDigest);
+ }
+
+ }
+
+ public ISignatureTransform createSignatureTransform(KeyPair keyPair, String digestString) {
+ return new PsBaseSignatureTransform(keyPair, digestString);
+ }
+}
diff --git a/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaSignature.java b/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaSignature.java
index 2e5a475..906ccd0 100644
--- a/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaSignature.java
+++ b/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaSignature.java
@@ -10,209 +10,414 @@
import java.security.KeyPair;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Arrays;
+import com.google.common.primitives.Bytes;
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 };
+ 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;
+ 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);
+
+ 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;
- }
+
+ 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);
+
+ 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);
+
+ 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.1.1
+ *
+ * @param mHash the hashed message (hashed with the corresponding digest: i.e., SHA-256 for PS256, SHA-384 for PS384, SHA-512 for PS512
+ * @param emBits the maximal bit length of the integer OS2IP(EM)
+ * @param messageDigest the messageDigest (or hash) that corresponds to the algorithm
+ * @return
+ */
+ protected byte[] EMSA_PSS_ENCODE_HASH(byte[] mHash, int emBits, MessageDigest messageDigest) {
+
+ // Let mHash = Hash(M), an octet string of length hLen.
+ // function takes in the mHash.
+
+ // salt length for the service corresponds to the digest length, which is the hash length / 8
+ int sLen = messageDigest.getDigestLength();
+ int hLen = mHash.length;
+ int emLen = (int) Math.ceil(emBits / 8.0);
+
+ // If emLen < hLen + sLen + 2, output "encoding error" and stop.
+ if (emLen < (hLen + sLen + 2)) {
+ throw new IllegalArgumentException("encoding error");
+ }
+
+ // Generate a random octet string salt of length sLen; if sLen = 0,
+ // then salt is the empty string.
+
+ byte[] salt = new byte[sLen];
+ SecureRandom rng = new SecureRandom();
+ rng.nextBytes(salt);
+
+ // 5. Let
+ // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt;
+ // M' is an octet string of length 8 + hLen + sLen with eight
+ // initial zero octets.
+ messageDigest.update(new byte[8]);
+ messageDigest.update(mHash);
+ messageDigest.update(salt);
+
+ // 6. Let H = Hash(M'), an octet string of length hLen.
+ byte[] H = messageDigest.digest();
+
+ // 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2
+ // zero octets. The length of PS may be 0.
+ byte[] PS = new byte[emLen - sLen - hLen - 2];
+
+ // 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
+ // emLen - hLen - 1.
+
+ byte[] DB = new byte[emLen - hLen - 1];
+
+ System.arraycopy(PS, 0, DB, 0, emLen - sLen - hLen - 2);
+ DB[emLen - sLen - hLen - 2] = (byte) 0x01;
+ System.arraycopy(salt, 0, DB, emLen - sLen - hLen - 1, sLen);
+
+ // 9. Let dbMask = MGF(H, emLen - hLen - 1).
+ byte[] dbMask = MGF(H, emLen - hLen - 1, messageDigest);
+
+ byte[] maskedDB = new byte[Math.min(DB.length, dbMask.length)];
+
+ // 10. Let maskedDB = DB \xor dbMask.
+ for (int i = 0; i < maskedDB.length; i++) {
+ maskedDB[i] = (byte) (((int) DB[i]) ^ ((int) dbMask[i]));
+ }
+
+ // 11. Set the leftmost 8emLen - emBits bits of the leftmost octet in
+ // maskedDB to zero.
+ int bitMask = 0x000000FF >>> (8 * emLen - emBits);
+ maskedDB[0] &= (byte) bitMask;
+
+ // 12. Let EM = maskedDB || H || 0xbc.
+ return Bytes.concat(maskedDB, H, new byte[] { (byte) 0xbc });
+
}
+ /**
+ * See https://tools.ietf.org/html/rfc3447#section-9.1.2
+ *
+ * @param mHash the hashed message (hashed with the corresponding digest: i.e., SHA-256 for PS256, SHA-384 for PS384, SHA-512 for PS512
+ * @param EM encoded message, an octet string of emLen = \ceil(emBits/8)
+ * @param emBits maximal bit length of the integer OS2IP(EM)
+ * @param messageDigest the messageDigest that corresponds to the algorithm (see above)
+ * @return true if output consistent with algorithm, false otherwise
+ */
+ protected boolean EMSA_PSS_VERIFY(byte[] mHash, byte[] EM, int emBits, MessageDigest messageDigest) {
+
+ // salt length for the service corresponds to the digest length, which is the hash length / 8
+ int sLen = messageDigest.getDigestLength();
+ int hLen = mHash.length;
+ int emLen = (int) Math.ceil(emBits / 8.0);
+
+ // 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop.
+ if (emLen < hLen + sLen + 2) {
+ return false;
+ }
+
+ // 4. If the rightmost octet of EM does not have hexadecimal value
+ // 0xbc, output "inconsistent" and stop.
+ if (EM[EM.length - 1] != (byte) 0xbc) {
+ return false;
+ }
+
+ // 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and
+ // let H be the next hLen octets.
+ byte[] maskedDB = Arrays.copyOfRange(EM, 0, emLen - hLen - 1);
+ byte[] H = Arrays.copyOfRange(EM, emLen - hLen - 1, emLen - 1);
+
+ // 6. If the leftmost 8emLen - emBits bits of the leftmost octet in
+ // maskedDB are not all equal to zero, output "inconsistent" and
+ // stop.
+ byte mask = 0x00;
+ for (int i = 0; i < (8 * emLen - emBits); i++) {
+ mask = (byte) (mask | (1 << i));
+ if ((maskedDB[0] & mask) != 0) {
+ return false;
+ }
+ mask = 0x00;
+ }
+
+ // 7. Let dbMask = MGF(H, emLen - hLen - 1).
+ byte[] dbMask = MGF(H, emLen - hLen - 1, messageDigest);
+
+ // 8. Let DB = maskedDB \xor dbMask.
+ byte[] DB = new byte[Math.min(maskedDB.length, dbMask.length)];
+ for (int i = 0; i < maskedDB.length; i++) {
+ DB[i] = (byte) (maskedDB[i] ^ dbMask[i]);
+ }
+
+ // 9. Set the leftmost 8emLen - emBits bits of the leftmost octet in DB
+ // to zero.
+
+ int bitMask = 0x000000FF >> (8 * emLen - emBits + 1);
+ DB[0] &= bitMask;
+
+ // 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero
+ // or if the octet at position emLen - hLen - sLen - 1 (the leftmost
+ // position is "position 1") does not have hexadecimal value 0x01,
+ // output "inconsistent" and stop.
+ for (int i = 0; i < (emLen - hLen - sLen - 2); i++) {
+ if (DB[i] != 0) {
+ return false;
+ }
+ }
+
+ if (DB[emLen - hLen - sLen - 2] != (byte) 0x01) {
+ return false;
+ }
+
+ // 11. Let salt be the last sLen octets of DB.
+ byte[] salt = Arrays.copyOfRange(DB, DB.length - sLen, DB.length);
+
+ // 12. Let
+ // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ;
+ // M' is an octet string of length 8 + hLen + sLen with eight
+ // initial zero octets.
+ // 13. Let H' = Hash(M'), an octet string of length hLen.
+
+ // 14. If H = H', output "consistent." Otherwise, output "inconsistent."
+ messageDigest.update(new byte[8]);
+ messageDigest.update(mHash);
+ return Arrays.equals(H, messageDigest.digest(salt));
+ }
+
+ /**
+ * See https://tools.ietf.org/html/rfc3447#appendix-B.2.1
+ *
+ * @param mgfSeed seed from which mask is generated, an octet string
+ * @param maskLen intended length in octets of the mask, at most 2^32 hLen
+ * @param digest messageDigest - the hash function corresponding to the length of the hash
+ * @return mask, an octet string of length maskLen
+ */
+ protected byte[] MGF(byte[] mgfSeed, int maskLen, MessageDigest digest) {
+
+ if (maskLen > Math.pow(2, 32) * 32) {
+ throw new IllegalArgumentException("mask too long");
+ }
+
+ int hashCount = (int) (Math.ceil(maskLen * 1.0 / digest.getDigestLength()) - 1);
+ byte[] mask = new byte[0];
+
+ // 3.For counter from 0 to \lceil{l / hLen}\ceil-1, do the following:
+ for (int i = 0; i <= hashCount; i++) {
+ digest.update(mgfSeed);
+
+ // a.Convert counter to an octet string C of length 4 with the primitive
+ // I2OSP: C = I2OSP (counter, 4)
+ digest.update(I2OSP(BigInteger.valueOf(i), 4));
+
+ // b.Concatenate the hash of the seed Z and C to the octet string T: T =
+ // T || Hash (Z || C)
+ byte[] hash = digest.digest();
+ mask = Bytes.concat(mask, hash);
+ }
+
+ byte[] output = new byte[maskLen];
+ System.arraycopy(mask, 0, output, 0, output.length);
+ return output;
+ }
+
/*
* 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);
+
+ // 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;
+ 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/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaesOaep256.java b/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaesOaep256.java
new file mode 100644
index 0000000..faff9f9
--- /dev/null
+++ b/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaesOaep256.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 RsaesOaep256 extends RsaEncryption {
+
+ class RsaesOaep256Decryptor implements ICryptoTransform {
+
+ private final Cipher _cipher;
+
+ RsaesOaep256Decryptor(KeyPair keyPair, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
+
+ // Create a cipher object using the provider, if specified
+ if (provider == null) {
+ _cipher = Cipher.getInstance(RSAESOAEP256);
+ } else {
+ _cipher = Cipher.getInstance(RSAESOAEP256, 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 RsaesOaep256Encryptor implements ICryptoTransform {
+
+ private final Cipher _cipher;
+
+ RsaesOaep256Encryptor(KeyPair keyPair, Provider provider) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {
+
+ // Create a cipher object using the provider, if specified
+ if (provider == null) {
+ _cipher = Cipher.getInstance(RSAESOAEP256);
+ } else {
+ _cipher = Cipher.getInstance(RSAESOAEP256, 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 RSAESOAEP256 = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";
+
+ public final static String ALGORITHM_NAME = "RSAES-OAEP-SHA256";
+
+ public RsaesOaep256() {
+ 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 RsaesOaep256Encryptor(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 RsaesOaep256Decryptor(keyPair, provider);
+ }
+
+}
diff --git a/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyBCProviderTest.java b/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyBCProviderTest.java
index c9a9c70..10d01e4 100644
--- a/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyBCProviderTest.java
+++ b/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyBCProviderTest.java
@@ -6,7 +6,7 @@
public class RsaKeyBCProviderTest extends RsaKeyTest {
@Before
- public void setUp() throws Exception {
+ public void beforeMethod() throws Exception {
try {
super.setProvider((Provider) Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider").newInstance());
} catch (Exception ex) {
diff --git a/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyTest.java b/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyTest.java
index 4944910..be7b43e 100644
--- a/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyTest.java
+++ b/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyTest.java
@@ -1,52 +1,72 @@
package com.microsoft.azure.keyvault.cryptography.test;
-import static org.junit.Assert.*;
-
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.KeyPair;
import java.security.MessageDigest;
import java.security.Provider;
+import java.security.spec.KeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.Arrays;
+import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
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.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestName;
import com.fasterxml.jackson.databind.ObjectMapper;
+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.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.cryptography.algorithms.RsaesOaep256;
+
import com.microsoft.azure.keyvault.webkey.JsonWebKey;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyOperation;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeySignatureAlgorithm;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyType;
+
+import com.microsoft.azure.serializer.AzureJacksonAdapter;
+import com.microsoft.rest.LogLevel;
+import com.microsoft.rest.RestClient;
+import com.microsoft.rest.credentials.ServiceClientCredentials;
+import com.microsoft.rest.interceptors.LoggingInterceptor;
public class RsaKeyTest {
- // A Content Encryption Key, or Message. This value is kept consistent with the .NET
+ // 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 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;
}
@@ -57,8 +77,8 @@ 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();
+ 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());
@@ -66,7 +86,7 @@ public void testRsa15() throws Exception {
// 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();
+ byte[] decrypted = key.decryptAsync(encrypted.getLeft(), null, null, null, encrypted.getRight()).get();
// Assert
assertEquals(Rsa15.ALGORITHM_NAME, encrypted.getRight());
@@ -81,8 +101,8 @@ 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();
+ 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());
@@ -90,7 +110,7 @@ public void testRsaOaep() throws Exception {
// 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();
+ byte[] decrypted = key.decryptAsync(encrypted.getLeft(), null, null, null, encrypted.getRight()).get();
// Assert
assertEquals(RsaOaep.ALGORITHM_NAME, encrypted.getRight());
@@ -99,6 +119,30 @@ public void testRsaOaep() throws Exception {
key.close();
}
+ @Test
+ public void testRsaesOaep256() throws Exception {
+
+ RsaKey key = getTestRsaKey();
+
+ // Wrap and Unwrap
+ Pair wrapped = key.wrapKeyAsync(CEK, RsaesOaep256.ALGORITHM_NAME).get();
+ byte[] unwrapped = key.unwrapKeyAsync(wrapped.getLeft(), wrapped.getRight()).get();
+
+ // Assert
+ assertEquals(RsaesOaep256.ALGORITHM_NAME, wrapped.getRight());
+ assertArrayEquals(CEK, unwrapped);
+
+ // Encrypt and Decrypt
+ Triple encrypted = key.encryptAsync(CEK, null, null, RsaesOaep256.ALGORITHM_NAME).get();
+ byte[] decrypted = key.decryptAsync(encrypted.getLeft(), null, null, null, encrypted.getRight()).get();
+
+ // Assert
+ assertEquals(RsaesOaep256.ALGORITHM_NAME, encrypted.getRight());
+ assertArrayEquals(CEK, decrypted);
+
+ key.close();
+ }
+
@Test
public void testDefaultAlgorithm() throws Exception {
@@ -109,16 +153,17 @@ public void testDefaultAlgorithm() throws Exception {
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();
+ 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();
+ 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());
@@ -135,16 +180,16 @@ public void testSignVerify() throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(CEK);
- byte[] crossPlatformHash = Base64.decodeBase64(CrossPlatformHash);
+ byte[] crossPlatformHash = Base64.decodeBase64(CrossPlatformHash);
byte[] crossPlatformSignature = Base64.decodeBase64(CrossPlatformSignature);
// Check the hash
- assertNotNull( hash );
- assertEquals( 32, hash.length );
+ 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();
+ boolean result = key.verifyAsync(hash, signature.getLeft(), "RS256").get();
// Check the signature
assertTrue(result);
@@ -158,12 +203,41 @@ public void testSignVerify() throws Exception {
key.close();
}
+ @Test
+ public void testSignVerifyPs256() throws Exception {
+ signVerifyLocal("PS256", "SHA-256");
+ }
+
+ @Test
+ public void testSignVerifyPs384() throws Exception {
+ signVerifyLocal("PS384", "SHA-384");
+ }
+
+ @Test
+ public void testSignVerifyPs512() throws Exception {
+ signVerifyLocal("PS512", "SHA-512");
+ }
+
+ private void signVerifyLocal(String algName, String digestAlg) throws Exception {
+ RsaKey key = getTestRsaKey();
+
+ MessageDigest digest = MessageDigest.getInstance(digestAlg);
+ byte[] hash = digest.digest(CEK);
+
+ Pair signature = key.signAsync(hash, algName).get();
+ boolean result = key.verifyAsync(hash, signature.getLeft(), algName).get();
+
+ assertTrue(result);
+
+ key.close();
+ }
+
@Test
public void testToFromJsonWebKey() throws Exception {
RsaKey key = getTestRsaKey();
JsonWebKey jwk = key.toJsonWebKey();
jwk.withKid("new kid");
- //setting kid
+ // setting kid
RsaKey sameKey = RsaKey.fromJsonWebKey(jwk, true, _provider);
JsonWebKey jwkSame = sameKey.toJsonWebKey();
jwkSame.withKid("new kid");
@@ -171,13 +245,14 @@ public void testToFromJsonWebKey() throws Exception {
}
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;
+ 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) );
+ return new RsaKey("foo", jwk.toRSA(true, _provider));
}
+
}
diff --git a/azure-keyvault-integration-tests/.gitignore b/azure-keyvault-integration-tests/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/azure-keyvault-integration-tests/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/azure-keyvault-integration-tests/pom.xml b/azure-keyvault-integration-tests/pom.xml
new file mode 100644
index 0000000..463fdf1
--- /dev/null
+++ b/azure-keyvault-integration-tests/pom.xml
@@ -0,0 +1,50 @@
+
+
+ 4.0.0
+
+ com.microsoft.azure
+ azure-keyvault-parent
+ 1.1-beta-1
+
+ azure-keyvault-integration-tests
+ azure-keyvault-integration-tests
+ http://maven.apache.org
+
+ UTF-8
+
+
+
+ junit
+ junit
+ test
+
+
+ com.microsoft.azure
+ azure-keyvault-webkey
+ test
+ 1.1-beta-1
+
+
+ com.microsoft.azure
+ azure-keyvault
+ test
+ 1.1-beta-1
+
+
+
+ com.microsoft.rest
+ client-runtime
+ 1.3.0
+ test
+
+
+ com.microsoft.azure
+ azure-mgmt-resources
+ 1.3.1-SNAPSHOT
+ test-jar
+ test
+
+
+
diff --git a/azure-keyvault-integration-tests/src/test/java/com/microsoft/azure/keyvault/test/AzureKeyVaultCryptographyIntegrationTests.java b/azure-keyvault-integration-tests/src/test/java/com/microsoft/azure/keyvault/test/AzureKeyVaultCryptographyIntegrationTests.java
new file mode 100644
index 0000000..293f77f
--- /dev/null
+++ b/azure-keyvault-integration-tests/src/test/java/com/microsoft/azure/keyvault/test/AzureKeyVaultCryptographyIntegrationTests.java
@@ -0,0 +1,322 @@
+package com.microsoft.azure.keyvault.test;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.MessageDigest;
+import java.security.spec.KeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.util.Arrays;
+import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+
+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.keyvault.KeyIdentifier;
+import com.microsoft.azure.keyvault.KeyVaultClient;
+import com.microsoft.azure.keyvault.authentication.KeyVaultCredentials;
+import com.microsoft.azure.keyvault.cryptography.RsaKey;
+import com.microsoft.azure.keyvault.models.KeyBundle;
+import com.microsoft.azure.keyvault.models.KeyOperationResult;
+import com.microsoft.azure.keyvault.models.KeyVerifyResult;
+import com.microsoft.azure.keyvault.requests.ImportKeyRequest;
+import com.microsoft.azure.keyvault.webkey.JsonWebKey;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyOperation;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeySignatureAlgorithm;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyType;
+import com.microsoft.azure.management.resources.core.InterceptorManager;
+import com.microsoft.azure.management.resources.core.TestBase;
+import com.microsoft.azure.management.resources.fluentcore.utils.ResourceManagerThrottlingInterceptor;
+import com.microsoft.azure.serializer.AzureJacksonAdapter;
+import com.microsoft.rest.LogLevel;
+import com.microsoft.rest.RestClient;
+import com.microsoft.rest.credentials.ServiceClientCredentials;
+import com.microsoft.rest.interceptors.LoggingInterceptor;
+public class AzureKeyVaultCryptographyIntegrationTests {
+
+ private static TestBase.TestMode testMode = null;
+
+ protected InterceptorManager interceptorManager = null;
+
+ 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:";
+ private static final String PLAYBACK_VAULT = "https://test-vault.vault.azure.net";
+
+ protected static String playbackUri = null;
+
+ static KeyVaultClient keyVaultClient;
+
+ final static String KEY_NAME = "otherkey2";
+ static String VAULT_URI;
+
+
+ @Rule
+ public TestName testName = new TestName();
+
+
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ initTestMode();
+ initPlaybackUri();
+ }
+
+ @Before
+ public void beforeMethod() throws Exception {
+
+ RestClient restClient;
+ ServiceClientCredentials credentials = createTestCredentials();
+ interceptorManager = InterceptorManager.create(testName.getMethodName(), testMode);
+
+ if (isRecordMode()) {
+ VAULT_URI = System.getenv("VAULT_URI");
+ restClient = 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()).build();
+
+ interceptorManager.addTextReplacementRule("https://management.azure.com/", playbackUri + "/");
+ interceptorManager.addTextReplacementRule("https://graph.windows.net/", playbackUri + "/");
+ interceptorManager.addTextReplacementRule(VAULT_URI, PLAYBACK_VAULT);
+ keyVaultClient = new KeyVaultClient(restClient);
+ } else { // is Playback Mode
+ VAULT_URI = PLAYBACK_VAULT;
+ restClient = 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()).build();
+ keyVaultClient = new KeyVaultClient(restClient);
+ }
+ }
+
+ @Test
+ public void testSignVerifyServicePs256() throws Exception {
+ signVerifyWithService(KEY_NAME, JsonWebKeySignatureAlgorithm.PS256, "SHA-256");
+ }
+
+ @Test
+ public void testSignVerifyServicePs384() throws Exception {
+ signVerifyWithService(KEY_NAME, JsonWebKeySignatureAlgorithm.PS384, "SHA-384");
+ }
+
+ @Test
+ public void testSignVerifyServicePs512() throws Exception {
+ signVerifyWithService(KEY_NAME, JsonWebKeySignatureAlgorithm.PS512, "SHA-512");
+ }
+
+ private void signVerifyWithService(String keyName, JsonWebKeySignatureAlgorithm algorithm, String digestAlg)
+ throws Exception {
+
+ JsonWebKey testKey = importTestKey(keyName);
+
+ RsaKey key = new RsaKey(testKey.kid(), getWellKnownKey());
+
+ KeyIdentifier keyId = new KeyIdentifier(testKey.kid());
+
+ // Test variables
+ byte[] plainText = new byte[100];
+ new Random(0x1234567L).nextBytes(plainText);
+ MessageDigest md = MessageDigest.getInstance(digestAlg);
+ md.update(plainText);
+ byte[] digest = md.digest();
+ byte[] signature;
+
+ KeyOperationResult result;
+ KeyVerifyResult verifyResult;
+
+ // Using kid WO version
+ {
+ signature = key.signAsync(digest, algorithm.toString()).get().getLeft();
+ verifyResult = keyVaultClient.verify(keyId.baseIdentifier(), algorithm, digest, signature);
+ Assert.assertEquals(new Boolean(true), verifyResult.value());
+ }
+
+ {
+ result = keyVaultClient.sign(keyId.baseIdentifier(), algorithm, digest);
+ signature = result.result();
+ Assert.assertTrue(key.verifyAsync(digest, signature, algorithm.toString()).get());
+ }
+ key.close();
+ }
+
+
+ private static JsonWebKey importTestKey(String keyName) throws Exception {
+
+ KeyBundle keyBundle = new KeyBundle();
+ JsonWebKey key = JsonWebKey.fromRSA(getTestKeyMaterial());
+
+ key.withKty(JsonWebKeyType.RSA);
+ key.withKeyOps(Arrays.asList(JsonWebKeyOperation.ENCRYPT, JsonWebKeyOperation.DECRYPT, JsonWebKeyOperation.SIGN,
+ JsonWebKeyOperation.VERIFY, JsonWebKeyOperation.WRAP_KEY, JsonWebKeyOperation.UNWRAP_KEY));
+
+ System.out.println(key.kid());
+
+ keyBundle = keyVaultClient
+ .importKey(new ImportKeyRequest.Builder(VAULT_URI, KEY_NAME, key).withHsm(false).build());
+
+ return keyBundle.key();
+ }
+
+ private static KeyPair getTestKeyMaterial() throws Exception {
+ return getWellKnownKey();
+ }
+
+ private static KeyPair getWellKnownKey() throws Exception {
+ BigInteger modulus = new BigInteger(
+ "27266783713040163753473734334021230592631652450892850648620119914958066181400432364213298181846462385257448168605902438305568194683691563208578540343969522651422088760509452879461613852042845039552547834002168737350264189810815735922734447830725099163869215360401162450008673869707774119785881115044406101346450911054819448375712432746968301739007624952483347278954755460152795801894283389540036131881712321193750961817346255102052653789197325341350920441746054233522546543768770643593655942246891652634114922277138937273034902434321431672058220631825053788262810480543541597284376261438324665363067125951152574540779");
+ BigInteger publicExponent = new BigInteger("65537");
+ BigInteger privateExponent = new BigInteger(
+ "10466613941269075477152428927796086150095892102279802916937552172064636326433780566497000814207416485739683286961848843255766652023400959086290344987308562817062506476465756840999981989957456897020361717197805192876094362315496459535960304928171129585813477132331538577519084006595335055487028872410579127692209642938724850603554885478763205394868103298473476811627231543504190652483290944218004086457805431824328448422034887148115990501701345535825110962804471270499590234116100216841170344686381902328362376624405803648588830575558058257742073963036264273582756620469659464278207233345784355220317478103481872995809");
+ BigInteger primeP = new BigInteger(
+ "175002941104568842715096339107566771592009112128184231961529953978142750732317724951747797764638217287618769007295505214923187971350518217670604044004381362495186864051394404165602744235299100790551775147322153206730562450301874236875459336154569893255570576967036237661594595803204808064127845257496057219227");
+ BigInteger primeQ = new BigInteger(
+ "155807574095269324897144428622185380283967159190626345335083690114147315509962698765044950001909553861571493035240542031420213144237033208612132704562174772894369053916729901982420535940939821673277140180113593951522522222348910536202664252481405241042414183668723338300649954708432681241621374644926879028977");
+ BigInteger primeExponentP = new BigInteger(
+ "79745606804504995938838168837578376593737280079895233277372027184693457251170125851946171360348440134236338520742068873132216695552312068793428432338173016914968041076503997528137698610601222912385953171485249299873377130717231063522112968474603281996190849604705284061306758152904594168593526874435238915345");
+ BigInteger primeExponentQ = new BigInteger(
+ "80619964983821018303966686284189517841976445905569830731617605558094658227540855971763115484608005874540349730961777634427740786642996065386667564038755340092176159839025706183161615488856833433976243963682074011475658804676349317075370362785860401437192843468423594688700132964854367053490737073471709030801");
+ BigInteger crtCoefficient = new BigInteger(
+ "2157818511040667226980891229484210846757728661751992467240662009652654684725325675037512595031058612950802328971801913498711880111052682274056041470625863586779333188842602381844572406517251106159327934511268610438516820278066686225397795046020275055545005189953702783748235257613991379770525910232674719428");
+
+ KeySpec publicKeySpec = new RSAPublicKeySpec(modulus, publicExponent);
+ KeySpec privateKeySpec = new RSAPrivateCrtKeySpec(modulus, publicExponent, privateExponent, primeP, primeQ,
+ primeExponentP, primeExponentQ, crtCoefficient);
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+
+ return new KeyPair(keyFactory.generatePublic(publicKeySpec), keyFactory.generatePrivate(privateKeySpec));
+ }
+
+ 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);
+ }
+ }
+ };
+ }
+
+ @After
+ public void afterMethod() throws IOException {
+ interceptorManager.finalizeInterceptor();
+ }
+
+ private static void initPlaybackUri() throws IOException {
+ if (isPlaybackMode()) {
+ // 11080 and 11081 needs to be in sync with values in jetty.xml file
+ playbackUri = PLAYBACK_URI_BASE + "11080";
+ } 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 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;
+ }
+ }
+
+}
diff --git a/azure-keyvault-integration-tests/target/test-classes/session-records/testSignVerifyServicePs256.json b/azure-keyvault-integration-tests/target/test-classes/session-records/testSignVerifyServicePs256.json
new file mode 100644
index 0000000..6070e58
--- /dev/null
+++ b/azure-keyvault-integration-tests/target/test-classes/session-records/testSignVerifyServicePs256.json
@@ -0,0 +1,112 @@
+{
+ "networkCallRecords" : [ {
+ "Method" : "PUT",
+ "Uri" : "https://test-vault.vault.azure.net/keys/otherkey2?api-version=7.0-preview",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0-preview)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 08 Jun 2018 22:49:34 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" : "b9cb5545-50a0-4938-a559-081d48bfdffe",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "PUT",
+ "Uri" : "https://test-vault.vault.azure.net/keys/otherkey2?api-version=7.0-preview",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0-preview)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 08 Jun 2018 22:49:39 GMT",
+ "content-length" : "666",
+ "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" : "4295eef2-ad71-4396-bc23-9b86e77df135",
+ "Body" : "{\"key\":{\"kid\":\"https://test-vault.vault.azure.net/keys/otherkey2/dc826d7462dd4e38bf0f207c3bf053ab\",\"kty\":\"RSA\",\"key_ops\":[\"encrypt\",\"decrypt\",\"sign\",\"verify\",\"wrapKey\",\"unwrapKey\"],\"n\":\"1_6ZtP288hEkKML-L6nFyZh1PD1rmAgwbbwjEvTSDK_008BYWhjp_6ULy9BhWtRIytNkPkm9gzaBTrCpp-vyDXPGa836Htp-w8u5JmxoUZchJh576m3m-8ZYWTmZSAp5SpruyKAmLSxPJHEWPXQntnmuTMjb9HBT9Ltrwc0ZDk-jsMLYunDJrNmrRUxQgb0zQ_Tl5fJjj8j-0KVx2RXtbfWFvf5fRdBYyP3m0aUpoopQPwtXszD2LcSKMJ_TnmnvMWr8MOA5aRlBaGdBk7zBgRafvDPam3Q2AvFA9mfcAVncpfZ3JFm73VARw6MofXtRqOHtZ7y4oNbY95xXwU2r6w\",\"e\":\"AQAB\"},\"attributes\":{\"enabled\":true,\"created\":1528498179,\"updated\":1528498179,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "POST",
+ "Uri" : "https://test-vault.vault.azure.net/keys/otherkey2//verify?api-version=7.0-preview",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0-preview)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 08 Jun 2018 22:49:41 GMT",
+ "content-length" : "14",
+ "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" : "8739205c-44e9-4a76-bf15-877a03d7686d",
+ "Body" : "{\"value\":true}"
+ }
+ }, {
+ "Method" : "POST",
+ "Uri" : "https://test-vault.vault.azure.net/keys/otherkey2//sign?api-version=7.0-preview",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0-preview)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 08 Jun 2018 22:49:43 GMT",
+ "content-length" : "457",
+ "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" : "7272cb1e-fb5c-4920-88d4-2037ab9f1597",
+ "Body" : "{\"kid\":\"https://test-vault.vault.azure.net/keys/otherkey2/dc826d7462dd4e38bf0f207c3bf053ab\",\"value\":\"oAnlOVb7hcetFCBhs5hyGc07zhmTMmyE6cv5m0MoU7tMl8eswnys6PVB2JvcQb1FSqrl9puQTFe3OkTF8gjA5yZFOMrFfhf0ASnlXceEW7ZbPi4-QRjD357uW-yZ0o7C7mrLUgVPCV79szJslVh1sVV7ivjxFZPD8LKld_QDv1OAubUEpOr_G1YAxSTlgB8QVdkliikECfb_XZDqblGdtlIHjN-hTfb7No6HnmKLEnjM7Fok5fN5Sjw4Ah2E-bkZstWYrExsRkadUniLAJhQeIZZkC8UtBOTBElgqhIJNK8aSejPn3tQ65rTlSCt9l_FeNTgjSEjWf2kKjGWYJSV9A\"}"
+ }
+ } ],
+ "variables" : [ ]
+}
\ No newline at end of file
diff --git a/azure-keyvault-integration-tests/target/test-classes/session-records/testSignVerifyServicePs384.json b/azure-keyvault-integration-tests/target/test-classes/session-records/testSignVerifyServicePs384.json
new file mode 100644
index 0000000..ee28d33
--- /dev/null
+++ b/azure-keyvault-integration-tests/target/test-classes/session-records/testSignVerifyServicePs384.json
@@ -0,0 +1,112 @@
+{
+ "networkCallRecords" : [ {
+ "Method" : "PUT",
+ "Uri" : "https://test-vault.vault.azure.net/keys/otherkey2?api-version=7.0-preview",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0-preview)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 08 Jun 2018 22:49:43 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" : "fa37b118-7261-4a97-aa9d-23c31e55f344",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "PUT",
+ "Uri" : "https://test-vault.vault.azure.net/keys/otherkey2?api-version=7.0-preview",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0-preview)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 08 Jun 2018 22:49:45 GMT",
+ "content-length" : "666",
+ "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" : "01b15906-28a8-4a74-a345-5afe3511bff2",
+ "Body" : "{\"key\":{\"kid\":\"https://test-vault.vault.azure.net/keys/otherkey2/a046f43b2e4e4e10b6c3b2de746a9ed7\",\"kty\":\"RSA\",\"key_ops\":[\"encrypt\",\"decrypt\",\"sign\",\"verify\",\"wrapKey\",\"unwrapKey\"],\"n\":\"1_6ZtP288hEkKML-L6nFyZh1PD1rmAgwbbwjEvTSDK_008BYWhjp_6ULy9BhWtRIytNkPkm9gzaBTrCpp-vyDXPGa836Htp-w8u5JmxoUZchJh576m3m-8ZYWTmZSAp5SpruyKAmLSxPJHEWPXQntnmuTMjb9HBT9Ltrwc0ZDk-jsMLYunDJrNmrRUxQgb0zQ_Tl5fJjj8j-0KVx2RXtbfWFvf5fRdBYyP3m0aUpoopQPwtXszD2LcSKMJ_TnmnvMWr8MOA5aRlBaGdBk7zBgRafvDPam3Q2AvFA9mfcAVncpfZ3JFm73VARw6MofXtRqOHtZ7y4oNbY95xXwU2r6w\",\"e\":\"AQAB\"},\"attributes\":{\"enabled\":true,\"created\":1528498185,\"updated\":1528498185,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "POST",
+ "Uri" : "https://test-vault.vault.azure.net/keys/otherkey2//verify?api-version=7.0-preview",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0-preview)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 08 Jun 2018 22:49:46 GMT",
+ "content-length" : "14",
+ "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" : "3359eb4c-303e-4236-85a2-83106393a901",
+ "Body" : "{\"value\":true}"
+ }
+ }, {
+ "Method" : "POST",
+ "Uri" : "https://test-vault.vault.azure.net/keys/otherkey2//sign?api-version=7.0-preview",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0-preview)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 08 Jun 2018 22:49:50 GMT",
+ "content-length" : "457",
+ "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" : "b1abe427-40a5-4590-8bf4-0c99e5caab4f",
+ "Body" : "{\"kid\":\"https://test-vault.vault.azure.net/keys/otherkey2/a046f43b2e4e4e10b6c3b2de746a9ed7\",\"value\":\"QsN05RCM9lADsZalIFlxeRBDr2zEQdlrdkjsqWr3t5wYt3R_X6driSEw-PRMw2JypZvB5I-OfPG716DSz-gZaYVIsNMLQdYj8pzhGly8meUClwRWWhZ_6GjSv0lkHTUEdsYTzDVYPz7F0Ykwxl8lBhaAM7GIcTzs4qyYDsGViMQzUjrwS9zDh-m7qgBvGGANul2Z5USc18aBRcLXEOmW7PADrnr3uxi0KNOhQeHHgtguuGyEMwF83fyD6jIf2NfYF75LOkeaSwAWfRhYJ_seX5gN_HI19wkRGF-2vPRu5z_IpCBtp7_Wk3f4zmURnotD5xpruZntbcitbZqXH0N1Yg\"}"
+ }
+ } ],
+ "variables" : [ ]
+}
\ No newline at end of file
diff --git a/azure-keyvault-integration-tests/target/test-classes/session-records/testSignVerifyServicePs512.json b/azure-keyvault-integration-tests/target/test-classes/session-records/testSignVerifyServicePs512.json
new file mode 100644
index 0000000..922603f
--- /dev/null
+++ b/azure-keyvault-integration-tests/target/test-classes/session-records/testSignVerifyServicePs512.json
@@ -0,0 +1,112 @@
+{
+ "networkCallRecords" : [ {
+ "Method" : "PUT",
+ "Uri" : "https://test-vault.vault.azure.net/keys/otherkey2?api-version=7.0-preview",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0-preview)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 08 Jun 2018 22:49:49 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" : "764b0170-345f-4204-ba41-55317c5e41b0",
+ "Body" : ""
+ }
+ }, {
+ "Method" : "PUT",
+ "Uri" : "https://test-vault.vault.azure.net/keys/otherkey2?api-version=7.0-preview",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0-preview)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 08 Jun 2018 22:49:54 GMT",
+ "content-length" : "666",
+ "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" : "cfdd5e4e-1f7a-4d61-a2c7-0e6ad6159f47",
+ "Body" : "{\"key\":{\"kid\":\"https://test-vault.vault.azure.net/keys/otherkey2/47041a5e3b994e4b9db708d6352408d0\",\"kty\":\"RSA\",\"key_ops\":[\"encrypt\",\"decrypt\",\"sign\",\"verify\",\"wrapKey\",\"unwrapKey\"],\"n\":\"1_6ZtP288hEkKML-L6nFyZh1PD1rmAgwbbwjEvTSDK_008BYWhjp_6ULy9BhWtRIytNkPkm9gzaBTrCpp-vyDXPGa836Htp-w8u5JmxoUZchJh576m3m-8ZYWTmZSAp5SpruyKAmLSxPJHEWPXQntnmuTMjb9HBT9Ltrwc0ZDk-jsMLYunDJrNmrRUxQgb0zQ_Tl5fJjj8j-0KVx2RXtbfWFvf5fRdBYyP3m0aUpoopQPwtXszD2LcSKMJ_TnmnvMWr8MOA5aRlBaGdBk7zBgRafvDPam3Q2AvFA9mfcAVncpfZ3JFm73VARw6MofXtRqOHtZ7y4oNbY95xXwU2r6w\",\"e\":\"AQAB\"},\"attributes\":{\"enabled\":true,\"created\":1528498195,\"updated\":1528498195,\"recoveryLevel\":\"Recoverable+Purgeable\"}}"
+ }
+ }, {
+ "Method" : "POST",
+ "Uri" : "https://test-vault.vault.azure.net/keys/otherkey2//verify?api-version=7.0-preview",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0-preview)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 08 Jun 2018 22:49:57 GMT",
+ "content-length" : "14",
+ "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" : "60f00eb1-21fe-458e-97b0-23c9d89610c2",
+ "Body" : "{\"value\":true}"
+ }
+ }, {
+ "Method" : "POST",
+ "Uri" : "https://test-vault.vault.azure.net/keys/otherkey2//sign?api-version=7.0-preview",
+ "Headers" : {
+ "User-Agent" : "Azure-SDK-For-Java/null OS:Windows 10/10.0 MacAddressHash:08b8c65810754c5927ba6275e7902c61544ffc9cb2de4d24196bc80b2fbba780 Java:1.8.0_172 (KeyVaultClientBase, 7.0-preview)",
+ "Content-Type" : "application/json; charset=utf-8"
+ },
+ "Response" : {
+ "date" : "Fri, 08 Jun 2018 22:49:57 GMT",
+ "content-length" : "457",
+ "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" : "4c7af713-5c3f-4436-a1b6-5e3e68048ca7",
+ "Body" : "{\"kid\":\"https://test-vault.vault.azure.net/keys/otherkey2/47041a5e3b994e4b9db708d6352408d0\",\"value\":\"Gf3Nw4iUaJI3Ob0M3x4WcQJl5K8JbRyGsU6ucPESEYB5aMSKeysMriinXCVZZnm6FMYh39BKqCrlhsv7mvMmwqRFVbGkfjiargwuB1ZS2j1xQOn0CCpIJ4WBpZVWjk8oALp_UuanmdmP6J1hoWa0CNeExMMU_5dDUYTafPM9ttHDmuEZ35cUucS5BxjKCqGI_j0wMbc2FjkpAg1NDuOHyos9fTbbMSF0ts0wp7FTSBoYE39-wj7PMTmA3YWodqH-ZCK8vpfbSQ0_zNvbF7nDxxvZ8HUj1oyrmg9DTwNBWKSb1bIkHjgYjW2ThN2VLVJaNel9J_1MukzeQT1NDyFbyA\"}"
+ }
+ } ],
+ "variables" : [ ]
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 5c78c38..5a79765 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,9 +1,9 @@
+
-
+-->
4.0.0
com.microsoft.azure
1.1-beta-1
@@ -302,7 +302,7 @@
-
+
@@ -345,7 +345,7 @@
-
+
@@ -361,5 +361,6 @@
./azure-keyvault-webkey
./azure-keyvault-cryptography
./azure-keyvault-extensions
+ ./azure-keyvault-integration-tests
-
+
\ No newline at end of file