From 1a2ca44e3fa181180e9aa65692a55111c32353f1 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Thu, 20 Oct 2022 18:23:49 +0700 Subject: Fix BinaryReader usage in Pqc.Crypto.Lms --- .../src/pqc/crypto/lms/HSSPrivateKeyParameters.cs | 35 +++---- .../src/pqc/crypto/lms/HSSPublicKeyParameters.cs | 7 +- crypto/src/pqc/crypto/lms/HSSSignature.cs | 6 +- crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs | 18 ++-- crypto/src/pqc/crypto/lms/LMOtsSignature.cs | 22 ++--- .../src/pqc/crypto/lms/LMSPrivateKeyParameters.cs | 107 +++++++-------------- .../src/pqc/crypto/lms/LMSPublicKeyParameters.cs | 38 +++----- crypto/src/pqc/crypto/lms/LMSSignature.cs | 12 +-- crypto/src/util/io/Streams.cs | 7 +- crypto/test/src/pqc/crypto/lms/test/LmsTests.cs | 16 ++- 10 files changed, 104 insertions(+), 164 deletions(-) diff --git a/crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs b/crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs index bcbccef1a..535654fd8 100644 --- a/crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs +++ b/crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs @@ -61,7 +61,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms return pKey; } - public static HSSPrivateKeyParameters GetInstance(Object src) + public static HSSPrivateKeyParameters GetInstance(object src) { if (src is HSSPrivateKeyParameters hssPrivateKeyParameters) { @@ -69,28 +69,17 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms } else if (src is BinaryReader binaryReader) { - byte[] data = binaryReader.ReadBytes(4); - Array.Reverse(data); - int version = BitConverter.ToInt32(data, 0); + int version = BinaryReaders.ReadInt32BigEndian(binaryReader); if (version != 0) - { - throw new Exception("unknown version for hss private key"); - } - data = binaryReader.ReadBytes(4); - Array.Reverse(data); - int d = BitConverter.ToInt32(data, 0); - - data = binaryReader.ReadBytes(8); - Array.Reverse(data); - long index = BitConverter.ToInt64(data, 0); - - data = binaryReader.ReadBytes(8); - Array.Reverse(data); - long maxIndex = BitConverter.ToInt64(data, 0);; - - data = binaryReader.ReadBytes(1); - Array.Reverse(data); - bool limited = BitConverter.ToBoolean(data, 0); + throw new Exception("unknown version for HSS private key"); + + int d = BinaryReaders.ReadInt32BigEndian(binaryReader); + + long index = BinaryReaders.ReadInt64BigEndian(binaryReader); + + long maxIndex = BinaryReaders.ReadInt64BigEndian(binaryReader); + + bool limited = binaryReader.ReadBoolean(); var keys = new List(); var signatures = new List(); @@ -133,7 +122,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms public int L => l; - public long GetIndex() + public long GetIndex() { lock (this) return index; diff --git a/crypto/src/pqc/crypto/lms/HSSPublicKeyParameters.cs b/crypto/src/pqc/crypto/lms/HSSPublicKeyParameters.cs index f6641d9c1..788b00fbd 100644 --- a/crypto/src/pqc/crypto/lms/HSSPublicKeyParameters.cs +++ b/crypto/src/pqc/crypto/lms/HSSPublicKeyParameters.cs @@ -26,10 +26,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms } else if (src is BinaryReader binaryReader) { - byte[] data = binaryReader.ReadBytes(4); - Array.Reverse(data); - int L = BitConverter.ToInt32(data, 0); - LMSPublicKeyParameters lmsPublicKey = LMSPublicKeyParameters.GetInstance(src);// todo check endianness + int L = BinaryReaders.ReadInt32BigEndian(binaryReader); + + LMSPublicKeyParameters lmsPublicKey = LMSPublicKeyParameters.GetInstance(src); return new HSSPublicKeyParameters(L, lmsPublicKey); } else if (src is byte[] bytes) diff --git a/crypto/src/pqc/crypto/lms/HSSSignature.cs b/crypto/src/pqc/crypto/lms/HSSSignature.cs index 793beda66..bd4af1bb8 100644 --- a/crypto/src/pqc/crypto/lms/HSSSignature.cs +++ b/crypto/src/pqc/crypto/lms/HSSSignature.cs @@ -27,7 +27,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms * @return An HSSSignature instance. * @throws IOException */ - public static HSSSignature GetInstance(Object src, int L) + public static HSSSignature GetInstance(object src, int L) { if (src is HSSSignature hssSignature) { @@ -35,9 +35,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms } else if (src is BinaryReader binaryReader) { - byte[] data = binaryReader.ReadBytes(4); - Array.Reverse(data); - int lminus = BitConverter.ToInt32(data, 0); + int lminus = BinaryReaders.ReadInt32BigEndian(binaryReader); if (lminus != L - 1) throw new Exception("nspk exceeded maxNspk"); diff --git a/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs b/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs index 49c0871f5..480cb3dbd 100644 --- a/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs +++ b/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs @@ -32,22 +32,16 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms } else if (src is BinaryReader binaryReader) { - byte[] data = binaryReader.ReadBytes(4); - Array.Reverse(data); - int index = BitConverter.ToInt32(data, 0); - + int index = BinaryReaders.ReadInt32BigEndian(binaryReader); LMOtsParameters parameter = LMOtsParameters.GetParametersByID(index); - byte[] I = new byte[16]; - binaryReader.Read(I, 0, I.Length); - - Array.Reverse(data); - int q = BitConverter.ToInt32(data, 0); - byte[] K = new byte[parameter.N]; - binaryReader.Read(K, 0, K.Length); + byte[] I = BinaryReaders.ReadBytesFully(binaryReader, 16); - return new LMOtsPublicKey(parameter, I, q, K); + 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) { diff --git a/crypto/src/pqc/crypto/lms/LMOtsSignature.cs b/crypto/src/pqc/crypto/lms/LMOtsSignature.cs index db4b25641..c55866661 100644 --- a/crypto/src/pqc/crypto/lms/LMOtsSignature.cs +++ b/crypto/src/pqc/crypto/lms/LMOtsSignature.cs @@ -13,9 +13,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms private readonly byte[] m_C; private readonly byte[] m_y; - public LMOtsSignature(LMOtsParameters ParamType, byte[] c, byte[] y) + public LMOtsSignature(LMOtsParameters paramType, byte[] c, byte[] y) { - m_paramType = ParamType; + m_paramType = paramType; m_C = c; m_y = y; } @@ -26,22 +26,16 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms { return lmOtsSignature; } - //TODO replace inputstreams with something - else if (src is BinaryReader binaryReader) { - byte[] data = binaryReader.ReadBytes(4); - Array.Reverse(data); - int index = BitConverter.ToInt32(data, 0); - LMOtsParameters type = LMOtsParameters.GetParametersByID(index); - byte[] C = new byte[type.N]; + int index = BinaryReaders.ReadInt32BigEndian(binaryReader); + LMOtsParameters parameter = LMOtsParameters.GetParametersByID(index); - binaryReader.Read(C, 0, C.Length); - - byte[] sig = new byte[type.P * type.N]; - binaryReader.Read(sig, 0, sig.Length); + byte[] C = BinaryReaders.ReadBytesFully(binaryReader, parameter.N); - return new LMOtsSignature(type, C, sig); + byte[] sig = BinaryReaders.ReadBytesFully(binaryReader, parameter.P * parameter.N); + + return new LMOtsSignature(parameter, C, sig); } else if (src is byte[] bytes) { diff --git a/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs b/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs index f83cdc5f4..ff1a9f6fd 100644 --- a/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs +++ b/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs @@ -42,7 +42,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms private LMSPublicKeyParameters publicKey; - public LMSPrivateKeyParameters(LMSigParameters lmsParameter, LMOtsParameters otsParameters, int q, byte[] I, int maxQ, byte[] masterSecret) + public LMSPrivateKeyParameters(LMSigParameters lmsParameter, LMOtsParameters otsParameters, int q, byte[] I, + int maxQ, byte[] masterSecret) : base(true) { this.parameters = lmsParameter; @@ -80,83 +81,44 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms return pKey; } - public static LMSPrivateKeyParameters GetInstance(Object src) + public static LMSPrivateKeyParameters GetInstance(object src) { - if (src is LMSPrivateKeyParameters) + if (src is LMSPrivateKeyParameters lmsPrivateKeyParameters) { - return (LMSPrivateKeyParameters)src; + return lmsPrivateKeyParameters; } - //TODO - else if (src is BinaryReader) + else if (src is BinaryReader binaryReader) { - BinaryReader dIn = (BinaryReader)src; - - /* - .u32str(0) // version - .u32str(parameters.getType()) // type - .u32str(otsParameters.getType()) // ots type - .bytes(I) // I at 16 bytes - .u32str(q) // q - .u32str(maxQ) // maximum q - .u32str(masterSecret.length) // length of master secret. - .bytes(masterSecret) // the master secret - .build(); - */ - - - if (dIn.ReadInt32() != 0) // todo check endienness - { + int version = BinaryReaders.ReadInt32BigEndian(binaryReader); + if (version != 0) throw new Exception("expected version 0 lms private key"); - } - - // todo check endienness - byte[] data = ((BinaryReader) src).ReadBytes(4); - Array.Reverse(data); - int paramType = BitConverter.ToInt32(data, 0); - LMSigParameters parameter = LMSigParameters.GetParametersByID(paramType); - - data = ((BinaryReader) src).ReadBytes(4); - Array.Reverse(data); - paramType = BitConverter.ToInt32(data, 0); - - LMOtsParameters otsParameter = LMOtsParameters.GetParametersByID(paramType); - byte[] I = new byte[16]; - dIn.Read(I, 0, I.Length); - - - data = ((BinaryReader) src).ReadBytes(4); - Array.Reverse(data); - int q = BitConverter.ToInt32(data, 0); - - data = ((BinaryReader) src).ReadBytes(4); - Array.Reverse(data); - int maxQ = BitConverter.ToInt32(data, 0); - - data = ((BinaryReader) src).ReadBytes(4); - Array.Reverse(data); - int l = BitConverter.ToInt32(data, 0); - - + + int sigParamType = BinaryReaders.ReadInt32BigEndian(binaryReader); + LMSigParameters sigParameter = LMSigParameters.GetParametersByID(sigParamType); + + int otsParamType = BinaryReaders.ReadInt32BigEndian(binaryReader); + LMOtsParameters otsParameter = LMOtsParameters.GetParametersByID(otsParamType); + + byte[] I = BinaryReaders.ReadBytesFully(binaryReader, 16); + + 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"); - } - if (l > dIn.BaseStream.Length) - { - throw new IOException("secret length exceeded " + dIn.BaseStream.Length); - } - byte[] masterSecret = new byte[l]; - dIn.Read(masterSecret, 0, masterSecret.Length); - - return new LMSPrivateKeyParameters(parameter, otsParameter, q, I, maxQ, masterSecret); - + + byte[] masterSecret = BinaryReaders.ReadBytesFully(binaryReader, l); + + return new LMSPrivateKeyParameters(sigParameter, otsParameter, q, I, maxQ, masterSecret); } - else if (src is byte[]) + else if (src is byte[] bytes) { BinaryReader input = null; try // 1.5 / 1.6 compatibility { - input = new BinaryReader(new MemoryStream((byte[])src, false)); + input = new BinaryReader(new MemoryStream(bytes, false)); return GetInstance(input); } finally @@ -167,9 +129,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms } } } - else if (src is MemoryStream) + else if (src is MemoryStream memoryStream) { - return GetInstance(Streams.ReadAll((Stream)src)); + return GetInstance(Streams.ReadAll(memoryStream)); } throw new ArgumentException($"cannot parse {src}"); @@ -181,9 +143,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms lock (this) { if (q >= maxQ) - { throw new Exception("ots private keys expired"); - } + return new LMOtsPrivateKey(otsParameters, I, q, masterSecret); } } @@ -247,9 +208,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms lock (this) { if (q >= maxQ) - { throw new Exception("ots private key exhausted"); - } + LMOtsPrivateKey otsPrivateKey = new LMOtsPrivateKey(otsParameters, I, q, masterSecret); IncIndex(); return otsPrivateKey; @@ -270,9 +230,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms lock (this) { if (q + usageCount >= maxQ) - { throw new ArgumentException("usageCount exceeds usages remaining"); - } + LMSPrivateKeyParameters keyParameters = new LMSPrivateKeyParameters(this, q, q + usageCount); q += usageCount; diff --git a/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs b/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs index 1bf857f60..80cf15827 100644 --- a/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs +++ b/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs @@ -23,33 +23,27 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms this.T1 = Arrays.Clone(T1); } - public static LMSPublicKeyParameters GetInstance(Object src) + public static LMSPublicKeyParameters GetInstance(object src) { if (src is LMSPublicKeyParameters lmsPublicKeyParameters) { return lmsPublicKeyParameters; } - // todo - else if (src is BinaryReader binaryReader) - { - byte[] data = binaryReader.ReadBytes(4); - Array.Reverse(data); - int pubType = BitConverter.ToInt32(data, 0); - LMSigParameters lmsParameter = LMSigParameters.GetParametersByID(pubType); - - data = binaryReader.ReadBytes(4); - Array.Reverse(data); - int index = BitConverter.ToInt32(data, 0); - LMOtsParameters ostTypeCode = LMOtsParameters.GetParametersByID(index); - - byte[] I = new byte[16]; - binaryReader.Read(I, 0, I.Length);//change to readbytes? - - byte[] T1 = new byte[lmsParameter.M]; - binaryReader.Read(T1, 0, T1.Length); - return new LMSPublicKeyParameters(lmsParameter, ostTypeCode, T1, I); - } - else if (src is byte[] bytes) + 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); + + byte[] I = BinaryReaders.ReadBytesFully(binaryReader, 16); + + byte[] T1 = BinaryReaders.ReadBytesFully(binaryReader, lmsParameter.M); + + return new LMSPublicKeyParameters(lmsParameter, ostTypeCode, T1, I); + } + else if (src is byte[] bytes) { BinaryReader input = null; try // 1.5 / 1.6 compatibility diff --git a/crypto/src/pqc/crypto/lms/LMSSignature.cs b/crypto/src/pqc/crypto/lms/LMSSignature.cs index 48026e2f6..3f95ec516 100644 --- a/crypto/src/pqc/crypto/lms/LMSSignature.cs +++ b/crypto/src/pqc/crypto/lms/LMSSignature.cs @@ -30,15 +30,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms } else if (src is BinaryReader binaryReader) { - byte[] data = binaryReader.ReadBytes(4); - Array.Reverse(data); - int q = BitConverter.ToInt32(data, 0); - + int q = BinaryReaders.ReadInt32BigEndian(binaryReader); + LMOtsSignature otsSignature = LMOtsSignature.GetInstance(src); - data = binaryReader.ReadBytes(4); - Array.Reverse(data); - int index = BitConverter.ToInt32(data, 0); + int index = BinaryReaders.ReadInt32BigEndian(binaryReader); LMSigParameters type = LMSigParameters.GetParametersByID(index); byte[][] path = new byte[type.H][]; @@ -47,7 +43,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms path[h] = new byte[type.M]; binaryReader.Read(path[h], 0, path[h].Length); } - + return new LMSSignature(q, otsSignature, type, path); } else if (src is byte[] bytes) diff --git a/crypto/src/util/io/Streams.cs b/crypto/src/util/io/Streams.cs index ac4bd3ae6..da8f01068 100644 --- a/crypto/src/util/io/Streams.cs +++ b/crypto/src/util/io/Streams.cs @@ -60,7 +60,12 @@ namespace Org.BouncyCastle.Utilities.IO return buf.ToArray(); } - public static byte[] ReadAllLimited(Stream inStr, int limit) + public static byte[] ReadAll(MemoryStream inStr) + { + return inStr.ToArray(); + } + + public static byte[] ReadAllLimited(Stream inStr, int limit) { MemoryStream buf = new MemoryStream(); PipeAllLimited(inStr, limit, buf); diff --git a/crypto/test/src/pqc/crypto/lms/test/LmsTests.cs b/crypto/test/src/pqc/crypto/lms/test/LmsTests.cs index 5a7a84031..a5bc26252 100644 --- a/crypto/test/src/pqc/crypto/lms/test/LmsTests.cs +++ b/crypto/test/src/pqc/crypto/lms/test/LmsTests.cs @@ -42,10 +42,22 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms.Tests LMOtsSignature sig = LM_OTS.LMOtsGenerateSignature(privateKey, ctx.GetQ(), ctx.C); Assert.True(LM_OTS.LMOtsValidateSignature(publicKey, sig, ms, false)); - // Vandalise signature + // Recreate signature + { + byte[] recreatedSignature = sig.GetEncoded(); + Assert.True(LM_OTS.LMOtsValidateSignature(publicKey, LMOtsSignature.GetInstance(recreatedSignature), ms, false)); + } + + // Recreate public key. + { + byte[] recreatedPubKey = Arrays.Clone(publicKey.GetEncoded()); + Assert.True(LM_OTS.LMOtsValidateSignature(LMOtsPublicKey.GetInstance(recreatedPubKey), sig, ms, false)); + } + + // Vandalise signature { - byte[] vandalisedSignature = sig.GetEncoded(); // Arrays.clone(sig); + byte[] vandalisedSignature = sig.GetEncoded(); vandalisedSignature[256] ^= 1; // Single bit error Assert.False(LM_OTS.LMOtsValidateSignature(publicKey, LMOtsSignature.GetInstance(vandalisedSignature), ms, false)); } -- cgit 1.4.1