培训考核三期,新版培训,网页版培训登录器
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.
 
 

242 lines
7.0 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.Math.EC.Multiplier;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Engines
{
/// <summary>
/// SM2 public key encryption engine - based on https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02.
/// </summary>
public class SM2Engine
{
private readonly IDigest mDigest;
private bool mForEncryption;
private ECKeyParameters mECKey;
private ECDomainParameters mECParams;
private int mCurveLength;
private SecureRandom mRandom;
public SM2Engine()
: this(new SM3Digest())
{
}
public SM2Engine(IDigest digest)
{
this.mDigest = digest;
}
public virtual void Init(bool forEncryption, ICipherParameters param)
{
this.mForEncryption = forEncryption;
if (forEncryption)
{
ParametersWithRandom rParam = (ParametersWithRandom)param;
mECKey = (ECKeyParameters)rParam.Parameters;
mECParams = mECKey.Parameters;
ECPoint s = ((ECPublicKeyParameters)mECKey).Q.Multiply(mECParams.H);
if (s.IsInfinity)
throw new ArgumentException("invalid key: [h]Q at infinity");
mRandom = rParam.Random;
}
else
{
mECKey = (ECKeyParameters)param;
mECParams = mECKey.Parameters;
}
mCurveLength = (mECParams.Curve.FieldSize + 7) / 8;
}
public virtual byte[] ProcessBlock(byte[] input, int inOff, int inLen)
{
if (mForEncryption)
{
return Encrypt(input, inOff, inLen);
}
else
{
return Decrypt(input, inOff, inLen);
}
}
protected virtual ECMultiplier CreateBasePointMultiplier()
{
return new FixedPointCombMultiplier();
}
private byte[] Encrypt(byte[] input, int inOff, int inLen)
{
byte[] c2 = new byte[inLen];
Array.Copy(input, inOff, c2, 0, c2.Length);
ECMultiplier multiplier = CreateBasePointMultiplier();
byte[] c1;
ECPoint kPB;
do
{
BigInteger k = NextK();
ECPoint c1P = multiplier.Multiply(mECParams.G, k).Normalize();
c1 = c1P.GetEncoded(false);
kPB = ((ECPublicKeyParameters)mECKey).Q.Multiply(k).Normalize();
Kdf(mDigest, kPB, c2);
}
while (NotEncrypted(c2, input, inOff));
AddFieldElement(mDigest, kPB.AffineXCoord);
mDigest.BlockUpdate(input, inOff, inLen);
AddFieldElement(mDigest, kPB.AffineYCoord);
byte[] c3 = DigestUtilities.DoFinal(mDigest);
return Arrays.ConcatenateAll(c1, c2, c3);
}
private byte[] Decrypt(byte[] input, int inOff, int inLen)
{
byte[] c1 = new byte[mCurveLength * 2 + 1];
Array.Copy(input, inOff, c1, 0, c1.Length);
ECPoint c1P = mECParams.Curve.DecodePoint(c1);
ECPoint s = c1P.Multiply(mECParams.H);
if (s.IsInfinity)
throw new InvalidCipherTextException("[h]C1 at infinity");
c1P = c1P.Multiply(((ECPrivateKeyParameters)mECKey).D).Normalize();
byte[] c2 = new byte[inLen - c1.Length - mDigest.GetDigestSize()];
Array.Copy(input, inOff + c1.Length, c2, 0, c2.Length);
Kdf(mDigest, c1P, c2);
AddFieldElement(mDigest, c1P.AffineXCoord);
mDigest.BlockUpdate(c2, 0, c2.Length);
AddFieldElement(mDigest, c1P.AffineYCoord);
byte[] c3 = DigestUtilities.DoFinal(mDigest);
int check = 0;
for (int i = 0; i != c3.Length; i++)
{
check |= c3[i] ^ input[inOff + c1.Length + c2.Length + i];
}
Arrays.Fill(c1, 0);
Arrays.Fill(c3, 0);
if (check != 0)
{
Arrays.Fill(c2, 0);
throw new InvalidCipherTextException("invalid cipher text");
}
return c2;
}
private bool NotEncrypted(byte[] encData, byte[] input, int inOff)
{
for (int i = 0; i != encData.Length; i++)
{
if (encData[i] != input[inOff + i])
{
return false;
}
}
return true;
}
private void Kdf(IDigest digest, ECPoint c1, byte[] encData)
{
int digestSize = digest.GetDigestSize();
byte[] buf = new byte[System.Math.Max(4, digestSize)];
int off = 0;
IMemoable memo = digest as IMemoable;
IMemoable copy = null;
if (memo != null)
{
AddFieldElement(digest, c1.AffineXCoord);
AddFieldElement(digest, c1.AffineYCoord);
copy = memo.Copy();
}
uint ct = 0;
while (off < encData.Length)
{
if (memo != null)
{
memo.Reset(copy);
}
else
{
AddFieldElement(digest, c1.AffineXCoord);
AddFieldElement(digest, c1.AffineYCoord);
}
Pack.UInt32_To_BE(++ct, buf, 0);
digest.BlockUpdate(buf, 0, 4);
digest.DoFinal(buf, 0);
int xorLen = System.Math.Min(digestSize, encData.Length - off);
Xor(encData, buf, off, xorLen);
off += xorLen;
}
}
private void Xor(byte[] data, byte[] kdfOut, int dOff, int dRemaining)
{
for (int i = 0; i != dRemaining; i++)
{
data[dOff + i] ^= kdfOut[i];
}
}
private BigInteger NextK()
{
int qBitLength = mECParams.N.BitLength;
BigInteger k;
do
{
k = new BigInteger(qBitLength, mRandom);
}
while (k.SignValue == 0 || k.CompareTo(mECParams.N) >= 0);
return k;
}
private void AddFieldElement(IDigest digest, ECFieldElement v)
{
byte[] p = v.GetEncoded();
digest.BlockUpdate(p, 0, p.Length);
}
}
}
#pragma warning restore
#endif