summary refs log tree commit diff
path: root/crypto/src/bcpg
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/bcpg')
-rw-r--r--crypto/src/bcpg/BcpgInputStream.cs18
-rw-r--r--crypto/src/bcpg/DsaPublicBcpgKey.cs102
-rw-r--r--crypto/src/bcpg/ECDHPublicBCPGKey.cs102
-rw-r--r--crypto/src/bcpg/ECDsaPublicBCPGKey.cs34
-rw-r--r--crypto/src/bcpg/ECPublicBCPGKey.cs97
-rw-r--r--crypto/src/bcpg/ECSecretBCPGKey.cs56
-rw-r--r--crypto/src/bcpg/PublicKeyAlgorithmTags.cs30
-rw-r--r--crypto/src/bcpg/PublicKeyEncSessionPacket.cs54
-rw-r--r--crypto/src/bcpg/PublicKeyPacket.cs54
-rw-r--r--crypto/src/bcpg/S2k.cs12
-rw-r--r--crypto/src/bcpg/SignaturePacket.cs5
-rw-r--r--crypto/src/bcpg/SignatureSubpacket.cs50
-rw-r--r--crypto/src/bcpg/SignatureSubpacketsReader.cs84
-rw-r--r--crypto/src/bcpg/UserAttributeSubpacket.cs42
-rw-r--r--crypto/src/bcpg/UserAttributeSubpacketsReader.cs100
-rw-r--r--crypto/src/bcpg/attr/ImageAttrib.cs70
-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
32 files changed, 816 insertions, 356 deletions
diff --git a/crypto/src/bcpg/BcpgInputStream.cs b/crypto/src/bcpg/BcpgInputStream.cs
index 3c69fbdf5..2e08cd090 100644
--- a/crypto/src/bcpg/BcpgInputStream.cs
+++ b/crypto/src/bcpg/BcpgInputStream.cs
@@ -105,19 +105,15 @@ namespace Org.BouncyCastle.Bcpg
                 next = true;
             }
 
-            if (nextB >= 0)
+            if (nextB < 0)
+                return (PacketTag)nextB;
+
+            int maskB = nextB & 0x3f;
+            if ((nextB & 0x40) == 0)    // old
             {
-                if ((nextB & 0x40) != 0)    // new
-                {
-                    return (PacketTag)(nextB & 0x3f);
-                }
-                else    // old
-                {
-                    return (PacketTag)((nextB & 0x3f) >> 2);
-                }
+                maskB >>= 2;
             }
-
-            return (PacketTag) nextB;
+            return (PacketTag)maskB;
         }
 
         public Packet ReadPacket()
diff --git a/crypto/src/bcpg/DsaPublicBcpgKey.cs b/crypto/src/bcpg/DsaPublicBcpgKey.cs
index 61159567c..11294cc22 100644
--- a/crypto/src/bcpg/DsaPublicBcpgKey.cs
+++ b/crypto/src/bcpg/DsaPublicBcpgKey.cs
@@ -4,46 +4,46 @@ using Org.BouncyCastle.Math;
 
 namespace Org.BouncyCastle.Bcpg
 {
-	/// <remarks>Base class for a DSA public key.</remarks>
-	public class DsaPublicBcpgKey
-		: BcpgObject, IBcpgKey
+    /// <remarks>Base class for a DSA public key.</remarks>
+    public class DsaPublicBcpgKey
+        : BcpgObject, IBcpgKey
     {
         private readonly MPInteger p, q, g, y;
 
-		/// <param name="bcpgIn">The stream to read the packet from.</param>
-		public DsaPublicBcpgKey(
-			BcpgInputStream bcpgIn)
-		{
-			this.p = new MPInteger(bcpgIn);
-			this.q = new MPInteger(bcpgIn);
-			this.g = new MPInteger(bcpgIn);
-			this.y = new MPInteger(bcpgIn);
-		}
+        /// <param name="bcpgIn">The stream to read the packet from.</param>
+        public DsaPublicBcpgKey(
+            BcpgInputStream bcpgIn)
+        {
+            this.p = new MPInteger(bcpgIn);
+            this.q = new MPInteger(bcpgIn);
+            this.g = new MPInteger(bcpgIn);
+            this.y = new MPInteger(bcpgIn);
+        }
 
-		public DsaPublicBcpgKey(
-			BigInteger	p,
-			BigInteger	q,
-			BigInteger	g,
-			BigInteger	y)
-		{
-			this.p = new MPInteger(p);
-			this.q = new MPInteger(q);
-			this.g = new MPInteger(g);
-			this.y = new MPInteger(y);
-		}
+        public DsaPublicBcpgKey(
+            BigInteger	p,
+            BigInteger	q,
+            BigInteger	g,
+            BigInteger	y)
+        {
+            this.p = new MPInteger(p);
+            this.q = new MPInteger(q);
+            this.g = new MPInteger(g);
+            this.y = new MPInteger(y);
+        }
 
-		/// <summary>The format, as a string, always "PGP".</summary>
-		public string Format
-		{
-			get { return "PGP"; }
-		}
+        /// <summary>The format, as a string, always "PGP".</summary>
+        public string Format
+        {
+            get { return "PGP"; }
+        }
 
-		/// <summary>Return the standard PGP encoding of the key.</summary>
+        /// <summary>Return the standard PGP encoding of the key.</summary>
         public override byte[] GetEncoded()
         {
             try
             {
-            	return base.GetEncoded();
+                return base.GetEncoded();
             }
             catch (Exception)
             {
@@ -51,30 +51,30 @@ namespace Org.BouncyCastle.Bcpg
             }
         }
 
-		public override void Encode(
-			BcpgOutputStream bcpgOut)
-		{
-			bcpgOut.WriteObjects(p, q, g, y);
-		}
+        public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+            bcpgOut.WriteObjects(p, q, g, y);
+        }
 
-		public BigInteger G
-		{
-			get { return g.Value; }
-		}
+        public BigInteger G
+        {
+            get { return g.Value; }
+        }
 
-		public BigInteger P
-		{
-			get { return p.Value; }
-		}
+        public BigInteger P
+        {
+            get { return p.Value; }
+        }
 
-		public BigInteger Q
-		{
-			get { return q.Value; }
-		}
+        public BigInteger Q
+        {
+            get { return q.Value; }
+        }
 
-		public BigInteger Y
-		{
-			get { return y.Value; }
-		}
+        public BigInteger Y
+        {
+            get { return y.Value; }
+        }
     }
 }
diff --git a/crypto/src/bcpg/ECDHPublicBCPGKey.cs b/crypto/src/bcpg/ECDHPublicBCPGKey.cs
new file mode 100644
index 000000000..dc225e31e
--- /dev/null
+++ b/crypto/src/bcpg/ECDHPublicBCPGKey.cs
@@ -0,0 +1,102 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Bcpg
+{
+    /// <remarks>Base class for an ECDH Public Key.</remarks>
+    public class ECDHPublicBcpgKey
+        : ECPublicBcpgKey
+    {
+        private byte reserved;
+        private HashAlgorithmTag hashFunctionId;
+        private SymmetricKeyAlgorithmTag symAlgorithmId;
+
+        /// <param name="bcpgIn">The stream to read the packet from.</param>
+        public ECDHPublicBcpgKey(
+            BcpgInputStream bcpgIn)
+            : base(bcpgIn)
+        {
+            int length = bcpgIn.ReadByte();
+            byte[] kdfParameters =  new byte[length];
+            if (kdfParameters.Length != 3)
+                throw new InvalidOperationException("kdf parameters size of 3 expected.");
+
+            bcpgIn.ReadFully(kdfParameters);
+
+            reserved = kdfParameters[0];
+            hashFunctionId = (HashAlgorithmTag)kdfParameters[1];
+            symAlgorithmId = (SymmetricKeyAlgorithmTag)kdfParameters[2];
+
+            VerifyHashAlgorithm();
+            VerifySymmetricKeyAlgorithm();
+        }
+
+        public ECDHPublicBcpgKey(
+            DerObjectIdentifier oid,
+            ECPoint point,
+            HashAlgorithmTag hashAlgorithm,
+            SymmetricKeyAlgorithmTag symmetricKeyAlgorithm)
+            : base(oid, point)
+        {
+            reserved = 1;
+            hashFunctionId = hashAlgorithm;
+            symAlgorithmId = symmetricKeyAlgorithm;
+
+            VerifyHashAlgorithm();
+            VerifySymmetricKeyAlgorithm();
+        }
+
+        public virtual byte Reserved
+        {
+            get { return reserved; }
+        }
+
+        public virtual HashAlgorithmTag HashAlgorithm
+        {
+            get { return hashFunctionId; }
+        }
+
+        public virtual SymmetricKeyAlgorithmTag SymmetricKeyAlgorithm
+        {
+            get { return symAlgorithmId; }
+        }
+
+        public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+            base.Encode(bcpgOut);
+            bcpgOut.WriteByte(0x3);
+            bcpgOut.WriteByte(reserved);
+            bcpgOut.WriteByte((byte)hashFunctionId);
+            bcpgOut.WriteByte((byte)symAlgorithmId);
+        }
+
+        private void VerifyHashAlgorithm()
+        {
+            switch ((HashAlgorithmTag)hashFunctionId)
+            {
+            case HashAlgorithmTag.Sha256:
+            case HashAlgorithmTag.Sha384:
+            case HashAlgorithmTag.Sha512:
+                break;
+            default:
+                throw new InvalidOperationException("Hash algorithm must be SHA-256 or stronger.");
+            }
+        }
+
+        private void VerifySymmetricKeyAlgorithm()
+        {
+            switch ((SymmetricKeyAlgorithmTag)symAlgorithmId)
+            {
+            case SymmetricKeyAlgorithmTag.Aes128:
+            case SymmetricKeyAlgorithmTag.Aes192:
+            case SymmetricKeyAlgorithmTag.Aes256:
+                break;
+            default:
+                throw new InvalidOperationException("Symmetric key algorithm must be AES-128 or stronger.");
+            }
+        }
+    }
+}
diff --git a/crypto/src/bcpg/ECDsaPublicBCPGKey.cs b/crypto/src/bcpg/ECDsaPublicBCPGKey.cs
new file mode 100644
index 000000000..5f0c8ac55
--- /dev/null
+++ b/crypto/src/bcpg/ECDsaPublicBCPGKey.cs
@@ -0,0 +1,34 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Bcpg
+{
+    /// <remarks>Base class for an ECDSA Public Key.</remarks>
+    public class ECDsaPublicBcpgKey
+        : ECPublicBcpgKey
+    {
+        /// <param name="bcpgIn">The stream to read the packet from.</param>
+        protected internal ECDsaPublicBcpgKey(
+            BcpgInputStream bcpgIn)
+            : base(bcpgIn)
+        {
+        }
+
+        public ECDsaPublicBcpgKey(
+            DerObjectIdentifier oid,
+            ECPoint point)
+            : base(oid, point)
+        {
+        }
+
+        public ECDsaPublicBcpgKey(
+            DerObjectIdentifier oid,
+            BigInteger encodedPoint)
+            : base(oid, encodedPoint)
+        {
+        }
+    }
+}
diff --git a/crypto/src/bcpg/ECPublicBCPGKey.cs b/crypto/src/bcpg/ECPublicBCPGKey.cs
new file mode 100644
index 000000000..f328f9dc3
--- /dev/null
+++ b/crypto/src/bcpg/ECPublicBCPGKey.cs
@@ -0,0 +1,97 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Bcpg
+{
+    /// <remarks>Base class for an EC Public Key.</remarks>
+    public abstract class ECPublicBcpgKey
+        : BcpgObject, IBcpgKey
+    {
+        internal DerObjectIdentifier oid;
+        internal BigInteger point;
+
+        /// <param name="bcpgIn">The stream to read the packet from.</param>
+        protected ECPublicBcpgKey(
+            BcpgInputStream bcpgIn)
+        {
+            this.oid = DerObjectIdentifier.GetInstance(Asn1Object.FromByteArray(ReadBytesOfEncodedLength(bcpgIn)));
+            this.point = new MPInteger(bcpgIn).Value;
+        }
+
+        protected ECPublicBcpgKey(
+            DerObjectIdentifier oid,
+            ECPoint point)
+        {
+            this.point = new BigInteger(1, point.GetEncoded());
+            this.oid = oid;
+        }
+
+        protected ECPublicBcpgKey(
+            DerObjectIdentifier oid,
+            BigInteger encodedPoint)
+        {
+            this.point = encodedPoint;
+            this.oid = oid;
+        }
+
+        /// <summary>The format, as a string, always "PGP".</summary>
+        public string Format
+        {
+            get { return "PGP"; }
+        }
+
+        /// <summary>Return the standard PGP encoding of the key.</summary>
+        public override byte[] GetEncoded()
+        {
+            try
+            {
+                return base.GetEncoded();
+            }
+            catch (IOException)
+            {
+                return null;
+            }
+        }
+
+        public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+            byte[] oid = this.oid.GetEncoded();
+            bcpgOut.Write(oid, 1, oid.Length - 1);
+
+            MPInteger point = new MPInteger(this.point);
+            bcpgOut.WriteObject(point);
+        }
+
+        public virtual BigInteger EncodedPoint
+        {
+            get { return point; }
+        }
+
+        public virtual DerObjectIdentifier CurveOid
+        {
+            get { return oid; }
+        }
+
+        protected static byte[] ReadBytesOfEncodedLength(
+            BcpgInputStream bcpgIn)
+        {
+            int length = bcpgIn.ReadByte();
+            if (length == 0 || length == 0xFF)
+            {
+                throw new IOException("future extensions not yet implemented.");
+            }
+
+            byte[] buffer = new byte[length + 2];
+            bcpgIn.ReadFully(buffer, 2, buffer.Length - 2);
+            buffer[0] = (byte)0x06;
+            buffer[1] = (byte)length;
+
+            return buffer;
+        }
+    }
+}
diff --git a/crypto/src/bcpg/ECSecretBCPGKey.cs b/crypto/src/bcpg/ECSecretBCPGKey.cs
new file mode 100644
index 000000000..22e0a3473
--- /dev/null
+++ b/crypto/src/bcpg/ECSecretBCPGKey.cs
@@ -0,0 +1,56 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Base class for an EC Secret Key.</remarks>
+    public class ECSecretBcpgKey
+        : BcpgObject, IBcpgKey
+    {
+        internal MPInteger x;
+
+        public ECSecretBcpgKey(
+            BcpgInputStream bcpgIn)
+        {
+            this.x = new MPInteger(bcpgIn);
+        }
+
+        public ECSecretBcpgKey(
+            BigInteger x)
+        {
+            this.x = new MPInteger(x);
+        }
+
+		/// <summary>The format, as a string, always "PGP".</summary>
+		public string Format
+		{
+			get { return "PGP"; }
+		}
+
+		/// <summary>Return the standard PGP encoding of the key.</summary>
+		public override byte[] GetEncoded()
+		{
+			try
+			{
+				return base.GetEncoded();
+			}
+			catch (Exception)
+			{
+				return null;
+			}
+		}
+
+        public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+            bcpgOut.WriteObject(x);
+        }
+
+        public virtual BigInteger X
+        {
+            get { return x.Value; }
+        }
+    }
+}
diff --git a/crypto/src/bcpg/PublicKeyAlgorithmTags.cs b/crypto/src/bcpg/PublicKeyAlgorithmTags.cs
index 85ae548eb..9e30b54f7 100644
--- a/crypto/src/bcpg/PublicKeyAlgorithmTags.cs
+++ b/crypto/src/bcpg/PublicKeyAlgorithmTags.cs
@@ -1,6 +1,8 @@
+using System;
+
 namespace Org.BouncyCastle.Bcpg
 {
-	/// <remarks>Public Key Algorithm tag numbers.</remarks>
+    /// <remarks>Public Key Algorithm tag numbers.</remarks>
     public enum PublicKeyAlgorithmTag
     {
         RsaGeneral = 1,			// RSA (Encrypt or Sign)
@@ -8,21 +10,23 @@ 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
         ElGamalGeneral = 20,	// Elgamal (Encrypt or Sign)
         DiffieHellman = 21,		// Reserved for Diffie-Hellman (X9.42, as defined for IETF-S/MIME)
 
-		Experimental_1 = 100,
-		Experimental_2 = 101,
-		Experimental_3 = 102,
-		Experimental_4 = 103,
-		Experimental_5 = 104,
-		Experimental_6 = 105,
-		Experimental_7 = 106,
-		Experimental_8 = 107,
-		Experimental_9 = 108,
-		Experimental_10 = 109,
-		Experimental_11 = 110,
-	}
+        Experimental_1 = 100,
+        Experimental_2 = 101,
+        Experimental_3 = 102,
+        Experimental_4 = 103,
+        Experimental_5 = 104,
+        Experimental_6 = 105,
+        Experimental_7 = 106,
+        Experimental_8 = 107,
+        Experimental_9 = 108,
+        Experimental_10 = 109,
+        Experimental_11 = 110,
+    }
 }
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 32d43149b..bbed941dc 100644
--- a/crypto/src/bcpg/PublicKeyPacket.cs
+++ b/crypto/src/bcpg/PublicKeyPacket.cs
@@ -5,11 +5,11 @@ using Org.BouncyCastle.Utilities.Date;
 
 namespace Org.BouncyCastle.Bcpg
 {
-	/// <remarks>Basic packet for a PGP public key.</remarks>
+    /// <remarks>Basic packet for a PGP public key.</remarks>
     public class PublicKeyPacket
         : ContainedPacket //, PublicKeyAlgorithmTag
     {
-		private int version;
+        private int version;
         private long time;
         private int validDays;
         private PublicKeyAlgorithmTag algorithm;
@@ -44,49 +44,55 @@ namespace Org.BouncyCastle.Bcpg
                 case PublicKeyAlgorithmTag.ElGamalGeneral:
                     key = new ElGamalPublicBcpgKey(bcpgIn);
                     break;
+                case PublicKeyAlgorithmTag.ECDH:
+                    key = new ECDHPublicBcpgKey(bcpgIn);
+                    break;
+                case PublicKeyAlgorithmTag.ECDsa:
+                    key = new ECDsaPublicBcpgKey(bcpgIn);
+                    break;
                 default:
                     throw new IOException("unknown PGP public key algorithm encountered");
             }
         }
 
-		/// <summary>Construct a version 4 public key packet.</summary>
+        /// <summary>Construct a version 4 public key packet.</summary>
         public PublicKeyPacket(
             PublicKeyAlgorithmTag	algorithm,
             DateTime				time,
             IBcpgKey				key)
         {
-			this.version = 4;
+            this.version = 4;
             this.time = DateTimeUtilities.DateTimeToUnixMs(time) / 1000L;
             this.algorithm = algorithm;
             this.key = key;
         }
 
-        public int Version
+        public virtual int Version
         {
-			get { return version; }
+            get { return version; }
         }
 
-        public PublicKeyAlgorithmTag Algorithm
+        public virtual PublicKeyAlgorithmTag Algorithm
         {
-			get { return algorithm; }
+            get { return algorithm; }
         }
 
-        public int ValidDays
+        public virtual int ValidDays
         {
-			get { return validDays; }
+            get { return validDays; }
         }
 
-		public DateTime GetTime()
+        public virtual DateTime GetTime()
         {
             return DateTimeUtilities.UnixMsToDateTime(time * 1000L);
         }
 
-        public IBcpgKey Key
+        public virtual IBcpgKey Key
         {
-			get { return key; }
+            get { return key; }
         }
 
-        public byte[] GetEncodedContents()
+        public virtual byte[] GetEncodedContents()
         {
             MemoryStream bOut = new MemoryStream();
             BcpgOutputStream pOut = new BcpgOutputStream(bOut);
@@ -94,22 +100,22 @@ namespace Org.BouncyCastle.Bcpg
             pOut.WriteByte((byte) version);
             pOut.WriteInt((int) time);
 
-			if (version <= 3)
+            if (version <= 3)
             {
                 pOut.WriteShort((short) validDays);
             }
 
-			pOut.WriteByte((byte) algorithm);
+            pOut.WriteByte((byte) algorithm);
 
-			pOut.WriteObject((BcpgObject)key);
+            pOut.WriteObject((BcpgObject)key);
 
-			return bOut.ToArray();
+            return bOut.ToArray();
         }
 
-		public override void Encode(
-			BcpgOutputStream bcpgOut)
-		{
-			bcpgOut.WritePacket(PacketTag.PublicKey, GetEncodedContents(), true);
-		}
-	}
+        public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+            bcpgOut.WritePacket(PacketTag.PublicKey, GetEncodedContents(), true);
+        }
+    }
 }
diff --git a/crypto/src/bcpg/S2k.cs b/crypto/src/bcpg/S2k.cs
index de08c016c..33fd792fe 100644
--- a/crypto/src/bcpg/S2k.cs
+++ b/crypto/src/bcpg/S2k.cs
@@ -16,6 +16,8 @@ namespace Org.BouncyCastle.Bcpg
         public const int Salted = 1;
         public const int SaltedAndIterated = 3;
         public const int GnuDummyS2K = 101;
+        public const int GnuProtectionModeNoPrivateKey = 1;
+        public const int GnuProtectionModeDivertToCard = 2;
 
         internal int type;
         internal HashAlgorithmTag algorithm;
@@ -82,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);
         }
@@ -106,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/SignaturePacket.cs b/crypto/src/bcpg/SignaturePacket.cs
index 605ce84c4..5b91c15a3 100644
--- a/crypto/src/bcpg/SignaturePacket.cs
+++ b/crypto/src/bcpg/SignaturePacket.cs
@@ -146,6 +146,11 @@ namespace Org.BouncyCastle.Bcpg
                     MPInteger y = new MPInteger(bcpgIn);
 					signature = new MPInteger[]{ p, g, y };
                     break;
+                case PublicKeyAlgorithmTag.ECDsa:
+                    MPInteger ecR = new MPInteger(bcpgIn);
+                    MPInteger ecS = new MPInteger(bcpgIn);
+                    signature = new MPInteger[]{ ecR, ecS };
+                    break;
                 default:
 					if (keyAlgorithm >= PublicKeyAlgorithmTag.Experimental_1 && keyAlgorithm <= PublicKeyAlgorithmTag.Experimental_11)
 					{
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/UserAttributeSubpacket.cs b/crypto/src/bcpg/UserAttributeSubpacket.cs
index bd49d2150..05f60ac17 100644
--- a/crypto/src/bcpg/UserAttributeSubpacket.cs
+++ b/crypto/src/bcpg/UserAttributeSubpacket.cs
@@ -10,40 +10,44 @@ namespace Org.BouncyCastle.Bcpg
     */
     public class UserAttributeSubpacket
     {
-        private readonly UserAttributeSubpacketTag	type;
-        private readonly byte[]						data;
+        internal readonly UserAttributeSubpacketTag	type;
+        private readonly bool longLength;   // we preserve this as not everyone encodes length properly.
+        protected readonly byte[] data;
 
-		internal UserAttributeSubpacket(
-            UserAttributeSubpacketTag	type,
-            byte[]						data)
+        protected internal UserAttributeSubpacket(UserAttributeSubpacketTag type, byte[] data)
+            : this(type, false, data)
+        {
+        }
+
+        protected internal UserAttributeSubpacket(UserAttributeSubpacketTag type, bool forceLongLength, byte[] data)
         {
             this.type = type;
+            this.longLength = forceLongLength;
             this.data = data;
         }
 
-		public UserAttributeSubpacketTag SubpacketType
+        public virtual UserAttributeSubpacketTag SubpacketType
         {
             get { return type; }
         }
 
-		/**
+        /**
         * return the generic data making up the packet.
         */
-        public byte[] GetData()
+        public virtual byte[] GetData()
         {
             return data;
         }
 
-        public void Encode(
-            Stream os)
+        public virtual void Encode(Stream os)
         {
             int bodyLen = data.Length + 1;
 
-            if (bodyLen < 192)
+            if (bodyLen < 192 && !longLength)
             {
                 os.WriteByte((byte)bodyLen);
             }
-            else if (bodyLen <= 8383)
+            else if (bodyLen <= 8383 && !longLength)
             {
                 bodyLen -= 192;
 
@@ -69,18 +73,18 @@ namespace Org.BouncyCastle.Bcpg
             if (obj == this)
                 return true;
 
-			UserAttributeSubpacket other = obj as UserAttributeSubpacket;
+            UserAttributeSubpacket other = obj as UserAttributeSubpacket;
 
-			if (other == null)
-				return false;
+            if (other == null)
+                return false;
 
-			return type == other.type
-				&& Arrays.AreEqual(data, other.data);
+            return type == other.type
+                && Arrays.AreEqual(data, other.data);
         }
 
-		public override int GetHashCode()
+        public override int GetHashCode()
         {
-			return type.GetHashCode() ^ Arrays.GetHashCode(data);
+            return type.GetHashCode() ^ Arrays.GetHashCode(data);
         }
     }
 }
diff --git a/crypto/src/bcpg/UserAttributeSubpacketsReader.cs b/crypto/src/bcpg/UserAttributeSubpacketsReader.cs
index 2e5ea0f3e..f0cc1b8e4 100644
--- a/crypto/src/bcpg/UserAttributeSubpacketsReader.cs
+++ b/crypto/src/bcpg/UserAttributeSubpacketsReader.cs
@@ -5,59 +5,61 @@ using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Bcpg
 {
-	/**
-	* reader for user attribute sub-packets
-	*/
-	public class UserAttributeSubpacketsParser
-	{
-		private readonly Stream input;
+    /**
+    * reader for user attribute sub-packets
+    */
+    public class UserAttributeSubpacketsParser
+    {
+        private readonly Stream input;
 
-		public UserAttributeSubpacketsParser(
-			Stream input)
-		{
-			this.input = input;
-		}
+        public UserAttributeSubpacketsParser(
+            Stream input)
+        {
+            this.input = input;
+        }
 
-		public UserAttributeSubpacket ReadPacket()
-		{
-			int l = input.ReadByte();
-			if (l < 0)
-				return null;
+        public virtual UserAttributeSubpacket ReadPacket()
+        {
+            int l = input.ReadByte();
+            if (l < 0)
+                return null;
 
-			int bodyLen = 0;
-			if (l < 192)
-			{
-				bodyLen = l;
-			}
-			else if (l <= 223)
-			{
-				bodyLen = ((l - 192) << 8) + (input.ReadByte()) + 192;
-			}
-			else if (l == 255)
-			{
-				bodyLen = (input.ReadByte() << 24) | (input.ReadByte() << 16)
-					|  (input.ReadByte() << 8)  | input.ReadByte();
-			}
-			else
-			{
-				// TODO Error?
-			}
+            int bodyLen = 0;
+            bool longLength = false;
+            if (l < 192)
+            {
+                bodyLen = l;
+            }
+            else if (l <= 223)
+            {
+                bodyLen = ((l - 192) << 8) + (input.ReadByte()) + 192;
+            }
+            else if (l == 255)
+            {
+                bodyLen = (input.ReadByte() << 24) | (input.ReadByte() << 16)
+                    |  (input.ReadByte() << 8)  | input.ReadByte();
+                longLength = true;
+            }
+            else
+            {
+                throw new IOException("unrecognised length reading user attribute sub packet");
+            }
 
-			int tag = input.ReadByte();
-			if (tag < 0)
-				throw new EndOfStreamException("unexpected EOF reading user attribute sub packet");
+            int tag = input.ReadByte();
+            if (tag < 0)
+                throw new EndOfStreamException("unexpected EOF reading user attribute sub packet");
 
-			byte[] data = new byte[bodyLen - 1];
-			if (Streams.ReadFully(input, data) < data.Length)
-				throw new EndOfStreamException();
+            byte[] data = new byte[bodyLen - 1];
+            if (Streams.ReadFully(input, data) < data.Length)
+                throw new EndOfStreamException();
 
-			UserAttributeSubpacketTag type = (UserAttributeSubpacketTag) tag;
-			switch (type)
-			{
-				case UserAttributeSubpacketTag.ImageAttribute:
-					return new ImageAttrib(data);
-			}
-			return new UserAttributeSubpacket(type, data);
-		}
-	}
+            UserAttributeSubpacketTag type = (UserAttributeSubpacketTag) tag;
+            switch (type)
+            {
+                case UserAttributeSubpacketTag.ImageAttribute:
+                    return new ImageAttrib(longLength, data);
+            }
+            return new UserAttributeSubpacket(type, longLength, data);
+        }
+    }
 }
diff --git a/crypto/src/bcpg/attr/ImageAttrib.cs b/crypto/src/bcpg/attr/ImageAttrib.cs
index 73490791c..2d0fef8b8 100644
--- a/crypto/src/bcpg/attr/ImageAttrib.cs
+++ b/crypto/src/bcpg/attr/ImageAttrib.cs
@@ -3,25 +3,29 @@ using System.IO;
 
 namespace Org.BouncyCastle.Bcpg.Attr
 {
-	/// <remarks>Basic type for a image attribute packet.</remarks>
+    /// <remarks>Basic type for a image attribute packet.</remarks>
     public class ImageAttrib
-		: UserAttributeSubpacket
+        : UserAttributeSubpacket
     {
-		public enum Format : byte
-		{
-			Jpeg = 1
-		}
+        public enum Format : byte
+        {
+            Jpeg = 1
+        }
 
-		private static readonly byte[] Zeroes = new byte[12];
+        private static readonly byte[] Zeroes = new byte[12];
 
-		private int     hdrLength;
+        private int     hdrLength;
         private int     _version;
         private int     _encoding;
         private byte[]  imageData;
 
-        public ImageAttrib(
-            byte[] data)
-            : base(UserAttributeSubpacketTag.ImageAttribute, data)
+        public ImageAttrib(byte[] data)
+            : this(false, data)
+        {
+        }
+
+        public ImageAttrib(bool forceLongLength, byte[] data)
+            : base(UserAttributeSubpacketTag.ImageAttribute, forceLongLength, data)
         {
             hdrLength = ((data[1] & 0xff) << 8) | (data[0] & 0xff);
             _version = data[2] & 0xff;
@@ -31,36 +35,36 @@ namespace Org.BouncyCastle.Bcpg.Attr
             Array.Copy(data, hdrLength, imageData, 0, imageData.Length);
         }
 
-		public ImageAttrib(
-			Format	imageType,
-			byte[]	imageData)
-			: this(ToByteArray(imageType, imageData))
-		{
-		}
+        public ImageAttrib(
+            Format	imageType,
+            byte[]	imageData)
+            : this(ToByteArray(imageType, imageData))
+        {
+        }
 
-		private static byte[] ToByteArray(
-			Format	imageType,
-			byte[]	imageData)
-		{
-			MemoryStream bOut = new MemoryStream();
-			bOut.WriteByte(0x10); bOut.WriteByte(0x00); bOut.WriteByte(0x01);
-			bOut.WriteByte((byte) imageType);
-			bOut.Write(Zeroes, 0, Zeroes.Length);
-			bOut.Write(imageData, 0, imageData.Length);
-			return bOut.ToArray();
-		}
+        private static byte[] ToByteArray(
+            Format	imageType,
+            byte[]	imageData)
+        {
+            MemoryStream bOut = new MemoryStream();
+            bOut.WriteByte(0x10); bOut.WriteByte(0x00); bOut.WriteByte(0x01);
+            bOut.WriteByte((byte) imageType);
+            bOut.Write(Zeroes, 0, Zeroes.Length);
+            bOut.Write(imageData, 0, imageData.Length);
+            return bOut.ToArray();
+        }
 
-		public int Version
+        public virtual int Version
         {
-			get { return _version; }
+            get { return _version; }
         }
 
-        public int Encoding
+        public virtual int Encoding
         {
-			get { return _encoding; }
+            get { return _encoding; }
         }
 
-		public byte[] GetImageData()
+        public virtual byte[] GetImageData()
         {
             return imageData;
         }
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))
         {
         }