#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) #pragma warning disable using System; using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Macs; using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters; using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math; using Best.HTTP.SecureProtocol.Org.BouncyCastle.Security; using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities; namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Signers { /** * A deterministic K calculator based on the algorithm in section 3.2 of RFC 6979. */ public class HMacDsaKCalculator : IDsaKCalculator { private readonly HMac hMac; private readonly byte[] K; private readonly byte[] V; private BigInteger n; /** * Base constructor. * * @param digest digest to build the HMAC on. */ public HMacDsaKCalculator(IDigest digest) { this.hMac = new HMac(digest); this.V = new byte[hMac.GetMacSize()]; this.K = new byte[hMac.GetMacSize()]; } public virtual bool IsDeterministic { get { return true; } } public virtual void Init(BigInteger n, SecureRandom random) { throw new InvalidOperationException("Operation not supported"); } public void Init(BigInteger n, BigInteger d, byte[] message) { this.n = n; Arrays.Fill(V, 0x01); Arrays.Fill(K, 0); BigInteger mInt = BitsToInt(message); if (mInt.CompareTo(n) >= 0) { mInt = mInt.Subtract(n); } int size = BigIntegers.GetUnsignedByteLength(n); #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER int xmSize = size * 2; Span xm = xmSize <= 512 ? stackalloc byte[xmSize] : new byte[xmSize]; BigIntegers.AsUnsignedByteArray(d, xm[..size]); BigIntegers.AsUnsignedByteArray(mInt, xm[size..]); #else byte[] x = BigIntegers.AsUnsignedByteArray(size, d); byte[] m = BigIntegers.AsUnsignedByteArray(size, mInt); #endif hMac.Init(new KeyParameter(K)); hMac.BlockUpdate(V, 0, V.Length); hMac.Update(0x00); #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER hMac.BlockUpdate(xm); #else hMac.BlockUpdate(x, 0, x.Length); hMac.BlockUpdate(m, 0, m.Length); #endif InitAdditionalInput0(hMac); hMac.DoFinal(K, 0); hMac.Init(new KeyParameter(K)); hMac.BlockUpdate(V, 0, V.Length); hMac.DoFinal(V, 0); hMac.BlockUpdate(V, 0, V.Length); hMac.Update(0x01); #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER hMac.BlockUpdate(xm); #else hMac.BlockUpdate(x, 0, x.Length); hMac.BlockUpdate(m, 0, m.Length); #endif hMac.DoFinal(K, 0); hMac.Init(new KeyParameter(K)); hMac.BlockUpdate(V, 0, V.Length); hMac.DoFinal(V, 0); } public virtual BigInteger NextK() { byte[] t = new byte[BigIntegers.GetUnsignedByteLength(n)]; for (;;) { int tOff = 0; while (tOff < t.Length) { hMac.BlockUpdate(V, 0, V.Length); hMac.DoFinal(V, 0); int len = System.Math.Min(t.Length - tOff, V.Length); Array.Copy(V, 0, t, tOff, len); tOff += len; } BigInteger k = BitsToInt(t); if (k.SignValue > 0 && k.CompareTo(n) < 0) return k; hMac.BlockUpdate(V, 0, V.Length); hMac.Update(0x00); hMac.DoFinal(K, 0); hMac.Init(new KeyParameter(K)); hMac.BlockUpdate(V, 0, V.Length); hMac.DoFinal(V, 0); } } /// Supports use of additional input. /// /// RFC 6979 3.6. Additional data may be added to the input of HMAC [..]. A use case may be a protocol that /// requires a non-deterministic signature algorithm on a system that does not have access to a high-quality /// random source. It suffices that the additional data[..] is non-repeating(e.g., a signature counter or a /// monotonic clock) to ensure "random-looking" signatures are indistinguishable, in a cryptographic way, from /// plain (EC)DSA signatures. /// /// By default there is no additional input. Override this method to supply additional input, bearing in mind /// that this calculator may be used for many signatures. /// /// The to which the additional input should be added. protected virtual void InitAdditionalInput0(HMac hmac0) { } private BigInteger BitsToInt(byte[] t) { BigInteger v = new BigInteger(1, t); if (t.Length * 8 > n.BitLength) { v = v.ShiftRight(t.Length * 8 - n.BitLength); } return v; } } } #pragma warning restore #endif