package org.bouncycastle.jce;

import java.io.UnsupportedEncodingException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X962Parameters;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

Utility class to allow conversion of EC key parameters to explicit from named curves and back (where possible).
/** * Utility class to allow conversion of EC key parameters to explicit from named * curves and back (where possible). */
public class ECKeyUtil {
Convert a passed in public EC key to have explicit parameters. If the key is already using explicit parameters it is returned.
Params:
  • key – key to be converted
  • providerName – provider name to be used.
Throws:
Returns:the equivalent key with explicit curve parameters
/** * Convert a passed in public EC key to have explicit parameters. If the key * is already using explicit parameters it is returned. * * @param key key to be converted * @param providerName provider name to be used. * @return the equivalent key with explicit curve parameters * @throws IllegalArgumentException * @throws NoSuchAlgorithmException * @throws NoSuchProviderException */
public static PublicKey publicToExplicitParameters(PublicKey key, String providerName) throws IllegalArgumentException, NoSuchAlgorithmException, NoSuchProviderException { Provider provider = Security.getProvider(providerName); if (provider == null) { throw new NoSuchProviderException("cannot find provider: " + providerName); } return publicToExplicitParameters(key, provider); }
Convert a passed in public EC key to have explicit parameters. If the key is already using explicit parameters it is returned.
Params:
  • key – key to be converted
  • provider – provider to be used.
Throws:
Returns:the equivalent key with explicit curve parameters
/** * Convert a passed in public EC key to have explicit parameters. If the key * is already using explicit parameters it is returned. * * @param key key to be converted * @param provider provider to be used. * @return the equivalent key with explicit curve parameters * @throws IllegalArgumentException * @throws NoSuchAlgorithmException */
public static PublicKey publicToExplicitParameters(PublicKey key, Provider provider) throws IllegalArgumentException, NoSuchAlgorithmException { try { SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(key.getEncoded())); if (info.getAlgorithm().getAlgorithm().equals(CryptoProObjectIdentifiers.gostR3410_2001)) { throw new IllegalArgumentException("cannot convert GOST key to explicit parameters."); } else { X962Parameters params = X962Parameters.getInstance(info.getAlgorithm().getParameters()); X9ECParameters curveParams; if (params.isNamedCurve()) { ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters()); curveParams = ECUtil.getNamedCurveByOid(oid); // ignore seed value due to JDK bug curveParams = new X9ECParameters(curveParams.getCurve(), curveParams.getG(), curveParams.getN(), curveParams.getH()); } else if (params.isImplicitlyCA()) { curveParams = new X9ECParameters(BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getG(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getN(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getH()); } else { return key; // already explicit } params = new X962Parameters(curveParams); info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), info.getPublicKeyData().getBytes()); KeyFactory keyFact = KeyFactory.getInstance(key.getAlgorithm(), provider); return keyFact.generatePublic(new X509EncodedKeySpec(info.getEncoded())); } } catch (IllegalArgumentException e) { throw e; } catch (NoSuchAlgorithmException e) { throw e; } catch (Exception e) { // shouldn't really happen... throw new UnexpectedException(e); } }
Convert a passed in private EC key to have explicit parameters. If the key is already using explicit parameters it is returned.
Params:
  • key – key to be converted
  • providerName – provider name to be used.
Throws:
Returns:the equivalent key with explicit curve parameters
/** * Convert a passed in private EC key to have explicit parameters. If the key * is already using explicit parameters it is returned. * * @param key key to be converted * @param providerName provider name to be used. * @return the equivalent key with explicit curve parameters * @throws IllegalArgumentException * @throws NoSuchAlgorithmException * @throws NoSuchProviderException */
public static PrivateKey privateToExplicitParameters(PrivateKey key, String providerName) throws IllegalArgumentException, NoSuchAlgorithmException, NoSuchProviderException { Provider provider = Security.getProvider(providerName); if (provider == null) { throw new NoSuchProviderException("cannot find provider: " + providerName); } return privateToExplicitParameters(key, provider); }
Convert a passed in private EC key to have explicit parameters. If the key is already using explicit parameters it is returned.
Params:
  • key – key to be converted
  • provider – provider to be used.
Throws:
Returns:the equivalent key with explicit curve parameters
/** * Convert a passed in private EC key to have explicit parameters. If the key * is already using explicit parameters it is returned. * * @param key key to be converted * @param provider provider to be used. * @return the equivalent key with explicit curve parameters * @throws IllegalArgumentException * @throws NoSuchAlgorithmException */
public static PrivateKey privateToExplicitParameters(PrivateKey key, Provider provider) throws IllegalArgumentException, NoSuchAlgorithmException { try { PrivateKeyInfo info = PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(key.getEncoded())); if (info.getPrivateKeyAlgorithm().getAlgorithm().equals(CryptoProObjectIdentifiers.gostR3410_2001)) { throw new UnsupportedEncodingException("cannot convert GOST key to explicit parameters."); } else { X962Parameters params = X962Parameters.getInstance(info.getPrivateKeyAlgorithm().getParameters()); X9ECParameters curveParams; if (params.isNamedCurve()) { ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters()); curveParams = ECUtil.getNamedCurveByOid(oid); // ignore seed value due to JDK bug curveParams = new X9ECParameters(curveParams.getCurve(), curveParams.getG(), curveParams.getN(), curveParams.getH()); } else if (params.isImplicitlyCA()) { curveParams = new X9ECParameters(BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getG(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getN(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getH()); } else { return key; // already explicit } params = new X962Parameters(curveParams); info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), info.parsePrivateKey()); KeyFactory keyFact = KeyFactory.getInstance(key.getAlgorithm(), provider); return keyFact.generatePrivate(new PKCS8EncodedKeySpec(info.getEncoded())); } } catch (IllegalArgumentException e) { throw e; } catch (NoSuchAlgorithmException e) { throw e; } catch (Exception e) { // shouldn't really happen throw new UnexpectedException(e); } } private static class UnexpectedException extends RuntimeException { private Throwable cause; UnexpectedException(Throwable cause) { super(cause.toString()); this.cause = cause; } public Throwable getCause() { return cause; } } }