summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-03-05 14:56:01 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-03-05 14:56:01 +0700
commitcc722c1881f86bd2c4690b84f8bd99969a63fc80 (patch)
tree08ffb1d22f99c5d0e16a8e5ca25b4d5362269bd9
parentSupport 'leaveOpen' in Asn1 streams (diff)
downloadBouncyCastle.NET-ed25519-cc722c1881f86bd2c4690b84f8bd99969a63fc80.tar.xz
Improve Asn1 encoding
- reduced allocations for GetEncoded
-rw-r--r--crypto/src/asn1/Asn1Encodable.cs21
-rw-r--r--crypto/src/asn1/Asn1Object.cs47
2 files changed, 39 insertions, 29 deletions
diff --git a/crypto/src/asn1/Asn1Encodable.cs b/crypto/src/asn1/Asn1Encodable.cs
index 15918afb0..a6b8d38b9 100644
--- a/crypto/src/asn1/Asn1Encodable.cs
+++ b/crypto/src/asn1/Asn1Encodable.cs
@@ -18,18 +18,16 @@ namespace Org.BouncyCastle.Asn1
             ToAsn1Object().EncodeTo(output, encoding);
         }
 
+		// TODO[api] Make virtual and override in Asn1Object
 		public byte[] GetEncoded()
         {
-            MemoryStream bOut = new MemoryStream();
-            ToAsn1Object().EncodeTo(bOut);
-            return bOut.ToArray();
+            return ToAsn1Object().InternalGetEncoded(Ber);
         }
 
+        // TODO[api] Make virtual and override in Asn1Object
         public byte[] GetEncoded(string encoding)
         {
-            MemoryStream bOut = new MemoryStream();
-            ToAsn1Object().EncodeTo(bOut, encoding);
-            return bOut.ToArray();
+			return ToAsn1Object().InternalGetEncoded(encoding);
         }
 
         /**
@@ -54,19 +52,16 @@ namespace Org.BouncyCastle.Asn1
 			return ToAsn1Object().CallAsn1GetHashCode();
 		}
 
-		public sealed override bool Equals(
-			object obj)
+		public sealed override bool Equals(object obj)
 		{
 			if (obj == this)
 				return true;
 
-			IAsn1Convertible other = obj as IAsn1Convertible;
-
-			if (other == null)
+			if (!(obj is IAsn1Convertible that))
 				return false;
 
-			Asn1Object o1 = ToAsn1Object();
-			Asn1Object o2 = other.ToAsn1Object();
+			Asn1Object o1 = this.ToAsn1Object();
+			Asn1Object o2 = that.ToAsn1Object();
 
 			return o1 == o2 || (null != o2 && o1.CallAsn1Equals(o2));
 		}
diff --git a/crypto/src/asn1/Asn1Object.cs b/crypto/src/asn1/Asn1Object.cs
index 0cf89052b..523476f3d 100644
--- a/crypto/src/asn1/Asn1Object.cs
+++ b/crypto/src/asn1/Asn1Object.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Diagnostics;
 using System.IO;
 
 namespace Org.BouncyCastle.Asn1
@@ -8,16 +9,31 @@ namespace Org.BouncyCastle.Asn1
     {
         public override void EncodeTo(Stream output)
         {
-            Asn1OutputStream asn1Out = Asn1OutputStream.Create(output);
-            GetEncoding(asn1Out.Encoding).Encode(asn1Out);
-            asn1Out.FlushInternal();
+            using (var asn1Out = Asn1OutputStream.Create(output, Ber, leaveOpen: true))
+            {
+                GetEncoding(asn1Out.Encoding).Encode(asn1Out);
+            }
         }
 
         public override void EncodeTo(Stream output, string encoding)
         {
-            Asn1OutputStream asn1Out = Asn1OutputStream.Create(output, encoding);
-            GetEncoding(asn1Out.Encoding).Encode(asn1Out);
-            asn1Out.FlushInternal();
+            using (var asn1Out = Asn1OutputStream.Create(output, encoding, leaveOpen: true))
+            {
+                GetEncoding(asn1Out.Encoding).Encode(asn1Out);
+            }
+        }
+
+        internal virtual byte[] InternalGetEncoded(string encoding)
+        {
+            var encodingType = Asn1OutputStream.GetEncodingType(encoding);
+            var asn1Encoding = GetEncoding(encodingType);
+            byte[] result = new byte[asn1Encoding.GetLength()];
+            using (var asn1Out = Asn1OutputStream.Create(new MemoryStream(result, true), encoding))
+            {
+                asn1Encoding.Encode(asn1Out);
+                Debug.Assert(result.Length == Convert.ToInt32(asn1Out.Position));
+            }
+            return result;
         }
 
         public bool Equals(Asn1Object other)
@@ -31,17 +47,17 @@ namespace Org.BouncyCastle.Asn1
         /// <exception cref="IOException">
         /// If there is a problem parsing the data, or parsing an object did not exhaust the available data.
         /// </exception>
-        public static Asn1Object FromByteArray(
-			byte[] data)
+        public static Asn1Object FromByteArray(byte[] data)
 		{
             try
 			{
-                MemoryStream input = new MemoryStream(data, false);
-                Asn1InputStream asn1 = new Asn1InputStream(input, data.Length);
-                Asn1Object result = asn1.ReadObject();
-                if (input.Position != input.Length)
-                    throw new IOException("extra data found after object");
-                return result;
+                using (var asn1In = new Asn1InputStream(new MemoryStream(data, false), data.Length))
+                {
+                    Asn1Object result = asn1In.ReadObject();
+                    if (data.Length != asn1In.Position)
+                        throw new IOException("extra data found after object");
+                    return result;
+                }
 			}
 			catch (InvalidCastException)
 			{
@@ -53,8 +69,7 @@ namespace Org.BouncyCastle.Asn1
 		/// <param name="inStr">The stream to parse.</param>
 		/// <returns>The base ASN.1 object represented by the byte array.</returns>
 		/// <exception cref="IOException">If there is a problem parsing the data.</exception>
-		public static Asn1Object FromStream(
-			Stream inStr)
+		public static Asn1Object FromStream(Stream inStr)
 		{
 			try
 			{