Skip to content

Commit

Permalink
Support signer reuse in SM2Signer
Browse files Browse the repository at this point in the history
  • Loading branch information
peterdettman committed Jan 29, 2024
1 parent 5ad15ee commit 196797d
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 9 deletions.
62 changes: 56 additions & 6 deletions crypto/src/crypto/signers/SM2Signer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -100,23 +108,28 @@ public virtual void Init(bool forSigning, ICipherParameters parameters)

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
Expand All @@ -125,6 +138,8 @@ public virtual void BlockUpdate(ReadOnlySpan<byte> input)

public virtual byte[] GenerateSignature()
{
CheckData();

byte[] eHash = DigestUtilities.DoFinal(digest);

BigInteger n = ecParams.N;
Expand Down Expand Up @@ -169,10 +184,16 @@ public virtual byte[] GenerateSignature()
{
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);
Expand All @@ -182,17 +203,28 @@ public virtual bool VerifySignature(byte[] signature)
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)
Expand Down Expand Up @@ -226,7 +258,25 @@ private bool VerifySignature(BigInteger r, BigInteger s)
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)
Expand Down
42 changes: 39 additions & 3 deletions crypto/test/src/crypto/test/SM2SignerTest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
using System;
using System.IO;

using NUnit.Framework;

using Org.BouncyCastle.Asn1;
Expand Down Expand Up @@ -135,6 +132,12 @@ private void DoSignerTest(string curveName, IDigest d, string ident, string msg,
}

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);
Expand Down Expand Up @@ -162,6 +165,39 @@ private void DoSignerTest(ECDomainParameters domainParams, IDigest d, string ide
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;
Expand Down

0 comments on commit 196797d

Please sign in to comment.