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)
diff --git a/crypto/test/src/crypto/test/SM2SignerTest.cs b/crypto/test/src/crypto/test/SM2SignerTest.cs
index a8cc016fd..e9d40fdc6 100644
--- a/crypto/test/src/crypto/test/SM2SignerTest.cs
+++ b/crypto/test/src/crypto/test/SM2SignerTest.cs
@@ -1,6 +1,3 @@
-using System;
-using System.IO;
-
using NUnit.Framework;
using Org.BouncyCastle.Asn1;
@@ -136,6 +133,12 @@ namespace Org.BouncyCastle.Crypto.Tests
private void DoSignerTest(ECDomainParameters domainParams, IDigest d, string ident, string msg, string x, string nonce, string r, string s)
{
+ ImplSignerTest(domainParams, d, ident, msg, x, nonce, r, s);
+ ImplSignerTestReuse(domainParams, d, ident, msg, x);
+ }
+
+ private void ImplSignerTest(ECDomainParameters domainParams, IDigest d, string ident, string msg, string x, string nonce, string r, string s)
+ {
byte[] idBytes = Strings.ToByteArray(ident);
byte[] msgBytes = Strings.ToByteArray(msg);
AsymmetricCipherKeyPair kp = GenerateKeyPair(domainParams, x);
@@ -162,6 +165,39 @@ namespace Org.BouncyCastle.Crypto.Tests
IsTrue("verification failed", signer.VerifySignature(sig));
}
+ private void ImplSignerTestReuse(ECDomainParameters domainParams, IDigest d, string ident, string msg, string x)
+ {
+ byte[] idBytes = Strings.ToByteArray(ident);
+ byte[] msgBytes = Strings.ToByteArray(msg);
+ AsymmetricCipherKeyPair kp = GenerateKeyPair(domainParams, x);
+
+ SM2Signer signer = new SM2Signer(d);
+
+ signer.Init(true, new ParametersWithID(kp.Private, idBytes));
+ signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
+ byte[] sig1 = signer.GenerateSignature();
+
+ signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
+ byte[] sig2 = signer.GenerateSignature();
+
+ signer.Update(0x00);
+ signer.Reset();
+ signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
+ byte[] sig3 = signer.GenerateSignature();
+
+ signer.Init(false, new ParametersWithID(kp.Public, idBytes));
+ signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
+ IsTrue("verification failed", signer.VerifySignature(sig1));
+
+ signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
+ IsTrue("verification failed", signer.VerifySignature(sig2));
+
+ signer.Update(0x00);
+ signer.Reset();
+ signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
+ IsTrue("verification failed", signer.VerifySignature(sig3));
+ }
+
private void DoVerifyBoundsCheck()
{
ECDomainParameters domainParams = ParametersF2m;
|