diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2017-09-16 15:21:21 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2017-09-16 15:21:21 +0700 |
commit | 574dbc0875687377c607a92765463986caa3da7a (patch) | |
tree | d461735ecdfa038c67fd9ead17c0c4b1e284b1e4 | |
parent | SM2 signing cleanup (diff) | |
download | BouncyCastle.NET-ed25519-574dbc0875687377c607a92765463986caa3da7a.tar.xz |
Port of SM2KeyExchange from Java
-rw-r--r-- | crypto/BouncyCastle.Android.csproj | 3 | ||||
-rw-r--r-- | crypto/BouncyCastle.csproj | 3 | ||||
-rw-r--r-- | crypto/BouncyCastle.iOS.csproj | 3 | ||||
-rw-r--r-- | crypto/crypto.csproj | 20 | ||||
-rw-r--r-- | crypto/src/crypto/agreement/SM2KeyExchange.cs | 272 | ||||
-rw-r--r-- | crypto/src/crypto/parameters/SM2KeyExchangePrivateParameters.cs | 64 | ||||
-rw-r--r-- | crypto/src/crypto/parameters/SM2KeyExchangePublicParameters.cs | 40 | ||||
-rw-r--r-- | crypto/test/UnitTests.csproj | 1 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/RegressionTest.cs | 1 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/SM2KeyExchangeTest.cs | 229 |
10 files changed, 636 insertions, 0 deletions
diff --git a/crypto/BouncyCastle.Android.csproj b/crypto/BouncyCastle.Android.csproj index 926e0fd94..3a716e52e 100644 --- a/crypto/BouncyCastle.Android.csproj +++ b/crypto/BouncyCastle.Android.csproj @@ -696,6 +696,7 @@ <Compile Include="src\crypto\agreement\ECDHWithKdfBasicAgreement.cs" /> <Compile Include="src\crypto\agreement\ECMqvBasicAgreement.cs" /> <Compile Include="src\crypto\agreement\ECMqvWithKdfBasicAgreement.cs" /> + <Compile Include="src\crypto\agreement\SM2KeyExchange.cs" /> <Compile Include="src\crypto\agreement\jpake\JPakeParticipant.cs" /> <Compile Include="src\crypto\agreement\jpake\JPakePrimeOrderGroup.cs" /> <Compile Include="src\crypto\agreement\jpake\JPakePrimeOrderGroups.cs" /> @@ -928,6 +929,8 @@ <Compile Include="src\crypto\parameters\RsaKeyParameters.cs" /> <Compile Include="src\crypto\parameters\RsaPrivateCrtKeyParameters.cs" /> <Compile Include="src\crypto\parameters\SkeinParameters.cs" /> + <Compile Include="src\crypto\parameters\SM2KeyExchangePrivateParameters.cs" /> + <Compile Include="src\crypto\parameters\SM2KeyExchangePublicParameters.cs" /> <Compile Include="src\crypto\parameters\Srp6GroupParameters.cs" /> <Compile Include="src\crypto\parameters\TweakableBlockCipherParameters.cs" /> <Compile Include="src\crypto\prng\CryptoApiRandomGenerator.cs" /> diff --git a/crypto/BouncyCastle.csproj b/crypto/BouncyCastle.csproj index 463ba2a1c..346092b76 100644 --- a/crypto/BouncyCastle.csproj +++ b/crypto/BouncyCastle.csproj @@ -690,6 +690,7 @@ <Compile Include="src\crypto\agreement\ECDHWithKdfBasicAgreement.cs" /> <Compile Include="src\crypto\agreement\ECMqvBasicAgreement.cs" /> <Compile Include="src\crypto\agreement\ECMqvWithKdfBasicAgreement.cs" /> + <Compile Include="src\crypto\agreement\SM2KeyExchange.cs" /> <Compile Include="src\crypto\agreement\jpake\JPakeParticipant.cs" /> <Compile Include="src\crypto\agreement\jpake\JPakePrimeOrderGroup.cs" /> <Compile Include="src\crypto\agreement\jpake\JPakePrimeOrderGroups.cs" /> @@ -922,6 +923,8 @@ <Compile Include="src\crypto\parameters\RsaKeyParameters.cs" /> <Compile Include="src\crypto\parameters\RsaPrivateCrtKeyParameters.cs" /> <Compile Include="src\crypto\parameters\SkeinParameters.cs" /> + <Compile Include="src\crypto\parameters\SM2KeyExchangePrivateParameters.cs" /> + <Compile Include="src\crypto\parameters\SM2KeyExchangePublicParameters.cs" /> <Compile Include="src\crypto\parameters\Srp6GroupParameters.cs" /> <Compile Include="src\crypto\parameters\TweakableBlockCipherParameters.cs" /> <Compile Include="src\crypto\prng\CryptoApiRandomGenerator.cs" /> diff --git a/crypto/BouncyCastle.iOS.csproj b/crypto/BouncyCastle.iOS.csproj index 783009d38..53597e3dd 100644 --- a/crypto/BouncyCastle.iOS.csproj +++ b/crypto/BouncyCastle.iOS.csproj @@ -691,6 +691,7 @@ <Compile Include="src\crypto\agreement\ECDHWithKdfBasicAgreement.cs" /> <Compile Include="src\crypto\agreement\ECMqvBasicAgreement.cs" /> <Compile Include="src\crypto\agreement\ECMqvWithKdfBasicAgreement.cs" /> + <Compile Include="src\crypto\agreement\SM2KeyExchange.cs" /> <Compile Include="src\crypto\agreement\jpake\JPakeParticipant.cs" /> <Compile Include="src\crypto\agreement\jpake\JPakePrimeOrderGroup.cs" /> <Compile Include="src\crypto\agreement\jpake\JPakePrimeOrderGroups.cs" /> @@ -923,6 +924,8 @@ <Compile Include="src\crypto\parameters\RsaKeyParameters.cs" /> <Compile Include="src\crypto\parameters\RsaPrivateCrtKeyParameters.cs" /> <Compile Include="src\crypto\parameters\SkeinParameters.cs" /> + <Compile Include="src\crypto\parameters\SM2KeyExchangePrivateParameters.cs" /> + <Compile Include="src\crypto\parameters\SM2KeyExchangePublicParameters.cs" /> <Compile Include="src\crypto\parameters\Srp6GroupParameters.cs" /> <Compile Include="src\crypto\parameters\TweakableBlockCipherParameters.cs" /> <Compile Include="src\crypto\prng\CryptoApiRandomGenerator.cs" /> diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj index 509638ff1..f9d38edd5 100644 --- a/crypto/crypto.csproj +++ b/crypto/crypto.csproj @@ -3234,6 +3234,11 @@ BuildAction = "Compile" /> <File + RelPath = "src\crypto\agreement\SM2KeyExchange.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\crypto\agreement\jpake\JPakeParticipant.cs" SubType = "Code" BuildAction = "Compile" @@ -4429,6 +4434,16 @@ BuildAction = "Compile" /> <File + RelPath = "src\crypto\parameters\SM2KeyExchangePrivateParameters.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "src\crypto\parameters\SM2KeyExchangePublicParameters.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "src\crypto\parameters\Srp6GroupParameters.cs" SubType = "Code" BuildAction = "Compile" @@ -11920,6 +11935,11 @@ BuildAction = "Compile" /> <File + RelPath = "test\src\crypto\test\SM2KeyExchangeTest.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "test\src\crypto\test\SM2SignerTest.cs" SubType = "Code" BuildAction = "Compile" diff --git a/crypto/src/crypto/agreement/SM2KeyExchange.cs b/crypto/src/crypto/agreement/SM2KeyExchange.cs new file mode 100644 index 000000000..1cfcd6a3a --- /dev/null +++ b/crypto/src/crypto/agreement/SM2KeyExchange.cs @@ -0,0 +1,272 @@ +using System; + +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Utilities; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Agreement +{ + /// <summary> + /// SM2 Key Exchange protocol - based on https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02 + /// </summary> + public class SM2KeyExchange + { + private readonly IDigest mDigest; + + private byte[] mUserID; + private ECPrivateKeyParameters mStaticKey; + private ECPoint mStaticPubPoint; + private ECPoint mEphemeralPubPoint; + private ECDomainParameters mECParams; + private int mW; + private ECPrivateKeyParameters mEphemeralKey; + private bool mInitiator; + + public SM2KeyExchange() + : this(new SM3Digest()) + { + } + + public SM2KeyExchange(IDigest digest) + { + this.mDigest = digest; + } + + public virtual void Init(ICipherParameters privParam) + { + SM2KeyExchangePrivateParameters baseParam; + + if (privParam is ParametersWithID) + { + baseParam = (SM2KeyExchangePrivateParameters)((ParametersWithID)privParam).Parameters; + mUserID = ((ParametersWithID)privParam).GetID(); + } + else + { + baseParam = (SM2KeyExchangePrivateParameters)privParam; + mUserID = new byte[0]; + } + + mInitiator = baseParam.IsInitiator; + mStaticKey = baseParam.StaticPrivateKey; + mEphemeralKey = baseParam.EphemeralPrivateKey; + mECParams = mStaticKey.Parameters; + mStaticPubPoint = baseParam.StaticPublicPoint; + mEphemeralPubPoint = baseParam.EphemeralPublicPoint; + mW = mECParams.Curve.FieldSize / 2 - 1; + } + + public virtual byte[] CalculateKey(int kLen, ICipherParameters pubParam) + { + SM2KeyExchangePublicParameters otherPub; + byte[] otherUserID; + + if (pubParam is ParametersWithID) + { + otherPub = (SM2KeyExchangePublicParameters)((ParametersWithID)pubParam).Parameters; + otherUserID = ((ParametersWithID)pubParam).GetID(); + } + else + { + otherPub = (SM2KeyExchangePublicParameters)pubParam; + otherUserID = new byte[0]; + } + + byte[] za = GetZ(mDigest, mUserID, mStaticPubPoint); + byte[] zb = GetZ(mDigest, otherUserID, otherPub.StaticPublicKey.Q); + + ECPoint U = CalculateU(otherPub); + + byte[] rv; + if (mInitiator) + { + rv = Kdf(U, za, zb, kLen); + } + else + { + rv = Kdf(U, zb, za, kLen); + } + + return rv; + } + + public virtual byte[][] CalculateKeyWithConfirmation(int kLen, byte[] confirmationTag, ICipherParameters pubParam) + { + SM2KeyExchangePublicParameters otherPub; + byte[] otherUserID; + + if (pubParam is ParametersWithID) + { + otherPub = (SM2KeyExchangePublicParameters)((ParametersWithID)pubParam).Parameters; + otherUserID = ((ParametersWithID)pubParam).GetID(); + } + else + { + otherPub = (SM2KeyExchangePublicParameters)pubParam; + otherUserID = new byte[0]; + } + + if (mInitiator && confirmationTag == null) + throw new ArgumentException("if initiating, confirmationTag must be set"); + + byte[] za = GetZ(mDigest, mUserID, mStaticPubPoint); + byte[] zb = GetZ(mDigest, otherUserID, otherPub.StaticPublicKey.Q); + + ECPoint U = CalculateU(otherPub); + + byte[] rv; + if (mInitiator) + { + rv = Kdf(U, za, zb, kLen); + + byte[] inner = CalculateInnerHash(mDigest, U, za, zb, mEphemeralPubPoint, otherPub.EphemeralPublicKey.Q); + + byte[] s1 = S1(mDigest, U, inner); + + if (!Arrays.ConstantTimeAreEqual(s1, confirmationTag)) + throw new InvalidOperationException("confirmation tag mismatch"); + + return new byte[][] { rv, S2(mDigest, U, inner)}; + } + else + { + rv = Kdf(U, zb, za, kLen); + + byte[] inner = CalculateInnerHash(mDigest, U, zb, za, otherPub.EphemeralPublicKey.Q, mEphemeralPubPoint); + + return new byte[][] { rv, S1(mDigest, U, inner), S2(mDigest, U, inner) }; + } + } + + protected virtual ECPoint CalculateU(SM2KeyExchangePublicParameters otherPub) + { + ECPoint p1 = otherPub.StaticPublicKey.Q; + ECPoint p2 = otherPub.EphemeralPublicKey.Q; + + BigInteger x1 = Reduce(mEphemeralPubPoint.AffineXCoord.ToBigInteger()); + BigInteger x2 = Reduce(p2.AffineXCoord.ToBigInteger()); + BigInteger tA = mStaticKey.D.Add(x1.Multiply(mEphemeralKey.D)); + BigInteger k1 = mECParams.H.Multiply(tA).Mod(mECParams.N); + BigInteger k2 = k1.Multiply(x2).Mod(mECParams.N); + + return ECAlgorithms.SumOfTwoMultiplies(p1, k1, p2, k2).Normalize(); + } + + protected virtual byte[] Kdf(ECPoint u, byte[] za, byte[] zb, int klen) + { + int digestSize = mDigest.GetDigestSize(); + byte[] buf = new byte[System.Math.Max(4, digestSize)]; + byte[] rv = new byte[(klen + 7) / 8]; + int off = 0; + + IMemoable memo = mDigest as IMemoable; + IMemoable copy = null; + + if (memo != null) + { + AddFieldElement(mDigest, u.AffineXCoord); + AddFieldElement(mDigest, u.AffineYCoord); + mDigest.BlockUpdate(za, 0, za.Length); + mDigest.BlockUpdate(zb, 0, zb.Length); + copy = memo.Copy(); + } + + uint ct = 0; + + while (off < rv.Length) + { + if (memo != null) + { + memo.Reset(copy); + } + else + { + AddFieldElement(mDigest, u.AffineXCoord); + AddFieldElement(mDigest, u.AffineYCoord); + mDigest.BlockUpdate(za, 0, za.Length); + mDigest.BlockUpdate(zb, 0, zb.Length); + } + + Pack.UInt32_To_BE(++ct, buf, 0); + mDigest.BlockUpdate(buf, 0, 4); + mDigest.DoFinal(buf, 0); + + int copyLen = System.Math.Min(digestSize, rv.Length - off); + Array.Copy(buf, 0, rv, off, copyLen); + off += copyLen; + } + + return rv; + } + + //x1~=2^w+(x1 AND (2^w-1)) + private BigInteger Reduce(BigInteger x) + { + return x.And(BigInteger.One.ShiftLeft(mW).Subtract(BigInteger.One)).SetBit(mW); + } + + private byte[] S1(IDigest digest, ECPoint u, byte[] inner) + { + digest.Update((byte)0x02); + AddFieldElement(digest, u.AffineYCoord); + digest.BlockUpdate(inner, 0, inner.Length); + + return DigestUtilities.DoFinal(digest); + } + + private byte[] CalculateInnerHash(IDigest digest, ECPoint u, byte[] za, byte[] zb, ECPoint p1, ECPoint p2) + { + AddFieldElement(digest, u.AffineXCoord); + digest.BlockUpdate(za, 0, za.Length); + digest.BlockUpdate(zb, 0, zb.Length); + AddFieldElement(digest, p1.AffineXCoord); + AddFieldElement(digest, p1.AffineYCoord); + AddFieldElement(digest, p2.AffineXCoord); + AddFieldElement(digest, p2.AffineYCoord); + + return DigestUtilities.DoFinal(digest); + } + + private byte[] S2(IDigest digest, ECPoint u, byte[] inner) + { + digest.Update((byte)0x03); + AddFieldElement(digest, u.AffineYCoord); + digest.BlockUpdate(inner, 0, inner.Length); + + return DigestUtilities.DoFinal(digest); + } + + private byte[] GetZ(IDigest digest, byte[] userID, ECPoint pubPoint) + { + AddUserID(digest, userID); + + AddFieldElement(digest, mECParams.Curve.A); + AddFieldElement(digest, mECParams.Curve.B); + AddFieldElement(digest, mECParams.G.AffineXCoord); + AddFieldElement(digest, mECParams.G.AffineYCoord); + AddFieldElement(digest, pubPoint.AffineXCoord); + AddFieldElement(digest, pubPoint.AffineYCoord); + + return DigestUtilities.DoFinal(digest); + } + + private void AddUserID(IDigest digest, byte[] userID) + { + uint len = (uint)(userID.Length * 8); + + digest.Update((byte)(len >> 8)); + digest.Update((byte)len); + digest.BlockUpdate(userID, 0, userID.Length); + } + + private void AddFieldElement(IDigest digest, ECFieldElement v) + { + byte[] p = v.GetEncoded(); + digest.BlockUpdate(p, 0, p.Length); + } + } +} diff --git a/crypto/src/crypto/parameters/SM2KeyExchangePrivateParameters.cs b/crypto/src/crypto/parameters/SM2KeyExchangePrivateParameters.cs new file mode 100644 index 000000000..8afb61544 --- /dev/null +++ b/crypto/src/crypto/parameters/SM2KeyExchangePrivateParameters.cs @@ -0,0 +1,64 @@ +using System; + +using Org.BouncyCastle.Math.EC; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + /// <summary>Private parameters for an SM2 key exchange.</summary> + /// <remarks>The ephemeralPrivateKey is used to calculate the random point used in the algorithm.</remarks> + public class SM2KeyExchangePrivateParameters + : ICipherParameters + { + private readonly bool mInitiator; + private readonly ECPrivateKeyParameters mStaticPrivateKey; + private readonly ECPoint mStaticPublicPoint; + private readonly ECPrivateKeyParameters mEphemeralPrivateKey; + private readonly ECPoint mEphemeralPublicPoint; + + public SM2KeyExchangePrivateParameters( + bool initiator, + ECPrivateKeyParameters staticPrivateKey, + ECPrivateKeyParameters ephemeralPrivateKey) + { + if (staticPrivateKey == null) + throw new ArgumentNullException("staticPrivateKey"); + if (ephemeralPrivateKey == null) + throw new ArgumentNullException("ephemeralPrivateKey"); + + ECDomainParameters parameters = staticPrivateKey.Parameters; + if (!parameters.Equals(ephemeralPrivateKey.Parameters)) + throw new ArgumentException("Static and ephemeral private keys have different domain parameters"); + + this.mInitiator = initiator; + this.mStaticPrivateKey = staticPrivateKey; + this.mStaticPublicPoint = parameters.G.Multiply(staticPrivateKey.D).Normalize(); + this.mEphemeralPrivateKey = ephemeralPrivateKey; + this.mEphemeralPublicPoint = parameters.G.Multiply(ephemeralPrivateKey.D).Normalize(); + } + + public virtual bool IsInitiator + { + get { return mInitiator; } + } + + public virtual ECPrivateKeyParameters StaticPrivateKey + { + get { return mStaticPrivateKey; } + } + + public virtual ECPoint StaticPublicPoint + { + get { return mStaticPublicPoint; } + } + + public virtual ECPrivateKeyParameters EphemeralPrivateKey + { + get { return mEphemeralPrivateKey; } + } + + public virtual ECPoint EphemeralPublicPoint + { + get { return mEphemeralPublicPoint; } + } + } +} diff --git a/crypto/src/crypto/parameters/SM2KeyExchangePublicParameters.cs b/crypto/src/crypto/parameters/SM2KeyExchangePublicParameters.cs new file mode 100644 index 000000000..5c213159e --- /dev/null +++ b/crypto/src/crypto/parameters/SM2KeyExchangePublicParameters.cs @@ -0,0 +1,40 @@ +using System; + +using Org.BouncyCastle.Math.EC; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + /// <summary>Public parameters for an SM2 key exchange.</summary> + /// <remarks>In this case the ephemeralPublicKey provides the random point used in the algorithm.</remarks> + public class SM2KeyExchangePublicParameters + : ICipherParameters + { + private readonly ECPublicKeyParameters mStaticPublicKey; + private readonly ECPublicKeyParameters mEphemeralPublicKey; + + public SM2KeyExchangePublicParameters( + ECPublicKeyParameters staticPublicKey, + ECPublicKeyParameters ephemeralPublicKey) + { + if (staticPublicKey == null) + throw new ArgumentNullException("staticPublicKey"); + if (ephemeralPublicKey == null) + throw new ArgumentNullException("ephemeralPublicKey"); + if (!staticPublicKey.Parameters.Equals(ephemeralPublicKey.Parameters)) + throw new ArgumentException("Static and ephemeral public keys have different domain parameters"); + + this.mStaticPublicKey = staticPublicKey; + this.mEphemeralPublicKey = ephemeralPublicKey; + } + + public virtual ECPublicKeyParameters StaticPublicKey + { + get { return mStaticPublicKey; } + } + + public virtual ECPublicKeyParameters EphemeralPublicKey + { + get { return mEphemeralPublicKey; } + } + } +} diff --git a/crypto/test/UnitTests.csproj b/crypto/test/UnitTests.csproj index f875c22b1..bd7ad5787 100644 --- a/crypto/test/UnitTests.csproj +++ b/crypto/test/UnitTests.csproj @@ -256,6 +256,7 @@ <Compile Include="src\crypto\test\SHA512HMacTest.cs" /> <Compile Include="src\crypto\test\SHA512t224DigestTest.cs" /> <Compile Include="src\crypto\test\SHA512t256DigestTest.cs" /> + <Compile Include="src\crypto\test\SM2KeyExchangeTest.cs" /> <Compile Include="src\crypto\test\SM2SignerTest.cs" /> <Compile Include="src\crypto\test\SM3DigestTest.cs" /> <Compile Include="src\crypto\test\SkeinDigestTest.cs" /> diff --git a/crypto/test/src/crypto/test/RegressionTest.cs b/crypto/test/src/crypto/test/RegressionTest.cs index f2a92fab3..bc857b5d0 100644 --- a/crypto/test/src/crypto/test/RegressionTest.cs +++ b/crypto/test/src/crypto/test/RegressionTest.cs @@ -128,6 +128,7 @@ namespace Org.BouncyCastle.Crypto.Tests new X931SignerTest(), new KeccakDigestTest(), new ShakeDigestTest(), + new SM2KeyExchangeTest(), new SM2SignerTest(), }; diff --git a/crypto/test/src/crypto/test/SM2KeyExchangeTest.cs b/crypto/test/src/crypto/test/SM2KeyExchangeTest.cs new file mode 100644 index 000000000..d7a2650eb --- /dev/null +++ b/crypto/test/src/crypto/test/SM2KeyExchangeTest.cs @@ -0,0 +1,229 @@ +using System; +using System.IO; + +using NUnit.Framework; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Crypto.Agreement; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Math.EC; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Crypto.Tests +{ + [TestFixture] + public class SM2KeyExchangeTest + : SimpleTest + { + public override string Name + { + get { return "SM2KeyExchange"; } + } + + private void DoKeyExchangeTestFp() + { + BigInteger SM2_ECC_P = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3", 16); + BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16); + BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16); + BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16); + BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16); + BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16); + + ECCurve curve = new FpCurve(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B); + + ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY); + ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N); + + ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); + + ECKeyGenerationParameters aKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("6FCBA2EF9AE0AB902BC3BDE3FF915D44BA4CC78F88E2F8E7F8996D3B8CCEEDEE", 16)); + + keyPairGenerator.Init(aKeyGenParams); + + AsymmetricCipherKeyPair aKp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters aPub = (ECPublicKeyParameters)aKp.Public; + ECPrivateKeyParameters aPriv = (ECPrivateKeyParameters)aKp.Private; + + ECKeyGenerationParameters aeKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("83A2C9C8B96E5AF70BD480B472409A9A327257F1EBB73F5B073354B248668563", 16)); + + keyPairGenerator.Init(aeKeyGenParams); + + AsymmetricCipherKeyPair aeKp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters aePub = (ECPublicKeyParameters)aeKp.Public; + ECPrivateKeyParameters aePriv = (ECPrivateKeyParameters)aeKp.Private; + + ECKeyGenerationParameters bKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("5E35D7D3F3C54DBAC72E61819E730B019A84208CA3A35E4C2E353DFCCB2A3B53", 16)); + + keyPairGenerator.Init(bKeyGenParams); + + AsymmetricCipherKeyPair bKp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters bPub = (ECPublicKeyParameters)bKp.Public; + ECPrivateKeyParameters bPriv = (ECPrivateKeyParameters)bKp.Private; + + ECKeyGenerationParameters beKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("33FE21940342161C55619C4A0C060293D543C80AF19748CE176D83477DE71C80", 16)); + + keyPairGenerator.Init(beKeyGenParams); + + AsymmetricCipherKeyPair beKp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters bePub = (ECPublicKeyParameters)beKp.Public; + ECPrivateKeyParameters bePriv = (ECPrivateKeyParameters)beKp.Private; + + SM2KeyExchange exch = new SM2KeyExchange(); + + exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(true, aPriv, aePriv), Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + byte[] k1 = exch.CalculateKey(128, new ParametersWithID(new SM2KeyExchangePublicParameters(bPub, bePub), Strings.ToByteArray("BILL456@YAHOO.COM"))); + + IsTrue("key 1 wrong", Arrays.AreEqual(Hex.Decode("55b0ac62a6b927ba23703832c853ded4"), k1)); + + exch = new SM2KeyExchange(); + + exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(false, bPriv, bePriv), Strings.ToByteArray("BILL456@YAHOO.COM"))); + + byte[] k2 = exch.CalculateKey(128, new ParametersWithID(new SM2KeyExchangePublicParameters(aPub, aePub), Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + IsTrue("key 2 wrong", Arrays.AreEqual(Hex.Decode("55b0ac62a6b927ba23703832c853ded4"), k2)); + + // with key confirmation + exch = new SM2KeyExchange(); + + exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(false, bPriv, bePriv), Strings.ToByteArray("BILL456@YAHOO.COM"))); + + byte[][] vals2 = exch.CalculateKeyWithConfirmation(128, null, new ParametersWithID(new SM2KeyExchangePublicParameters(aPub, aePub), Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + IsTrue("key 2 wrong", Arrays.AreEqual(Hex.Decode("55b0ac62a6b927ba23703832c853ded4"), k2)); + + IsTrue("conf a tag 2 wrong", Arrays.AreEqual(Hex.Decode("284C8F198F141B502E81250F1581C7E9EEB4CA6990F9E02DF388B45471F5BC5C"), vals2[1])); + IsTrue("conf b tag 2 wrong", Arrays.AreEqual(Hex.Decode("23444DAF8ED7534366CB901C84B3BDBB63504F4065C1116C91A4C00697E6CF7A"), vals2[2])); + + exch = new SM2KeyExchange(); + + exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(true, aPriv, aePriv), Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + byte[][] vals1 = exch.CalculateKeyWithConfirmation(128, vals2[1], new ParametersWithID(new SM2KeyExchangePublicParameters(bPub, bePub), Strings.ToByteArray("BILL456@YAHOO.COM"))); + + IsTrue("conf key 1 wrong", Arrays.AreEqual(Hex.Decode("55b0ac62a6b927ba23703832c853ded4"), vals1[0])); + IsTrue("conf tag 1 wrong", Arrays.AreEqual(Hex.Decode("23444DAF8ED7534366CB901C84B3BDBB63504F4065C1116C91A4C00697E6CF7A"), vals1[1])); + } + + private void DoKeyExchangeTestF2m() + { + BigInteger SM2_ECC_A = new BigInteger("00", 16); + BigInteger SM2_ECC_B = new BigInteger("E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B", 16); + BigInteger SM2_ECC_N = new BigInteger("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC972CF7E6B6F900945B3C6A0CF6161D", 16); + BigInteger SM2_ECC_GX = new BigInteger("00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD", 16); + BigInteger SM2_ECC_GY = new BigInteger("013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E", 16); + BigInteger SM2_ECC_H = BigInteger.ValueOf(4); + + ECCurve curve = new F2mCurve(257, 12, SM2_ECC_A, SM2_ECC_B); + + ECPoint g = curve.CreatePoint(SM2_ECC_GX, SM2_ECC_GY); + ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N, SM2_ECC_H); + + ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); + + ECKeyGenerationParameters aKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("4813903D254F2C20A94BC5704238496954BB5279F861952EF2C5298E84D2CEAA", 16)); + + keyPairGenerator.Init(aKeyGenParams); + + AsymmetricCipherKeyPair aKp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters aPub = (ECPublicKeyParameters)aKp.Public; + ECPrivateKeyParameters aPriv = (ECPrivateKeyParameters)aKp.Private; + + ECKeyGenerationParameters aeKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("54A3D6673FF3A6BD6B02EBB164C2A3AF6D4A4906229D9BFCE68CC366A2E64BA4", 16)); + + keyPairGenerator.Init(aeKeyGenParams); + + AsymmetricCipherKeyPair aeKp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters aePub = (ECPublicKeyParameters)aeKp.Public; + ECPrivateKeyParameters aePriv = (ECPrivateKeyParameters)aeKp.Private; + + ECKeyGenerationParameters bKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("08F41BAE0922F47C212803FE681AD52B9BF28A35E1CD0EC273A2CF813E8FD1DC", 16)); + + keyPairGenerator.Init(bKeyGenParams); + + AsymmetricCipherKeyPair bKp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters bPub = (ECPublicKeyParameters)bKp.Public; + ECPrivateKeyParameters bPriv = (ECPrivateKeyParameters)bKp.Private; + + ECKeyGenerationParameters beKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("1F21933387BEF781D0A8F7FD708C5AE0A56EE3F423DBC2FE5BDF6F068C53F7AD", 16)); + + keyPairGenerator.Init(beKeyGenParams); + + AsymmetricCipherKeyPair beKp = keyPairGenerator.GenerateKeyPair(); + + ECPublicKeyParameters bePub = (ECPublicKeyParameters)beKp.Public; + ECPrivateKeyParameters bePriv = (ECPrivateKeyParameters)beKp.Private; + + SM2KeyExchange exch = new SM2KeyExchange(); + + exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(true, aPriv, aePriv), Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + byte[] k1 = exch.CalculateKey(128, new ParametersWithID(new SM2KeyExchangePublicParameters(bPub, bePub), Strings.ToByteArray("BILL456@YAHOO.COM"))); + + // there appears to be typo for ZA in the draft + //IsTrue("F2m key 1 wrong", Arrays.AreEqual(Hex.Decode("4E587E5C66634F22D973A7D98BF8BE23"), k1)); + IsTrue("F2m key 1 wrong", Arrays.AreEqual(Hex.Decode("8c2b03289aa7126555dc660cfc29fd74"), k1)); + + exch = new SM2KeyExchange(); + + exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(false, bPriv, bePriv), Strings.ToByteArray("BILL456@YAHOO.COM"))); + + byte[] k2 = exch.CalculateKey(128, new ParametersWithID(new SM2KeyExchangePublicParameters(aPub, aePub), Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + //IsTrue("F2m key 2 wrong", Arrays.AreEqual(Hex.Decode("4E587E5C66634F22D973A7D98BF8BE23"), k2)); + IsTrue("F2m key 2 wrong", Arrays.AreEqual(Hex.Decode("8c2b03289aa7126555dc660cfc29fd74"), k2)); + + // with key confirmation + exch = new SM2KeyExchange(); + + exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(false, bPriv, bePriv), Strings.ToByteArray("BILL456@YAHOO.COM"))); + + byte[][] vals2 = exch.CalculateKeyWithConfirmation(128, null, new ParametersWithID(new SM2KeyExchangePublicParameters(aPub, aePub), Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + IsTrue("key 2 wrong", Arrays.AreEqual(Hex.Decode("8c2b03289aa7126555dc660cfc29fd74"), k2)); + + IsTrue("conf a tag 2 wrong", Arrays.AreEqual(Hex.Decode("d8294c4c0f0ac180feac95e8a0d786638c9e915b9a684b2348809af03a0de2a5"), vals2[1])); + IsTrue("conf b tag 2 wrong", Arrays.AreEqual(Hex.Decode("52089e706911b58fd5e7c7b2ab5cf32bb61e481ef1e114a1e33d99eec84b5a4f"), vals2[2])); + + exch = new SM2KeyExchange(); + + exch.Init(new ParametersWithID(new SM2KeyExchangePrivateParameters(true, aPriv, aePriv), Strings.ToByteArray("ALICE123@YAHOO.COM"))); + + byte[][] vals1 = exch.CalculateKeyWithConfirmation(128, vals2[1], new ParametersWithID(new SM2KeyExchangePublicParameters(bPub, bePub), Strings.ToByteArray("BILL456@YAHOO.COM"))); + + IsTrue("conf key 1 wrong", Arrays.AreEqual(Hex.Decode("8c2b03289aa7126555dc660cfc29fd74"), vals1[0])); + IsTrue("conf tag 1 wrong", Arrays.AreEqual(Hex.Decode("52089e706911b58fd5e7c7b2ab5cf32bb61e481ef1e114a1e33d99eec84b5a4f"), vals1[1])); + } + + public override void PerformTest() + { + DoKeyExchangeTestFp(); + DoKeyExchangeTestF2m(); + } + + public static void Main(string[] args) + { + RunTest(new SM2KeyExchangeTest()); + } + + [Test] + public void TestFunction() + { + string resultText = Perform().ToString(); + + Assert.AreEqual(Name + ": Okay", resultText); + } + } +} |