summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crypto/src/bcpg/ArmoredOutputStream.cs120
-rw-r--r--crypto/src/openpgp/PgpKeyRingGenerator.cs95
-rw-r--r--crypto/src/openpgp/PgpSecretKey.cs54
3 files changed, 209 insertions, 60 deletions
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.");