summary refs log tree commit diff
path: root/Crypto/src/openpgp/PgpSecretKeyRingBundle.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Crypto/src/openpgp/PgpSecretKeyRingBundle.cs')
-rw-r--r--Crypto/src/openpgp/PgpSecretKeyRingBundle.cs281
1 files changed, 281 insertions, 0 deletions
diff --git a/Crypto/src/openpgp/PgpSecretKeyRingBundle.cs b/Crypto/src/openpgp/PgpSecretKeyRingBundle.cs
new file mode 100644
index 000000000..18636dd65
--- /dev/null
+++ b/Crypto/src/openpgp/PgpSecretKeyRingBundle.cs
@@ -0,0 +1,281 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>
+	/// Often a PGP key ring file is made up of a succession of master/sub-key key rings.
+	/// If you want to read an entire secret key file in one hit this is the class for you.
+	/// </remarks>
+    public class PgpSecretKeyRingBundle
+    {
+        private readonly IDictionary secretRings;
+        private readonly IList order;
+
+		private PgpSecretKeyRingBundle(
+            IDictionary	secretRings,
+            IList       order)
+        {
+            this.secretRings = secretRings;
+            this.order = order;
+        }
+
+		public PgpSecretKeyRingBundle(
+            byte[] encoding)
+            : this(new MemoryStream(encoding, false))
+		{
+        }
+
+		/// <summary>Build a PgpSecretKeyRingBundle from the passed in input stream.</summary>
+		/// <param name="inputStream">Input stream containing data.</param>
+		/// <exception cref="IOException">If a problem parsing the stream occurs.</exception>
+		/// <exception cref="PgpException">If an object is encountered which isn't a PgpSecretKeyRing.</exception>
+		public PgpSecretKeyRingBundle(
+            Stream inputStream)
+			: this(new PgpObjectFactory(inputStream).AllPgpObjects())
+        {
+        }
+
+		public PgpSecretKeyRingBundle(
+            IEnumerable e)
+        {
+			this.secretRings = Platform.CreateHashtable();
+            this.order = Platform.CreateArrayList();
+
+			foreach (object obj in e)
+			{
+				PgpSecretKeyRing pgpSecret = obj as PgpSecretKeyRing;
+
+				if (pgpSecret == null)
+				{
+					throw new PgpException(obj.GetType().FullName + " found where PgpSecretKeyRing expected");
+				}
+
+				long key = pgpSecret.GetPublicKey().KeyId;
+				secretRings.Add(key, pgpSecret);
+				order.Add(key);
+			}
+        }
+
+		[Obsolete("Use 'Count' property instead")]
+		public int Size
+		{
+			get { return order.Count; }
+		}
+
+		/// <summary>Return the number of rings in this collection.</summary>
+		public int Count
+        {
+			get { return order.Count; }
+        }
+
+		/// <summary>Allow enumeration of the secret key rings making up this collection.</summary>
+		public IEnumerable GetKeyRings()
+        {
+            return new EnumerableProxy(secretRings.Values);
+        }
+
+		/// <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+		/// <param name="userId">The user ID to be matched.</param>
+		/// <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+		public IEnumerable GetKeyRings(
+			string userId)
+		{
+			return GetKeyRings(userId, false, false);
+		}
+
+		/// <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+		/// <param name="userId">The user ID to be matched.</param>
+		/// <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
+		/// <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+		public IEnumerable GetKeyRings(
+            string	userId,
+            bool	matchPartial)
+        {
+			return GetKeyRings(userId, matchPartial, false);
+        }
+
+		/// <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+		/// <param name="userId">The user ID to be matched.</param>
+		/// <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
+		/// <param name="ignoreCase">If true, case is ignored in user ID comparisons.</param>
+		/// <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+		public IEnumerable GetKeyRings(
+			string	userId,
+			bool	matchPartial,
+			bool	ignoreCase)
+		{
+            IList rings = Platform.CreateArrayList();
+
+			if (ignoreCase)
+			{
+				userId = userId.ToLowerInvariant();
+			}
+
+			foreach (PgpSecretKeyRing secRing in GetKeyRings())
+			{
+				foreach (string nextUserID in secRing.GetSecretKey().UserIds)
+				{
+					string next = nextUserID;
+					if (ignoreCase)
+					{
+						next = next.ToLowerInvariant();
+					}
+
+					if (matchPartial)
+					{
+						if (next.IndexOf(userId) > -1)
+						{
+							rings.Add(secRing);
+						}
+					}
+					else
+					{
+						if (next.Equals(userId))
+						{
+							rings.Add(secRing);
+						}
+					}
+				}
+			}
+
+			return new EnumerableProxy(rings);
+		}
+
+		/// <summary>Return the PGP secret key associated with the given key id.</summary>
+		/// <param name="keyId">The ID of the secret key to return.</param>
+		public PgpSecretKey GetSecretKey(
+            long keyId)
+        {
+            foreach (PgpSecretKeyRing secRing in GetKeyRings())
+            {
+                PgpSecretKey sec = secRing.GetSecretKey(keyId);
+
+				if (sec != null)
+                {
+                    return sec;
+                }
+            }
+
+            return null;
+        }
+
+		/// <summary>Return the secret key ring which contains the key referred to by keyId</summary>
+		/// <param name="keyId">The ID of the secret key</param>
+		public PgpSecretKeyRing GetSecretKeyRing(
+            long keyId)
+        {
+            long id = keyId;
+
+            if (secretRings.Contains(id))
+            {
+                return (PgpSecretKeyRing) secretRings[id];
+            }
+
+			foreach (PgpSecretKeyRing secretRing in GetKeyRings())
+            {
+                PgpSecretKey secret = secretRing.GetSecretKey(keyId);
+
+                if (secret != null)
+                {
+                    return secretRing;
+                }
+            }
+
+            return null;
+        }
+
+		/// <summary>
+		/// Return true if a key matching the passed in key ID is present, false otherwise.
+		/// </summary>
+		/// <param name="keyID">key ID to look for.</param>
+		public bool Contains(
+			long keyID)
+		{
+			return GetSecretKey(keyID) != null;
+		}
+
+		public byte[] GetEncoded()
+        {
+            MemoryStream bOut = new MemoryStream();
+
+			Encode(bOut);
+
+			return bOut.ToArray();
+        }
+
+		public void Encode(
+			Stream outStr)
+        {
+			BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
+
+			foreach (long key in order)
+            {
+                PgpSecretKeyRing pub = (PgpSecretKeyRing) secretRings[key];
+
+				pub.Encode(bcpgOut);
+            }
+        }
+
+		/// <summary>
+		/// Return a new bundle containing the contents of the passed in bundle and
+		/// the passed in secret key ring.
+		/// </summary>
+		/// <param name="bundle">The <c>PgpSecretKeyRingBundle</c> the key ring is to be added to.</param>
+		/// <param name="secretKeyRing">The key ring to be added.</param>
+		/// <returns>A new <c>PgpSecretKeyRingBundle</c> merging the current one with the passed in key ring.</returns>
+		/// <exception cref="ArgumentException">If the keyId for the passed in key ring is already present.</exception>
+        public static PgpSecretKeyRingBundle AddSecretKeyRing(
+            PgpSecretKeyRingBundle  bundle,
+            PgpSecretKeyRing        secretKeyRing)
+        {
+            long key = secretKeyRing.GetPublicKey().KeyId;
+
+            if (bundle.secretRings.Contains(key))
+            {
+                throw new ArgumentException("Collection already contains a key with a keyId for the passed in ring.");
+            }
+
+            IDictionary newSecretRings = Platform.CreateHashtable(bundle.secretRings);
+            IList newOrder = Platform.CreateArrayList(bundle.order);
+
+            newSecretRings[key] = secretKeyRing;
+            newOrder.Add(key);
+
+            return new PgpSecretKeyRingBundle(newSecretRings, newOrder);
+        }
+
+		/// <summary>
+		/// Return a new bundle containing the contents of the passed in bundle with
+		/// the passed in secret key ring removed.
+		/// </summary>
+		/// <param name="bundle">The <c>PgpSecretKeyRingBundle</c> the key ring is to be removed from.</param>
+		/// <param name="secretKeyRing">The key ring to be removed.</param>
+		/// <returns>A new <c>PgpSecretKeyRingBundle</c> not containing the passed in key ring.</returns>
+		/// <exception cref="ArgumentException">If the keyId for the passed in key ring is not present.</exception>
+        public static PgpSecretKeyRingBundle RemoveSecretKeyRing(
+            PgpSecretKeyRingBundle  bundle,
+            PgpSecretKeyRing        secretKeyRing)
+        {
+            long key = secretKeyRing.GetPublicKey().KeyId;
+
+			if (!bundle.secretRings.Contains(key))
+            {
+                throw new ArgumentException("Collection does not contain a key with a keyId for the passed in ring.");
+            }
+
+            IDictionary newSecretRings = Platform.CreateHashtable(bundle.secretRings);
+            IList newOrder = Platform.CreateArrayList(bundle.order);
+
+			newSecretRings.Remove(key);
+			newOrder.Remove(key);
+
+			return new PgpSecretKeyRingBundle(newSecretRings, newOrder);
+        }
+    }
+}