summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2024-01-29 21:23:42 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2024-01-29 21:23:42 +0700
commit196797d73f1b675e1e6b49ea538c8e22ba3b2a5f (patch)
treea0c3e65ebdeacc0a64fb7b9dc6448a38ca639697 /crypto/src
parentAdd Prehash digest for safer raw signers (diff)
downloadBouncyCastle.NET-ed25519-196797d73f1b675e1e6b49ea538c8e22ba3b2a5f.tar.xz
Support signer reuse in SM2Signer
Diffstat (limited to 'crypto/src')
-rw-r--r--crypto/src/crypto/signers/SM2Signer.cs62
1 files changed, 56 insertions, 6 deletions
diff --git a/crypto/src/crypto/signers/SM2Signer.cs b/crypto/src/crypto/signers/SM2Signer.cs
index cd4b2d554..10244a7f3 100644
--- a/crypto/src/crypto/signers/SM2Signer.cs
+++ b/crypto/src/crypto/signers/SM2Signer.cs
@@ -15,10 +15,18 @@ namespace Org.BouncyCastle.Crypto.Signers
     public class SM2Signer
         : ISigner
     {
+        private enum State
+        {
+            Uninitialized = 0,
+            Init          = 1,
+            Data          = 2,
+        }
+
         private readonly IDsaKCalculator kCalculator = new RandomDsaKCalculator();
         private readonly IDigest digest;
         private readonly IDsaEncoding encoding;
 
+        private State m_state = State.Uninitialized;
         private ECDomainParameters ecParams;
         private ECPoint pubPoint;
         private ECKeyParameters ecKey;
@@ -100,23 +108,28 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             digest.Reset();
             z = GetZ(userID);
-
-            digest.BlockUpdate(z, 0, z.Length);
+            m_state = State.Init;
         }
 
         public virtual void Update(byte b)
         {
+            CheckData();
+
             digest.Update(b);
         }
 
         public virtual void BlockUpdate(byte[] input, int inOff, int inLen)
         {
+            CheckData();
+
             digest.BlockUpdate(input, inOff, inLen);
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public virtual void BlockUpdate(ReadOnlySpan<byte> input)
         {
+            CheckData();
+
             digest.BlockUpdate(input);
         }
 #endif
@@ -125,6 +138,8 @@ namespace Org.BouncyCastle.Crypto.Signers
 
         public virtual byte[] GenerateSignature()
         {
+            CheckData();
+
             byte[] eHash = DigestUtilities.DoFinal(digest);
 
             BigInteger n = ecParams.N;
@@ -169,10 +184,16 @@ namespace Org.BouncyCastle.Crypto.Signers
             {
                 throw new CryptoException("unable to encode signature: " + ex.Message, ex);
             }
+            finally
+            {
+                Reset();
+            }
         }
 
         public virtual bool VerifySignature(byte[] signature)
         {
+            CheckData();
+
             try
             {
                 BigInteger[] rs = encoding.Decode(ecParams.N, signature);
@@ -182,17 +203,28 @@ namespace Org.BouncyCastle.Crypto.Signers
             catch (Exception)
             {
             }
+            finally
+            {
+                Reset();
+            }
 
             return false;
         }
 
         public virtual void Reset()
         {
-            if (z != null)
+            switch (m_state)
             {
-                digest.Reset();
-                digest.BlockUpdate(z, 0, z.Length);
+            case State.Init:
+                return;
+            case State.Data:
+                break;
+            default:
+                throw new InvalidOperationException(AlgorithmName + " needs to be initialized");
             }
+
+            digest.Reset();
+            m_state = State.Init;
         }
 
         private bool VerifySignature(BigInteger r, BigInteger s)
@@ -226,7 +258,25 @@ namespace Org.BouncyCastle.Crypto.Signers
                 return false;
 
             // B7
-            return r.Equals(e.Add(x1y1.AffineXCoord.ToBigInteger()).Mod(n));
+            BigInteger expectedR = e.Add(x1y1.AffineXCoord.ToBigInteger()).Mod(n);
+
+            return expectedR.Equals(r);
+        }
+
+        private void CheckData()
+        {
+            switch (m_state)
+            {
+            case State.Init:
+                break;
+            case State.Data:
+                return;
+            default:
+                throw new InvalidOperationException(AlgorithmName + " needs to be initialized");
+            }
+
+            digest.BlockUpdate(z, 0, z.Length);
+            m_state = State.Data;
         }
 
         private byte[] GetZ(byte[] userID)