summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-11-17 10:09:10 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-11-17 10:09:10 +0700
commitae66e668da98ed3ceac7fa28bb2e9f92a220e595 (patch)
treed207ea604246fe78526ffb88fc0f959eab6bd0c9
parentImprovements to OaepEncoding (diff)
downloadBouncyCastle.NET-ed25519-ae66e668da98ed3ceac7fa28bb2e9f92a220e595.tar.xz
Refactor LMS parsing
-rw-r--r--crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs67
-rw-r--r--crypto/src/pqc/crypto/lms/HSSPublicKeyParameters.cs41
-rw-r--r--crypto/src/pqc/crypto/lms/HSSSignature.cs68
-rw-r--r--crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs59
-rw-r--r--crypto/src/pqc/crypto/lms/LMOtsSignature.cs54
-rw-r--r--crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs71
-rw-r--r--crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs55
-rw-r--r--crypto/src/pqc/crypto/lms/LMSSignature.cs56
-rw-r--r--crypto/src/util/io/BinaryReaders.cs9
9 files changed, 210 insertions, 270 deletions
diff --git a/crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs b/crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs
index 447dbad27..676da3db4 100644
--- a/crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs
+++ b/crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs
@@ -64,60 +64,47 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
         public static HssPrivateKeyParameters GetInstance(object src)
         {
             if (src is HssPrivateKeyParameters hssPrivateKeyParameters)
-            {
                 return hssPrivateKeyParameters;
-            }
-            else if (src is BinaryReader binaryReader)
-            {
-                int version = BinaryReaders.ReadInt32BigEndian(binaryReader);
-                if (version != 0)
-                    throw new Exception("unknown version for HSS private key");
 
-                int d = BinaryReaders.ReadInt32BigEndian(binaryReader);
+            if (src is BinaryReader binaryReader)
+                return Parse(binaryReader);
 
-                long index = BinaryReaders.ReadInt64BigEndian(binaryReader);
+            if (src is Stream stream)
+                return BinaryReaders.Parse(Parse, stream, leaveOpen: true);
 
-                long maxIndex = BinaryReaders.ReadInt64BigEndian(binaryReader);
+            if (src is byte[] bytes)
+                return BinaryReaders.Parse(Parse, new MemoryStream(bytes, false), leaveOpen: false);
 
-                bool limited = binaryReader.ReadBoolean();
+            throw new ArgumentException($"cannot parse {src}");
+        }
 
-                var keys = new List<LmsPrivateKeyParameters>();
-                var signatures = new List<LmsSignature>();
+        internal static HssPrivateKeyParameters Parse(BinaryReader binaryReader)
+        {
+            int version = BinaryReaders.ReadInt32BigEndian(binaryReader);
+            if (version != 0)
+                throw new Exception("unknown version for HSS private key");
 
-                for (int t = 0; t < d; t++)
-                {
-                    keys.Add(LmsPrivateKeyParameters.GetInstance(src));
-                }
+            int d = BinaryReaders.ReadInt32BigEndian(binaryReader);
 
-                for (int t = 0; t < d - 1; t++)
-                {
-                    signatures.Add(LmsSignature.GetInstance(src));
-                }
+            long index = BinaryReaders.ReadInt64BigEndian(binaryReader);
 
-                return new HssPrivateKeyParameters(d, keys, signatures, index, maxIndex, limited);
-            }
-            else if (src is byte[] bytes)
+            long maxIndex = BinaryReaders.ReadInt64BigEndian(binaryReader);
+
+            bool limited = binaryReader.ReadBoolean();
+
+            var keys = new List<LmsPrivateKeyParameters>(d);
+            for (int t = 0; t < d; t++)
             {
-                BinaryReader input = null;
-                try // 1.5 / 1.6 compatibility
-                {
-                    input = new BinaryReader(new MemoryStream(bytes));
-                    return GetInstance(input);
-                }
-                finally
-                {
-                    if (input != null)
-                    {
-                        input.Close();
-                    }
-                }
+                keys.Add(LmsPrivateKeyParameters.Parse(binaryReader));
             }
-            else if (src is MemoryStream memoryStream)
+
+            var signatures = new List<LmsSignature>(d - 1);
+            for (int t = 1; t < d; t++)
             {
-                return GetInstance(Streams.ReadAll(memoryStream));
+                signatures.Add(LmsSignature.Parse(binaryReader));
             }
 
-            throw new Exception($"cannot parse {src}");
+            return new HssPrivateKeyParameters(d, keys, signatures, index, maxIndex, limited);
         }
 
         public int L => l;
diff --git a/crypto/src/pqc/crypto/lms/HSSPublicKeyParameters.cs b/crypto/src/pqc/crypto/lms/HSSPublicKeyParameters.cs
index 01bac93b8..d3bc697d9 100644
--- a/crypto/src/pqc/crypto/lms/HSSPublicKeyParameters.cs
+++ b/crypto/src/pqc/crypto/lms/HSSPublicKeyParameters.cs
@@ -1,5 +1,6 @@
 using System;
 using System.IO;
+using System.Text;
 
 using Org.BouncyCastle.Utilities.IO;
 
@@ -21,37 +22,27 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
         public static HssPublicKeyParameters GetInstance(object src)
         {
             if (src is HssPublicKeyParameters hssPublicKeyParameters)
-            {
                 return hssPublicKeyParameters;
-            }
-            else if (src is BinaryReader binaryReader)
-            {
-                int L = BinaryReaders.ReadInt32BigEndian(binaryReader);
 
-                LmsPublicKeyParameters lmsPublicKey = LmsPublicKeyParameters.GetInstance(src);
-                return new HssPublicKeyParameters(L, lmsPublicKey);
-            }
-            else if (src is byte[] bytes)
-            {
-                BinaryReader input = null;
-                try // 1.5 / 1.6 compatibility
-                {
-                    input = new BinaryReader(new MemoryStream(bytes));
-                    return GetInstance(input);
-                }
-                finally
-                {
-                    if (input != null) input.Close();
-                }
-            }
-            else if (src is MemoryStream memoryStream)
-            {
-                return GetInstance(Streams.ReadAll(memoryStream));
-            }
+            if (src is BinaryReader binaryReader)
+                return Parse(binaryReader);
+
+            if (src is Stream stream)
+                return BinaryReaders.Parse(Parse, stream, leaveOpen: true);
+
+            if (src is byte[] bytes)
+                return BinaryReaders.Parse(Parse, new MemoryStream(bytes, false), leaveOpen: false);
 
             throw new ArgumentException($"cannot parse {src}");
         }
 
+        internal static HssPublicKeyParameters Parse(BinaryReader binaryReader)
+        {
+            int L = BinaryReaders.ReadInt32BigEndian(binaryReader);
+            LmsPublicKeyParameters lmsPublicKey = LmsPublicKeyParameters.Parse(binaryReader);
+            return new HssPublicKeyParameters(L, lmsPublicKey);
+        }
+
         public int L => m_l;
 
         public LmsPublicKeyParameters LmsPublicKey => m_lmsPublicKey;
diff --git a/crypto/src/pqc/crypto/lms/HSSSignature.cs b/crypto/src/pqc/crypto/lms/HSSSignature.cs
index 21f0397c8..bbf0c6f0f 100644
--- a/crypto/src/pqc/crypto/lms/HSSSignature.cs
+++ b/crypto/src/pqc/crypto/lms/HSSSignature.cs
@@ -1,5 +1,6 @@
 using System;
 using System.IO;
+using System.Text;
 
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.IO;
@@ -13,6 +14,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
         private readonly LmsSignedPubKey[] m_signedPubKey;
         private readonly LmsSignature m_signature;
 
+        // TODO[api] signedPubKeys
         public HssSignature(int lMinus1, LmsSignedPubKey[] signedPubKey, LmsSignature signature)
         {
             m_lMinus1 = lMinus1;
@@ -29,48 +31,48 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
         public static HssSignature GetInstance(object src, int L)
         {
             if (src is HssSignature hssSignature)
-            {
                 return hssSignature;
-            }
-            else if (src is BinaryReader binaryReader)
-            {
-                int lminus = BinaryReaders.ReadInt32BigEndian(binaryReader);
-                if (lminus != L - 1)
-                    throw new Exception("nspk exceeded maxNspk");
 
-                LmsSignedPubKey[] signedPubKeys = new LmsSignedPubKey[lminus];
-                if (lminus != 0)
-                {
-                    for (int t = 0; t < signedPubKeys.Length; t++)
-                    {
-                        signedPubKeys[t] = new LmsSignedPubKey(LmsSignature.GetInstance(src),
-                            LmsPublicKeyParameters.GetInstance(src));
-                    }
-                }
+            if (src is BinaryReader binaryReader)
+                return Parse(L, binaryReader);
 
-                LmsSignature sig = LmsSignature.GetInstance(src);
+            if (src is Stream stream)
+                return Parse(L, stream, leaveOpen: true);
 
-                return new HssSignature(lminus, signedPubKeys, sig);
-            }
-            else if (src is byte[] bytes)
+            if (src is byte[] bytes)
+                return Parse(L, new MemoryStream(bytes, false), leaveOpen: false);
+
+            throw new ArgumentException($"cannot parse {src}");
+        }
+
+        internal static HssSignature Parse(int L, BinaryReader binaryReader)
+        {
+            int lMinus1 = BinaryReaders.ReadInt32BigEndian(binaryReader);
+            if (lMinus1 != L - 1)
+                throw new Exception("nspk exceeded maxNspk");
+
+            var signedPubKeys = new LmsSignedPubKey[lMinus1];
+            for (int t = 0; t < lMinus1; t++)
             {
-                BinaryReader input = null;
-                try // 1.5 / 1.6 compatibility
-                {
-                    input = new BinaryReader(new MemoryStream(bytes));
-                    return GetInstance(input, L);
-                }
-                finally
-                {
-                    if (input != null) input.Close();
-                }
+                var signature = LmsSignature.Parse(binaryReader);
+                var publicKey = LmsPublicKeyParameters.Parse(binaryReader);
+
+                signedPubKeys[t] = new LmsSignedPubKey(signature, publicKey);
             }
-            else if (src is MemoryStream memoryStream)
+
             {
-                return GetInstance(Streams.ReadAll(memoryStream), L);
+                var signature = LmsSignature.Parse(binaryReader);
+
+                return new HssSignature(lMinus1, signedPubKeys, signature);
             }
+        }
 
-            throw new ArgumentException($"cannot parse {src}");
+        private static HssSignature Parse(int L, Stream stream, bool leaveOpen)
+        {
+            using (var binaryReader = new BinaryReader(stream, Encoding.UTF8, leaveOpen))
+            {
+                return Parse(L, binaryReader);
+            }
         }
 
         public int GetLMinus1()
diff --git a/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs b/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs
index ef3d4aced..5be482e25 100644
--- a/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs
+++ b/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs
@@ -25,42 +25,33 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
 
         public static LMOtsPublicKey GetInstance(object src)
         {
-            //todo
             if (src is LMOtsPublicKey lmOtsPublicKey)
-            {
                 return lmOtsPublicKey;
-            }
-            else if (src is BinaryReader binaryReader)
-            {
-                int index = BinaryReaders.ReadInt32BigEndian(binaryReader);
-                LMOtsParameters parameter = LMOtsParameters.GetParametersByID(index);
-
-                byte[] I = BinaryReaders.ReadBytesFully(binaryReader, 16);
-
-                int q = BinaryReaders.ReadInt32BigEndian(binaryReader);
-
-                byte[] K = BinaryReaders.ReadBytesFully(binaryReader, parameter.N);
-
-                return new LMOtsPublicKey(parameter, I, q, K);
-            }
-            else if (src is byte[] bytes)
-            {
-                BinaryReader input = null;
-                try // 1.5 / 1.6 compatibility
-                {
-                    input = new BinaryReader(new MemoryStream(bytes, false));
-                    return GetInstance(input);
-                }
-                finally
-                {
-                    if (input != null) input.Close();//todo Platform Dispose
-                }
-            }
-            else if (src is MemoryStream memoryStream)
-            {
-                return GetInstance(Streams.ReadAll(memoryStream));
-            }
-            throw new Exception ($"cannot parse {src}");
+
+            if (src is BinaryReader binaryReader)
+                return Parse(binaryReader);
+
+            if (src is Stream stream)
+                return BinaryReaders.Parse(Parse, stream, leaveOpen: true);
+
+            if (src is byte[] bytes)
+                return BinaryReaders.Parse(Parse, new MemoryStream(bytes, false), leaveOpen: false);
+
+            throw new ArgumentException($"cannot parse {src}");
+        }
+
+        internal static LMOtsPublicKey Parse(BinaryReader binaryReader)
+        {
+            int index = BinaryReaders.ReadInt32BigEndian(binaryReader);
+            LMOtsParameters parameter = LMOtsParameters.GetParametersByID(index);
+
+            byte[] I = BinaryReaders.ReadBytesFully(binaryReader, 16);
+
+            int q = BinaryReaders.ReadInt32BigEndian(binaryReader);
+
+            byte[] K = BinaryReaders.ReadBytesFully(binaryReader, parameter.N);
+
+            return new LMOtsPublicKey(parameter, I, q, K);
         }
 
         public LMOtsParameters Parameters => m_parameters;
diff --git a/crypto/src/pqc/crypto/lms/LMOtsSignature.cs b/crypto/src/pqc/crypto/lms/LMOtsSignature.cs
index c55866661..afc309be6 100644
--- a/crypto/src/pqc/crypto/lms/LMOtsSignature.cs
+++ b/crypto/src/pqc/crypto/lms/LMOtsSignature.cs
@@ -23,38 +23,30 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
         public static LMOtsSignature GetInstance(object src)
         {
             if (src is LMOtsSignature lmOtsSignature)
-            {
                 return lmOtsSignature;
-            }
-            else if (src is BinaryReader binaryReader)
-            {
-                int index = BinaryReaders.ReadInt32BigEndian(binaryReader);
-                LMOtsParameters parameter = LMOtsParameters.GetParametersByID(index);
-
-                byte[] C = BinaryReaders.ReadBytesFully(binaryReader, parameter.N);
-
-                byte[] sig = BinaryReaders.ReadBytesFully(binaryReader, parameter.P * parameter.N);
-
-                return new LMOtsSignature(parameter, C, sig);
-            }
-            else if (src is byte[] bytes)
-            {
-                BinaryReader input = null;
-                try // 1.5 / 1.4 compatibility
-                {
-                    input = new BinaryReader(new MemoryStream(bytes, false));
-                    return GetInstance(input);
-                }
-                finally
-                {
-                    if (input != null) input.Close();
-                }
-            }
-            else if (src is MemoryStream memoryStream)
-            {
-                return GetInstance(Streams.ReadAll(memoryStream));
-            }
-            throw new Exception ($"cannot parse {src}");
+
+            if (src is BinaryReader binaryReader)
+                return Parse(binaryReader);
+
+            if (src is Stream stream)
+                return BinaryReaders.Parse(Parse, stream, leaveOpen: true);
+
+            if (src is byte[] bytes)
+                return BinaryReaders.Parse(Parse, new MemoryStream(bytes, false), leaveOpen: false);
+
+            throw new ArgumentException($"cannot parse {src}");
+        }
+
+        internal static LMOtsSignature Parse(BinaryReader binaryReader)
+        {
+            int index = BinaryReaders.ReadInt32BigEndian(binaryReader);
+            LMOtsParameters parameter = LMOtsParameters.GetParametersByID(index);
+
+            byte[] C = BinaryReaders.ReadBytesFully(binaryReader, parameter.N);
+
+            byte[] sig = BinaryReaders.ReadBytesFully(binaryReader, parameter.P * parameter.N);
+
+            return new LMOtsSignature(parameter, C, sig);
         }
 
         public LMOtsParameters ParamType => m_paramType;
diff --git a/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs b/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs
index 278cbb04b..c5a188748 100644
--- a/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs
+++ b/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs
@@ -91,59 +91,46 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
         public static LmsPrivateKeyParameters GetInstance(object src)
         {
             if (src is LmsPrivateKeyParameters lmsPrivateKeyParameters)
-            {
                 return lmsPrivateKeyParameters;
-            }
-            else if (src is BinaryReader binaryReader)
-            {
-                int version = BinaryReaders.ReadInt32BigEndian(binaryReader);
-                if (version != 0)
-                    throw new Exception("unknown version for LMS private key");
 
-                int sigParamType = BinaryReaders.ReadInt32BigEndian(binaryReader);
-                LMSigParameters sigParameter = LMSigParameters.GetParametersByID(sigParamType);
+            if (src is BinaryReader binaryReader)
+                return Parse(binaryReader);
 
-                int otsParamType = BinaryReaders.ReadInt32BigEndian(binaryReader);
-                LMOtsParameters otsParameter = LMOtsParameters.GetParametersByID(otsParamType);
+            if (src is Stream stream)
+                return BinaryReaders.Parse(Parse, stream, leaveOpen: true);
 
-                byte[] I = BinaryReaders.ReadBytesFully(binaryReader, 16);
+            if (src is byte[] bytes)
+                return BinaryReaders.Parse(Parse, new MemoryStream(bytes, false), leaveOpen: false);
 
-                int q = BinaryReaders.ReadInt32BigEndian(binaryReader);
+            throw new ArgumentException($"cannot parse {src}");
+        }
 
-                int maxQ = BinaryReaders.ReadInt32BigEndian(binaryReader);
+        internal static LmsPrivateKeyParameters Parse(BinaryReader binaryReader)
+        {
+            int version = BinaryReaders.ReadInt32BigEndian(binaryReader);
+            if (version != 0)
+                throw new Exception("unknown version for LMS private key");
 
-                int l = BinaryReaders.ReadInt32BigEndian(binaryReader);
-                if (l < 0)
-                    throw new Exception("secret length less than zero");
+            int sigParamType = BinaryReaders.ReadInt32BigEndian(binaryReader);
+            LMSigParameters sigParameter = LMSigParameters.GetParametersByID(sigParamType);
 
-                byte[] masterSecret = BinaryReaders.ReadBytesFully(binaryReader, l);
+            int otsParamType = BinaryReaders.ReadInt32BigEndian(binaryReader);
+            LMOtsParameters otsParameter = LMOtsParameters.GetParametersByID(otsParamType);
 
-                return new LmsPrivateKeyParameters(sigParameter, otsParameter, q, I, maxQ, masterSecret);
-            }
-            else if (src is byte[] bytes)
-            {
-                BinaryReader input = null;
-                try // 1.5 / 1.6 compatibility
-                {
-                    input = new BinaryReader(new MemoryStream(bytes, false));
-                    return GetInstance(input);
-                }
-                finally
-                {
-                    if (input != null)
-                    {
-                        input.Close();
-                    }
-                }
-            }
-            else if (src is MemoryStream memoryStream)
-            {
-                return GetInstance(Streams.ReadAll(memoryStream));
-            }
+            byte[] I = BinaryReaders.ReadBytesFully(binaryReader, 16);
 
-            throw new ArgumentException($"cannot parse {src}");
-        }
+            int q = BinaryReaders.ReadInt32BigEndian(binaryReader);
+
+            int maxQ = BinaryReaders.ReadInt32BigEndian(binaryReader);
+
+            int l = BinaryReaders.ReadInt32BigEndian(binaryReader);
+            if (l < 0)
+                throw new Exception("secret length less than zero");
 
+            byte[] masterSecret = BinaryReaders.ReadBytesFully(binaryReader, l);
+
+            return new LmsPrivateKeyParameters(sigParameter, otsParameter, q, I, maxQ, masterSecret);
+        }
 
         internal LMOtsPrivateKey GetCurrentOtsKey()
         {
diff --git a/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs b/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs
index e8c5d07e5..37fa76e2d 100644
--- a/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs
+++ b/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs
@@ -26,44 +26,33 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
         public static LmsPublicKeyParameters GetInstance(object src)
         {
             if (src is LmsPublicKeyParameters lmsPublicKeyParameters)
-            {
                 return lmsPublicKeyParameters;
-            }
-            else if (src is BinaryReader binaryReader)
-            {
-                int pubType = BinaryReaders.ReadInt32BigEndian(binaryReader);
-                LMSigParameters lmsParameter = LMSigParameters.GetParametersByID(pubType);
 
-                int index = BinaryReaders.ReadInt32BigEndian(binaryReader);
-                LMOtsParameters ostTypeCode = LMOtsParameters.GetParametersByID(index);
+            if (src is BinaryReader binaryReader)
+                return Parse(binaryReader);
 
-                byte[] I = BinaryReaders.ReadBytesFully(binaryReader, 16);
+            if (src is Stream stream)
+                return BinaryReaders.Parse(Parse, stream, leaveOpen: true);
 
-                byte[] T1 = BinaryReaders.ReadBytesFully(binaryReader, lmsParameter.M);
+            if (src is byte[] bytes)
+                return BinaryReaders.Parse(Parse, new MemoryStream(bytes, false), leaveOpen: false);
 
-                return new LmsPublicKeyParameters(lmsParameter, ostTypeCode, T1, I);
-            }
-            else if (src is byte[] bytes)
-             {
-                 BinaryReader input = null;
-                 try // 1.5 / 1.6 compatibility
-                 {
-                     input = new BinaryReader(new MemoryStream(bytes, false));
-                     return GetInstance(input);
-                 }
-                 finally
-                 {
-                     if (input != null)
-                     {
-                         input.Close();
-                     }
-                 }
-             }
-            else if (src is MemoryStream memoryStream)
-            {
-                return GetInstance(Streams.ReadAll(memoryStream));
-            }
-            throw new Exception ($"cannot parse {src}");
+            throw new ArgumentException($"cannot parse {src}");
+        }
+
+        internal static LmsPublicKeyParameters Parse(BinaryReader binaryReader)
+        {
+            int pubType = BinaryReaders.ReadInt32BigEndian(binaryReader);
+            LMSigParameters lmsParameter = LMSigParameters.GetParametersByID(pubType);
+
+            int index = BinaryReaders.ReadInt32BigEndian(binaryReader);
+            LMOtsParameters ostTypeCode = LMOtsParameters.GetParametersByID(index);
+
+            byte[] I = BinaryReaders.ReadBytesFully(binaryReader, 16);
+
+            byte[] T1 = BinaryReaders.ReadBytesFully(binaryReader, lmsParameter.M);
+
+            return new LmsPublicKeyParameters(lmsParameter, ostTypeCode, T1, I);
         }
 
         public override byte[] GetEncoded()
diff --git a/crypto/src/pqc/crypto/lms/LMSSignature.cs b/crypto/src/pqc/crypto/lms/LMSSignature.cs
index a1ae475c1..d25a498ea 100644
--- a/crypto/src/pqc/crypto/lms/LMSSignature.cs
+++ b/crypto/src/pqc/crypto/lms/LMSSignature.cs
@@ -25,45 +25,37 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
         public static LmsSignature GetInstance(object src)
         {
             if (src is LmsSignature lmsSignature)
-            {
                 return lmsSignature;
-            }
-            else if (src is BinaryReader binaryReader)
-            {
-                int q = BinaryReaders.ReadInt32BigEndian(binaryReader);
 
-                LMOtsSignature otsSignature = LMOtsSignature.GetInstance(src);
+            if (src is BinaryReader binaryReader)
+                return Parse(binaryReader);
 
-                int index = BinaryReaders.ReadInt32BigEndian(binaryReader);
-                LMSigParameters type = LMSigParameters.GetParametersByID(index);
+            if (src is Stream stream)
+                return BinaryReaders.Parse(Parse, stream, leaveOpen: true);
 
-                byte[][] path = new byte[type.H][];
-                for (int h = 0; h < path.Length; h++)
-                {
-                    path[h] = new byte[type.M];
-                    binaryReader.Read(path[h], 0, path[h].Length);
-                }
+            if (src is byte[] bytes)
+                return BinaryReaders.Parse(Parse, new MemoryStream(bytes, false), leaveOpen: false);
 
-                return new LmsSignature(q, otsSignature, type, path);
-            }
-            else if (src is byte[] bytes)
-            {
-                BinaryReader input = null;
-                try // 1.5 / 1.6 compatibility
-                {
-                    input = new BinaryReader(new MemoryStream(bytes, false));
-                    return GetInstance(input);
-                }
-                finally
-                {
-                    if (input != null) input.Close();// todo platform dispose
-                }
-            }
-            else if (src is MemoryStream memoryStream)
+            throw new ArgumentException($"cannot parse {src}");
+        }
+
+        internal static LmsSignature Parse(BinaryReader binaryReader)
+        {
+            int q = BinaryReaders.ReadInt32BigEndian(binaryReader);
+
+            LMOtsSignature otsSignature = LMOtsSignature.Parse(binaryReader);
+
+            int index = BinaryReaders.ReadInt32BigEndian(binaryReader);
+            LMSigParameters type = LMSigParameters.GetParametersByID(index);
+
+            byte[][] path = new byte[type.H][];
+            for (int h = 0; h < path.Length; h++)
             {
-                return GetInstance(Streams.ReadAll(memoryStream));
+                path[h] = new byte[type.M];
+                binaryReader.Read(path[h], 0, path[h].Length);
             }
-            throw new Exception ($"cannot parse {src}");
+
+            return new LmsSignature(q, otsSignature, type, path);
         }
 
         public override bool Equals(Object o)
diff --git a/crypto/src/util/io/BinaryReaders.cs b/crypto/src/util/io/BinaryReaders.cs
index c5f99a712..ed4b57d0a 100644
--- a/crypto/src/util/io/BinaryReaders.cs
+++ b/crypto/src/util/io/BinaryReaders.cs
@@ -1,10 +1,19 @@
 using System;
 using System.IO;
+using System.Text;
 
 namespace Org.BouncyCastle.Utilities.IO
 {
     public static class BinaryReaders
     {
+        internal static T Parse<T>(Func<BinaryReader, T> parse, Stream stream, bool leaveOpen)
+        {
+            using (var binaryReader = new BinaryReader(stream, Encoding.UTF8, leaveOpen))
+            {
+                return parse(binaryReader);
+            }
+        }
+
         public static byte[] ReadBytesFully(BinaryReader binaryReader, int count)
         {
             byte[] bytes = binaryReader.ReadBytes(count);