ECDSAKeyGenerator.java
/*
* @copyright defined in LICENSE.txt
*/
package hera.util.pki;
import static java.security.Security.addProvider;
import static java.security.Security.getProvider;
import static org.bouncycastle.jce.ECNamedCurveTable.getParameterSpec;
import static org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
import static org.slf4j.LoggerFactory.getLogger;
import hera.util.Sha256Utils;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.prng.FixedSecureRandom;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECPoint;
import org.slf4j.Logger;
public class ECDSAKeyGenerator implements KeyGenerator<ECDSAKey> {
protected static final String KEY_ALGORITHM = "ECDSA";
protected static final String CURVE_NAME = "secp256k1";
protected static final ECNamedCurveParameterSpec ecSpec;
public static final ECDomainParameters ecParams;
static {
java.security.Provider provider = getProvider(PROVIDER_NAME);
if (provider != null) {
Security.removeProvider(PROVIDER_NAME);
}
addProvider(new BouncyCastleProvider());
ecSpec = getParameterSpec(CURVE_NAME);
ecParams = new ECDomainParameters(ecSpec.getCurve(), ecSpec.getG(), ecSpec.getN(),
ecSpec.getH(), ecSpec.getSeed());
}
protected final transient Logger logger = getLogger(getClass());
protected ECDSAKey generateKey(final SecureRandom secureRandom)
throws NoSuchProviderException, NoSuchAlgorithmException, InvalidAlgorithmParameterException {
final KeyPairGenerator generator = getKeyPairGenerator(secureRandom);
final KeyPair pair = generator.generateKeyPair();
final PrivateKey privateKey = pair.getPrivate();
final PublicKey publicKey = pair.getPublic();
logger.trace("Public key: {}", publicKey);
return new ECDSAKey(privateKey, publicKey, ecParams);
}
protected KeyPairGenerator getKeyPairGenerator(final SecureRandom secureRandom)
throws NoSuchProviderException, NoSuchAlgorithmException, InvalidAlgorithmParameterException {
final KeyPairGenerator keyPairGenerator =
KeyPairGenerator.getInstance(KEY_ALGORITHM, PROVIDER_NAME);
keyPairGenerator.initialize(ecSpec, secureRandom);
logger.debug("Generator: {}", keyPairGenerator);
return keyPairGenerator;
}
@Override
public ECDSAKey create() throws Exception {
return generateKey(new SecureRandom());
}
@Override
public ECDSAKey create(final String seed) throws Exception {
final byte[] digested = Sha256Utils.digest(seed.getBytes());
final SecureRandom secureRandom = new FixedSecureRandom(digested);
return generateKey(secureRandom);
}
/**
* Create key-pair from encoded private key.
*
* @param encodedPrivateKey PKCS #8 encoded private key
* @return key pair to be recovered
* @throws Exception On failure of recovery
*/
public ECDSAKey create(final byte[] encodedPrivateKey) throws Exception {
final KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
final PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(encodedPrivateKey);
return create(factory.generatePrivate(spec));
}
/**
* Create key-pair from encoded private key.
*
* @param d d value of private key
* @return key pair to be recovered
* @throws Exception On failure of recovery
*/
public ECDSAKey create(final BigInteger d) throws Exception {
return create(createPrivateKey(d));
}
/**
* Create key-pair from a private key.
*
* @param privateKey a private key
* @return key pair to be recovered
* @throws Exception On failure of recovery
*/
public ECDSAKey create(final PrivateKey privateKey) throws Exception {
final KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
final ECPoint Q = ecSpec.getG()
.multiply(((org.bouncycastle.jce.interfaces.ECPrivateKey) privateKey).getD());
final ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(Q, ecSpec);
final PublicKey publicKey = factory.generatePublic(ecPublicKeySpec);
return new ECDSAKey(privateKey, publicKey, ecParams);
}
/**
* Create private key from d value.
*
* @param d d value of private key
* @return a generated private key
* @throws Exception on failure of create
*/
public PrivateKey createPrivateKey(final BigInteger d) throws Exception {
final KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
final ECPrivateKeySpec spec = new ECPrivateKeySpec(d, ecSpec);
return factory.generatePrivate(spec);
}
/**
* Create public key from compressed one. The compression format is <code>F<sub>p</sub></code>(
* X9.62 s 4.2.1).
*
* @param compressed an compressed
* @return a generated public key
* @throws Exception on failure of create
*/
public PublicKey createPublicKey(final byte[] compressed) throws Exception {
return createPublicKey(ecParams.getCurve().decodePoint(compressed));
}
/**
* Create public key from ECPoint x, y value.
*
* @param x x value of public key
* @param y y value of public key
* @return a generated public key
* @throws Exception on failure of create
*/
public PublicKey createPublicKey(final BigInteger x, final BigInteger y) throws Exception {
return createPublicKey(ecParams.getCurve().createPoint(x, y));
}
protected PublicKey createPublicKey(final ECPoint ecPoint) throws Exception {
final KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
final ECPublicKeySpec spec = new ECPublicKeySpec(ecPoint, ecSpec);
return factory.generatePublic(spec);
}
}