From cc722c1881f86bd2c4690b84f8bd99969a63fc80 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sun, 5 Mar 2023 14:56:01 +0700 Subject: Improve Asn1 encoding - reduced allocations for GetEncoded --- crypto/src/asn1/Asn1Encodable.cs | 21 +++++++----------- crypto/src/asn1/Asn1Object.cs | 47 ++++++++++++++++++++++++++-------------- 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 /// /// If there is a problem parsing the data, or parsing an object did not exhaust the available data. /// - 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 /// The stream to parse. /// The base ASN.1 object represented by the byte array. /// If there is a problem parsing the data. - public static Asn1Object FromStream( - Stream inStr) + public static Asn1Object FromStream(Stream inStr) { try { -- cgit 1.4.1