BouncyKeyPairGenerator.java
/*
* GordianKnot: Security Suite
* Copyright 2012-2026. Tony Washer
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.github.tonywasher.joceanus.gordianknot.impl.bc.keypair;
import io.github.tonywasher.joceanus.gordianknot.api.base.GordianException;
import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianKeyPair;
import io.github.tonywasher.joceanus.gordianknot.api.keypair.spec.GordianKeyPairSpec;
import io.github.tonywasher.joceanus.gordianknot.impl.bc.keypair.BouncyKeyPair.BouncyPrivateKey;
import io.github.tonywasher.joceanus.gordianknot.impl.bc.keypair.BouncyKeyPair.BouncyPublicKey;
import io.github.tonywasher.joceanus.gordianknot.impl.bc.keypair.BouncyKeyPair.BouncyStateAwareKeyPair;
import io.github.tonywasher.joceanus.gordianknot.impl.bc.keypair.BouncyKeyPair.BouncyStateAwarePrivateKey;
import io.github.tonywasher.joceanus.gordianknot.impl.core.base.GordianBaseFactory;
import io.github.tonywasher.joceanus.gordianknot.impl.core.keypair.GordianCoreKeyPairGenerator;
import io.github.tonywasher.joceanus.gordianknot.impl.core.keypair.GordianKeyPairValidity;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* BouncyCastle KeyPair generator.
*
* @param <S> the private parameters
* @param <P> the public parameters
*/
public abstract class BouncyKeyPairGenerator<S extends AsymmetricKeyParameter, P extends AsymmetricKeyParameter>
extends GordianCoreKeyPairGenerator {
/**
* Parsing error.
*/
static final String ERROR_PARSE = "Failed to parse encoding";
/**
* Prime certainty.
*/
static final int PRIME_CERTAINTY = 128;
/**
* Generator.
*/
private AsymmetricCipherKeyPairGenerator theGenerator;
/**
* The factorySet.
*/
private BouncyKeyFactorySet theFactorySet;
/**
* Constructor.
*
* @param pFactory the Security Factory
* @param pKeySpec the keySpec
*/
protected BouncyKeyPairGenerator(final GordianBaseFactory pFactory,
final GordianKeyPairSpec pKeySpec) {
super(pFactory, pKeySpec);
}
/**
* set keyPairGenerator.
*
* @param pGenerator the generator
* @param pParams the initiation parameters
*/
void setGenerator(final AsymmetricCipherKeyPairGenerator pGenerator,
final KeyGenerationParameters pParams) {
theGenerator = pGenerator;
theGenerator.init(pParams);
}
/**
* set factorySet.
*
* @param pFactorySet the factorySet
*/
void setFactorySet(final BouncyKeyFactorySet pFactorySet) {
theFactorySet = pFactorySet;
}
@Override
public BouncyKeyPair generateKeyPair() {
/* Generate and return the keyPair */
final AsymmetricCipherKeyPair myPair = theGenerator.generateKeyPair();
final BouncyPublicKey<P> myPublic = newPublicKey(myPair.getPublic());
final BouncyPrivateKey<S> myPrivate = newPrivateKey(myPair.getPrivate());
return createKeyPair(myPublic, myPrivate);
}
/**
* Create keyPair.
*
* @param pPublicKey the public key
* @param pPrivateKey the private key
* @return the keyPair
*/
private BouncyKeyPair createKeyPair(final BouncyPublicKey<P> pPublicKey,
final BouncyPrivateKey<S> pPrivateKey) {
return pPrivateKey instanceof BouncyStateAwarePrivateKey<?> myPrivate
? new BouncyStateAwareKeyPair(pPublicKey, myPrivate)
: new BouncyKeyPair(pPublicKey, pPrivateKey);
}
@Override
public BouncyKeyPair deriveKeyPair(final X509EncodedKeySpec pPublicKey,
final PKCS8EncodedKeySpec pPrivateKey) throws GordianException {
/* Check the keySpecs */
checkKeySpec(pPrivateKey);
/* derive keyPair */
final BouncyPublicKey<P> myPublic = derivePublicKey(pPublicKey);
final AsymmetricKeyParameter myParms = theFactorySet.parsePKCS8EncodedKeySpec(pPrivateKey);
final BouncyPrivateKey<S> myPrivate = newPrivateKey(myParms);
final BouncyKeyPair myPair = createKeyPair(myPublic, myPrivate);
/* Check that we have a matching pair */
GordianKeyPairValidity.checkValidity(getFactory(), myPair);
/* If this is a stateAware privateKey */
if (myPrivate instanceof BouncyStateAwarePrivateKey) {
/* Rebuild and return the keyPair to avoid incrementing usage count */
final AsymmetricKeyParameter myNewParms = theFactorySet.parsePKCS8EncodedKeySpec(pPrivateKey);
final BouncyStateAwarePrivateKey<?> myNewPrivate = (BouncyStateAwarePrivateKey<?>) newPrivateKey(myNewParms);
return new BouncyStateAwareKeyPair(myPublic, myNewPrivate);
}
/* Return the keyPair */
return myPair;
}
@Override
public PKCS8EncodedKeySpec getPKCS8Encoding(final GordianKeyPair pKeyPair) throws GordianException {
/* Check the keyPair type and keySpecs */
BouncyKeyPair.checkKeyPair(pKeyPair, getKeySpec());
/* build and return the encoding */
final BouncyPrivateKey<?> myPrivateKey = (BouncyPrivateKey<?>) getPrivateKey(pKeyPair);
final AsymmetricKeyParameter myParms = myPrivateKey.getPrivateKey();
return theFactorySet.createPKCS8EncodedKeySpec(myParms);
}
@Override
public X509EncodedKeySpec getX509Encoding(final GordianKeyPair pKeyPair) throws GordianException {
/* Check the keyPair type and keySpecs */
BouncyKeyPair.checkKeyPair(pKeyPair, getKeySpec());
/* build and return the encoding */
final BouncyPublicKey<?> myPublicKey = (BouncyPublicKey<?>) getPublicKey(pKeyPair);
final AsymmetricKeyParameter myParms = myPublicKey.getPublicKey();
return theFactorySet.createX509EncodedKeySpec(myParms);
}
@Override
public BouncyKeyPair derivePublicOnlyKeyPair(final X509EncodedKeySpec pEncodedKey) throws GordianException {
final BouncyPublicKey<?> myPublic = derivePublicKey(pEncodedKey);
return new BouncyKeyPair(myPublic);
}
/**
* Derive public key from encoded.
*
* @param pEncodedKey the encoded key
* @return the public key
* @throws GordianException on error
*/
private BouncyPublicKey<P> derivePublicKey(final X509EncodedKeySpec pEncodedKey) throws GordianException {
/* Check the keySpecs */
checkKeySpec(pEncodedKey);
/* derive publicKey */
final AsymmetricKeyParameter myParms = theFactorySet.parseX509EncodedKeySpec(pEncodedKey);
return newPublicKey(myParms);
}
/**
* Create new private key from parameters.
*
* @param pParms the parameters
* @return the new public key
*/
abstract BouncyPrivateKey<S> newPrivateKey(AsymmetricKeyParameter pParms);
/**
* Create new public key from parameters.
*
* @param pParms the parameters
* @return the new public key
*/
abstract BouncyPublicKey<P> newPublicKey(AsymmetricKeyParameter pParms);
/**
* KeyFactorySet.
*/
interface BouncyKeyFactorySet {
/**
* parse PKCS8EncodedKeySpec to PrivateKeyParams.
*
* @param pEncoded the encodedKeySpec
* @return the PrivateKeyParams
* @throws GordianException on error
*/
AsymmetricKeyParameter parsePKCS8EncodedKeySpec(PKCS8EncodedKeySpec pEncoded) throws GordianException;
/**
* create PKCS8EncodedKeySpec for PrivateKeyParams.
*
* @param pParams the privateKeyParameters
* @return the PKCS8EncodedKeySpec
* @throws GordianException on error
*/
PKCS8EncodedKeySpec createPKCS8EncodedKeySpec(AsymmetricKeyParameter pParams) throws GordianException;
/**
* parse X509EncodedKeySpec to PublicKeyParams.
*
* @param pEncoded the encodedKeySpec
* @return the PublicKeyParams
* @throws GordianException on error
*/
AsymmetricKeyParameter parseX509EncodedKeySpec(X509EncodedKeySpec pEncoded) throws GordianException;
/**
* create X509EncodedKeySpec for PublicKeyParams.
*
* @param pParams the publicKeyParameters
* @return the X509EncodedKeySpec
* @throws GordianException on error
*/
X509EncodedKeySpec createX509EncodedKeySpec(AsymmetricKeyParameter pParams) throws GordianException;
}
}