diff --git a/crypto/src/bcpg/ArmoredOutputStream.cs b/crypto/src/bcpg/ArmoredOutputStream.cs
index b3a32c6f5..5d4b6b5a7 100644
--- a/crypto/src/bcpg/ArmoredOutputStream.cs
+++ b/crypto/src/bcpg/ArmoredOutputStream.cs
@@ -36,46 +36,46 @@ namespace Org.BouncyCastle.Bcpg
* encode the input data producing a base 64 encoded byte array.
*/
private static void Encode(
- Stream outStream,
- int[] data,
- int len)
+ Stream outStream,
+ int[] data,
+ int len)
{
- Debug.Assert(len > 0);
- Debug.Assert(len < 4);
+ Debug.Assert(len > 0);
+ Debug.Assert(len < 4);
- byte[] bs = new byte[4];
- int d1 = data[0];
- bs[0] = encodingTable[(d1 >> 2) & 0x3f];
+ byte[] bs = new byte[4];
+ int d1 = data[0];
+ bs[0] = encodingTable[(d1 >> 2) & 0x3f];
- switch (len)
+ switch (len)
{
- case 1:
- {
- bs[1] = encodingTable[(d1 << 4) & 0x3f];
- bs[2] = (byte)'=';
- bs[3] = (byte)'=';
- break;
- }
- case 2:
- {
- int d2 = data[1];
- bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
- bs[2] = encodingTable[(d2 << 2) & 0x3f];
- bs[3] = (byte)'=';
- break;
- }
- case 3:
- {
- int d2 = data[1];
- int d3 = data[2];
- bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
- bs[2] = encodingTable[((d2 << 2) | (d3 >> 6)) & 0x3f];
- bs[3] = encodingTable[d3 & 0x3f];
- break;
- }
+ case 1:
+ {
+ bs[1] = encodingTable[(d1 << 4) & 0x3f];
+ bs[2] = (byte)'=';
+ bs[3] = (byte)'=';
+ break;
+ }
+ case 2:
+ {
+ int d2 = data[1];
+ bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
+ bs[2] = encodingTable[(d2 << 2) & 0x3f];
+ bs[3] = (byte)'=';
+ break;
+ }
+ case 3:
+ {
+ int d2 = data[1];
+ int d3 = data[2];
+ bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
+ bs[2] = encodingTable[((d2 << 2) | (d3 >> 6)) & 0x3f];
+ bs[3] = encodingTable[d3 & 0x3f];
+ break;
+ }
}
- outStream.Write(bs, 0, bs.Length);
+ outStream.Write(bs, 0, bs.Length);
}
private readonly Stream outStream;
@@ -91,18 +91,18 @@ namespace Org.BouncyCastle.Bcpg
private string type;
- private static readonly string nl = Platform.NewLine;
- private static readonly string headerStart = "-----BEGIN PGP ";
- private static readonly string headerTail = "-----";
- private static readonly string footerStart = "-----END PGP ";
- private static readonly string footerTail = "-----";
+ private static readonly string nl = Platform.NewLine;
+ private static readonly string headerStart = "-----BEGIN PGP ";
+ private static readonly string headerTail = "-----";
+ private static readonly string footerStart = "-----END PGP ";
+ private static readonly string footerTail = "-----";
private static readonly string version = "BCPG C# v"
- + Assembly.GetExecutingAssembly().GetName().Version;
+ + Assembly.GetExecutingAssembly().GetName().Version;
- private readonly IDictionary headers;
+ private readonly IDictionary headers;
- public ArmoredOutputStream(Stream outStream)
+ public ArmoredOutputStream(Stream outStream)
{
this.outStream = outStream;
this.headers = Platform.CreateHashtable();
@@ -174,10 +174,10 @@ namespace Org.BouncyCastle.Bcpg
throw new IOException("unknown hash algorithm tag in beginClearText: " + hashAlgorithm);
}
- DoWrite("-----BEGIN PGP SIGNED MESSAGE-----" + nl);
+ DoWrite("-----BEGIN PGP SIGNED MESSAGE-----" + nl);
DoWrite("Hash: " + hash + nl + nl);
- clearText = true;
+ clearText = true;
newLine = true;
lastb = 0;
}
@@ -218,7 +218,7 @@ namespace Org.BouncyCastle.Bcpg
{
bool newPacket = (b & 0x40) != 0;
- int tag;
+ int tag;
if (newPacket)
{
tag = b & 0x3f;
@@ -241,7 +241,7 @@ namespace Org.BouncyCastle.Bcpg
break;
default:
type = "MESSAGE";
- break;
+ break;
}
DoWrite(headerStart + type + headerTail + nl);
@@ -277,23 +277,23 @@ namespace Org.BouncyCastle.Bcpg
}
/**
- * <b>Note</b>: close does nor close the underlying stream. So it is possible to write
+ * <b>Note</b>: Close() does not close the underlying stream. So it is possible to write
* multiple objects using armoring to a single stream.
*/
public override void Close()
{
if (type != null)
{
- if (bufPtr > 0)
- {
- Encode(outStream, buf, bufPtr);
- }
+ if (bufPtr > 0)
+ {
+ Encode(outStream, buf, bufPtr);
+ }
DoWrite(nl + '=');
int crcV = crc.Value;
- buf[0] = ((crcV >> 16) & 0xff);
+ buf[0] = ((crcV >> 16) & 0xff);
buf[1] = ((crcV >> 8) & 0xff);
buf[2] = (crcV & 0xff);
@@ -309,22 +309,22 @@ namespace Org.BouncyCastle.Bcpg
type = null;
start = true;
- base.Close();
- }
+ base.Close();
+ }
}
- private void WriteHeaderEntry(
- string name,
- string v)
+ private void WriteHeaderEntry(
+ string name,
+ string v)
{
DoWrite(name + ": " + v + nl);
}
- private void DoWrite(
- string s)
+ private void DoWrite(
+ string s)
{
byte[] bs = Strings.ToAsciiByteArray(s);
- outStream.Write(bs, 0, bs.Length);
+ outStream.Write(bs, 0, bs.Length);
}
}
}
diff --git a/crypto/src/openpgp/PgpKeyRingGenerator.cs b/crypto/src/openpgp/PgpKeyRingGenerator.cs
index e85fc2eef..92ea394a2 100644
--- a/crypto/src/openpgp/PgpKeyRingGenerator.cs
+++ b/crypto/src/openpgp/PgpKeyRingGenerator.cs
@@ -15,6 +15,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
private IList keys = Platform.CreateArrayList();
private string id;
private SymmetricKeyAlgorithmTag encAlgorithm;
+ private HashAlgorithmTag hashAlgorithm;
private int certificationLevel;
private char[] passPhrase;
private bool useSha1;
@@ -84,6 +85,45 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand));
}
+ /// <summary>
+ /// Create a new key ring generator.
+ /// </summary>
+ /// <param name="certificationLevel">The certification level for keys on this ring.</param>
+ /// <param name="masterKey">The master key pair.</param>
+ /// <param name="id">The id to be associated with the ring.</param>
+ /// <param name="encAlgorithm">The algorithm to be used to protect secret keys.</param>
+ /// <param name="hashAlgorithm">The hash algorithm.</param>
+ /// <param name="passPhrase">The passPhrase to be used to protect secret keys.</param>
+ /// <param name="useSha1">Checksum the secret keys with SHA1 rather than the older 16 bit checksum.</param>
+ /// <param name="hashedPackets">Packets to be included in the certification hash.</param>
+ /// <param name="unhashedPackets">Packets to be attached unhashed to the certification.</param>
+ /// <param name="rand">input secured random.</param>
+ public PgpKeyRingGenerator(
+ int certificationLevel,
+ PgpKeyPair masterKey,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ HashAlgorithmTag hashAlgorithm,
+ char[] passPhrase,
+ bool useSha1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ {
+ this.certificationLevel = certificationLevel;
+ this.masterKey = masterKey;
+ this.id = id;
+ this.encAlgorithm = encAlgorithm;
+ this.passPhrase = passPhrase;
+ this.useSha1 = useSha1;
+ this.hashedPacketVector = hashedPackets;
+ this.unhashedPacketVector = unhashedPackets;
+ this.rand = rand;
+ this.hashAlgorithm = hashAlgorithm;
+
+ keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand));
+ }
+
/// <summary>Add a subkey to the key ring to be generated with default certification.</summary>
public void AddSubKey(
PgpKeyPair keyPair)
@@ -91,6 +131,17 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector);
}
+
+ /// <summary>
+ /// Add a subkey to the key ring to be generated with default certification.
+ /// </summary>
+ /// <param name="keyPair">The key pair.</param>
+ /// <param name="hashAlgorithm">The hash algorithm.</param>
+ public void AddSubKey(PgpKeyPair keyPair, HashAlgorithmTag hashAlgorithm)
+ {
+ this.AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector, hashAlgorithm);
+ }
+
/// <summary>
/// Add a subkey with specific hashed and unhashed packets associated with it and
/// default certification.
@@ -133,6 +184,50 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
}
}
+ /// <summary>
+ /// Add a subkey with specific hashed and unhashed packets associated with it and
+ /// default certification.
+ /// </summary>
+ /// <param name="keyPair">Public/private key pair.</param>
+ /// <param name="hashedPackets">Hashed packet values to be included in certification.</param>
+ /// <param name="unhashedPackets">Unhashed packets values to be included in certification.</param>
+ /// <param name="hashAlgorithm">The hash algorithm.</param>
+ /// <exception cref="Org.BouncyCastle.Bcpg.OpenPgp.PgpException">exception adding subkey: </exception>
+ /// <exception cref="PgpException"></exception>
+ public void AddSubKey(
+ PgpKeyPair keyPair,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ HashAlgorithmTag hashAlgorithm)
+ {
+ try
+ {
+ var 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, passPhrase, useSha1, rand));
+ }
+ catch (PgpException)
+ {
+ throw;
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("exception adding subkey: ", e);
+ }
+ }
+
+
/// <summary>Return the secret key ring.</summary>
public PgpSecretKeyRing GenerateSecretKeyRing()
{
diff --git a/crypto/src/openpgp/PgpSecretKey.cs b/crypto/src/openpgp/PgpSecretKey.cs
index 980f9222b..1027393ce 100644
--- a/crypto/src/openpgp/PgpSecretKey.cs
+++ b/crypto/src/openpgp/PgpSecretKey.cs
@@ -166,6 +166,21 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
{
}
+ public PgpSecretKey(
+ int certificationLevel,
+ PgpKeyPair keyPair,
+ string id,
+ SymmetricKeyAlgorithmTag encAlgorithm,
+ HashAlgorithmTag hashAlgorithm,
+ char[] passPhrase,
+ bool useSha1,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ SecureRandom rand)
+ : this(keyPair.PrivateKey, CertifiedPublicKey(certificationLevel, keyPair, id, hashedPackets, unhashedPackets, hashAlgorithm), encAlgorithm, passPhrase, useSha1, rand, true)
+ {
+ }
+
private static PgpPublicKey CertifiedPublicKey(
int certificationLevel,
PgpKeyPair keyPair,
@@ -202,6 +217,44 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
}
}
+
+ private static PgpPublicKey CertifiedPublicKey(
+ int certificationLevel,
+ PgpKeyPair keyPair,
+ string id,
+ PgpSignatureSubpacketVector hashedPackets,
+ PgpSignatureSubpacketVector unhashedPackets,
+ HashAlgorithmTag hashAlgorithm)
+ {
+ PgpSignatureGenerator sGen;
+ try
+ {
+ sGen = new PgpSignatureGenerator(keyPair.PublicKey.Algorithm, hashAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Creating signature generator: " + e.Message, e);
+ }
+
+ //
+ // Generate the certification
+ //
+ sGen.InitSign(certificationLevel, keyPair.PrivateKey);
+
+ sGen.SetHashedSubpackets(hashedPackets);
+ sGen.SetUnhashedSubpackets(unhashedPackets);
+
+ try
+ {
+ PgpSignature certification = sGen.GenerateCertification(id, keyPair.PublicKey);
+ return PgpPublicKey.AddCertification(keyPair.PublicKey, id, certification);
+ }
+ catch (Exception e)
+ {
+ throw new PgpException("Exception doing certification: " + e.Message, e);
+ }
+ }
+
public PgpSecretKey(
int certificationLevel,
PublicKeyAlgorithmTag algorithm,
@@ -611,6 +664,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
SymmetricKeyAlgorithmTag newEncAlgorithm,
SecureRandom rand)
{
+
if (key.IsPrivateKeyEmpty)
throw new PgpException("no private key in this SecretKey - public key present only.");
|