ECDSAKeyGenerator.java

  1. /*
  2.  * @copyright defined in LICENSE.txt
  3.  */


  4. package hera.util.pki;

  5. import static java.security.Security.addProvider;
  6. import static java.security.Security.getProvider;
  7. import static org.bouncycastle.jce.ECNamedCurveTable.getParameterSpec;
  8. import static org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
  9. import static org.slf4j.LoggerFactory.getLogger;

  10. import hera.util.Sha256Utils;
  11. import java.math.BigInteger;
  12. import java.security.InvalidAlgorithmParameterException;
  13. import java.security.KeyFactory;
  14. import java.security.KeyPair;
  15. import java.security.KeyPairGenerator;
  16. import java.security.NoSuchAlgorithmException;
  17. import java.security.NoSuchProviderException;
  18. import java.security.PrivateKey;
  19. import java.security.PublicKey;
  20. import java.security.SecureRandom;
  21. import java.security.Security;
  22. import java.security.spec.PKCS8EncodedKeySpec;
  23. import org.bouncycastle.crypto.params.ECDomainParameters;
  24. import org.bouncycastle.crypto.prng.FixedSecureRandom;
  25. import org.bouncycastle.jce.provider.BouncyCastleProvider;
  26. import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
  27. import org.bouncycastle.jce.spec.ECPrivateKeySpec;
  28. import org.bouncycastle.jce.spec.ECPublicKeySpec;
  29. import org.bouncycastle.math.ec.ECPoint;
  30. import org.slf4j.Logger;

  31. public class ECDSAKeyGenerator implements KeyGenerator<ECDSAKey> {

  32.   protected static final String KEY_ALGORITHM = "ECDSA";

  33.   protected static final String CURVE_NAME = "secp256k1";

  34.   protected static final ECNamedCurveParameterSpec ecSpec;

  35.   public static final ECDomainParameters ecParams;

  36.   static {
  37.     java.security.Provider provider = getProvider(PROVIDER_NAME);
  38.     if (provider != null) {
  39.       Security.removeProvider(PROVIDER_NAME);
  40.     }
  41.     addProvider(new BouncyCastleProvider());
  42.     ecSpec = getParameterSpec(CURVE_NAME);
  43.     ecParams = new ECDomainParameters(ecSpec.getCurve(), ecSpec.getG(), ecSpec.getN(),
  44.         ecSpec.getH(), ecSpec.getSeed());
  45.   }

  46.   protected final transient Logger logger = getLogger(getClass());

  47.   protected ECDSAKey generateKey(final SecureRandom secureRandom)
  48.       throws NoSuchProviderException, NoSuchAlgorithmException, InvalidAlgorithmParameterException {
  49.     final KeyPairGenerator generator = getKeyPairGenerator(secureRandom);
  50.     final KeyPair pair = generator.generateKeyPair();
  51.     final PrivateKey privateKey = pair.getPrivate();
  52.     final PublicKey publicKey = pair.getPublic();
  53.     logger.trace("Public key: {}", publicKey);
  54.     return new ECDSAKey(privateKey, publicKey, ecParams);
  55.   }

  56.   protected KeyPairGenerator getKeyPairGenerator(final SecureRandom secureRandom)
  57.       throws NoSuchProviderException, NoSuchAlgorithmException, InvalidAlgorithmParameterException {
  58.     final KeyPairGenerator keyPairGenerator =
  59.         KeyPairGenerator.getInstance(KEY_ALGORITHM, PROVIDER_NAME);
  60.     keyPairGenerator.initialize(ecSpec, secureRandom);
  61.     logger.debug("Generator: {}", keyPairGenerator);
  62.     return keyPairGenerator;
  63.   }

  64.   @Override
  65.   public ECDSAKey create() throws Exception {
  66.     return generateKey(new SecureRandom());
  67.   }

  68.   @Override
  69.   public ECDSAKey create(final String seed) throws Exception {
  70.     final byte[] digested = Sha256Utils.digest(seed.getBytes());
  71.     final SecureRandom secureRandom = new FixedSecureRandom(digested);
  72.     return generateKey(secureRandom);
  73.   }

  74.   /**
  75.    * Create key-pair from encoded private key.
  76.    *
  77.    * @param encodedPrivateKey PKCS #8 encoded private key
  78.    * @return key pair to be recovered
  79.    * @throws Exception On failure of recovery
  80.    */
  81.   public ECDSAKey create(final byte[] encodedPrivateKey) throws Exception {
  82.     final KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
  83.     final PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(encodedPrivateKey);
  84.     return create(factory.generatePrivate(spec));
  85.   }

  86.   /**
  87.    * Create key-pair from encoded private key.
  88.    *
  89.    * @param d d value of private key
  90.    * @return key pair to be recovered
  91.    * @throws Exception On failure of recovery
  92.    */
  93.   public ECDSAKey create(final BigInteger d) throws Exception {
  94.     return create(createPrivateKey(d));
  95.   }

  96.   /**
  97.    * Create key-pair from a private key.
  98.    *
  99.    * @param privateKey a private key
  100.    * @return key pair to be recovered
  101.    * @throws Exception On failure of recovery
  102.    */
  103.   public ECDSAKey create(final PrivateKey privateKey) throws Exception {
  104.     final KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
  105.     final ECPoint Q = ecSpec.getG()
  106.         .multiply(((org.bouncycastle.jce.interfaces.ECPrivateKey) privateKey).getD());
  107.     final ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(Q, ecSpec);
  108.     final PublicKey publicKey = factory.generatePublic(ecPublicKeySpec);
  109.     return new ECDSAKey(privateKey, publicKey, ecParams);
  110.   }

  111.   /**
  112.    * Create private key from d value.
  113.    *
  114.    * @param d d value of private key
  115.    * @return a generated private key
  116.    * @throws Exception on failure of create
  117.    */
  118.   public PrivateKey createPrivateKey(final BigInteger d) throws Exception {
  119.     final KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
  120.     final ECPrivateKeySpec spec = new ECPrivateKeySpec(d, ecSpec);
  121.     return factory.generatePrivate(spec);
  122.   }

  123.   /**
  124.    * Create public key from compressed one. The compression format is <code>F<sub>p</sub></code>(
  125.    * X9.62 s 4.2.1).
  126.    *
  127.    * @param compressed an compressed
  128.    * @return a generated public key
  129.    * @throws Exception on failure of create
  130.    */

  131.   public PublicKey createPublicKey(final byte[] compressed) throws Exception {
  132.     return createPublicKey(ecParams.getCurve().decodePoint(compressed));
  133.   }

  134.   /**
  135.    * Create public key from ECPoint x, y value.
  136.    *
  137.    * @param x x value of public key
  138.    * @param y y value of public key
  139.    * @return a generated public key
  140.    * @throws Exception on failure of create
  141.    */
  142.   public PublicKey createPublicKey(final BigInteger x, final BigInteger y) throws Exception {
  143.     return createPublicKey(ecParams.getCurve().createPoint(x, y));
  144.   }

  145.   protected PublicKey createPublicKey(final ECPoint ecPoint) throws Exception {
  146.     final KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
  147.     final ECPublicKeySpec spec = new ECPublicKeySpec(ecPoint, ecSpec);
  148.     return factory.generatePublic(spec);
  149.   }

  150. }