using System;
using System.Collections;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Bcpg.OpenPgp
{
///
/// Generator for a PGP master and subkey ring.
/// This class will generate both the secret and public key rings
///
public class PgpKeyRingGenerator
{
private IList keys = Platform.CreateArrayList();
private string id;
private SymmetricKeyAlgorithmTag encAlgorithm;
private HashAlgorithmTag hashAlgorithm;
private int certificationLevel;
private byte[] rawPassPhrase;
private bool useSha1;
private PgpKeyPair masterKey;
private PgpSignatureSubpacketVector hashedPacketVector;
private PgpSignatureSubpacketVector unhashedPacketVector;
private SecureRandom rand;
///
/// Create a new key ring generator.
///
///
/// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
/// the historical behaviour of the library (1.7 and earlier).
///
/// The certification level for keys on this ring.
/// The master key pair.
/// The id to be associated with the ring.
/// The algorithm to be used to protect secret keys.
/// The passPhrase to be used to protect secret keys.
/// Checksum the secret keys with SHA1 rather than the older 16 bit checksum.
/// Packets to be included in the certification hash.
/// Packets to be attached unhashed to the certification.
/// input secured random.
public PgpKeyRingGenerator(
int certificationLevel,
PgpKeyPair masterKey,
string id,
SymmetricKeyAlgorithmTag encAlgorithm,
char[] passPhrase,
bool useSha1,
PgpSignatureSubpacketVector hashedPackets,
PgpSignatureSubpacketVector unhashedPackets,
SecureRandom rand)
: this(certificationLevel, masterKey, id, encAlgorithm, false, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
{
}
///
/// Create a new key ring generator.
///
/// The certification level for keys on this ring.
/// The master key pair.
/// The id to be associated with the ring.
/// The algorithm to be used to protect secret keys.
///
/// If true, conversion of the passphrase to bytes uses Encoding.UTF8.GetBytes(), otherwise the conversion
/// is performed using Convert.ToByte(), which is the historical behaviour of the library (1.7 and earlier).
///
/// The passPhrase to be used to protect secret keys.
/// Checksum the secret keys with SHA1 rather than the older 16 bit checksum.
/// Packets to be included in the certification hash.
/// Packets to be attached unhashed to the certification.
/// input secured random.
public PgpKeyRingGenerator(
int certificationLevel,
PgpKeyPair masterKey,
string id,
SymmetricKeyAlgorithmTag encAlgorithm,
bool utf8PassPhrase,
char[] passPhrase,
bool useSha1,
PgpSignatureSubpacketVector hashedPackets,
PgpSignatureSubpacketVector unhashedPackets,
SecureRandom rand)
: this(certificationLevel, masterKey, id, encAlgorithm,
PgpUtilities.EncodePassPhrase(passPhrase, utf8PassPhrase),
useSha1, hashedPackets, unhashedPackets, rand)
{
}
///
/// Create a new key ring generator.
///
/// The certification level for keys on this ring.
/// The master key pair.
/// The id to be associated with the ring.
/// The algorithm to be used to protect secret keys.
/// The passPhrase to be used to protect secret keys.
/// Checksum the secret keys with SHA1 rather than the older 16 bit checksum.
/// Packets to be included in the certification hash.
/// Packets to be attached unhashed to the certification.
/// input secured random.
public PgpKeyRingGenerator(
int certificationLevel,
PgpKeyPair masterKey,
string id,
SymmetricKeyAlgorithmTag encAlgorithm,
byte[] rawPassPhrase,
bool useSha1,
PgpSignatureSubpacketVector hashedPackets,
PgpSignatureSubpacketVector unhashedPackets,
SecureRandom rand)
{
this.certificationLevel = certificationLevel;
this.masterKey = masterKey;
this.id = id;
this.encAlgorithm = encAlgorithm;
this.rawPassPhrase = rawPassPhrase;
this.useSha1 = useSha1;
this.hashedPacketVector = hashedPackets;
this.unhashedPacketVector = unhashedPackets;
this.rand = rand;
keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, rawPassPhrase, false, useSha1, hashedPackets, unhashedPackets, rand));
}
///
/// Create a new key ring generator.
///
///
/// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
/// the historical behaviour of the library (1.7 and earlier).
///
/// The certification level for keys on this ring.
/// The master key pair.
/// The id to be associated with the ring.
/// The algorithm to be used to protect secret keys.
/// The hash algorithm.
/// The passPhrase to be used to protect secret keys.
/// Checksum the secret keys with SHA1 rather than the older 16 bit checksum.
/// Packets to be included in the certification hash.
/// Packets to be attached unhashed to the certification.
/// input secured random.
public PgpKeyRingGenerator(
int certificationLevel,
PgpKeyPair masterKey,
string id,
SymmetricKeyAlgorithmTag encAlgorithm,
HashAlgorithmTag hashAlgorithm,
char[] passPhrase,
bool useSha1,
PgpSignatureSubpacketVector hashedPackets,
PgpSignatureSubpacketVector unhashedPackets,
SecureRandom rand)
: this(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm, false, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
{
}
///
/// Create a new key ring generator.
///
/// The certification level for keys on this ring.
/// The master key pair.
/// The id to be associated with the ring.
/// The algorithm to be used to protect secret keys.
/// The hash algorithm.
///
/// If true, conversion of the passphrase to bytes uses Encoding.UTF8.GetBytes(), otherwise the conversion
/// is performed using Convert.ToByte(), which is the historical behaviour of the library (1.7 and earlier).
///
/// The passPhrase to be used to protect secret keys.
/// Checksum the secret keys with SHA1 rather than the older 16 bit checksum.
/// Packets to be included in the certification hash.
/// Packets to be attached unhashed to the certification.
/// input secured random.
public PgpKeyRingGenerator(
int certificationLevel,
PgpKeyPair masterKey,
string id,
SymmetricKeyAlgorithmTag encAlgorithm,
HashAlgorithmTag hashAlgorithm,
bool utf8PassPhrase,
char[] passPhrase,
bool useSha1,
PgpSignatureSubpacketVector hashedPackets,
PgpSignatureSubpacketVector unhashedPackets,
SecureRandom rand)
: this(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm,
PgpUtilities.EncodePassPhrase(passPhrase, utf8PassPhrase),
useSha1, hashedPackets, unhashedPackets, rand)
{
}
///
/// Create a new key ring generator.
///
///
/// Allows the caller to handle the encoding of the passphrase to bytes.
///
/// The certification level for keys on this ring.
/// The master key pair.
/// The id to be associated with the ring.
/// The algorithm to be used to protect secret keys.
/// The hash algorithm.
/// The passPhrase to be used to protect secret keys.
/// Checksum the secret keys with SHA1 rather than the older 16 bit checksum.
/// Packets to be included in the certification hash.
/// Packets to be attached unhashed to the certification.
/// input secured random.
public PgpKeyRingGenerator(
int certificationLevel,
PgpKeyPair masterKey,
string id,
SymmetricKeyAlgorithmTag encAlgorithm,
HashAlgorithmTag hashAlgorithm,
byte[] rawPassPhrase,
bool useSha1,
PgpSignatureSubpacketVector hashedPackets,
PgpSignatureSubpacketVector unhashedPackets,
SecureRandom rand)
{
this.certificationLevel = certificationLevel;
this.masterKey = masterKey;
this.id = id;
this.encAlgorithm = encAlgorithm;
this.rawPassPhrase = rawPassPhrase;
this.useSha1 = useSha1;
this.hashedPacketVector = hashedPackets;
this.unhashedPacketVector = unhashedPackets;
this.rand = rand;
this.hashAlgorithm = hashAlgorithm;
keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm, rawPassPhrase, false, useSha1, hashedPackets, unhashedPackets, rand));
}
/// Add a subkey to the key ring to be generated with default certification.
public void AddSubKey(
PgpKeyPair keyPair)
{
AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector);
}
///
/// Add a subkey to the key ring to be generated with default certification.
///
/// The key pair.
/// The hash algorithm.
public void AddSubKey(PgpKeyPair keyPair, HashAlgorithmTag hashAlgorithm)
{
this.AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector, hashAlgorithm);
}
///
/// Add a signing subkey to the key ring to be generated with default certification and a primary key binding signature.
///
/// The key pair.
/// The hash algorithm.
/// The primary-key binding hash algorithm.
public void AddSubKey(PgpKeyPair keyPair, HashAlgorithmTag hashAlgorithm, HashAlgorithmTag primaryKeyBindingHashAlgorithm)
{
this.AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector, hashAlgorithm, primaryKeyBindingHashAlgorithm);
}
///
/// Add a subkey with specific hashed and unhashed packets associated with it and
/// default certification using SHA-1.
///
/// Public/private key pair.
/// Hashed packet values to be included in certification.
/// Unhashed packets values to be included in certification.
///
public void AddSubKey(
PgpKeyPair keyPair,
PgpSignatureSubpacketVector hashedPackets,
PgpSignatureSubpacketVector unhashedPackets)
{
AddSubKey(keyPair, hashedPackets, unhashedPackets, HashAlgorithmTag.Sha1);
}
///
/// Add a subkey with specific hashed and unhashed packets associated with it and
/// default certification.
///
/// Public/private key pair.
/// Hashed packet values to be included in certification.
/// Unhashed packets values to be included in certification.
/// The hash algorithm.
/// exception adding subkey:
///
public void AddSubKey(
PgpKeyPair keyPair,
PgpSignatureSubpacketVector hashedPackets,
PgpSignatureSubpacketVector unhashedPackets,
HashAlgorithmTag hashAlgorithm)
{
try
{
PgpSignatureGenerator sGen = new PgpSignatureGenerator(masterKey.PublicKey.Algorithm, hashAlgorithm);
//
// Generate the certification
//
sGen.InitSign(PgpSignature.SubkeyBinding, masterKey.PrivateKey);
sGen.SetHashedSubpackets(hashedPackets);
sGen.SetUnhashedSubpackets(unhashedPackets);
IList subSigs = Platform.CreateArrayList();
subSigs.Add(sGen.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey));
keys.Add(new PgpSecretKey(keyPair.PrivateKey, new PgpPublicKey(keyPair.PublicKey, null, subSigs), encAlgorithm,
rawPassPhrase, false, useSha1, rand, false));
}
catch (PgpException)
{
throw;
}
catch (Exception e)
{
throw new PgpException("exception adding subkey: ", e);
}
}
///
/// Add a signing subkey with specific hashed and unhashed packets associated with it and
/// default certifications, including the primary-key binding signature.
///
/// Public/private key pair.
/// Hashed packet values to be included in certification.
/// Unhashed packets values to be included in certification.
/// The hash algorithm.
/// The primary-key binding hash algorithm.
/// exception adding subkey:
///
public void AddSubKey(
PgpKeyPair keyPair,
PgpSignatureSubpacketVector hashedPackets,
PgpSignatureSubpacketVector unhashedPackets,
HashAlgorithmTag hashAlgorithm,
HashAlgorithmTag primaryKeyBindingHashAlgorithm)
{
try
{
PgpSignatureGenerator sGen = new PgpSignatureGenerator(masterKey.PublicKey.Algorithm, hashAlgorithm);
//
// Generate the certification
//
sGen.InitSign(PgpSignature.SubkeyBinding, masterKey.PrivateKey);
// add primary key binding sub packet
PgpSignatureGenerator pGen = new PgpSignatureGenerator(keyPair.PublicKey.Algorithm, primaryKeyBindingHashAlgorithm);
pGen.InitSign(PgpSignature.PrimaryKeyBinding, keyPair.PrivateKey);
PgpSignatureSubpacketGenerator spGen = new PgpSignatureSubpacketGenerator(hashedPackets);
spGen.SetEmbeddedSignature(false,
pGen.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey));
sGen.SetHashedSubpackets(spGen.Generate());
sGen.SetUnhashedSubpackets(unhashedPackets);
IList subSigs = Platform.CreateArrayList();
subSigs.Add(sGen.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey));
keys.Add(new PgpSecretKey(keyPair.PrivateKey, new PgpPublicKey(keyPair.PublicKey, null, subSigs), encAlgorithm,
rawPassPhrase, false, useSha1, rand, false));
}
catch (PgpException)
{
throw;
}
catch (Exception e)
{
throw new PgpException("exception adding subkey: ", e);
}
}
/// Return the secret key ring.
public PgpSecretKeyRing GenerateSecretKeyRing()
{
return new PgpSecretKeyRing(keys);
}
/// Return the public key ring that corresponds to the secret key ring.
public PgpPublicKeyRing GeneratePublicKeyRing()
{
IList pubKeys = Platform.CreateArrayList();
IEnumerator enumerator = keys.GetEnumerator();
enumerator.MoveNext();
PgpSecretKey pgpSecretKey = (PgpSecretKey) enumerator.Current;
pubKeys.Add(pgpSecretKey.PublicKey);
while (enumerator.MoveNext())
{
pgpSecretKey = (PgpSecretKey) enumerator.Current;
PgpPublicKey k = new PgpPublicKey(pgpSecretKey.PublicKey);
k.publicPk = new PublicSubkeyPacket(
k.Algorithm, k.CreationTime, k.publicPk.Key);
pubKeys.Add(k);
}
return new PgpPublicKeyRing(pubKeys);
}
}
}