123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
- #pragma warning disable
- using System;
- using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Digests;
- using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
- using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
- using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math;
- using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math.EC;
- using Best.HTTP.SecureProtocol.Org.BouncyCastle.Security;
- using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
- namespace Best.HTTP.SecureProtocol.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)
- {
- ECDomainParameters dp = mStaticKey.Parameters;
- ECPoint p1 = ECAlgorithms.CleanPoint(dp.Curve, otherPub.StaticPublicKey.Q);
- ECPoint p2 = ECAlgorithms.CleanPoint(dp.Curve, 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);
- }
- }
- }
- #pragma warning restore
- #endif
|