package org.spongycastle.openpgp;
import java.security.NoSuchProviderException;
import java.security.Provider;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.spongycastle.bcpg.HashAlgorithmTags;
import org.spongycastle.bcpg.PublicSubkeyPacket;
import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor;
import org.spongycastle.openpgp.operator.PGPContentSignerBuilder;
import org.spongycastle.openpgp.operator.PGPDigestCalculator;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
/**
* Generator for a PGP master and subkey ring. This class will generate
* both the secret and public key rings
*/
public class PGPKeyRingGenerator
{
List keys = new ArrayList();
private PBESecretKeyEncryptor keyEncryptor;
private PGPDigestCalculator checksumCalculator;
private PGPKeyPair masterKey;
private PGPSignatureSubpacketVector hashedPcks;
private PGPSignatureSubpacketVector unhashedPcks;
private PGPContentSignerBuilder keySignerBuilder;
/**
* Create a new key ring generator using old style checksumming. It is recommended to use
* SHA1 checksumming where possible.
*
* @param certificationLevel the certification level for keys on this ring.
* @param masterKey the master key pair.
* @param id the id to be associated with the ring.
* @param encAlgorithm the algorithm to be used to protect secret keys.
* @param passPhrase the passPhrase to be used to protect secret keys.
* @param hashedPcks packets to be included in the certification hash.
* @param unhashedPcks packets to be attached unhashed to the certification.
* @param rand input secured random
* @param provider the provider to use for encryption.
*
* @throws PGPException
* @throws NoSuchProviderException
* @deprecated use method taking PBESecretKeyDecryptor
*/
public PGPKeyRingGenerator(
int certificationLevel,
PGPKeyPair masterKey,
String id,
int encAlgorithm,
char[] passPhrase,
PGPSignatureSubpacketVector hashedPcks,
PGPSignatureSubpacketVector unhashedPcks,
SecureRandom rand,
String provider)
throws PGPException, NoSuchProviderException
{
this(certificationLevel, masterKey, id, encAlgorithm, passPhrase, false, hashedPcks, unhashedPcks, rand, provider);
}
/**
* Create a new key ring generator.
*
* @param certificationLevel the certification level for keys on this ring.
* @param masterKey the master key pair.
* @param id the id to be associated with the ring.
* @param encAlgorithm the algorithm to be used to protect secret keys.
* @param passPhrase the passPhrase to be used to protect secret keys.
* @param useSHA1 checksum the secret keys with SHA1 rather than the older 16 bit checksum.
* @param hashedPcks packets to be included in the certification hash.
* @param unhashedPcks packets to be attached unhashed to the certification.
* @param rand input secured random
* @param provider the provider to use for encryption.
*
* @throws PGPException
* @throws NoSuchProviderException
* @deprecated use method taking PBESecretKeyDecryptor
*/
public PGPKeyRingGenerator(
int certificationLevel,
PGPKeyPair masterKey,
String id,
int encAlgorithm,
char[] passPhrase,
boolean useSHA1,
PGPSignatureSubpacketVector hashedPcks,
PGPSignatureSubpacketVector unhashedPcks,
SecureRandom rand,
String provider)
throws PGPException, NoSuchProviderException
{
this(certificationLevel, masterKey, id, encAlgorithm, passPhrase, useSHA1, hashedPcks, unhashedPcks, rand, PGPUtil.getProvider(provider));
}
/**
* Create a new key ring generator.
*
* @param certificationLevel the certification level for keys on this ring.
* @param masterKey the master key pair.
* @param id the id to be associated with the ring.
* @param encAlgorithm the algorithm to be used to protect secret keys.
* @param passPhrase the passPhrase to be used to protect secret keys.
* @param useSHA1 checksum the secret keys with SHA1 rather than the older 16 bit checksum.
* @param hashedPcks packets to be included in the certification hash.
* @param unhashedPcks packets to be attached unhashed to the certification.
* @param rand input secured random
* @param provider the provider to use for encryption.
*
* @throws PGPException
* @throws NoSuchProviderException
* @deprecated use method taking PBESecretKeyEncryptor
*/
public PGPKeyRingGenerator(
int certificationLevel,
PGPKeyPair masterKey,
String id,
int encAlgorithm,
char[] passPhrase,
boolean useSHA1,
PGPSignatureSubpacketVector hashedPcks,
PGPSignatureSubpacketVector unhashedPcks,
SecureRandom rand,
Provider provider)
throws PGPException, NoSuchProviderException
{
this.masterKey = masterKey;
this.hashedPcks = hashedPcks;
this.unhashedPcks = unhashedPcks;
this.keyEncryptor = new JcePBESecretKeyEncryptorBuilder(encAlgorithm).setProvider(provider).setSecureRandom(rand).build(passPhrase);
this.checksumCalculator = convertSHA1Flag(useSHA1);
this.keySignerBuilder = new JcaPGPContentSignerBuilder(masterKey.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1);
keys.add(new PGPSecretKey(certificationLevel, masterKey, id, checksumCalculator, hashedPcks, unhashedPcks, keySignerBuilder, keyEncryptor));
}
/**
* Create a new key ring generator.
*
* @param certificationLevel
* @param masterKey
* @param id
* @param checksumCalculator
* @param hashedPcks
* @param unhashedPcks
* @param keySignerBuilder
* @param keyEncryptor
* @throws PGPException
*/
public PGPKeyRingGenerator(
int certificationLevel,
PGPKeyPair masterKey,
String id,
PGPDigestCalculator checksumCalculator,
PGPSignatureSubpacketVector hashedPcks,
PGPSignatureSubpacketVector unhashedPcks,
PGPContentSignerBuilder keySignerBuilder,
PBESecretKeyEncryptor keyEncryptor)
throws PGPException
{
this.masterKey = masterKey;
this.keyEncryptor = keyEncryptor;
this.checksumCalculator = checksumCalculator;
this.keySignerBuilder = keySignerBuilder;
this.hashedPcks = hashedPcks;
this.unhashedPcks = unhashedPcks;
keys.add(new PGPSecretKey(certificationLevel, masterKey, id, checksumCalculator, hashedPcks, unhashedPcks, keySignerBuilder, keyEncryptor));
}
/**
* Add a sub key to the key ring to be generated with default certification and inheriting
* the hashed/unhashed packets of the master key.
*
* @param keyPair
* @throws PGPException
*/
public void addSubKey(
PGPKeyPair keyPair)
throws PGPException
{
addSubKey(keyPair, hashedPcks, unhashedPcks);
}
/**
* Add a subkey with specific hashed and unhashed packets associated with it and default
* certification.
*
* @param keyPair public/private key pair.
* @param hashedPcks hashed packet values to be included in certification.
* @param unhashedPcks unhashed packets values to be included in certification.
* @throws PGPException
*/
public void addSubKey(
PGPKeyPair keyPair,
PGPSignatureSubpacketVector hashedPcks,
PGPSignatureSubpacketVector unhashedPcks)
throws PGPException
{
try
{
//
// generate the certification
//
PGPSignatureGenerator sGen = new PGPSignatureGenerator(keySignerBuilder);
sGen.init(PGPSignature.SUBKEY_BINDING, masterKey.getPrivateKey());
sGen.setHashedSubpackets(hashedPcks);
sGen.setUnhashedSubpackets(unhashedPcks);
List subSigs = new ArrayList();
subSigs.add(sGen.generateCertification(masterKey.getPublicKey(), keyPair.getPublicKey()));
keys.add(new PGPSecretKey(keyPair.getPrivateKey(), new PGPPublicKey(keyPair.getPublicKey(), null, subSigs), checksumCalculator, keyEncryptor));
}
catch (PGPException e)
{
throw e;
}
catch (Exception e)
{
throw new PGPException("exception adding subkey: ", e);
}
}
/**
* Return the secret key ring.
*
* @return a secret key ring.
*/
public PGPSecretKeyRing generateSecretKeyRing()
{
return new PGPSecretKeyRing(keys);
}
/**
* Return the public key ring that corresponds to the secret key ring.
*
* @return a public key ring.
*/
public PGPPublicKeyRing generatePublicKeyRing()
{
Iterator it = keys.iterator();
List pubKeys = new ArrayList();
pubKeys.add(((PGPSecretKey)it.next()).getPublicKey());
while (it.hasNext())
{
PGPPublicKey k = new PGPPublicKey(((PGPSecretKey)it.next()).getPublicKey());
k.publicPk = new PublicSubkeyPacket(k.getAlgorithm(), k.getCreationTime(), k.publicPk.getKey());
pubKeys.add(k);
}
return new PGPPublicKeyRing(pubKeys);
}
private static PGPDigestCalculator convertSHA1Flag(boolean useSHA1)
throws PGPException
{
return useSHA1 ? new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1) : null;
}
}