summary refs log tree commit diff
path: root/crypto/src/asn1
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/asn1')
-rw-r--r--crypto/src/asn1/Asn1Object.cs10
-rw-r--r--crypto/src/asn1/Asn1ObjectDescriptor.cs14
-rw-r--r--crypto/src/asn1/Asn1OutputStream.cs179
-rw-r--r--crypto/src/asn1/Asn1RelativeOid.cs13
-rw-r--r--crypto/src/asn1/Asn1Sequence.cs16
-rw-r--r--crypto/src/asn1/Asn1Set.cs16
-rw-r--r--crypto/src/asn1/Asn1TaggedObject.cs24
-rw-r--r--crypto/src/asn1/BERBitString.cs88
-rw-r--r--crypto/src/asn1/BEROctetStringGenerator.cs8
-rw-r--r--crypto/src/asn1/BerOctetString.cs78
-rw-r--r--crypto/src/asn1/BerSequence.cs31
-rw-r--r--crypto/src/asn1/BerSet.cs27
-rw-r--r--crypto/src/asn1/BerTaggedObject.cs63
-rw-r--r--crypto/src/asn1/ConstructedDLEncoding.cs35
-rw-r--r--crypto/src/asn1/ConstructedILEncoding.cs35
-rw-r--r--crypto/src/asn1/ConstructedLazyDLEncoding.cs33
-rw-r--r--crypto/src/asn1/DERExternal.cs15
-rw-r--r--crypto/src/asn1/DLSequence.cs66
-rw-r--r--crypto/src/asn1/DLSet.cs78
-rw-r--r--crypto/src/asn1/DLTaggedObject.cs72
-rw-r--r--crypto/src/asn1/DerApplicationSpecific.cs14
-rw-r--r--crypto/src/asn1/DerBMPString.cs14
-rw-r--r--crypto/src/asn1/DerBitString.cs70
-rw-r--r--crypto/src/asn1/DerBoolean.cs30
-rw-r--r--crypto/src/asn1/DerEnumerated.cs13
-rw-r--r--crypto/src/asn1/DerGeneralString.cs13
-rw-r--r--crypto/src/asn1/DerGeneralizedTime.cs13
-rw-r--r--crypto/src/asn1/DerGraphicString.cs13
-rw-r--r--crypto/src/asn1/DerIA5String.cs13
-rw-r--r--crypto/src/asn1/DerInteger.cs13
-rw-r--r--crypto/src/asn1/DerNull.cs13
-rw-r--r--crypto/src/asn1/DerNumericString.cs13
-rw-r--r--crypto/src/asn1/DerObjectIdentifier.cs13
-rw-r--r--crypto/src/asn1/DerOctetString.cs24
-rw-r--r--crypto/src/asn1/DerOutputStream.cs5
-rw-r--r--crypto/src/asn1/DerPrintableString.cs13
-rw-r--r--crypto/src/asn1/DerSequence.cs63
-rw-r--r--crypto/src/asn1/DerSet.cs89
-rw-r--r--crypto/src/asn1/DerT61String.cs13
-rw-r--r--crypto/src/asn1/DerTaggedObject.cs57
-rw-r--r--crypto/src/asn1/DerUTCTime.cs13
-rw-r--r--crypto/src/asn1/DerUTF8String.cs13
-rw-r--r--crypto/src/asn1/DerUniversalString.cs13
-rw-r--r--crypto/src/asn1/DerVideotexString.cs13
-rw-r--r--crypto/src/asn1/DerVisibleString.cs13
-rw-r--r--crypto/src/asn1/IAsn1Encoding.cs11
-rw-r--r--crypto/src/asn1/LazyDLSequence.cs19
-rw-r--r--crypto/src/asn1/LazyDLSet.cs21
-rw-r--r--crypto/src/asn1/PrimitiveEncoding.cs33
-rw-r--r--crypto/src/asn1/PrimitiveEncodingSuffixed.cs36
50 files changed, 535 insertions, 1060 deletions
diff --git a/crypto/src/asn1/Asn1Object.cs b/crypto/src/asn1/Asn1Object.cs
index 9945a7fae..0cf89052b 100644
--- a/crypto/src/asn1/Asn1Object.cs
+++ b/crypto/src/asn1/Asn1Object.cs
@@ -9,14 +9,14 @@ namespace Org.BouncyCastle.Asn1
         public override void EncodeTo(Stream output)
         {
             Asn1OutputStream asn1Out = Asn1OutputStream.Create(output);
-            Encode(asn1Out, true);
+            GetEncoding(asn1Out.Encoding).Encode(asn1Out);
             asn1Out.FlushInternal();
         }
 
         public override void EncodeTo(Stream output, string encoding)
         {
             Asn1OutputStream asn1Out = Asn1OutputStream.Create(output, encoding);
-            Encode(asn1Out, true);
+            GetEncoding(asn1Out.Encoding).Encode(asn1Out);
             asn1Out.FlushInternal();
         }
 
@@ -71,11 +71,9 @@ namespace Org.BouncyCastle.Asn1
             return this;
         }
 
-        internal abstract bool EncodeConstructed(int encoding);
+        internal abstract IAsn1Encoding GetEncoding(int encoding);
 
-        internal abstract int EncodedLength(int encoding, bool withID);
-
-        internal abstract void Encode(Asn1OutputStream asn1Out, bool withID);
+        internal abstract IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo);
 
         protected abstract bool Asn1Equals(Asn1Object asn1Object);
 		protected abstract int Asn1GetHashCode();
diff --git a/crypto/src/asn1/Asn1ObjectDescriptor.cs b/crypto/src/asn1/Asn1ObjectDescriptor.cs
index e306d827e..289a0e16f 100644
--- a/crypto/src/asn1/Asn1ObjectDescriptor.cs
+++ b/crypto/src/asn1/Asn1ObjectDescriptor.cs
@@ -78,20 +78,14 @@ namespace Org.BouncyCastle.Asn1
             get { return m_baseGraphicString; }
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return m_baseGraphicString.GetEncodingImplicit(encoding, Asn1Tags.Universal, Asn1Tags.ObjectDescriptor);
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return m_baseGraphicString.EncodedLength(encoding, withID);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteIdentifier(withID, Asn1Tags.ObjectDescriptor);
-            m_baseGraphicString.Encode(asn1Out, false);
+            return m_baseGraphicString.GetEncodingImplicit(encoding, tagClass, tagNo);
         }
 
         protected override int Asn1GetHashCode()
diff --git a/crypto/src/asn1/Asn1OutputStream.cs b/crypto/src/asn1/Asn1OutputStream.cs
index eeca2754c..096b569e3 100644
--- a/crypto/src/asn1/Asn1OutputStream.cs
+++ b/crypto/src/asn1/Asn1OutputStream.cs
@@ -37,7 +37,7 @@ namespace Org.BouncyCastle.Asn1
             if (null == asn1Encodable)
                 throw new ArgumentNullException("asn1Encodable");
 
-            asn1Encodable.ToAsn1Object().Encode(this, true);
+            asn1Encodable.ToAsn1Object().GetEncoding(this.Encoding).Encode(this);
             FlushInternal();
         }
 
@@ -46,18 +46,16 @@ namespace Org.BouncyCastle.Asn1
             if (null == asn1Object)
                 throw new ArgumentNullException("asn1Object");
 
-            asn1Object.Encode(this, true);
+            asn1Object.GetEncoding(this.Encoding).Encode(this);
             FlushInternal();
         }
 
-        internal void FlushInternal()
+        internal void EncodeContents(IAsn1Encoding[] contentsEncodings)
         {
-            // Placeholder to support future internal buffering
-        }
-
-        internal virtual DerOutputStreamNew GetDerSubStream()
-        {
-            return new DerOutputStreamNew(s);
+            for (int i = 0, count = contentsEncodings.Length; i < count; ++i)
+            {
+                contentsEncodings[i].Encode(this);
+            }
         }
 
         internal virtual int Encoding
@@ -65,136 +63,77 @@ namespace Org.BouncyCastle.Asn1
             get { return EncodingBer; }
         }
 
-        internal void WriteDL(int length)
+        internal void FlushInternal()
         {
-            if (length < 128)
-            {
-                WriteByte((byte)length);
-            }
-            else
-            {
-                byte[] stack = new byte[5];
-                int pos = stack.Length;
-
-                do
-                {
-                    stack[--pos] = (byte)length;
-                    length >>= 8;
-                }
-                while (length > 0);
-
-                int count = stack.Length - pos;
-                stack[--pos] = (byte)(0x80 | count);
-
-                Write(stack, pos, count + 1);
-            }
+            // Placeholder to support future internal buffering
         }
 
-        internal virtual void WriteElements(Asn1Encodable[] elements)
+        internal void WriteDL(int dl)
         {
-            for (int i = 0, count = elements.Length; i < count; ++i)
+            if (dl < 128)
             {
-                elements[i].ToAsn1Object().Encode(this, true);
+                WriteByte((byte)dl);
+                return;
             }
-        }
 
-        internal void WriteEncodingDL(bool withID, int identifier, byte contents)
-        {
-            WriteIdentifier(withID, identifier);
-            WriteDL(1);
-            WriteByte(contents);
-        }
-
-        internal void WriteEncodingDL(bool withID, int identifier, byte[] contents)
-        {
-            WriteIdentifier(withID, identifier);
-            WriteDL(contents.Length);
-            Write(contents, 0, contents.Length);
-        }
-
-        internal void WriteEncodingDL(bool withID, int identifier, byte[] contents, int contentsOff, int contentsLen)
-        {
-            WriteIdentifier(withID, identifier);
-            WriteDL(contentsLen);
-            Write(contents, contentsOff, contentsLen);
-        }
+            byte[] stack = new byte[5];
+            int pos = stack.Length;
 
-        internal void WriteEncodingDL(bool withID, int identifier, byte contentsPrefix, byte[] contents,
-            int contentsOff, int contentsLen)
-        {
-            WriteIdentifier(withID, identifier);
-            WriteDL(1 + contentsLen);
-            WriteByte(contentsPrefix);
-            Write(contents, contentsOff, contentsLen);
-        }
+            do
+            {
+                stack[--pos] = (byte)dl;
+                dl >>= 8;
+            }
+            while (dl > 0);
 
-        internal void WriteEncodingDL(bool withID, int identifier, byte[] contents, int contentsOff, int contentsLen,
-            byte contentsSuffix)
-        {
-            WriteIdentifier(withID, identifier);
-            WriteDL(contentsLen + 1);
-            Write(contents, contentsOff, contentsLen);
-            WriteByte(contentsSuffix);
-        }
+            int count = stack.Length - pos;
+            stack[--pos] = (byte)(0x80 | count);
 
-        internal void WriteEncodingDL(bool withID, int flags, int tag, byte[] contents)
-        {
-            WriteIdentifier(withID, flags, tag);
-            WriteDL(contents.Length);
-            Write(contents, 0, contents.Length);
+            Write(stack, pos, count + 1);
         }
 
-        internal void WriteEncodingIL(bool withID, int identifier, Asn1Encodable[] elements)
+        internal void WriteIdentifier(int tagClass, int tagNo)
         {
-            WriteIdentifier(withID, identifier);
-            WriteByte(0x80);
-            WriteElements(elements);
-            WriteByte(0x00);
-            WriteByte(0x00);
-        }
-
-        internal void WriteIdentifier(bool withID, int identifier)
-        {
-            if (withID)
+            if (tagNo < 31)
             {
-                WriteByte((byte)identifier);
+                WriteByte((byte)(tagClass | tagNo));
+                return;
             }
-        }
 
-        internal void WriteIdentifier(bool withID, int flags, int tag)
-        {
-            if (!withID)
-            {
-                // Don't write the identifier
-            }
-            else if (tag < 31)
+            byte[] stack = new byte[6];
+            int pos = stack.Length;
+
+            stack[--pos] = (byte)(tagNo & 0x7F);
+            while (tagNo > 127)
             {
-                WriteByte((byte)(flags | tag));
+                tagNo >>= 7;
+                stack[--pos] = (byte)(tagNo & 0x7F | 0x80);
             }
-            else
-            {
-                byte[] stack = new byte[6];
-                int pos = stack.Length;
 
-                stack[--pos] = (byte)(tag & 0x7F);
-                while (tag > 127)
-                {
-                    tag >>= 7;
-                    stack[--pos] = (byte)(tag & 0x7F | 0x80);
-                }
+            stack[--pos] = (byte)(tagClass | 0x1F);
 
-                stack[--pos] = (byte)(flags | 0x1F);
+            Write(stack, pos, stack.Length - pos);
+        }
 
-                Write(stack, pos, stack.Length - pos);
+        internal static IAsn1Encoding[] GetContentsEncodings(int encoding, Asn1Encodable[] elements)
+        {
+            int count = elements.Length;
+            IAsn1Encoding[] contentsEncodings = new IAsn1Encoding[count];
+            for (int i = 0; i < count; ++i)
+            {
+                contentsEncodings[i] = elements[i].ToAsn1Object().GetEncoding(encoding);
             }
+            return contentsEncodings;
         }
 
-        internal void WritePrimitives(Asn1Object[] primitives)
+        internal static int GetLengthOfContents(IAsn1Encoding[] contentsEncodings)
         {
-            for (int i = 0, count = primitives.Length; i < count; ++i)
+            int contentsLength = 0;
+            for (int i = 0, count = contentsEncodings.Length; i < count; ++i)
             {
-                primitives[i].Encode(this, true);
+                contentsLength += contentsEncodings[i].GetLength();
             }
+            return contentsLength;
         }
 
         internal static int GetLengthOfDL(int dl)
@@ -210,23 +149,13 @@ namespace Org.BouncyCastle.Asn1
             return length;
         }
 
-        internal static int GetLengthOfEncodingDL(bool withID, int contentsLength)
-        {
-            return (withID ? 1 : 0) + GetLengthOfDL(contentsLength) + contentsLength;
-        }
-
-        internal static int GetLengthOfEncodingDL(bool withID, int tag, int contentsLength)
-        {
-            return (withID ? GetLengthOfIdentifier(tag) : 0) + GetLengthOfDL(contentsLength) + contentsLength;
-        }
-
-        internal static int GetLengthOfIdentifier(int tag)
+        internal static int GetLengthOfIdentifier(int tagNo)
         {
-            if (tag < 31)
+            if (tagNo < 31)
                 return 1;
 
             int length = 2;
-            while ((tag >>= 7) > 0)
+            while ((tagNo >>= 7) > 0)
             {
                 ++length;
             }
diff --git a/crypto/src/asn1/Asn1RelativeOid.cs b/crypto/src/asn1/Asn1RelativeOid.cs
index efa050413..a960b50bf 100644
--- a/crypto/src/asn1/Asn1RelativeOid.cs
+++ b/crypto/src/asn1/Asn1RelativeOid.cs
@@ -110,19 +110,14 @@ namespace Org.BouncyCastle.Asn1
             return identifier.GetHashCode();
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.RelativeOid, GetContents());
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, GetContents().Length);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.RelativeOid, GetContents());
+            return new PrimitiveEncoding(tagClass, tagNo, GetContents());
         }
 
         private void DoOutput(MemoryStream bOut)
diff --git a/crypto/src/asn1/Asn1Sequence.cs b/crypto/src/asn1/Asn1Sequence.cs
index bd1b46b49..cfe0d37aa 100644
--- a/crypto/src/asn1/Asn1Sequence.cs
+++ b/crypto/src/asn1/Asn1Sequence.cs
@@ -235,27 +235,11 @@ namespace Org.BouncyCastle.Asn1
             return true;
         }
 
-        internal override bool EncodeConstructed(int encoding)
-        {
-            return true;
-        }
-
         public override string ToString()
         {
             return CollectionUtilities.ToString(elements);
         }
 
-        internal int CalculateContentsLength(int encoding)
-        {
-            int contentsLength = 0;
-            for (int i = 0, count = elements.Length; i < count; ++i)
-            {
-                Asn1Object asn1Object = elements[i].ToAsn1Object();
-                contentsLength += asn1Object.EncodedLength(encoding, true);
-            }
-            return contentsLength;
-        }
-
         // TODO[asn1] Preferably return an Asn1BitString[] (doesn't exist yet)
         internal DerBitString[] GetConstructedBitStrings()
         {
diff --git a/crypto/src/asn1/Asn1Set.cs b/crypto/src/asn1/Asn1Set.cs
index 45febabaf..42180fd71 100644
--- a/crypto/src/asn1/Asn1Set.cs
+++ b/crypto/src/asn1/Asn1Set.cs
@@ -266,27 +266,11 @@ namespace Org.BouncyCastle.Asn1
             return true;
         }
 
-        internal override bool EncodeConstructed(int encoding)
-        {
-            return true;
-        }
-
         public override string ToString()
         {
             return CollectionUtilities.ToString(elements);
         }
 
-        internal int CalculateContentsLength(int encoding)
-        {
-            int contentsLength = 0;
-            for (int i = 0, count = elements.Length; i < count; ++i)
-            {
-                Asn1Object asn1Object = elements[i].ToAsn1Object();
-                contentsLength += asn1Object.EncodedLength(encoding, true);
-            }
-            return contentsLength;
-        }
-
         internal static Asn1Encodable[] Sort(Asn1Encodable[] elements)
         {
             int count = elements.Length;
diff --git a/crypto/src/asn1/Asn1TaggedObject.cs b/crypto/src/asn1/Asn1TaggedObject.cs
index 13d1ff283..7fafa4c52 100644
--- a/crypto/src/asn1/Asn1TaggedObject.cs
+++ b/crypto/src/asn1/Asn1TaggedObject.cs
@@ -234,16 +234,24 @@ namespace Org.BouncyCastle.Asn1
             }
         }
 
-        /**
-         * Return true if the object is marked as constructed, false otherwise.
-         *
-         * @return true if constructed, otherwise false.
-         */
-        // TODO Need this public if/when DerApplicationSpecific extends Asn1TaggedObject
         internal bool IsConstructed()
         {
-            int encoding = Asn1Encoding == Ber ? Asn1OutputStream.EncodingBer : Asn1OutputStream.EncodingDer;
-            return EncodeConstructed(encoding);
+            switch (explicitness)
+            {
+                case DeclaredImplicit:
+                {
+                    Asn1Object baseObject = obj.ToAsn1Object();
+                    if (baseObject is Asn1Sequence || baseObject is Asn1Set)
+                        return true;
+
+                    Asn1TaggedObject baseTagged = baseObject as Asn1TaggedObject;
+                    return null != baseTagged && baseTagged.IsConstructed();
+                }
+                case ParsedImplicit:
+                    return obj is Asn1Sequence;
+                default:
+                    return true;
+            }
         }
 
         /**
diff --git a/crypto/src/asn1/BERBitString.cs b/crypto/src/asn1/BERBitString.cs
index a012d2a7c..2f5bd9cb7 100644
--- a/crypto/src/asn1/BERBitString.cs
+++ b/crypto/src/asn1/BERBitString.cs
@@ -111,90 +111,28 @@ namespace Org.BouncyCastle.Asn1
             this.segmentLimit = DefaultSegmentLimit;
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
             if (Asn1OutputStream.EncodingBer != encoding)
-                return base.EncodeConstructed(encoding);
+                return base.GetEncoding(encoding);
 
-            return null != elements || contents.Length > segmentLimit;
-        }
-
-        internal override int EncodedLength(int encoding, bool withID)
-        {
-            if (Asn1OutputStream.EncodingBer != encoding)
-                return base.EncodedLength(encoding, withID);
-
-            if (!EncodeConstructed(encoding))
-                return EncodedLength(withID, contents.Length);
-
-            int totalLength = withID ? 4 : 3;
-
-            if (null != elements)
-            {
-                for (int i = 0; i < elements.Length; ++i)
-                {
-                    totalLength += elements[i].EncodedLength(encoding, true);
-                }
-            }
-            else if (contents.Length < 2)
-            {
-                // No bits
-            }
-            else
-            {
-                int extraSegments = (contents.Length - 2) / (segmentLimit - 1);
-                totalLength += extraSegments * EncodedLength(true, segmentLimit);
-
-                int lastSegmentLength = contents.Length - (extraSegments * (segmentLimit - 1));
-                totalLength += EncodedLength(true, lastSegmentLength);
-            }
+            if (null == elements)
+                return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.BitString, contents);
 
-            return totalLength;
+            return new ConstructedILEncoding(Asn1Tags.Universal, Asn1Tags.BitString,
+                Asn1OutputStream.GetContentsEncodings(encoding, elements));
         }
 
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            if (Asn1OutputStream.EncodingBer != asn1Out.Encoding)
-            {
-                base.Encode(asn1Out, withID);
-                return;
-            }
-
-            if (!EncodeConstructed(asn1Out.Encoding))
-            {
-                Encode(asn1Out, withID, contents, 0, contents.Length);
-                return;
-            }
-
-            asn1Out.WriteIdentifier(withID, Asn1Tags.Constructed | Asn1Tags.BitString);
-            asn1Out.WriteByte(0x80);
-
-            if (null != elements)
-            {
-                asn1Out.WritePrimitives(elements);
-            }
-            else if (contents.Length < 2)
-            {
-                // No bits
-            }
-            else
-            {
-                byte pad = contents[0];
-                int length = contents.Length;
-                int remaining = length - 1;
-                int segmentLength = segmentLimit - 1;
-
-                while (remaining > segmentLength)
-                {
-                    Encode(asn1Out, true, (byte)0, contents, length - remaining, segmentLength);
-                    remaining -= segmentLength;
-                }
+            if (Asn1OutputStream.EncodingBer != encoding)
+                return base.GetEncodingImplicit(encoding, tagClass, tagNo);
 
-                Encode(asn1Out, true, pad, contents, length - remaining, remaining);
-            }
+            if (null == elements)
+                return new PrimitiveEncoding(tagClass, tagNo, contents);
 
-            asn1Out.WriteByte(0x00);
-            asn1Out.WriteByte(0x00);
+            return new ConstructedILEncoding(tagClass, tagNo,
+                Asn1OutputStream.GetContentsEncodings(encoding, elements));
         }
     }
 }
diff --git a/crypto/src/asn1/BEROctetStringGenerator.cs b/crypto/src/asn1/BEROctetStringGenerator.cs
index 37e46bea5..de0a6c0b8 100644
--- a/crypto/src/asn1/BEROctetStringGenerator.cs
+++ b/crypto/src/asn1/BEROctetStringGenerator.cs
@@ -67,7 +67,7 @@ namespace Org.BouncyCastle.Asn1
 
 				if (_off == _buf.Length)
 				{
-					DerOctetString.Encode(_derOut, true, _buf, 0, _off);
+					DerOctetString.Encode(_derOut, _buf, 0, _off);
 					_off = 0;
 				}
 			}
@@ -88,13 +88,13 @@ namespace Org.BouncyCastle.Asn1
                 {
                     Array.Copy(b, off, _buf, _off, available);
                     count += available;
-                    DerOctetString.Encode(_derOut, true, _buf, 0, bufLen);
+                    DerOctetString.Encode(_derOut, _buf, 0, bufLen);
                 }
 
                 int remaining;
                 while ((remaining = len - count) >= bufLen)
                 {
-                    DerOctetString.Encode(_derOut, true, b, off + count, bufLen);
+                    DerOctetString.Encode(_derOut, b, off + count, bufLen);
                     count += bufLen;
                 }
 
@@ -123,7 +123,7 @@ namespace Org.BouncyCastle.Asn1
 			{
 				if (_off != 0)
 				{
-					DerOctetString.Encode(_derOut, true, _buf, 0, _off);
+					DerOctetString.Encode(_derOut, _buf, 0, _off);
 				}
 
                 _derOut.FlushInternal();
diff --git a/crypto/src/asn1/BerOctetString.cs b/crypto/src/asn1/BerOctetString.cs
index 52ddd51c3..8e51f8bca 100644
--- a/crypto/src/asn1/BerOctetString.cs
+++ b/crypto/src/asn1/BerOctetString.cs
@@ -120,80 +120,28 @@ namespace Org.BouncyCastle.Asn1
 			return GetEnumerator();
 		}
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
             if (Asn1OutputStream.EncodingBer != encoding)
-                return base.EncodeConstructed(encoding);
+                return base.GetEncoding(encoding);
 
-            return null != elements || contents.Length > segmentLimit;
-        }
-
-        internal override int EncodedLength(int encoding, bool withID)
-        {
-            if (Asn1OutputStream.EncodingBer != encoding)
-                return base.EncodedLength(encoding, withID);
-
-            if (!EncodeConstructed(encoding))
-                return EncodedLength(withID, contents.Length);
-
-            int totalLength = withID ? 4 : 3;
-
-            if (null != elements)
-            {
-                for (int i = 0; i < elements.Length; ++i)
-                {
-                    totalLength += elements[i].EncodedLength(encoding, true);
-                }
-            }
-            else
-            {
-                int fullSegments = contents.Length / segmentLimit;
-                totalLength += fullSegments * EncodedLength(true, segmentLimit);
-
-                int lastSegmentLength = contents.Length - (fullSegments * segmentLimit);
-                if (lastSegmentLength > 0)
-                {
-                    totalLength += EncodedLength(true, lastSegmentLength);
-                }
-            }
+            if (null == elements)
+                return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.OctetString, contents);
 
-            return totalLength;
+            return new ConstructedILEncoding(Asn1Tags.Universal, Asn1Tags.OctetString,
+                Asn1OutputStream.GetContentsEncodings(encoding, elements));
         }
 
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            if (Asn1OutputStream.EncodingBer != asn1Out.Encoding)
-            {
-                base.Encode(asn1Out, withID);
-                return;
-            }
-
-            if (!EncodeConstructed(asn1Out.Encoding))
-            {
-                Encode(asn1Out, withID, contents, 0, contents.Length);
-                return;
-            }
-
-            asn1Out.WriteIdentifier(withID, Asn1Tags.Constructed | Asn1Tags.OctetString);
-            asn1Out.WriteByte(0x80);
+            if (Asn1OutputStream.EncodingBer != encoding)
+                return base.GetEncodingImplicit(encoding, tagClass, tagNo);
 
-            if (null != elements)
-            {
-                asn1Out.WritePrimitives(elements);
-            }
-            else
-            {
-                int pos = 0;
-                while (pos < contents.Length)
-                {
-                    int segmentLength = System.Math.Min(contents.Length - pos, segmentLimit);
-                    Encode(asn1Out, true, contents, pos, segmentLength);
-                    pos += segmentLength;
-                }
-            }
+            if (null == elements)
+                return new PrimitiveEncoding(tagClass, tagNo, contents);
 
-            asn1Out.WriteByte(0x00);
-            asn1Out.WriteByte(0x00);
+            return new ConstructedILEncoding(tagClass, tagNo,
+                Asn1OutputStream.GetContentsEncodings(encoding, elements));
         }
 
         private class ChunkEnumerator
diff --git a/crypto/src/asn1/BerSequence.cs b/crypto/src/asn1/BerSequence.cs
index a92b70f98..deed8fbb9 100644
--- a/crypto/src/asn1/BerSequence.cs
+++ b/crypto/src/asn1/BerSequence.cs
@@ -46,32 +46,23 @@ namespace Org.BouncyCastle.Asn1
         {
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
             if (Asn1OutputStream.EncodingBer != encoding)
-                return base.EncodedLength(encoding, withID);
+                return base.GetEncoding(encoding);
 
-            int totalLength = withID ? 4 : 3;
-
-            for (int i = 0, count = elements.Length; i < count; ++i)
-            {
-                Asn1Object asn1Object = elements[i].ToAsn1Object();
-                totalLength += asn1Object.EncodedLength(encoding, true);
-            }
-
-            return totalLength;
+            return new ConstructedILEncoding(Asn1Tags.Universal, Asn1Tags.Sequence,
+                Asn1OutputStream.GetContentsEncodings(encoding, elements));
         }
 
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-		{
-            if (Asn1OutputStream.EncodingBer != asn1Out.Encoding)
-            {
-                base.Encode(asn1Out, withID);
-                return;
-            }
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
+        {
+            if (Asn1OutputStream.EncodingBer != encoding)
+                return base.GetEncodingImplicit(encoding, tagClass, tagNo);
 
-            asn1Out.WriteEncodingIL(withID, Asn1Tags.Constructed | Asn1Tags.Sequence, elements);
-		}
+            return new ConstructedILEncoding(tagClass, tagNo,
+                Asn1OutputStream.GetContentsEncodings(encoding, elements));
+        }
 
         internal override DerBitString ToAsn1BitString()
         {
diff --git a/crypto/src/asn1/BerSet.cs b/crypto/src/asn1/BerSet.cs
index c0d00537c..0a273b3f3 100644
--- a/crypto/src/asn1/BerSet.cs
+++ b/crypto/src/asn1/BerSet.cs
@@ -48,31 +48,22 @@ namespace Org.BouncyCastle.Asn1
         {
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
             if (Asn1OutputStream.EncodingBer != encoding)
-                return base.EncodedLength(encoding, withID);
+                return base.GetEncoding(encoding);
 
-            int totalLength = withID ? 4 : 3;
-
-            for (int i = 0, count = elements.Length; i < count; ++i)
-            {
-                Asn1Object asn1Object = elements[i].ToAsn1Object();
-                totalLength += asn1Object.EncodedLength(encoding, true);
-            }
-
-            return totalLength;
+            return new ConstructedILEncoding(Asn1Tags.Universal, Asn1Tags.Set,
+                Asn1OutputStream.GetContentsEncodings(encoding, elements));
         }
 
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            if (Asn1OutputStream.EncodingBer != asn1Out.Encoding)
-            {
-                base.Encode(asn1Out, withID);
-                return;
-            }
+            if (Asn1OutputStream.EncodingBer != encoding)
+                return base.GetEncodingImplicit(encoding, tagClass, tagNo);
 
-            asn1Out.WriteEncodingIL(withID, Asn1Tags.Constructed | Asn1Tags.Set, elements);
+            return new ConstructedILEncoding(tagClass, tagNo,
+                Asn1OutputStream.GetContentsEncodings(encoding, elements));
         }
     }
 }
diff --git a/crypto/src/asn1/BerTaggedObject.cs b/crypto/src/asn1/BerTaggedObject.cs
index a97a8e143..e613d98d9 100644
--- a/crypto/src/asn1/BerTaggedObject.cs
+++ b/crypto/src/asn1/BerTaggedObject.cs
@@ -59,69 +59,32 @@ namespace Org.BouncyCastle.Asn1
             get { return Ber; }
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
             if (Asn1OutputStream.EncodingBer != encoding)
-                return base.EncodeConstructed(encoding);
+                return base.GetEncoding(encoding);
 
-            return IsExplicit() || GetBaseObject().ToAsn1Object().EncodeConstructed(encoding);
+            Asn1Object baseObject = GetBaseObject().ToAsn1Object();
+
+            if (!IsExplicit())
+                return baseObject.GetEncodingImplicit(encoding, TagClass, TagNo);
+
+            return new ConstructedILEncoding(TagClass, TagNo, new IAsn1Encoding[]{ baseObject.GetEncoding(encoding) });
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
             if (Asn1OutputStream.EncodingBer != encoding)
-                return base.EncodedLength(encoding, withID);
+                return base.GetEncodingImplicit(encoding, tagClass, tagNo);
 
             Asn1Object baseObject = GetBaseObject().ToAsn1Object();
-            bool withBaseID = IsExplicit();
-
-            int length = baseObject.EncodedLength(encoding, withBaseID);
-
-            if (withBaseID)
-            {
-                length += 3;
-            }
 
-            length += withID ? Asn1OutputStream.GetLengthOfIdentifier(TagNo) : 0;
+            if (!IsExplicit())
+                return baseObject.GetEncodingImplicit(encoding, tagClass, tagNo);
 
-            return length;
+            return new ConstructedILEncoding(tagClass, tagNo, new IAsn1Encoding[]{ baseObject.GetEncoding(encoding) });
         }
 
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-		{
-            if (Asn1OutputStream.EncodingBer != asn1Out.Encoding)
-            {
-                base.Encode(asn1Out, withID);
-                return;
-            }
-
-            Asn1Object baseObject = GetBaseObject().ToAsn1Object();
-            bool withBaseID = IsExplicit();
-
-            if (withID)
-            {
-                int flags = TagClass;
-                if (withBaseID || baseObject.EncodeConstructed(asn1Out.Encoding))
-                {
-                    flags |= Asn1Tags.Constructed;
-                }
-
-                asn1Out.WriteIdentifier(true, flags, TagNo);
-            }
-
-            if (withBaseID)
-            {
-                asn1Out.WriteByte(0x80);
-                baseObject.Encode(asn1Out, true);
-                asn1Out.WriteByte(0x00);
-                asn1Out.WriteByte(0x00);
-            }
-            else
-            {
-                baseObject.Encode(asn1Out, false);
-            }
-		}
-
         internal override Asn1Sequence RebuildConstructed(Asn1Object asn1Object)
         {
             return new BerSequence(asn1Object);
diff --git a/crypto/src/asn1/ConstructedDLEncoding.cs b/crypto/src/asn1/ConstructedDLEncoding.cs
new file mode 100644
index 000000000..f7d8bec5d
--- /dev/null
+++ b/crypto/src/asn1/ConstructedDLEncoding.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+    internal class ConstructedDLEncoding
+        : IAsn1Encoding
+    {
+        private readonly int m_tagClass;
+        private readonly int m_tagNo;
+        private readonly IAsn1Encoding[] m_contentsElements;
+        private readonly int m_contentsLength;
+
+        internal ConstructedDLEncoding(int tagClass, int tagNo, IAsn1Encoding[] contentsElements)
+        {
+            m_tagClass = tagClass;
+            m_tagNo = tagNo;
+            m_contentsElements = contentsElements;
+            m_contentsLength = Asn1OutputStream.GetLengthOfContents(contentsElements);
+        }
+
+        void IAsn1Encoding.Encode(Asn1OutputStream asn1Out)
+        {
+            asn1Out.WriteIdentifier(Asn1Tags.Constructed | m_tagClass, m_tagNo);
+            asn1Out.WriteDL(m_contentsLength);
+            asn1Out.EncodeContents(m_contentsElements);
+        }
+
+        int IAsn1Encoding.GetLength()
+        {
+            return Asn1OutputStream.GetLengthOfIdentifier(m_tagNo)
+                +  Asn1OutputStream.GetLengthOfDL(m_contentsLength)
+                +  m_contentsLength;
+        }
+    }
+}
diff --git a/crypto/src/asn1/ConstructedILEncoding.cs b/crypto/src/asn1/ConstructedILEncoding.cs
new file mode 100644
index 000000000..1934c6f48
--- /dev/null
+++ b/crypto/src/asn1/ConstructedILEncoding.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+    internal class ConstructedILEncoding
+        : IAsn1Encoding
+    {
+        private readonly int m_tagClass;
+        private readonly int m_tagNo;
+        private readonly IAsn1Encoding[] m_contentsElements;
+
+        internal ConstructedILEncoding(int tagClass, int tagNo, IAsn1Encoding[] contentsElements)
+        {
+            m_tagClass = tagClass;
+            m_tagNo = tagNo;
+            m_contentsElements = contentsElements;
+        }
+
+        void IAsn1Encoding.Encode(Asn1OutputStream asn1Out)
+        {
+            asn1Out.WriteIdentifier(Asn1Tags.Constructed | m_tagClass, m_tagNo);
+            asn1Out.WriteByte(0x80);
+            asn1Out.EncodeContents(m_contentsElements);
+            asn1Out.WriteByte(0x00);
+            asn1Out.WriteByte(0x00);
+        }
+
+        int IAsn1Encoding.GetLength()
+        {
+            return Asn1OutputStream.GetLengthOfIdentifier(m_tagNo)
+                +  3
+                +  Asn1OutputStream.GetLengthOfContents(m_contentsElements);
+        }
+    }
+}
diff --git a/crypto/src/asn1/ConstructedLazyDLEncoding.cs b/crypto/src/asn1/ConstructedLazyDLEncoding.cs
new file mode 100644
index 000000000..3847b465b
--- /dev/null
+++ b/crypto/src/asn1/ConstructedLazyDLEncoding.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+    internal class ConstructedLazyDLEncoding
+        : IAsn1Encoding
+    {
+        private readonly int m_tagClass;
+        private readonly int m_tagNo;
+        private readonly byte[] m_contentsOctets;
+
+        internal ConstructedLazyDLEncoding(int tagClass, int tagNo, byte[] contentsOctets)
+        {
+            m_tagClass = tagClass;
+            m_tagNo = tagNo;
+            m_contentsOctets = contentsOctets;
+        }
+
+        void IAsn1Encoding.Encode(Asn1OutputStream asn1Out)
+        {
+            asn1Out.WriteIdentifier(Asn1Tags.Constructed | m_tagClass, m_tagNo);
+            asn1Out.WriteDL(m_contentsOctets.Length);
+            asn1Out.Write(m_contentsOctets, 0, m_contentsOctets.Length);
+        }
+
+        int IAsn1Encoding.GetLength()
+        {
+            return Asn1OutputStream.GetLengthOfIdentifier(m_tagNo)
+                +  Asn1OutputStream.GetLengthOfDL(m_contentsOctets.Length)
+                +  m_contentsOctets.Length;
+        }
+    }
+}
diff --git a/crypto/src/asn1/DERExternal.cs b/crypto/src/asn1/DERExternal.cs
index 32fc8d6d8..67dad0534 100644
--- a/crypto/src/asn1/DERExternal.cs
+++ b/crypto/src/asn1/DERExternal.cs
@@ -155,21 +155,14 @@ namespace Org.BouncyCastle.Asn1
             return new DerSequence(v);
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            //return BuildSequence().EncodeConstructed(encoding);
-            return true;
+            return BuildSequence().GetEncodingImplicit(encoding, Asn1Tags.Universal, Asn1Tags.External);
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return BuildSequence().EncodedLength(encoding, withID);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteIdentifier(withID, Asn1Tags.Constructed | Asn1Tags.External);
-            BuildSequence().Encode(asn1Out, false);
+            return BuildSequence().GetEncodingImplicit(encoding, tagClass, tagNo);
         }
 
         protected override int Asn1GetHashCode()
diff --git a/crypto/src/asn1/DLSequence.cs b/crypto/src/asn1/DLSequence.cs
index 0fede574a..8cf8d5bcb 100644
--- a/crypto/src/asn1/DLSequence.cs
+++ b/crypto/src/asn1/DLSequence.cs
@@ -12,8 +12,6 @@ namespace Org.BouncyCastle.Asn1
             return elementVector.Count < 1 ? Empty : new DLSequence(elementVector);
         }
 
-        private int m_contentsLengthDL = -1;
-
         /**
 		 * create an empty sequence
 		 */
@@ -48,73 +46,27 @@ namespace Org.BouncyCastle.Asn1
         {
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
             if (Asn1OutputStream.EncodingDer == encoding)
-                return base.EncodedLength(encoding, withID);
+                return base.GetEncoding(encoding);
 
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, GetContentsLengthDL());
+            return new ConstructedDLEncoding(Asn1Tags.Universal, Asn1Tags.Sequence,
+                Asn1OutputStream.GetContentsEncodings(encoding, elements));
         }
 
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            if (Asn1OutputStream.EncodingDer == asn1Out.Encoding)
-            {
-                base.Encode(asn1Out, withID);
-                return;
-            }
-
-            // TODO[asn1] Use DL encoding when supported
-            //asn1Out = asn1Out.GetDLSubStream();
-
-            asn1Out.WriteIdentifier(withID, Asn1Tags.Constructed | Asn1Tags.Sequence);
-
-            int count = elements.Length;
-            if (m_contentsLengthDL >= 0 || count > 16)
-            {
-                asn1Out.WriteDL(GetContentsLengthDL());
-
-                for (int i = 0; i < count; ++i)
-                {
-                    Asn1Object asn1Object = elements[i].ToAsn1Object();
-                    asn1Object.Encode(asn1Out, true);
-                }
-            }
-            else
-            {
-                int contentsLength = 0;
-
-                Asn1Object[] asn1Objects = new Asn1Object[count];
-                for (int i = 0; i < count; ++i)
-                {
-                    Asn1Object asn1Object = elements[i].ToAsn1Object();
-                    asn1Objects[i] = asn1Object;
-                    contentsLength += asn1Object.EncodedLength(asn1Out.Encoding, true);
-                }
-
-                this.m_contentsLengthDL = contentsLength;
-                asn1Out.WriteDL(contentsLength);
+            if (Asn1OutputStream.EncodingDer == encoding)
+                return base.GetEncodingImplicit(encoding, tagClass, tagNo);
 
-                for (int i = 0; i < count; ++i)
-                {
-                    asn1Objects[i].Encode(asn1Out, true);
-                }
-            }
+            return new ConstructedDLEncoding(tagClass, tagNo,
+                Asn1OutputStream.GetContentsEncodings(encoding, elements));
         }
 
         internal override Asn1Set ToAsn1Set()
         {
             return new DLSet(false, elements);
         }
-
-        private int GetContentsLengthDL()
-        {
-            if (m_contentsLengthDL < 0)
-            {
-                // TODO[asn1] Use DL encoding when supported
-                m_contentsLengthDL = CalculateContentsLength(Asn1OutputStream.EncodingBer);
-            }
-            return m_contentsLengthDL;
-        }
     }
 }
diff --git a/crypto/src/asn1/DLSet.cs b/crypto/src/asn1/DLSet.cs
index 7dcac25c2..ba55be826 100644
--- a/crypto/src/asn1/DLSet.cs
+++ b/crypto/src/asn1/DLSet.cs
@@ -12,8 +12,6 @@ namespace Org.BouncyCastle.Asn1
             return elementVector.Count < 1 ? Empty : new DLSet(elementVector);
         }
 
-        private int m_contentsLengthDL = -1;
-
         /**
          * create an empty set
          */
@@ -48,80 +46,22 @@ namespace Org.BouncyCastle.Asn1
         {
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
             if (Asn1OutputStream.EncodingDer == encoding)
-                return base.EncodedLength(encoding, withID);
-
-            // TODO[asn1] Force DL encoding when supported
-            //encoding = Asn1OutputStream.EncodingDL;
-
-            int count = elements.Length;
-            int contentsLength = 0;
-
-            for (int i = 0; i < count; ++i)
-            {
-                Asn1Object asn1Object = elements[i].ToAsn1Object();
-                contentsLength += asn1Object.EncodedLength(encoding, true);
-            }
+                return base.GetEncoding(encoding);
 
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, contentsLength);
+            return new ConstructedDLEncoding(Asn1Tags.Universal, Asn1Tags.Set,
+                Asn1OutputStream.GetContentsEncodings(encoding, elements));
         }
 
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            if (Asn1OutputStream.EncodingDer == asn1Out.Encoding)
-            {
-                base.Encode(asn1Out, withID);
-                return;
-            }
-
-            // TODO[asn1] Force DL encoding when supported
-            //asn1Out = asn1Out.GetDLSubStream();
-
-            asn1Out.WriteIdentifier(withID, Asn1Tags.Constructed | Asn1Tags.Set);
-
-            int count = elements.Length;
-            if (m_contentsLengthDL >= 0 || count > 16)
-            {
-                asn1Out.WriteDL(GetContentsLengthDL());
-
-                for (int i = 0; i < count; ++i)
-                {
-                    Asn1Object asn1Object = elements[i].ToAsn1Object();
-                    asn1Object.Encode(asn1Out, true);
-                }
-            }
-            else
-            {
-                int contentsLength = 0;
-
-                Asn1Object[] asn1Objects = new Asn1Object[count];
-                for (int i = 0; i < count; ++i)
-                {
-                    Asn1Object asn1Object = elements[i].ToAsn1Object();
-                    asn1Objects[i] = asn1Object;
-                    contentsLength += asn1Object.EncodedLength(asn1Out.Encoding, true);
-                }
-
-                this.m_contentsLengthDL = contentsLength;
-                asn1Out.WriteDL(contentsLength);
-
-                for (int i = 0; i < count; ++i)
-                {
-                    asn1Objects[i].Encode(asn1Out, true);
-                }
-            }
-        }
+            if (Asn1OutputStream.EncodingDer == encoding)
+                return base.GetEncodingImplicit(encoding, tagClass, tagNo);
 
-        private int GetContentsLengthDL()
-        {
-            if (m_contentsLengthDL < 0)
-            {
-                // TODO[asn1] Use DL encoding when supported
-                m_contentsLengthDL = CalculateContentsLength(Asn1OutputStream.EncodingBer);
-            }
-            return m_contentsLengthDL;
+            return new ConstructedDLEncoding(tagClass, tagNo,
+                Asn1OutputStream.GetContentsEncodings(encoding, elements));
         }
     }
 }
diff --git a/crypto/src/asn1/DLTaggedObject.cs b/crypto/src/asn1/DLTaggedObject.cs
index 314b42799..c06dd8e87 100644
--- a/crypto/src/asn1/DLTaggedObject.cs
+++ b/crypto/src/asn1/DLTaggedObject.cs
@@ -5,8 +5,6 @@ namespace Org.BouncyCastle.Asn1
     internal class DLTaggedObject
         : DerTaggedObject
     {
-        private int m_contentsLengthDL = -1;
-
         internal DLTaggedObject(int tagNo, Asn1Encodable obj)
             : base(tagNo, obj)
         {
@@ -38,68 +36,30 @@ namespace Org.BouncyCastle.Asn1
             get { return Ber; }
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
             if (Asn1OutputStream.EncodingDer == encoding)
-                return base.EncodeConstructed(encoding);
-
-            // TODO[asn1] Use DL encoding when supported
-            //encoding = Asn1OutputStream.EncodingDL;
-
-            return IsExplicit() || GetBaseObject().ToAsn1Object().EncodeConstructed(encoding);
-        }
-
-        internal override int EncodedLength(int encoding, bool withID)
-        {
-            if (Asn1OutputStream.EncodingDer == encoding)
-                return base.EncodedLength(encoding, withID);
+                return base.GetEncoding(encoding);
 
             Asn1Object baseObject = GetBaseObject().ToAsn1Object();
-            bool withBaseID = IsExplicit();
-
-            int length = GetContentsLengthDL(baseObject, withBaseID);
 
-            if (withBaseID)
-            {
-                length += Asn1OutputStream.GetLengthOfDL(length);
-            }
+            if (!IsExplicit())
+                return baseObject.GetEncodingImplicit(encoding, TagClass, TagNo);
 
-            length += withID ? Asn1OutputStream.GetLengthOfIdentifier(TagNo) : 0;
-
-            return length;
+            return new ConstructedDLEncoding(TagClass, TagNo, new IAsn1Encoding[]{ baseObject.GetEncoding(encoding) });
         }
 
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            if (Asn1OutputStream.EncodingDer == asn1Out.Encoding)
-            {
-                base.Encode(asn1Out, withID);
-                return;
-            }
-
-            // TODO[asn1] Use DL encoding when supported
-            //asn1Out = asn1Out.GetDLSubStream();
+            if (Asn1OutputStream.EncodingDer == encoding)
+                return base.GetEncodingImplicit(encoding, tagClass, tagNo);
 
             Asn1Object baseObject = GetBaseObject().ToAsn1Object();
-            bool withBaseID = IsExplicit();
-
-            if (withID)
-            {
-                int flags = TagClass;
-                if (withBaseID || baseObject.EncodeConstructed(asn1Out.Encoding))
-                {
-                    flags |= Asn1Tags.Constructed;
-                }
 
-                asn1Out.WriteIdentifier(true, flags, TagNo);
-            }
+            if (!IsExplicit())
+                return baseObject.GetEncodingImplicit(encoding, tagClass, tagNo);
 
-            if (withBaseID)
-            {
-                asn1Out.WriteDL(GetContentsLengthDL(baseObject, true));
-            }
-
-            baseObject.Encode(asn1Out, withBaseID);
+            return new ConstructedDLEncoding(tagClass, tagNo, new IAsn1Encoding[]{ baseObject.GetEncoding(encoding) });
         }
 
         internal override Asn1Sequence RebuildConstructed(Asn1Object asn1Object)
@@ -111,15 +71,5 @@ namespace Org.BouncyCastle.Asn1
         {
             return new DLTaggedObject(explicitness, tagClass, tagNo, obj);
         }
-
-        private int GetContentsLengthDL(Asn1Object baseObject, bool withBaseID)
-        {
-            if (m_contentsLengthDL < 0)
-            {
-                // TODO[asn1] Use DL encoding when supported
-                m_contentsLengthDL = baseObject.EncodedLength(Asn1OutputStream.EncodingBer, withBaseID);
-            }
-            return m_contentsLengthDL;
-        }
     }
 }
diff --git a/crypto/src/asn1/DerApplicationSpecific.cs b/crypto/src/asn1/DerApplicationSpecific.cs
index 39c2aec28..13b725325 100644
--- a/crypto/src/asn1/DerApplicationSpecific.cs
+++ b/crypto/src/asn1/DerApplicationSpecific.cs
@@ -134,6 +134,7 @@ namespace Org.BouncyCastle.Asn1
             return m_taggedObject.HasTag(Asn1Tags.Application, tagNo);
         }
 
+        [Obsolete("Will be removed")]
         public bool IsConstructed()
         {
             return m_taggedObject.IsConstructed();
@@ -175,19 +176,14 @@ namespace Org.BouncyCastle.Asn1
             return m_taggedObject.CallAsn1GetHashCode();
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return m_taggedObject.EncodeConstructed(encoding);
+            return m_taggedObject.GetEncoding(encoding);
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return m_taggedObject.EncodedLength(encoding, withID);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            m_taggedObject.Encode(asn1Out, withID);
+            return m_taggedObject.GetEncodingImplicit(encoding, tagClass, tagNo);
         }
 
         private byte[] ReplaceTagNumber(int newTag, byte[] input)
diff --git a/crypto/src/asn1/DerBMPString.cs b/crypto/src/asn1/DerBMPString.cs
index d3c7b3b46..4e35dfff8 100644
--- a/crypto/src/asn1/DerBMPString.cs
+++ b/crypto/src/asn1/DerBMPString.cs
@@ -111,28 +111,28 @@ namespace Org.BouncyCastle.Asn1
 			return this.str.Equals(other.str);
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.BmpString, GetContents());
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, str.Length * 2);
+            return new PrimitiveEncoding(tagClass, tagNo, GetContents());
         }
 
-		internal override void Encode(Asn1OutputStream asn1Out, bool withID)
+        private byte[] GetContents()
         {
             char[] c = str.ToCharArray();
             byte[] b = new byte[c.Length * 2];
 
-			for (int i = 0; i != c.Length; i++)
+            for (int i = 0; i != c.Length; i++)
             {
                 b[2 * i] = (byte)(c[i] >> 8);
                 b[2 * i + 1] = (byte)c[i];
             }
 
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.BmpString, b);
+            return b;
         }
     }
 }
diff --git a/crypto/src/asn1/DerBitString.cs b/crypto/src/asn1/DerBitString.cs
index 2814b9677..375abb479 100644
--- a/crypto/src/asn1/DerBitString.cs
+++ b/crypto/src/asn1/DerBitString.cs
@@ -216,34 +216,37 @@ namespace Org.BouncyCastle.Asn1
             }
 		}
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
-        }
+            int padBits = contents[0];
+            if (padBits != 0)
+            {
+                int last = contents.Length - 1;
+                byte lastBer = contents[last];
+                byte lastDer = (byte)(lastBer & (0xFF << padBits));
 
-        internal override int EncodedLength(int encoding, bool withID)
-        {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, contents.Length);
+                if (lastBer != lastDer)
+                    return new PrimitiveEncodingSuffixed(Asn1Tags.Universal, Asn1Tags.BitString, contents, lastDer);
+            }
+
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.BitString, contents);
         }
 
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-		{
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
+        {
             int padBits = contents[0];
-            int length = contents.Length;
-            int last = length - 1;
-
-            byte lastOctet = contents[last];
-            byte lastOctetDer = (byte)(contents[last] & (0xFF << padBits));
-
-            if (lastOctet == lastOctetDer)
-            {
-                asn1Out.WriteEncodingDL(withID, Asn1Tags.BitString, contents);
-            }
-            else
+            if (padBits != 0)
             {
-                asn1Out.WriteEncodingDL(withID, Asn1Tags.BitString, contents, 0, last, lastOctetDer);
+                int last = contents.Length - 1;
+                byte lastBer = contents[last];
+                byte lastDer = (byte)(lastBer & (0xFF << padBits));
+
+                if (lastBer != lastDer)
+                    return new PrimitiveEncodingSuffixed(tagClass, tagNo, contents, lastDer);
             }
-		}
+
+            return new PrimitiveEncoding(tagClass, tagNo, contents);
+        }
 
         protected override int Asn1GetHashCode()
 		{
@@ -253,11 +256,11 @@ namespace Org.BouncyCastle.Asn1
             int padBits = contents[0];
             int last = contents.Length - 1;
 
-            byte lastOctetDer = (byte)(contents[last] & (0xFF << padBits));
+            byte lastDer = (byte)(contents[last] & (0xFF << padBits));
 
             int hc = Arrays.GetHashCode(contents, 0, last);
             hc *= 257;
-            hc ^= lastOctetDer;
+            hc ^= lastDer;
             return hc;
         }
 
@@ -283,10 +286,10 @@ namespace Org.BouncyCastle.Asn1
             }
 
             int padBits = thisContents[0];
-            byte thisLastOctetDer = (byte)(thisContents[last] & (0xFF << padBits));
-            byte thatLastOctetDer = (byte)(thatContents[last] & (0xFF << padBits));
+            byte thisLastDer = (byte)(thisContents[last] & (0xFF << padBits));
+            byte thatLastDer = (byte)(thatContents[last] & (0xFF << padBits));
 
-            return thisLastOctetDer == thatLastOctetDer;
+            return thisLastDer == thatLastDer;
         }
 
         public override string GetString()
@@ -306,21 +309,6 @@ namespace Org.BouncyCastle.Asn1
 			return buffer.ToString();
 		}
 
-        internal static int EncodedLength(bool withID, int contentsLength)
-        {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, contentsLength);
-        }
-
-        internal static void Encode(Asn1OutputStream asn1Out, bool withID, byte[] buf, int off, int len)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.BitString, buf, off, len);
-        }
-
-        internal static void Encode(Asn1OutputStream asn1Out, bool withID, byte pad, byte[] buf, int off, int len)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.BitString, pad, buf, off, len);
-        }
-
 		internal static DerBitString CreatePrimitive(byte[] contents)
 		{
             int length = contents.Length;
diff --git a/crypto/src/asn1/DerBoolean.cs b/crypto/src/asn1/DerBoolean.cs
index a6f972629..29e2d8bd9 100644
--- a/crypto/src/asn1/DerBoolean.cs
+++ b/crypto/src/asn1/DerBoolean.cs
@@ -81,25 +81,14 @@ namespace Org.BouncyCastle.Asn1
             get { return value != 0; }
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.Boolean, GetContents(encoding));
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, 1);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            byte contents = value;
-            if (Asn1OutputStream.EncodingDer == asn1Out.Encoding && IsTrue)
-            {
-                contents = 0xFF;
-            }
-
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.Boolean, contents);
+            return new PrimitiveEncoding(tagClass, tagNo, GetContents(encoding));
         }
 
         protected override bool Asn1Equals(
@@ -134,5 +123,16 @@ namespace Org.BouncyCastle.Asn1
 
             return b == 0 ? False : b == 0xFF ? True : new DerBoolean(value);
         }
+
+        private byte[] GetContents(int encoding)
+        {
+            byte contents = value;
+            if (Asn1OutputStream.EncodingDer == encoding && IsTrue)
+            {
+                contents = 0xFF;
+            }
+
+            return new byte[]{ contents };
+        }
     }
 }
diff --git a/crypto/src/asn1/DerEnumerated.cs b/crypto/src/asn1/DerEnumerated.cs
index af9e6330a..6fd2f9b62 100644
--- a/crypto/src/asn1/DerEnumerated.cs
+++ b/crypto/src/asn1/DerEnumerated.cs
@@ -119,19 +119,14 @@ namespace Org.BouncyCastle.Asn1
             }
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.Enumerated, bytes);
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, bytes.Length);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.Enumerated, bytes);
+            return new PrimitiveEncoding(tagClass, tagNo, bytes);
         }
 
         protected override bool Asn1Equals(Asn1Object asn1Object)
diff --git a/crypto/src/asn1/DerGeneralString.cs b/crypto/src/asn1/DerGeneralString.cs
index f5575650b..f2a47c370 100644
--- a/crypto/src/asn1/DerGeneralString.cs
+++ b/crypto/src/asn1/DerGeneralString.cs
@@ -61,19 +61,14 @@ namespace Org.BouncyCastle.Asn1
             return Strings.ToAsciiByteArray(str);
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.GeneralString, GetOctets());
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, str.Length);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.GeneralString, GetOctets());
+            return new PrimitiveEncoding(tagClass, tagNo, GetOctets());
         }
 
         protected override bool Asn1Equals(
diff --git a/crypto/src/asn1/DerGeneralizedTime.cs b/crypto/src/asn1/DerGeneralizedTime.cs
index e70a481dc..41c897751 100644
--- a/crypto/src/asn1/DerGeneralizedTime.cs
+++ b/crypto/src/asn1/DerGeneralizedTime.cs
@@ -295,19 +295,14 @@ namespace Org.BouncyCastle.Asn1
             return Strings.ToAsciiByteArray(time);
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.GeneralizedTime, GetOctets());
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, time.Length);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.GeneralizedTime, GetOctets());
+            return new PrimitiveEncoding(tagClass, tagNo, GetOctets());
         }
 
         protected override bool Asn1Equals(
diff --git a/crypto/src/asn1/DerGraphicString.cs b/crypto/src/asn1/DerGraphicString.cs
index 4a864ea8c..52ccb7e93 100644
--- a/crypto/src/asn1/DerGraphicString.cs
+++ b/crypto/src/asn1/DerGraphicString.cs
@@ -83,19 +83,14 @@ namespace Org.BouncyCastle.Asn1
             return Arrays.Clone(m_contents);
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.GraphicString, m_contents);
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, m_contents.Length);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.GraphicString, m_contents);
+            return new PrimitiveEncoding(tagClass, tagNo, m_contents);
         }
 
         protected override int Asn1GetHashCode()
diff --git a/crypto/src/asn1/DerIA5String.cs b/crypto/src/asn1/DerIA5String.cs
index 97a9222c2..d608930fd 100644
--- a/crypto/src/asn1/DerIA5String.cs
+++ b/crypto/src/asn1/DerIA5String.cs
@@ -100,19 +100,14 @@ namespace Org.BouncyCastle.Asn1
             return Strings.ToAsciiByteArray(str);
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.IA5String, GetOctets());
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, str.Length);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.IA5String, GetOctets());
+            return new PrimitiveEncoding(tagClass, tagNo, GetOctets());
         }
 
         protected override int Asn1GetHashCode()
diff --git a/crypto/src/asn1/DerInteger.cs b/crypto/src/asn1/DerInteger.cs
index 36fd58870..8b112f693 100644
--- a/crypto/src/asn1/DerInteger.cs
+++ b/crypto/src/asn1/DerInteger.cs
@@ -169,19 +169,14 @@ namespace Org.BouncyCastle.Asn1
             }
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.Integer, bytes);
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, bytes.Length);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.Integer, bytes);
+            return new PrimitiveEncoding(tagClass, tagNo, bytes);
         }
 
         protected override int Asn1GetHashCode()
diff --git a/crypto/src/asn1/DerNull.cs b/crypto/src/asn1/DerNull.cs
index 947acaf0b..ddf61391b 100644
--- a/crypto/src/asn1/DerNull.cs
+++ b/crypto/src/asn1/DerNull.cs
@@ -16,19 +16,14 @@ namespace Org.BouncyCastle.Asn1
 		{
 		}
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.Null, ZeroBytes);
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, 0);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-		{
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.Null, ZeroBytes);
+            return new PrimitiveEncoding(tagClass, tagNo, ZeroBytes);
         }
 
         protected override bool Asn1Equals(Asn1Object asn1Object)
diff --git a/crypto/src/asn1/DerNumericString.cs b/crypto/src/asn1/DerNumericString.cs
index 4412f973e..bec0c3a52 100644
--- a/crypto/src/asn1/DerNumericString.cs
+++ b/crypto/src/asn1/DerNumericString.cs
@@ -100,19 +100,14 @@ namespace Org.BouncyCastle.Asn1
             return Strings.ToAsciiByteArray(str);
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.NumericString, GetOctets());
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, str.Length);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.NumericString, GetOctets());
+            return new PrimitiveEncoding(tagClass, tagNo, GetOctets());
         }
 
         protected override bool Asn1Equals(
diff --git a/crypto/src/asn1/DerObjectIdentifier.cs b/crypto/src/asn1/DerObjectIdentifier.cs
index f24bbf984..f91ad2150 100644
--- a/crypto/src/asn1/DerObjectIdentifier.cs
+++ b/crypto/src/asn1/DerObjectIdentifier.cs
@@ -128,19 +128,14 @@ namespace Org.BouncyCastle.Asn1
             return identifier.GetHashCode();
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.ObjectIdentifier, GetContents());
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, GetContents().Length);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.ObjectIdentifier, GetContents());
+            return new PrimitiveEncoding(tagClass, tagNo, GetContents());
         }
 
         private void DoOutput(MemoryStream bOut)
diff --git a/crypto/src/asn1/DerOctetString.cs b/crypto/src/asn1/DerOctetString.cs
index d49393641..d9913f065 100644
--- a/crypto/src/asn1/DerOctetString.cs
+++ b/crypto/src/asn1/DerOctetString.cs
@@ -21,29 +21,21 @@ namespace Org.BouncyCastle.Asn1
         {
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.OctetString, contents);
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, contents.Length);
+            return new PrimitiveEncoding(tagClass, tagNo, contents);
         }
 
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.OctetString, contents);
-        }
-
-        internal static void Encode(Asn1OutputStream asn1Out, bool withID, byte[] buf, int off, int len)
+        internal static void Encode(Asn1OutputStream asn1Out, byte[] buf, int off, int len)
 		{
-			asn1Out.WriteEncodingDL(withID, Asn1Tags.OctetString, buf, off, len);
-		}
-
-        internal static int EncodedLength(bool withID, int contentsLength)
-        {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, contentsLength);
+            asn1Out.WriteIdentifier(Asn1Tags.Universal, Asn1Tags.OctetString);
+            asn1Out.WriteDL(len);
+            asn1Out.Write(buf, off, len);
         }
     }
 }
diff --git a/crypto/src/asn1/DerOutputStream.cs b/crypto/src/asn1/DerOutputStream.cs
index dda9ce1c0..4c7dd1fd7 100644
--- a/crypto/src/asn1/DerOutputStream.cs
+++ b/crypto/src/asn1/DerOutputStream.cs
@@ -34,11 +34,6 @@ namespace Org.BouncyCastle.Asn1
         {
         }
 
-        internal override DerOutputStreamNew GetDerSubStream()
-        {
-            return this;
-        }
-
         internal override int Encoding
         {
             get { return EncodingDer; }
diff --git a/crypto/src/asn1/DerPrintableString.cs b/crypto/src/asn1/DerPrintableString.cs
index 3d911a6ac..30358e219 100644
--- a/crypto/src/asn1/DerPrintableString.cs
+++ b/crypto/src/asn1/DerPrintableString.cs
@@ -99,19 +99,14 @@ namespace Org.BouncyCastle.Asn1
             return Strings.ToAsciiByteArray(str);
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.PrintableString, GetOctets());
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, str.Length);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.PrintableString, GetOctets());
+            return new PrimitiveEncoding(tagClass, tagNo, GetOctets());
         }
 
         protected override bool Asn1Equals(
diff --git a/crypto/src/asn1/DerSequence.cs b/crypto/src/asn1/DerSequence.cs
index e60796091..2ac977fe0 100644
--- a/crypto/src/asn1/DerSequence.cs
+++ b/crypto/src/asn1/DerSequence.cs
@@ -12,8 +12,6 @@ namespace Org.BouncyCastle.Asn1
             return elementVector.Count < 1 ? Empty : new DerSequence(elementVector);
 		}
 
-        private int m_contentsLengthDer = -1;
-
         /**
 		 * create an empty sequence
 		 */
@@ -48,56 +46,16 @@ namespace Org.BouncyCastle.Asn1
         {
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, GetContentsLengthDer());
+            return new ConstructedDLEncoding(Asn1Tags.Universal, Asn1Tags.Sequence,
+                Asn1OutputStream.GetContentsEncodings(Asn1OutputStream.EncodingDer, elements));
         }
 
-        /*
-		 * A note on the implementation:
-		 * <p>
-		 * As Der requires the constructed, definite-length model to
-		 * be used for structured types, this varies slightly from the
-		 * ASN.1 descriptions given. Rather than just outputing Sequence,
-		 * we also have to specify Constructed, and the objects length.
-		 */
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            asn1Out = asn1Out.GetDerSubStream();
-
-            asn1Out.WriteIdentifier(withID, Asn1Tags.Constructed | Asn1Tags.Sequence);
-
-            int count = elements.Length;
-            if (m_contentsLengthDer >= 0 || count > 16)
-            {
-                asn1Out.WriteDL(GetContentsLengthDer());
-
-                for (int i = 0; i < count; ++i)
-                {
-                    Asn1Object asn1Object = elements[i].ToAsn1Object();
-                    asn1Object.Encode(asn1Out, true);
-                }
-            }
-            else
-            {
-                int contentsLength = 0;
-
-                Asn1Object[] asn1Objects = new Asn1Object[count];
-                for (int i = 0; i < count; ++i)
-                {
-                    Asn1Object asn1Object = elements[i].ToAsn1Object();
-                    asn1Objects[i] = asn1Object;
-                    contentsLength += asn1Object.EncodedLength(asn1Out.Encoding, true);
-                }
-
-                this.m_contentsLengthDer = contentsLength;
-                asn1Out.WriteDL(contentsLength);
-
-                for (int i = 0; i < count; ++i)
-                {
-                    asn1Objects[i].Encode(asn1Out, true);
-                }
-            }
+            return new ConstructedDLEncoding(tagClass, tagNo,
+                Asn1OutputStream.GetContentsEncodings(Asn1OutputStream.EncodingDer, elements));
         }
 
         internal override DerBitString ToAsn1BitString()
@@ -120,14 +78,5 @@ namespace Org.BouncyCastle.Asn1
             // NOTE: DLSet is intentional, we don't want sorting
             return new DLSet(false, elements);
         }
-
-        private int GetContentsLengthDer()
-        {
-            if (m_contentsLengthDer < 0)
-            {
-                m_contentsLengthDer = CalculateContentsLength(Asn1OutputStream.EncodingDer);
-            }
-            return m_contentsLengthDer;
-        }
     }
 }
diff --git a/crypto/src/asn1/DerSet.cs b/crypto/src/asn1/DerSet.cs
index d89285d9e..3e52094c3 100644
--- a/crypto/src/asn1/DerSet.cs
+++ b/crypto/src/asn1/DerSet.cs
@@ -15,8 +15,6 @@ namespace Org.BouncyCastle.Asn1
             return elementVector.Count < 1 ? Empty : new DerSet(elementVector);
 		}
 
-        private int m_contentsLengthDer = -1;
-
         /**
 		 * create an empty set
 		 */
@@ -61,88 +59,31 @@ namespace Org.BouncyCastle.Asn1
         {
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            encoding = Asn1OutputStream.EncodingDer;
-
-            int count = elements.Length;
-            int contentsLength = 0;
-
-            for (int i = 0; i < count; ++i)
-            {
-                Asn1Object asn1Object = elements[i].ToAsn1Object();
-                contentsLength += asn1Object.EncodedLength(encoding, true);
-            }
-
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, contentsLength);
+            return new ConstructedDLEncoding(Asn1Tags.Universal, Asn1Tags.Set,
+                Asn1OutputStream.GetContentsEncodings(Asn1OutputStream.EncodingDer, GetSortedElements()));
         }
 
-        /*
-		 * A note on the implementation:
-		 * <p>
-		 * As Der requires the constructed, definite-length model to
-		 * be used for structured types, this varies slightly from the
-		 * ASN.1 descriptions given. Rather than just outputing Set,
-		 * we also have to specify Constructed, and the objects length.
-		 */
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            if (Count < 1)
-            {
-                asn1Out.WriteEncodingDL(withID, Asn1Tags.Constructed | Asn1Tags.Set, Asn1OctetString.EmptyOctets);
-                return;
-            }
-
-            Asn1Encodable[] elements = this.elements;
-            if (!isSorted)
-            {
-                elements = Sort((Asn1Encodable[])elements.Clone());
-            }
-
-            asn1Out = asn1Out.GetDerSubStream();
+            return new ConstructedDLEncoding(tagClass, tagNo,
+                Asn1OutputStream.GetContentsEncodings(Asn1OutputStream.EncodingDer, GetSortedElements()));
+        }
 
-            asn1Out.WriteIdentifier(withID, Asn1Tags.Constructed | Asn1Tags.Set);
+        private Asn1Encodable[] GetSortedElements()
+        {
+            if (isSorted)
+                return elements;
 
             int count = elements.Length;
-            if (m_contentsLengthDer >= 0 || count > 16)
-            {
-                asn1Out.WriteDL(GetContentsLengthDer());
-
-                for (int i = 0; i < count; ++i)
-                {
-                    Asn1Object asn1Object = elements[i].ToAsn1Object();
-                    asn1Object.Encode(asn1Out, true);
-                }
-            }
-            else
+            Asn1Object[] asn1Objects = new Asn1Object[count];
+            for (int i = 0; i < count; ++i)
             {
-                int contentsLength = 0;
-
-                Asn1Object[] asn1Objects = new Asn1Object[count];
-                for (int i = 0; i < count; ++i)
-                {
-                    Asn1Object asn1Object = elements[i].ToAsn1Object();
-                    asn1Objects[i] = asn1Object;
-                    contentsLength += asn1Object.EncodedLength(asn1Out.Encoding, true);
-                }
-
-                this.m_contentsLengthDer = contentsLength;
-                asn1Out.WriteDL(contentsLength);
-
-                for (int i = 0; i < count; ++i)
-                {
-                    asn1Objects[i].Encode(asn1Out, true);
-                }
+                asn1Objects[i] = elements[i].ToAsn1Object();
             }
-        }
 
-        private int GetContentsLengthDer()
-        {
-            if (m_contentsLengthDer < 0)
-            {
-                m_contentsLengthDer = CalculateContentsLength(Asn1OutputStream.EncodingDer);
-            }
-            return m_contentsLengthDer;
+            return Sort(asn1Objects);
         }
     }
 }
diff --git a/crypto/src/asn1/DerT61String.cs b/crypto/src/asn1/DerT61String.cs
index 79a7ef8e4..64a9bd469 100644
--- a/crypto/src/asn1/DerT61String.cs
+++ b/crypto/src/asn1/DerT61String.cs
@@ -77,19 +77,14 @@ namespace Org.BouncyCastle.Asn1
             return str;
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.T61String, GetOctets());
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, str.Length);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.T61String, GetOctets());
+            return new PrimitiveEncoding(tagClass, tagNo, GetOctets());
         }
 
         public byte[] GetOctets()
diff --git a/crypto/src/asn1/DerTaggedObject.cs b/crypto/src/asn1/DerTaggedObject.cs
index 66f804ebb..68a32e435 100644
--- a/crypto/src/asn1/DerTaggedObject.cs
+++ b/crypto/src/asn1/DerTaggedObject.cs
@@ -10,8 +10,6 @@ namespace Org.BouncyCastle.Asn1
 	public class DerTaggedObject
 		: Asn1TaggedObject
 	{
-        private int m_contentsLengthDer = -1;
-
         /**
 		 * create an implicitly tagged object that contains a zero
 		 * length sequence.
@@ -57,56 +55,28 @@ namespace Org.BouncyCastle.Asn1
             get { return Der; }
         }
 
-        internal override bool EncodeConstructed(int encoding)
-        {
-            encoding = Asn1OutputStream.EncodingDer;
-
-            return IsExplicit() || GetBaseObject().ToAsn1Object().EncodeConstructed(encoding);
-        }
-
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
             encoding = Asn1OutputStream.EncodingDer;
 
             Asn1Object baseObject = GetBaseObject().ToAsn1Object();
-            bool withBaseID = IsExplicit();
-
-            int length = GetContentsLengthDer(baseObject, withBaseID);
 
-            if (withBaseID)
-            {
-                length += Asn1OutputStream.GetLengthOfDL(length);
-            }
+            if (!IsExplicit())
+                return baseObject.GetEncodingImplicit(encoding, TagClass, TagNo);
 
-            length += withID ? Asn1OutputStream.GetLengthOfIdentifier(TagNo) : 0;
-
-            return length;
+            return new ConstructedDLEncoding(TagClass, TagNo, new IAsn1Encoding[]{ baseObject.GetEncoding(encoding) });
         }
 
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            asn1Out = asn1Out.GetDerSubStream();
+            encoding = Asn1OutputStream.EncodingDer;
 
             Asn1Object baseObject = GetBaseObject().ToAsn1Object();
-            bool withBaseID = IsExplicit();
-
-            if (withID)
-            {
-                int flags = TagClass;
-                if (withBaseID || baseObject.EncodeConstructed(asn1Out.Encoding))
-                {
-                    flags |= Asn1Tags.Constructed;
-                }
-
-                asn1Out.WriteIdentifier(true, flags, TagNo);
-            }
 
-            if (withBaseID)
-            {
-                asn1Out.WriteDL(GetContentsLengthDer(baseObject, true));
-            }
+            if (!IsExplicit())
+                return baseObject.GetEncodingImplicit(encoding, tagClass, tagNo);
 
-            baseObject.Encode(asn1Out, withBaseID);
+            return new ConstructedDLEncoding(tagClass, tagNo, new IAsn1Encoding[]{ baseObject.GetEncoding(encoding) });
         }
 
         internal override Asn1Sequence RebuildConstructed(Asn1Object asn1Object)
@@ -118,14 +88,5 @@ namespace Org.BouncyCastle.Asn1
         {
             return new DerTaggedObject(explicitness, tagClass, tagNo, obj);
         }
-
-        private int GetContentsLengthDer(Asn1Object baseObject, bool withBaseID)
-        {
-            if (m_contentsLengthDer < 0)
-            {
-                m_contentsLengthDer = baseObject.EncodedLength(Asn1OutputStream.EncodingDer, withBaseID);
-            }
-            return m_contentsLengthDer;
-        }
     }
 }
diff --git a/crypto/src/asn1/DerUTCTime.cs b/crypto/src/asn1/DerUTCTime.cs
index 17d02df19..eaa902e71 100644
--- a/crypto/src/asn1/DerUTCTime.cs
+++ b/crypto/src/asn1/DerUTCTime.cs
@@ -237,19 +237,14 @@ namespace Org.BouncyCastle.Asn1
             return Strings.ToAsciiByteArray(time);
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.UtcTime, GetOctets());
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, time.Length);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.UtcTime, GetOctets());
+            return new PrimitiveEncoding(tagClass, tagNo, GetOctets());
         }
 
         protected override bool Asn1Equals(
diff --git a/crypto/src/asn1/DerUTF8String.cs b/crypto/src/asn1/DerUTF8String.cs
index 7bc9ff524..24023cd6c 100644
--- a/crypto/src/asn1/DerUTF8String.cs
+++ b/crypto/src/asn1/DerUTF8String.cs
@@ -89,19 +89,14 @@ namespace Org.BouncyCastle.Asn1
 			return this.str.Equals(other.str);
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.Utf8String, Encoding.UTF8.GetBytes(str));
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, Encoding.UTF8.GetByteCount(str));
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.Utf8String, Encoding.UTF8.GetBytes(str));
+            return new PrimitiveEncoding(tagClass, tagNo, Encoding.UTF8.GetBytes(str));
         }
     }
 }
diff --git a/crypto/src/asn1/DerUniversalString.cs b/crypto/src/asn1/DerUniversalString.cs
index ab89a0e12..1ae989f93 100644
--- a/crypto/src/asn1/DerUniversalString.cs
+++ b/crypto/src/asn1/DerUniversalString.cs
@@ -86,19 +86,14 @@ namespace Org.BouncyCastle.Asn1
             return (byte[]) str.Clone();
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.UniversalString, this.str);
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, this.str.Length);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.UniversalString, this.str);
+            return new PrimitiveEncoding(tagClass, tagNo, this.str);
         }
 
         protected override bool Asn1Equals(
diff --git a/crypto/src/asn1/DerVideotexString.cs b/crypto/src/asn1/DerVideotexString.cs
index 5b9ad09f9..3511663d2 100644
--- a/crypto/src/asn1/DerVideotexString.cs
+++ b/crypto/src/asn1/DerVideotexString.cs
@@ -79,19 +79,14 @@ namespace Org.BouncyCastle.Asn1
             return Arrays.Clone(mString);
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.VideotexString, mString);
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, mString.Length);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.VideotexString, mString);
+            return new PrimitiveEncoding(tagClass, tagNo, mString);
         }
 
         protected override int Asn1GetHashCode()
diff --git a/crypto/src/asn1/DerVisibleString.cs b/crypto/src/asn1/DerVisibleString.cs
index 9e34ef65e..cbbd9cc98 100644
--- a/crypto/src/asn1/DerVisibleString.cs
+++ b/crypto/src/asn1/DerVisibleString.cs
@@ -86,19 +86,14 @@ namespace Org.BouncyCastle.Asn1
             return Strings.ToAsciiByteArray(str);
         }
 
-        internal override bool EncodeConstructed(int encoding)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return false;
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.VisibleString, GetOctets());
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return Asn1OutputStream.GetLengthOfEncodingDL(withID, str.Length);
-        }
-
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
-        {
-            asn1Out.WriteEncodingDL(withID, Asn1Tags.VisibleString, GetOctets());
+            return new PrimitiveEncoding(tagClass, tagNo, GetOctets());
         }
 
         protected override bool Asn1Equals(
diff --git a/crypto/src/asn1/IAsn1Encoding.cs b/crypto/src/asn1/IAsn1Encoding.cs
new file mode 100644
index 000000000..557064af8
--- /dev/null
+++ b/crypto/src/asn1/IAsn1Encoding.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+    internal interface IAsn1Encoding
+    {
+        void Encode(Asn1OutputStream asn1Out);
+
+        int GetLength();
+    }
+}
diff --git a/crypto/src/asn1/LazyDLSequence.cs b/crypto/src/asn1/LazyDLSequence.cs
index bf9fc0800..96b9bbca1 100644
--- a/crypto/src/asn1/LazyDLSequence.cs
+++ b/crypto/src/asn1/LazyDLSequence.cs
@@ -63,39 +63,36 @@ namespace Org.BouncyCastle.Asn1
             return base.ToString();
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
             if (Asn1OutputStream.EncodingBer == encoding)
             {
                 byte[] encoded = GetContents();
-                if (null != encoded)
-                    return Asn1OutputStream.GetLengthOfEncodingDL(withID, encoded.Length);
+                if (encoded != null)
+                    return new ConstructedLazyDLEncoding(Asn1Tags.Universal, Asn1Tags.Sequence, encoded);
             }
             else
             {
                 Force();
             }
 
-            return base.EncodedLength(encoding, withID);
+            return base.GetEncoding(encoding);
         }
 
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            if (Asn1OutputStream.EncodingBer == asn1Out.Encoding)
+            if (Asn1OutputStream.EncodingBer == encoding)
             {
                 byte[] encoded = GetContents();
                 if (encoded != null)
-                {
-                    asn1Out.WriteEncodingDL(withID, Asn1Tags.Constructed | Asn1Tags.Sequence, encoded);
-                    return;
-                }
+                    return new ConstructedLazyDLEncoding(tagClass, tagNo, encoded);
             }
             else
             {
                 Force();
             }
 
-            base.Encode(asn1Out, withID);
+            return base.GetEncodingImplicit(encoding, tagClass, tagNo);
         }
 
         private void Force()
diff --git a/crypto/src/asn1/LazyDLSet.cs b/crypto/src/asn1/LazyDLSet.cs
index a426bb4cb..551200513 100644
--- a/crypto/src/asn1/LazyDLSet.cs
+++ b/crypto/src/asn1/LazyDLSet.cs
@@ -32,9 +32,7 @@ namespace Org.BouncyCastle.Asn1
         {
             byte[] encoded = GetContents();
             if (null != encoded)
-            {
                 return new LazyDLEnumerator(encoded);
-            }
 
             return base.GetEnumerator();
         }
@@ -63,39 +61,36 @@ namespace Org.BouncyCastle.Asn1
             return base.ToString();
         }
 
-        internal override int EncodedLength(int encoding, bool withID)
+        internal override IAsn1Encoding GetEncoding(int encoding)
         {
             if (Asn1OutputStream.EncodingBer == encoding)
             {
                 byte[] encoded = GetContents();
                 if (null != encoded)
-                    return Asn1OutputStream.GetLengthOfEncodingDL(withID, encoded.Length);
+                    return new ConstructedLazyDLEncoding(Asn1Tags.Universal, Asn1Tags.Set, encoded);
             }
             else
             {
                 Force();
             }
 
-            return base.EncodedLength(encoding, withID);
+            return base.GetEncoding(encoding);
         }
 
-        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            if (Asn1OutputStream.EncodingBer == asn1Out.Encoding)
+            if (Asn1OutputStream.EncodingBer == encoding)
             {
                 byte[] encoded = GetContents();
-                if (encoded != null)
-                {
-                    asn1Out.WriteEncodingDL(withID, Asn1Tags.Constructed | Asn1Tags.Set, encoded);
-                    return;
-                }
+                if (null != encoded)
+                    return new ConstructedLazyDLEncoding(tagClass, tagNo, encoded);
             }
             else
             {
                 Force();
             }
 
-            base.Encode(asn1Out, withID);
+            return base.GetEncodingImplicit(encoding, tagClass, tagNo);
         }
 
         private void Force()
diff --git a/crypto/src/asn1/PrimitiveEncoding.cs b/crypto/src/asn1/PrimitiveEncoding.cs
new file mode 100644
index 000000000..72c3219ef
--- /dev/null
+++ b/crypto/src/asn1/PrimitiveEncoding.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+    internal class PrimitiveEncoding
+        : IAsn1Encoding
+    {
+        private readonly int m_tagClass;
+        private readonly int m_tagNo;
+        private readonly byte[] m_contentsOctets;
+
+        internal PrimitiveEncoding(int tagClass, int tagNo, byte[] contentsOctets)
+        {
+            m_tagClass = tagClass;
+            m_tagNo = tagNo;
+            m_contentsOctets = contentsOctets;
+        }
+
+        void IAsn1Encoding.Encode(Asn1OutputStream asn1Out)
+        {
+            asn1Out.WriteIdentifier(m_tagClass, m_tagNo);
+            asn1Out.WriteDL(m_contentsOctets.Length);
+            asn1Out.Write(m_contentsOctets, 0, m_contentsOctets.Length);
+        }
+
+        int IAsn1Encoding.GetLength()
+        {
+            return Asn1OutputStream.GetLengthOfIdentifier(m_tagNo)
+                +  Asn1OutputStream.GetLengthOfDL(m_contentsOctets.Length)
+                +  m_contentsOctets.Length;
+        }
+    }
+}
diff --git a/crypto/src/asn1/PrimitiveEncodingSuffixed.cs b/crypto/src/asn1/PrimitiveEncodingSuffixed.cs
new file mode 100644
index 000000000..ef0ef49ac
--- /dev/null
+++ b/crypto/src/asn1/PrimitiveEncodingSuffixed.cs
@@ -0,0 +1,36 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+    internal class PrimitiveEncodingSuffixed
+        : IAsn1Encoding
+    {
+        private readonly int m_tagClass;
+        private readonly int m_tagNo;
+        private readonly byte[] m_contentsOctets;
+        private readonly byte m_contentsSuffix;
+
+        internal PrimitiveEncodingSuffixed(int tagClass, int tagNo, byte[] contentsOctets, byte contentsSuffix)
+        {
+            m_tagClass = tagClass;
+            m_tagNo = tagNo;
+            m_contentsOctets = contentsOctets;
+            m_contentsSuffix = contentsSuffix;
+        }
+
+        void IAsn1Encoding.Encode(Asn1OutputStream asn1Out)
+        {
+            asn1Out.WriteIdentifier(m_tagClass, m_tagNo);
+            asn1Out.WriteDL(m_contentsOctets.Length);
+            asn1Out.Write(m_contentsOctets, 0, m_contentsOctets.Length - 1);
+            asn1Out.WriteByte(m_contentsSuffix);
+        }
+
+        int IAsn1Encoding.GetLength()
+        {
+            return Asn1OutputStream.GetLengthOfIdentifier(m_tagNo)
+                +  Asn1OutputStream.GetLengthOfDL(m_contentsOctets.Length)
+                +  m_contentsOctets.Length;
+        }
+    }
+}