培训考核三期,新版培训,网页版培训登录器
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

279 lines
9.5 KiB

#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Digests;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Math;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
namespace BestHTTP.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