188 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Collections;
 | 
						|
using System.IO;
 | 
						|
 | 
						|
using Org.BouncyCastle.Utilities.Collections;
 | 
						|
 | 
						|
namespace Org.BouncyCastle.Bcpg.OpenPgp
 | 
						|
{
 | 
						|
	/// <remarks>
 | 
						|
	/// Class to hold a single master public key and its subkeys.
 | 
						|
	/// <p>
 | 
						|
	/// Often PGP keyring files consist of multiple master keys, if you are trying to process
 | 
						|
	/// or construct one of these you should use the <c>PgpPublicKeyRingBundle</c> class.
 | 
						|
	/// </p>
 | 
						|
	/// </remarks>
 | 
						|
	public class PgpPublicKeyRing
 | 
						|
		: PgpKeyRing
 | 
						|
    {
 | 
						|
        private readonly ArrayList keys;
 | 
						|
 | 
						|
		public PgpPublicKeyRing(
 | 
						|
            byte[] encoding)
 | 
						|
            : this(new MemoryStream(encoding, false))
 | 
						|
        {
 | 
						|
        }
 | 
						|
 | 
						|
		internal PgpPublicKeyRing(
 | 
						|
            ArrayList pubKeys)
 | 
						|
        {
 | 
						|
            this.keys = pubKeys;
 | 
						|
        }
 | 
						|
 | 
						|
		public PgpPublicKeyRing(
 | 
						|
            Stream inputStream)
 | 
						|
        {
 | 
						|
			this.keys = new ArrayList();
 | 
						|
 | 
						|
            BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream);
 | 
						|
 | 
						|
			PacketTag initialTag = bcpgInput.NextPacketTag();
 | 
						|
            if (initialTag != PacketTag.PublicKey && initialTag != PacketTag.PublicSubkey)
 | 
						|
            {
 | 
						|
                throw new IOException("public key ring doesn't start with public key tag: "
 | 
						|
					+ "tag 0x" + ((int)initialTag).ToString("X"));
 | 
						|
            }
 | 
						|
 | 
						|
			PublicKeyPacket pubPk = (PublicKeyPacket) bcpgInput.ReadPacket();;
 | 
						|
			TrustPacket trustPk = ReadOptionalTrustPacket(bcpgInput);
 | 
						|
 | 
						|
            // direct signatures and revocations
 | 
						|
			ArrayList keySigs = ReadSignaturesAndTrust(bcpgInput);
 | 
						|
 | 
						|
			ArrayList ids, idTrusts, idSigs;
 | 
						|
			ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs);
 | 
						|
 | 
						|
			keys.Add(new PgpPublicKey(pubPk, trustPk, keySigs, ids, idTrusts, idSigs));
 | 
						|
 | 
						|
 | 
						|
			// Read subkeys
 | 
						|
			while (bcpgInput.NextPacketTag() == PacketTag.PublicSubkey)
 | 
						|
            {
 | 
						|
                PublicKeyPacket	pk = (PublicKeyPacket) bcpgInput.ReadPacket();
 | 
						|
				TrustPacket kTrust = ReadOptionalTrustPacket(bcpgInput);
 | 
						|
 | 
						|
				// PGP 8 actually leaves out the signature.
 | 
						|
				ArrayList sigList = ReadSignaturesAndTrust(bcpgInput);
 | 
						|
 | 
						|
				keys.Add(new PgpPublicKey(pk, kTrust, sigList));
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
		/// <summary>Return the first public key in the ring.</summary>
 | 
						|
        public PgpPublicKey GetPublicKey()
 | 
						|
        {
 | 
						|
            return (PgpPublicKey) keys[0];
 | 
						|
        }
 | 
						|
 | 
						|
		/// <summary>Return the public key referred to by the passed in key ID if it is present.</summary>
 | 
						|
        public PgpPublicKey GetPublicKey(
 | 
						|
            long keyId)
 | 
						|
        {
 | 
						|
			foreach (PgpPublicKey k in keys)
 | 
						|
			{
 | 
						|
				if (keyId == k.KeyId)
 | 
						|
                {
 | 
						|
                    return k;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
			return null;
 | 
						|
        }
 | 
						|
 | 
						|
		/// <summary>Allows enumeration of all the public keys.</summary>
 | 
						|
		/// <returns>An <c>IEnumerable</c> of <c>PgpPublicKey</c> objects.</returns>
 | 
						|
        public IEnumerable GetPublicKeys()
 | 
						|
        {
 | 
						|
            return new EnumerableProxy(keys);
 | 
						|
        }
 | 
						|
 | 
						|
		public byte[] GetEncoded()
 | 
						|
        {
 | 
						|
            MemoryStream bOut = new MemoryStream();
 | 
						|
 | 
						|
			Encode(bOut);
 | 
						|
 | 
						|
			return bOut.ToArray();
 | 
						|
        }
 | 
						|
 | 
						|
		public void Encode(
 | 
						|
            Stream outStr)
 | 
						|
        {
 | 
						|
			if (outStr == null)
 | 
						|
				throw new ArgumentNullException("outStr");
 | 
						|
 | 
						|
			foreach (PgpPublicKey k in keys)
 | 
						|
			{
 | 
						|
				k.Encode(outStr);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
		/// <summary>
 | 
						|
		/// Returns a new key ring with the public key passed in either added or
 | 
						|
		/// replacing an existing one.
 | 
						|
		/// </summary>
 | 
						|
		/// <param name="pubRing">The public key ring to be modified.</param>
 | 
						|
		/// <param name="pubKey">The public key to be inserted.</param>
 | 
						|
		/// <returns>A new <c>PgpPublicKeyRing</c></returns>
 | 
						|
        public static PgpPublicKeyRing InsertPublicKey(
 | 
						|
            PgpPublicKeyRing	pubRing,
 | 
						|
            PgpPublicKey		pubKey)
 | 
						|
        {
 | 
						|
            ArrayList keys = new ArrayList(pubRing.keys);
 | 
						|
            bool found = false;
 | 
						|
			bool masterFound = false;
 | 
						|
 | 
						|
			for (int i = 0; i != keys.Count; i++)
 | 
						|
            {
 | 
						|
                PgpPublicKey key = (PgpPublicKey) keys[i];
 | 
						|
 | 
						|
				if (key.KeyId == pubKey.KeyId)
 | 
						|
                {
 | 
						|
                    found = true;
 | 
						|
                    keys[i] = pubKey;
 | 
						|
                }
 | 
						|
				if (key.IsMasterKey)
 | 
						|
				{
 | 
						|
					masterFound = true;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (!found)
 | 
						|
            {
 | 
						|
				if (pubKey.IsMasterKey && masterFound)
 | 
						|
					throw new ArgumentException("cannot add a master key to a ring that already has one");
 | 
						|
 | 
						|
				keys.Add(pubKey);
 | 
						|
            }
 | 
						|
 | 
						|
			return new PgpPublicKeyRing(keys);
 | 
						|
        }
 | 
						|
 | 
						|
		/// <summary>Returns a new key ring with the public key passed in removed from the key ring.</summary>
 | 
						|
		/// <param name="pubRing">The public key ring to be modified.</param>
 | 
						|
		/// <param name="pubKey">The public key to be removed.</param>
 | 
						|
		/// <returns>A new <c>PgpPublicKeyRing</c>, or null if pubKey is not found.</returns>
 | 
						|
        public static PgpPublicKeyRing RemovePublicKey(
 | 
						|
            PgpPublicKeyRing	pubRing,
 | 
						|
            PgpPublicKey		pubKey)
 | 
						|
        {
 | 
						|
            ArrayList keys = new ArrayList(pubRing.keys);
 | 
						|
            bool found = false;
 | 
						|
 | 
						|
			for (int i = 0; i < keys.Count; i++)
 | 
						|
            {
 | 
						|
                PgpPublicKey key = (PgpPublicKey) keys[i];
 | 
						|
 | 
						|
				if (key.KeyId == pubKey.KeyId)
 | 
						|
                {
 | 
						|
                    found = true;
 | 
						|
                    keys.RemoveAt(i);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
			return found ? new PgpPublicKeyRing(keys) : null;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |