com.microsoft.azure.keyvault.cryptography.EcKey Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of azure-keyvault-cryptography Show documentation
Show all versions of azure-keyvault-cryptography Show documentation
This package contains Microsoft Azure SDK for Key Vault Cryptography.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
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 {
this.kid = kid;
this.provider = provider;
this.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");
}
this.kid = kid;
this.keyPair = keyPair;
this.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);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy