<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.0" />

LmsPrivateKeyParameters

using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Utilities; using Org.BouncyCastle.Utilities.IO; using System; using System.Collections.Concurrent; using System.IO; using System.Runtime.CompilerServices; namespace Org.BouncyCastle.Pqc.Crypto.Lms { public sealed class LmsPrivateKeyParameters : LmsKeyParameters, ILmsContextBasedSigner { private byte[] I; private readonly LMSigParameters sigParameters; private LMOtsParameters otsParameters; private int maxQ; private byte[] masterSecret; private ConcurrentDictionary<int, byte[]> tCache; private int maxCacheR; private int q; private readonly bool m_isPlaceholder; private LmsPublicKeyParameters m_publicKey; public LMSigParameters SigParameters => sigParameters; public LMOtsParameters OtsParameters => otsParameters; public int IndexLimit => maxQ; private static LmsPublicKeyParameters DerivePublicKey(LmsPrivateKeyParameters privateKey) { return new LmsPublicKeyParameters(privateKey.sigParameters, privateKey.otsParameters, privateKey.FindT(1), privateKey.I); } public LmsPrivateKeyParameters(LMSigParameters lmsParameter, LMOtsParameters otsParameters, int q, byte[] I, int maxQ, byte[] masterSecret) : this(lmsParameter, otsParameters, q, I, maxQ, masterSecret, false) { } internal LmsPrivateKeyParameters(LMSigParameters lmsParameter, LMOtsParameters otsParameters, int q, byte[] I, int maxQ, byte[] masterSecret, bool isPlaceholder) : base(true) { sigParameters = lmsParameter; this.otsParameters = otsParameters; this.q = q; this.I = Arrays.Clone(I); this.maxQ = maxQ; this.masterSecret = Arrays.Clone(masterSecret); maxCacheR = 1 << sigParameters.H + 1; tCache = new ConcurrentDictionary<int, byte[]>(); m_isPlaceholder = isPlaceholder; } private LmsPrivateKeyParameters(LmsPrivateKeyParameters parent, int q, int maxQ) : base(true) { sigParameters = parent.sigParameters; otsParameters = parent.otsParameters; this.q = q; I = parent.I; this.maxQ = maxQ; masterSecret = parent.masterSecret; maxCacheR = 1 << sigParameters.H; tCache = parent.tCache; m_publicKey = parent.m_publicKey; } public static LmsPrivateKeyParameters GetInstance(byte[] privEnc, byte[] pubEnc) { return Parse(privEnc, 0, privEnc.Length, LmsPublicKeyParameters.Parse(pubEnc)); } public static LmsPrivateKeyParameters GetInstance(object src) { LmsPrivateKeyParameters lmsPrivateKeyParameters = src as LmsPrivateKeyParameters; if (lmsPrivateKeyParameters != null) return lmsPrivateKeyParameters; BinaryReader binaryReader = src as BinaryReader; if (binaryReader != null) return Parse(binaryReader); Stream stream = src as Stream; if (stream != null) return Parse(stream); byte[] array = src as byte[]; if (array != null) return Parse(array); DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(13, 1); defaultInterpolatedStringHandler.AppendLiteral("cannot parse "); defaultInterpolatedStringHandler.AppendFormatted<object>(src); throw new ArgumentException(defaultInterpolatedStringHandler.ToStringAndClear()); } internal static LmsPrivateKeyParameters Parse(BinaryReader binaryReader) { if (BinaryReaders.ReadInt32BigEndian(binaryReader) != 0) throw new Exception("unknown version for LMS private key"); LMSigParameters lmsParameter = LMSigParameters.ParseByID(binaryReader); LMOtsParameters lMOtsParameters = LMOtsParameters.ParseByID(binaryReader); byte[] i = BinaryReaders.ReadBytesFully(binaryReader, 16); int num = BinaryReaders.ReadInt32BigEndian(binaryReader); int num2 = BinaryReaders.ReadInt32BigEndian(binaryReader); int num3 = BinaryReaders.ReadInt32BigEndian(binaryReader); if (num3 < 0) throw new Exception("secret length less than zero"); byte[] array = BinaryReaders.ReadBytesFully(binaryReader, num3); return new LmsPrivateKeyParameters(lmsParameter, lMOtsParameters, num, i, num2, array); } internal static LmsPrivateKeyParameters Parse(Stream stream) { return BinaryReaders.Parse(Parse, stream, true); } internal static LmsPrivateKeyParameters Parse(byte[] buf) { return BinaryReaders.Parse(Parse, new MemoryStream(buf, false), false); } internal static LmsPrivateKeyParameters Parse(byte[] buf, int off, int len) { return BinaryReaders.Parse(Parse, new MemoryStream(buf, off, len, false), false); } internal static LmsPrivateKeyParameters Parse(byte[] buf, int off, int len, LmsPublicKeyParameters publicKey) { LmsPrivateKeyParameters lmsPrivateKeyParameters = Parse(buf, off, len); lmsPrivateKeyParameters.m_publicKey = publicKey; return lmsPrivateKeyParameters; } internal LMOtsPrivateKey GetCurrentOtsKey() { lock (this) { if (q >= maxQ) throw new Exception("ots private keys expired"); return new LMOtsPrivateKey(otsParameters, I, q, masterSecret); } } public int GetIndex() { lock (this) { return q; } } internal void IncIndex() { lock (this) { q++; } } public LmsContext GenerateLmsContext() { int h = SigParameters.H; int index = GetIndex(); LMOtsPrivateKey nextOtsPrivateKey = GetNextOtsPrivateKey(); int num = 0; int num2 = (1 << h) + index; byte[][] array = new byte[h][]; while (num < h) { int r = (num2 / (1 << num)) ^ 1; array[num++] = FindT(r); } return nextOtsPrivateKey.GetSignatureContext(sigParameters, array); } public byte[] GenerateSignature(LmsContext context) { try { return Lms.GenerateSign(context).GetEncoded(); } catch (IOException ex) { throw new Exception("unable to encode signature: " + ex.Message, ex); } } internal LMOtsPrivateKey GetNextOtsPrivateKey() { if (m_isPlaceholder) throw new Exception("placeholder only"); lock (this) { if (q >= maxQ) throw new Exception("ots private key exhausted"); LMOtsPrivateKey result = new LMOtsPrivateKey(otsParameters, I, q, masterSecret); IncIndex(); return result; } } public LmsPrivateKeyParameters ExtractKeyShard(int usageCount) { lock (this) { if (usageCount < 0) throw new ArgumentOutOfRangeException("cannot be negative", "usageCount"); if (usageCount > maxQ - q) throw new ArgumentException("exceeds usages remaining", "usageCount"); int num = q; return new LmsPrivateKeyParameters(this, num, q += usageCount); } } [Obsolete("Use 'SigParameters' instead")] public LMSigParameters GetSigParameters() { return sigParameters; } [Obsolete("Use 'OtsParameters' instead")] public LMOtsParameters GetOtsParameters() { return otsParameters; } public byte[] GetI() { return Arrays.Clone(I); } public byte[] GetMasterSecret() { return Arrays.Clone(masterSecret); } public long GetUsagesRemaining() { return IndexLimit - GetIndex(); } public LmsPublicKeyParameters GetPublicKey() { if (m_isPlaceholder) throw new Exception("placeholder only"); return Objects.EnsureSingletonInitialized(ref m_publicKey, this, DerivePublicKey); } internal byte[] FindT(int r) { if (r >= maxCacheR) return CalcT(r); return tCache.GetOrAdd(r, CalcT); } private byte[] CalcT(int r) { IDigest digest = LmsUtilities.GetDigest(sigParameters); int h = sigParameters.H; int num = 1 << h; byte[] array = new byte[digest.GetDigestSize()]; if (r >= num) { LmsUtilities.ByteArray(I, digest); LmsUtilities.U32Str(r, digest); LmsUtilities.U16Str((short)Lms.D_LEAF, digest); LmsUtilities.ByteArray(LMOts.LmsOtsGeneratePublicKey(otsParameters, I, r - num, masterSecret), digest); } else { byte[] array2 = FindT(2 * r); byte[] array3 = FindT(2 * r + 1); LmsUtilities.ByteArray(I, digest); LmsUtilities.U32Str(r, digest); LmsUtilities.U16Str((short)Lms.D_INTR, digest); LmsUtilities.ByteArray(array2, digest); LmsUtilities.ByteArray(array3, digest); } digest.DoFinal(array, 0); return array; } public override bool Equals(object o) { if (this == o) return true; LmsPrivateKeyParameters lmsPrivateKeyParameters = o as LmsPrivateKeyParameters; if (lmsPrivateKeyParameters != null && q == lmsPrivateKeyParameters.q && maxQ == lmsPrivateKeyParameters.maxQ && Arrays.AreEqual(I, lmsPrivateKeyParameters.I) && object.Equals(sigParameters, lmsPrivateKeyParameters.sigParameters) && object.Equals(otsParameters, lmsPrivateKeyParameters.otsParameters)) return Arrays.AreEqual(masterSecret, lmsPrivateKeyParameters.masterSecret); return false; } public override int GetHashCode() { int num = q; num = 31 * num + maxQ; num = 31 * num + Arrays.GetHashCode(I); num = 31 * num + Objects.GetHashCode(sigParameters); num = 31 * num + Objects.GetHashCode(otsParameters); return 31 * num + Arrays.GetHashCode(masterSecret); } public override byte[] GetEncoded() { return Composer.Compose().U32Str(0).U32Str(sigParameters.ID) .U32Str(otsParameters.ID) .Bytes(I) .U32Str(q) .U32Str(maxQ) .U32Str(masterSecret.Length) .Bytes(masterSecret) .Build(); } } }