summary refs log tree commit diff
path: root/crypto/src/bcpg
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2015-10-12 15:49:54 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2015-10-12 15:49:54 +0700
commit06ba713c9b19102310675a6c58e07c68d8efb3c7 (patch)
tree2d4e747d988f74abca2a5513713e4ff0e8ed8e69 /crypto/src/bcpg
parentAdd new file entries (diff)
downloadBouncyCastle.NET-ed25519-06ba713c9b19102310675a6c58e07c68d8efb3c7.tar.xz
Port of latest PGP tests and supporting code changes
Diffstat (limited to 'crypto/src/bcpg')
-rw-r--r--crypto/src/bcpg/ECDHPublicBCPGKey.cs24
-rw-r--r--crypto/src/bcpg/PublicKeyAlgorithmTags.cs3
-rw-r--r--crypto/src/bcpg/PublicKeyEncSessionPacket.cs54
-rw-r--r--crypto/src/bcpg/PublicKeyPacket.cs2
-rw-r--r--crypto/src/bcpg/S2k.cs10
-rw-r--r--crypto/src/bcpg/SignatureSubpacket.cs50
-rw-r--r--crypto/src/bcpg/SignatureSubpacketsReader.cs84
-rw-r--r--crypto/src/bcpg/sig/EmbeddedSignature.cs3
-rw-r--r--crypto/src/bcpg/sig/Exportable.cs9
-rw-r--r--crypto/src/bcpg/sig/Features.cs75
-rw-r--r--crypto/src/bcpg/sig/IssuerKeyId.cs9
-rw-r--r--crypto/src/bcpg/sig/KeyExpirationTime.cs11
-rw-r--r--crypto/src/bcpg/sig/KeyFlags.cs11
-rw-r--r--crypto/src/bcpg/sig/NotationData.cs11
-rw-r--r--crypto/src/bcpg/sig/PreferredAlgorithms.cs21
-rw-r--r--crypto/src/bcpg/sig/PrimaryUserId.cs9
-rw-r--r--crypto/src/bcpg/sig/Revocable.cs13
-rw-r--r--crypto/src/bcpg/sig/RevocationKey.cs9
-rw-r--r--crypto/src/bcpg/sig/RevocationReason.cs14
-rw-r--r--crypto/src/bcpg/sig/SignatureCreationTime.cs16
-rw-r--r--crypto/src/bcpg/sig/SignatureExpirationTime.cs19
-rw-r--r--crypto/src/bcpg/sig/SignerUserId.cs17
-rw-r--r--crypto/src/bcpg/sig/TrustSignature.cs15
23 files changed, 320 insertions, 169 deletions
diff --git a/crypto/src/bcpg/ECDHPublicBCPGKey.cs b/crypto/src/bcpg/ECDHPublicBCPGKey.cs
index b85379586..dc225e31e 100644
--- a/crypto/src/bcpg/ECDHPublicBCPGKey.cs
+++ b/crypto/src/bcpg/ECDHPublicBCPGKey.cs
@@ -10,8 +10,8 @@ namespace Org.BouncyCastle.Bcpg
         : ECPublicBcpgKey
     {
         private byte reserved;
-        private byte hashFunctionId;
-        private byte symAlgorithmId;
+        private HashAlgorithmTag hashFunctionId;
+        private SymmetricKeyAlgorithmTag symAlgorithmId;
 
         /// <param name="bcpgIn">The stream to read the packet from.</param>
         public ECDHPublicBcpgKey(
@@ -26,8 +26,8 @@ namespace Org.BouncyCastle.Bcpg
             bcpgIn.ReadFully(kdfParameters);
 
             reserved = kdfParameters[0];
-            hashFunctionId = kdfParameters[1];
-            symAlgorithmId = kdfParameters[2];
+            hashFunctionId = (HashAlgorithmTag)kdfParameters[1];
+            symAlgorithmId = (SymmetricKeyAlgorithmTag)kdfParameters[2];
 
             VerifyHashAlgorithm();
             VerifySymmetricKeyAlgorithm();
@@ -36,13 +36,13 @@ namespace Org.BouncyCastle.Bcpg
         public ECDHPublicBcpgKey(
             DerObjectIdentifier oid,
             ECPoint point,
-            int hashAlgorithm,
-            int symmetricKeyAlgorithm)
+            HashAlgorithmTag hashAlgorithm,
+            SymmetricKeyAlgorithmTag symmetricKeyAlgorithm)
             : base(oid, point)
         {
             reserved = 1;
-            hashFunctionId = (byte)hashAlgorithm;
-            symAlgorithmId = (byte)symmetricKeyAlgorithm;
+            hashFunctionId = hashAlgorithm;
+            symAlgorithmId = symmetricKeyAlgorithm;
 
             VerifyHashAlgorithm();
             VerifySymmetricKeyAlgorithm();
@@ -53,12 +53,12 @@ namespace Org.BouncyCastle.Bcpg
             get { return reserved; }
         }
 
-        public virtual byte HashAlgorithm
+        public virtual HashAlgorithmTag HashAlgorithm
         {
             get { return hashFunctionId; }
         }
 
-        public virtual byte SymmetricKeyAlgorithm
+        public virtual SymmetricKeyAlgorithmTag SymmetricKeyAlgorithm
         {
             get { return symAlgorithmId; }
         }
@@ -69,8 +69,8 @@ namespace Org.BouncyCastle.Bcpg
             base.Encode(bcpgOut);
             bcpgOut.WriteByte(0x3);
             bcpgOut.WriteByte(reserved);
-            bcpgOut.WriteByte(hashFunctionId);
-            bcpgOut.WriteByte(symAlgorithmId);
+            bcpgOut.WriteByte((byte)hashFunctionId);
+            bcpgOut.WriteByte((byte)symAlgorithmId);
         }
 
         private void VerifyHashAlgorithm()
diff --git a/crypto/src/bcpg/PublicKeyAlgorithmTags.cs b/crypto/src/bcpg/PublicKeyAlgorithmTags.cs
index 4a6704c14..9e30b54f7 100644
--- a/crypto/src/bcpg/PublicKeyAlgorithmTags.cs
+++ b/crypto/src/bcpg/PublicKeyAlgorithmTags.cs
@@ -1,3 +1,5 @@
+using System;
+
 namespace Org.BouncyCastle.Bcpg
 {
     /// <remarks>Public Key Algorithm tag numbers.</remarks>
@@ -8,6 +10,7 @@ namespace Org.BouncyCastle.Bcpg
         RsaSign = 3,			// RSA Sign-Only
         ElGamalEncrypt = 16,	// Elgamal (Encrypt-Only), see [ELGAMAL]
         Dsa = 17,				// DSA (Digital Signature Standard)
+        [Obsolete("Use 'ECDH' instead")]
         EC = 18,				// Reserved for Elliptic Curve
         ECDH = 18,              // Reserved for Elliptic Curve (actual algorithm name)
         ECDsa = 19,				// Reserved for ECDSA
diff --git a/crypto/src/bcpg/PublicKeyEncSessionPacket.cs b/crypto/src/bcpg/PublicKeyEncSessionPacket.cs
index d10605f1d..74d04f7aa 100644
--- a/crypto/src/bcpg/PublicKeyEncSessionPacket.cs
+++ b/crypto/src/bcpg/PublicKeyEncSessionPacket.cs
@@ -2,6 +2,8 @@ using System;
 using System.IO;
 
 using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Bcpg
 {
@@ -12,7 +14,7 @@ namespace Org.BouncyCastle.Bcpg
 		private int version;
 		private long keyId;
 		private PublicKeyAlgorithmTag algorithm;
-		private BigInteger[] data;
+        private byte[][] data;
 
 		internal PublicKeyEncSessionPacket(
 			BcpgInputStream bcpgIn)
@@ -34,33 +36,41 @@ namespace Org.BouncyCastle.Bcpg
 			{
 				case PublicKeyAlgorithmTag.RsaEncrypt:
 				case PublicKeyAlgorithmTag.RsaGeneral:
-					data = new BigInteger[]{ new MPInteger(bcpgIn).Value };
+					data = new byte[][]{ new MPInteger(bcpgIn).GetEncoded() };
 					break;
 				case PublicKeyAlgorithmTag.ElGamalEncrypt:
 				case PublicKeyAlgorithmTag.ElGamalGeneral:
-					data = new BigInteger[]
-					{
-						new MPInteger(bcpgIn).Value,
-						new MPInteger(bcpgIn).Value
-					};
+                    MPInteger p = new MPInteger(bcpgIn);
+                    MPInteger g = new MPInteger(bcpgIn);
+					data = new byte[][]{
+                        p.GetEncoded(),
+                        g.GetEncoded(),
+                    };
 					break;
+                case PublicKeyAlgorithmTag.ECDH:
+                    data = new byte[][]{ Streams.ReadAll(bcpgIn) };
+                    break;
 				default:
 					throw new IOException("unknown PGP public key algorithm encountered");
 			}
 		}
 
-		public PublicKeyEncSessionPacket(
-			long					keyId,
-			PublicKeyAlgorithmTag	algorithm,
-			BigInteger[]			data)
+        public PublicKeyEncSessionPacket(
+			long                    keyId,
+			PublicKeyAlgorithmTag   algorithm,
+			byte[][]                data)
 		{
 			this.version = 3;
 			this.keyId = keyId;
 			this.algorithm = algorithm;
-			this.data = (BigInteger[]) data.Clone();
+            this.data = new byte[data.Length][];
+            for (int i = 0; i < data.Length; ++i)
+            {
+                this.data[i] = Arrays.Clone(data[i]);
+            }
 		}
 
-		public int Version
+        public int Version
 		{
 			get { return version; }
 		}
@@ -75,12 +85,12 @@ namespace Org.BouncyCastle.Bcpg
 			get { return algorithm; }
 		}
 
-		public BigInteger[] GetEncSessionKey()
+        public byte[][] GetEncSessionKey()
 		{
-			return (BigInteger[]) data.Clone();
+			return data;
 		}
 
-		public override void Encode(
+        public override void Encode(
 			BcpgOutputStream bcpgOut)
 		{
 			MemoryStream bOut = new MemoryStream();
@@ -92,12 +102,14 @@ namespace Org.BouncyCastle.Bcpg
 
 			pOut.WriteByte((byte)algorithm);
 
-			for (int i = 0; i != data.Length; i++)
-			{
-				MPInteger.Encode(pOut, data[i]);
-			}
+            for (int i = 0; i < data.Length; ++i)
+            {
+                pOut.Write(data[i]);
+            }
+
+            pOut.Close();
 
-			bcpgOut.WritePacket(PacketTag.PublicKeyEncryptedSession , bOut.ToArray(), true);
+            bcpgOut.WritePacket(PacketTag.PublicKeyEncryptedSession , bOut.ToArray(), true);
 		}
 	}
 }
diff --git a/crypto/src/bcpg/PublicKeyPacket.cs b/crypto/src/bcpg/PublicKeyPacket.cs
index cea5c8ed2..bbed941dc 100644
--- a/crypto/src/bcpg/PublicKeyPacket.cs
+++ b/crypto/src/bcpg/PublicKeyPacket.cs
@@ -44,7 +44,7 @@ namespace Org.BouncyCastle.Bcpg
                 case PublicKeyAlgorithmTag.ElGamalGeneral:
                     key = new ElGamalPublicBcpgKey(bcpgIn);
                     break;
-                case PublicKeyAlgorithmTag.EC:
+                case PublicKeyAlgorithmTag.ECDH:
                     key = new ECDHPublicBcpgKey(bcpgIn);
                     break;
                 case PublicKeyAlgorithmTag.ECDsa:
diff --git a/crypto/src/bcpg/S2k.cs b/crypto/src/bcpg/S2k.cs
index f6d306890..33fd792fe 100644
--- a/crypto/src/bcpg/S2k.cs
+++ b/crypto/src/bcpg/S2k.cs
@@ -84,19 +84,19 @@ namespace Org.BouncyCastle.Bcpg
             this.itCount = itCount;
         }
 
-        public int Type
+        public virtual int Type
         {
 			get { return type; }
         }
 
 		/// <summary>The hash algorithm.</summary>
-        public HashAlgorithmTag HashAlgorithm
+        public virtual HashAlgorithmTag HashAlgorithm
         {
 			get { return algorithm; }
 		}
 
 		/// <summary>The IV for the key generation algorithm.</summary>
-        public byte[] GetIV()
+        public virtual byte[] GetIV()
         {
             return Arrays.Clone(iv);
         }
@@ -108,13 +108,13 @@ namespace Org.BouncyCastle.Bcpg
         }
 
 		/// <summary>The iteration count</summary>
-		public long IterationCount
+        public virtual long IterationCount
 		{
 			get { return (16 + (itCount & 15)) << ((itCount >> 4) + ExpBias); }
 		}
 
 		/// <summary>The protection mode - only if GnuDummyS2K</summary>
-        public int ProtectionMode
+        public virtual int ProtectionMode
         {
 			get { return protectionMode; }
         }
diff --git a/crypto/src/bcpg/SignatureSubpacket.cs b/crypto/src/bcpg/SignatureSubpacket.cs
index ac26f8a3c..d99315599 100644
--- a/crypto/src/bcpg/SignatureSubpacket.cs
+++ b/crypto/src/bcpg/SignatureSubpacket.cs
@@ -7,20 +7,22 @@ namespace Org.BouncyCastle.Bcpg
     {
         private readonly SignatureSubpacketTag type;
         private readonly bool critical;
-
-		internal readonly byte[] data;
+        private readonly bool isLongLength;
+		internal byte[] data;
 
 		protected internal SignatureSubpacket(
             SignatureSubpacketTag	type,
             bool					critical,
+            bool                    isLongLength,
             byte[]					data)
         {
             this.type = type;
             this.critical = critical;
+            this.isLongLength = isLongLength;
             this.data = data;
         }
 
-		public SignatureSubpacketTag SubpacketType
+        public SignatureSubpacketTag SubpacketType
         {
 			get { return type; }
         }
@@ -30,7 +32,12 @@ namespace Org.BouncyCastle.Bcpg
             return critical;
         }
 
-		/// <summary>Return the generic data making up the packet.</summary>
+        public bool IsLongLength()
+        {
+            return isLongLength;
+        }
+
+        /// <summary>Return the generic data making up the packet.</summary>
         public byte[] GetData()
         {
             return (byte[]) data.Clone();
@@ -41,18 +48,7 @@ namespace Org.BouncyCastle.Bcpg
         {
             int bodyLen = data.Length + 1;
 
-            if (bodyLen < 192)
-            {
-                os.WriteByte((byte)bodyLen);
-            }
-            else if (bodyLen <= 8383)
-            {
-                bodyLen -= 192;
-
-                os.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192));
-                os.WriteByte((byte)bodyLen);
-            }
-            else
+            if (isLongLength)
             {
                 os.WriteByte(0xff);
                 os.WriteByte((byte)(bodyLen >> 24));
@@ -60,6 +56,28 @@ namespace Org.BouncyCastle.Bcpg
                 os.WriteByte((byte)(bodyLen >> 8));
                 os.WriteByte((byte)bodyLen);
             }
+            else
+            {
+                if (bodyLen < 192)
+                {
+                    os.WriteByte((byte)bodyLen);
+                }
+                else if (bodyLen <= 8383)
+                {
+                    bodyLen -= 192;
+
+                    os.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192));
+                    os.WriteByte((byte)bodyLen);
+                }
+                else
+                {
+                    os.WriteByte(0xff);
+                    os.WriteByte((byte)(bodyLen >> 24));
+                    os.WriteByte((byte)(bodyLen >> 16));
+                    os.WriteByte((byte)(bodyLen >> 8));
+                    os.WriteByte((byte)bodyLen);
+                }
+            }
 
             if (critical)
             {
diff --git a/crypto/src/bcpg/SignatureSubpacketsReader.cs b/crypto/src/bcpg/SignatureSubpacketsReader.cs
index 8dd1af332..80bedb07c 100644
--- a/crypto/src/bcpg/SignatureSubpacketsReader.cs
+++ b/crypto/src/bcpg/SignatureSubpacketsReader.cs
@@ -1,6 +1,8 @@
 using System;
 using System.IO;
+
 using Org.BouncyCastle.Bcpg.Sig;
+using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Bcpg
@@ -25,7 +27,9 @@ namespace Org.BouncyCastle.Bcpg
 				return null;
 
 			int bodyLen = 0;
-			if (l < 192)
+            bool isLongLength = false;
+
+            if (l < 192)
 			{
 				bodyLen = l;
 			}
@@ -35,54 +39,90 @@ namespace Org.BouncyCastle.Bcpg
 			}
 			else if (l == 255)
 			{
+                isLongLength = true;
 				bodyLen = (input.ReadByte() << 24) | (input.ReadByte() << 16)
 					|  (input.ReadByte() << 8)  | input.ReadByte();
 			}
 			else
 			{
-				// TODO Error?
+                throw new IOException("unexpected length header");
 			}
 
-			int tag = input.ReadByte();
+            int tag = input.ReadByte();
 			if (tag < 0)
 				throw new EndOfStreamException("unexpected EOF reading signature sub packet");
 
-			byte[] data = new byte[bodyLen - 1];
-			if (Streams.ReadFully(input, data) < data.Length)
-				throw new EndOfStreamException();
+            byte[] data = new byte[bodyLen - 1];
+
+            //
+            // this may seem a bit strange but it turns out some applications miscode the length
+            // in fixed length fields, so we check the length we do get, only throwing an exception if
+            // we really cannot continue
+            //
+            int bytesRead = Streams.ReadFully(input, data);
+
+            bool isCritical = ((tag & 0x80) != 0);
+            SignatureSubpacketTag type = (SignatureSubpacketTag)(tag & 0x7f);
 
-			bool isCritical = ((tag & 0x80) != 0);
-			SignatureSubpacketTag type = (SignatureSubpacketTag)(tag & 0x7f);
-			switch (type)
+            if (bytesRead != data.Length)
+            {
+                switch (type)
+                {
+                case SignatureSubpacketTag.CreationTime:
+                    data = CheckData(data, 4, bytesRead, "Signature Creation Time");
+                    break;
+                case SignatureSubpacketTag.IssuerKeyId:
+                    data = CheckData(data, 8, bytesRead, "Issuer");
+                    break;
+                case SignatureSubpacketTag.KeyExpireTime:
+                    data = CheckData(data, 4, bytesRead, "Signature Key Expiration Time");
+                    break;
+                case SignatureSubpacketTag.ExpireTime:
+                    data = CheckData(data, 4, bytesRead, "Signature Expiration Time");
+                    break;
+                default:
+                    throw new EndOfStreamException("truncated subpacket data.");
+                }
+            }
+
+            switch (type)
 			{
 				case SignatureSubpacketTag.CreationTime:
-					return new SignatureCreationTime(isCritical, data);
+					return new SignatureCreationTime(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.KeyExpireTime:
-					return new KeyExpirationTime(isCritical, data);
+                    return new KeyExpirationTime(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.ExpireTime:
-					return new SignatureExpirationTime(isCritical, data);
+                    return new SignatureExpirationTime(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.Revocable:
-					return new Revocable(isCritical, data);
+                    return new Revocable(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.Exportable:
-					return new Exportable(isCritical, data);
+                    return new Exportable(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.IssuerKeyId:
-					return new IssuerKeyId(isCritical, data);
+                    return new IssuerKeyId(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.TrustSig:
-					return new TrustSignature(isCritical, data);
+                    return new TrustSignature(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.PreferredCompressionAlgorithms:
 				case SignatureSubpacketTag.PreferredHashAlgorithms:
 				case SignatureSubpacketTag.PreferredSymmetricAlgorithms:
-					return new PreferredAlgorithms(type, isCritical, data);
+                    return new PreferredAlgorithms(type, isCritical, isLongLength, data);
 				case SignatureSubpacketTag.KeyFlags:
-					return new KeyFlags(isCritical, data);
+                    return new KeyFlags(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.PrimaryUserId:
-					return new PrimaryUserId(isCritical, data);
+                    return new PrimaryUserId(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.SignerUserId:
-					return new SignerUserId(isCritical, data);
+                    return new SignerUserId(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.NotationData:
-					return new NotationData(isCritical, data);
+                    return new NotationData(isCritical, isLongLength, data);
 			}
-			return new SignatureSubpacket(type, isCritical, data);
+            return new SignatureSubpacket(type, isCritical, isLongLength, data);
 		}
+
+        private byte[] CheckData(byte[] data, int expected, int bytesRead, string name)
+        {
+            if (bytesRead != expected)
+                throw new EndOfStreamException("truncated " + name + " subpacket data.");
+
+            return Arrays.CopyOfRange(data, 0, expected);
+        }
 	}
 }
diff --git a/crypto/src/bcpg/sig/EmbeddedSignature.cs b/crypto/src/bcpg/sig/EmbeddedSignature.cs
index e47604ac8..fffdaef73 100644
--- a/crypto/src/bcpg/sig/EmbeddedSignature.cs
+++ b/crypto/src/bcpg/sig/EmbeddedSignature.cs
@@ -10,8 +10,9 @@ namespace Org.BouncyCastle.Bcpg.Sig
 	{
 		public EmbeddedSignature(
 			bool	critical,
+            bool    isLongLength,
 			byte[]	data)
-			: base(SignatureSubpacketTag.EmbeddedSignature, critical, data)
+			: base(SignatureSubpacketTag.EmbeddedSignature, critical, isLongLength, data)
 		{
 		}
 	}
diff --git a/crypto/src/bcpg/sig/Exportable.cs b/crypto/src/bcpg/sig/Exportable.cs
index 4455c3814..4d030346f 100644
--- a/crypto/src/bcpg/sig/Exportable.cs
+++ b/crypto/src/bcpg/sig/Exportable.cs
@@ -1,7 +1,5 @@
 using System;
 
-
-
 namespace Org.BouncyCastle.Bcpg.Sig
 {
     /**
@@ -27,15 +25,16 @@ namespace Org.BouncyCastle.Bcpg.Sig
 
         public Exportable(
             bool    critical,
-            byte[]     data)
-            : base(SignatureSubpacketTag.Exportable, critical, data)
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.Exportable, critical, isLongLength, data)
         {
         }
 
         public Exportable(
             bool    critical,
             bool    isExportable)
-            : base(SignatureSubpacketTag.Exportable, critical, BooleanToByteArray(isExportable))
+            : base(SignatureSubpacketTag.Exportable, critical, false, BooleanToByteArray(isExportable))
         {
         }
 
diff --git a/crypto/src/bcpg/sig/Features.cs b/crypto/src/bcpg/sig/Features.cs
new file mode 100644
index 000000000..29584239a
--- /dev/null
+++ b/crypto/src/bcpg/sig/Features.cs
@@ -0,0 +1,75 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+    /**
+    * packet giving signature expiration time.
+    */
+    public class Features
+        : SignatureSubpacket
+    {
+        /** Identifier for the modification detection feature */
+        public static readonly byte FEATURE_MODIFICATION_DETECTION = 1;
+
+        private static byte[] FeatureToByteArray(byte feature)
+        {
+            return new byte[]{ feature };
+        }
+
+        public Features(
+            bool    critical,
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.Features, critical, isLongLength, data)
+        {
+        }
+
+        public Features(bool critical, byte feature)
+            : base(SignatureSubpacketTag.Features, critical, false, FeatureToByteArray(feature))
+        {
+        }
+
+        /**
+         * Returns if modification detection is supported.
+         */
+        public bool SupportsModificationDetection
+        {
+            get { return SupportsFeature(FEATURE_MODIFICATION_DETECTION); }
+        }
+
+        /**
+         * Returns if a particular feature is supported.
+         */
+        public bool SupportsFeature(byte feature)
+        {
+            return Array.IndexOf(data, feature) >= 0;
+        }
+
+        /**
+         * Sets support for a particular feature.
+         */
+        private void SetSupportsFeature(byte feature, bool support)
+        {
+            if (feature == 0)
+                throw new ArgumentException("cannot be 0", "feature");
+
+            int i = Array.IndexOf(data, feature);
+            if ((i >= 0) == support)
+                return;
+
+            if (support)
+            {
+                data = Arrays.Append(data, feature);
+            }
+            else
+            {
+                byte[] temp = new byte[data.Length - 1];
+                Array.Copy(data, 0, temp, 0, i);
+                Array.Copy(data, i + 1, temp, i, temp.Length - i);
+                data = temp;
+            }
+        }
+    }
+}
diff --git a/crypto/src/bcpg/sig/IssuerKeyId.cs b/crypto/src/bcpg/sig/IssuerKeyId.cs
index 91490d33b..627ea3ecf 100644
--- a/crypto/src/bcpg/sig/IssuerKeyId.cs
+++ b/crypto/src/bcpg/sig/IssuerKeyId.cs
@@ -29,15 +29,16 @@ namespace Org.BouncyCastle.Bcpg.Sig
 
         public IssuerKeyId(
             bool    critical,
-            byte[]     data)
-            : base(SignatureSubpacketTag.IssuerKeyId, critical, data)
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.IssuerKeyId, critical, isLongLength, data)
         {
         }
 
         public IssuerKeyId(
             bool    critical,
-            long       keyId)
-            : base(SignatureSubpacketTag.IssuerKeyId, critical, KeyIdToBytes(keyId))
+            long    keyId)
+            : base(SignatureSubpacketTag.IssuerKeyId, critical, false, KeyIdToBytes(keyId))
         {
         }
 
diff --git a/crypto/src/bcpg/sig/KeyExpirationTime.cs b/crypto/src/bcpg/sig/KeyExpirationTime.cs
index 23b4cac29..dfd3e76fd 100644
--- a/crypto/src/bcpg/sig/KeyExpirationTime.cs
+++ b/crypto/src/bcpg/sig/KeyExpirationTime.cs
@@ -1,7 +1,5 @@
 using System;
 
-
-
 namespace Org.BouncyCastle.Bcpg.Sig
 {
     /**
@@ -25,15 +23,16 @@ namespace Org.BouncyCastle.Bcpg.Sig
 
         public KeyExpirationTime(
             bool    critical,
-            byte[]     data)
-            : base(SignatureSubpacketTag.KeyExpireTime, critical, data)
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.KeyExpireTime, critical, isLongLength, data)
         {
         }
 
         public KeyExpirationTime(
             bool    critical,
-            long       seconds)
-            : base(SignatureSubpacketTag.KeyExpireTime, critical, TimeToBytes(seconds))
+            long    seconds)
+            : base(SignatureSubpacketTag.KeyExpireTime, critical, false, TimeToBytes(seconds))
         {
         }
 
diff --git a/crypto/src/bcpg/sig/KeyFlags.cs b/crypto/src/bcpg/sig/KeyFlags.cs
index 0592301b3..5b5d85a72 100644
--- a/crypto/src/bcpg/sig/KeyFlags.cs
+++ b/crypto/src/bcpg/sig/KeyFlags.cs
@@ -40,15 +40,16 @@ namespace Org.BouncyCastle.Bcpg.Sig
 
 		public KeyFlags(
             bool	critical,
-            byte[]	data)
-            : base(SignatureSubpacketTag.KeyFlags, critical, data)
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.KeyFlags, critical, isLongLength, data)
         {
         }
 
 		public KeyFlags(
-			bool	critical,
-			int		flags)
-            : base(SignatureSubpacketTag.KeyFlags, critical, IntToByteArray(flags))
+			bool    critical,
+			int     flags)
+            : base(SignatureSubpacketTag.KeyFlags, critical, false, IntToByteArray(flags))
         {
         }
 
diff --git a/crypto/src/bcpg/sig/NotationData.cs b/crypto/src/bcpg/sig/NotationData.cs
index ccc9aa745..9ac6f89cf 100644
--- a/crypto/src/bcpg/sig/NotationData.cs
+++ b/crypto/src/bcpg/sig/NotationData.cs
@@ -17,8 +17,9 @@ namespace Org.BouncyCastle.Bcpg.Sig
 
 		public NotationData(
 			bool	critical,
-			byte[]	data)
-			: base(SignatureSubpacketTag.NotationData, critical, data)
+            bool    isLongLength,
+            byte[]  data)
+			: base(SignatureSubpacketTag.NotationData, critical, isLongLength, data)
 		{
 		}
 
@@ -27,12 +28,12 @@ namespace Org.BouncyCastle.Bcpg.Sig
 			bool	humanReadable,
 			string	notationName,
 			string	notationValue)
-			: base(SignatureSubpacketTag.NotationData, critical,
-				createData(humanReadable, notationName, notationValue))
+			: base(SignatureSubpacketTag.NotationData, critical, false,
+				CreateData(humanReadable, notationName, notationValue))
 		{
 		}
 
-		private static byte[] createData(
+		private static byte[] CreateData(
 			bool	humanReadable,
 			string	notationName,
 			string	notationValue)
diff --git a/crypto/src/bcpg/sig/PreferredAlgorithms.cs b/crypto/src/bcpg/sig/PreferredAlgorithms.cs
index 0f282a38c..9514bed2b 100644
--- a/crypto/src/bcpg/sig/PreferredAlgorithms.cs
+++ b/crypto/src/bcpg/sig/PreferredAlgorithms.cs
@@ -1,7 +1,5 @@
 using System;
 
-
-
 namespace Org.BouncyCastle.Bcpg.Sig
 {
     /**
@@ -24,24 +22,25 @@ namespace Org.BouncyCastle.Bcpg.Sig
         }
 
         public PreferredAlgorithms(
-            SignatureSubpacketTag        type,
-            bool    critical,
-            byte[]     data)
-            : base(type, critical, data)
+            SignatureSubpacketTag   type,
+            bool                    critical,
+            bool                    isLongLength,
+            byte[]                  data)
+            : base(type, critical, isLongLength, data)
         {
         }
 
         public PreferredAlgorithms(
-            SignatureSubpacketTag        type,
-            bool    critical,
-            int[]      preferences)
-            : base(type, critical, IntToByteArray(preferences))
+            SignatureSubpacketTag   type,
+            bool                    critical,
+            int[]                   preferences)
+            : base(type, critical, false, IntToByteArray(preferences))
         {
         }
 
         public int[] GetPreferences()
         {
-            int[]    v = new int[data.Length];
+            int[] v = new int[data.Length];
 
             for (int i = 0; i != v.Length; i++)
             {
diff --git a/crypto/src/bcpg/sig/PrimaryUserId.cs b/crypto/src/bcpg/sig/PrimaryUserId.cs
index fc0353afd..1f16f40eb 100644
--- a/crypto/src/bcpg/sig/PrimaryUserId.cs
+++ b/crypto/src/bcpg/sig/PrimaryUserId.cs
@@ -1,7 +1,5 @@
 using System;
 
-
-
 namespace Org.BouncyCastle.Bcpg.Sig
 {
     /**
@@ -28,15 +26,16 @@ namespace Org.BouncyCastle.Bcpg.Sig
 
         public PrimaryUserId(
             bool    critical,
-            byte[]     data)
-            : base(SignatureSubpacketTag.PrimaryUserId, critical, data)
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.PrimaryUserId, critical, isLongLength, data)
         {
         }
 
         public PrimaryUserId(
             bool    critical,
             bool    isPrimaryUserId)
-            : base(SignatureSubpacketTag.PrimaryUserId, critical, BooleanToByteArray(isPrimaryUserId))
+            : base(SignatureSubpacketTag.PrimaryUserId, critical, false, BooleanToByteArray(isPrimaryUserId))
         {
         }
 
diff --git a/crypto/src/bcpg/sig/Revocable.cs b/crypto/src/bcpg/sig/Revocable.cs
index b5e94feec..7aa91391f 100644
--- a/crypto/src/bcpg/sig/Revocable.cs
+++ b/crypto/src/bcpg/sig/Revocable.cs
@@ -1,7 +1,5 @@
 using System;
 
-
-
 namespace Org.BouncyCastle.Bcpg.Sig
 {
     /**
@@ -28,16 +26,17 @@ namespace Org.BouncyCastle.Bcpg.Sig
 
         public Revocable(
             bool    critical,
-            byte[]     data)
-            : base(SignatureSubpacketTag.Revocable, critical, data)
-    {
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.Revocable, critical, isLongLength, data)
+        {
         }
 
         public Revocable(
             bool    critical,
             bool    isRevocable)
-            : base(SignatureSubpacketTag.Revocable, critical, BooleanToByteArray(isRevocable))
-    {
+            : base(SignatureSubpacketTag.Revocable, critical, false, BooleanToByteArray(isRevocable))
+        {
         }
 
         public bool IsRevocable()
diff --git a/crypto/src/bcpg/sig/RevocationKey.cs b/crypto/src/bcpg/sig/RevocationKey.cs
index 66982cb5a..11467d2af 100644
--- a/crypto/src/bcpg/sig/RevocationKey.cs
+++ b/crypto/src/bcpg/sig/RevocationKey.cs
@@ -14,17 +14,18 @@ namespace Org.BouncyCastle.Bcpg
 		// 20 octets of fingerprint
 		public RevocationKey(
 			bool	isCritical,
-			byte[]	data)
-			: base(SignatureSubpacketTag.RevocationKey, isCritical, data)
+            bool    isLongLength,
+            byte[]  data)
+			: base(SignatureSubpacketTag.RevocationKey, isCritical, isLongLength, data)
 		{
 		}
 
-		public RevocationKey(
+        public RevocationKey(
 			bool					isCritical,
 			RevocationKeyTag		signatureClass,
 			PublicKeyAlgorithmTag	keyAlgorithm,
 			byte[]					fingerprint)
-			: base(SignatureSubpacketTag.RevocationKey, isCritical,
+			: base(SignatureSubpacketTag.RevocationKey, isCritical, false,
 				CreateData(signatureClass, keyAlgorithm, fingerprint))
 		{
 		}
diff --git a/crypto/src/bcpg/sig/RevocationReason.cs b/crypto/src/bcpg/sig/RevocationReason.cs
index 98e9b0a3d..42afd5f5b 100644
--- a/crypto/src/bcpg/sig/RevocationReason.cs
+++ b/crypto/src/bcpg/sig/RevocationReason.cs
@@ -11,16 +11,16 @@ namespace Org.BouncyCastle.Bcpg
     public class RevocationReason
 		: SignatureSubpacket
     {
-        public RevocationReason(bool isCritical, byte[] data)
-            : base(SignatureSubpacketTag.RevocationReason, isCritical, data)
+        public RevocationReason(bool isCritical, bool isLongLength, byte[] data)
+            : base(SignatureSubpacketTag.RevocationReason, isCritical, isLongLength, data)
         {
         }
 
-		public RevocationReason(
-			bool				isCritical,
-			RevocationReasonTag	reason,
-			string				description)
-            : base(SignatureSubpacketTag.RevocationReason, isCritical, CreateData(reason, description))
+        public RevocationReason(
+			bool                isCritical,
+			RevocationReasonTag reason,
+			string              description)
+            : base(SignatureSubpacketTag.RevocationReason, isCritical, false, CreateData(reason, description))
         {
         }
 
diff --git a/crypto/src/bcpg/sig/SignatureCreationTime.cs b/crypto/src/bcpg/sig/SignatureCreationTime.cs
index e6f241f11..d172e5d52 100644
--- a/crypto/src/bcpg/sig/SignatureCreationTime.cs
+++ b/crypto/src/bcpg/sig/SignatureCreationTime.cs
@@ -21,18 +21,22 @@ namespace Org.BouncyCastle.Bcpg.Sig
             data[3] = (byte)t;
             return data;
         }
+
         public SignatureCreationTime(
-            bool	critical,
-            byte[]	data)
-            : base(SignatureSubpacketTag.CreationTime, critical, data)
+            bool    critical,
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.CreationTime, critical, isLongLength, data)
         {
         }
+
         public SignatureCreationTime(
-            bool		critical,
-            DateTime	date)
-            : base(SignatureSubpacketTag.CreationTime, critical, TimeToBytes(date))
+            bool        critical,
+            DateTime    date)
+            : base(SignatureSubpacketTag.CreationTime, critical, false, TimeToBytes(date))
         {
         }
+
         public DateTime GetTime()
         {
 			long time = (long)(
diff --git a/crypto/src/bcpg/sig/SignatureExpirationTime.cs b/crypto/src/bcpg/sig/SignatureExpirationTime.cs
index 7fddf5743..24f0a9f8a 100644
--- a/crypto/src/bcpg/sig/SignatureExpirationTime.cs
+++ b/crypto/src/bcpg/sig/SignatureExpirationTime.cs
@@ -1,7 +1,5 @@
 using System;
 
-
-
 namespace Org.BouncyCastle.Bcpg.Sig
 {
     /**
@@ -11,29 +9,28 @@ namespace Org.BouncyCastle.Bcpg.Sig
         : SignatureSubpacket
     {
         protected static byte[] TimeToBytes(
-            long      t)
+            long    t)
         {
-            byte[]    data = new byte[4];
-
+            byte[] data = new byte[4];
             data[0] = (byte)(t >> 24);
             data[1] = (byte)(t >> 16);
             data[2] = (byte)(t >> 8);
             data[3] = (byte)t;
-
             return data;
         }
 
         public SignatureExpirationTime(
             bool    critical,
-            byte[]     data)
-            : base(SignatureSubpacketTag.ExpireTime, critical, data)
-    {
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.ExpireTime, critical, isLongLength, data)
+        {
         }
 
         public SignatureExpirationTime(
             bool    critical,
-            long       seconds)
-            : base(SignatureSubpacketTag.ExpireTime, critical, TimeToBytes(seconds))
+            long    seconds)
+            : base(SignatureSubpacketTag.ExpireTime, critical, false, TimeToBytes(seconds))
         {
         }
 
diff --git a/crypto/src/bcpg/sig/SignerUserId.cs b/crypto/src/bcpg/sig/SignerUserId.cs
index 98cc808e7..8ab62ed2e 100644
--- a/crypto/src/bcpg/sig/SignerUserId.cs
+++ b/crypto/src/bcpg/sig/SignerUserId.cs
@@ -24,20 +24,21 @@ namespace Org.BouncyCastle.Bcpg.Sig
         }
 
         public SignerUserId(
-            bool	critical,
-            byte[]	data)
-            : base(SignatureSubpacketTag.SignerUserId, critical, data)
+            bool    critical,
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.SignerUserId, critical, isLongLength, data)
 		{
 		}
 
-		public SignerUserId(
-            bool	critical,
-            string	userId)
-            : base(SignatureSubpacketTag.SignerUserId, critical, UserIdToBytes(userId))
+        public SignerUserId(
+            bool    critical,
+            string  userId)
+            : base(SignatureSubpacketTag.SignerUserId, critical, false, UserIdToBytes(userId))
 		{
         }
 
-		public string GetId()
+        public string GetId()
         {
             char[] chars = new char[data.Length];
 
diff --git a/crypto/src/bcpg/sig/TrustSignature.cs b/crypto/src/bcpg/sig/TrustSignature.cs
index bbadd3067..91458826d 100644
--- a/crypto/src/bcpg/sig/TrustSignature.cs
+++ b/crypto/src/bcpg/sig/TrustSignature.cs
@@ -16,17 +16,18 @@ namespace Org.BouncyCastle.Bcpg.Sig
         }
 
 		public TrustSignature(
-            bool	critical,
-            byte[]	data)
-            : base(SignatureSubpacketTag.TrustSig, critical, data)
+            bool    critical,
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.TrustSig, critical, isLongLength, data)
         {
         }
 
         public TrustSignature(
-            bool	critical,
-            int		depth,
-            int		trustAmount)
-            : base(SignatureSubpacketTag.TrustSig, critical, IntToByteArray(depth, trustAmount))
+            bool    critical,
+            int     depth,
+            int     trustAmount)
+            : base(SignatureSubpacketTag.TrustSig, critical, false, IntToByteArray(depth, trustAmount))
         {
         }