new_10009_YanCheng_Metrology/Assets/Scripts/SecretUtils/Crypto/SM2Util.cs

321 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.GM;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.Sec;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;
namespace SecretUtils.Crypto
{
internal class SM2Util
{
private static readonly byte[] defaultUserID = System.Text.Encoding.ASCII.GetBytes("1234567812345678");
/**
* 获取der格式中的纯公钥数据
*/
public static byte[] GetPublicKeyFormDER(byte[] derData)
{
SubjectPublicKeyInfo info = SubjectPublicKeyInfo.GetInstance(derData);
return info.PublicKeyData.GetBytes();
}
/**
* 获取der编码格式中的纯私钥数据
*/
public static byte[] GetPrivateKeyFormDER(byte[] derData)
{
PrivateKeyInfo pinfo = PrivateKeyInfo.GetInstance(derData);
ECPrivateKeyStructure cpk = ECPrivateKeyStructure.GetInstance(pinfo.ParsePrivateKey());
int length = 32;
byte[] bytes = cpk.GetKey().ToByteArray();
if (bytes.Length == length)
{
return bytes;
}
int start = bytes[0] == 0 ? 1 : 0;
int count = bytes.Length - start;
if (count > length)
{
throw new ArgumentException("privateKey data is error");
}
byte[] tmp = new byte[length];
Buffer.BlockCopy(bytes, start, tmp, tmp.Length - count, count);
return tmp;
}
/**
* 生成sm2公私钥对
* @return
*/
public static SM2KeyPair GenerateKeyPair()
{
X9ECParameters sm2p256v1 = GMNamedCurves.GetByName("sm2p256v1");
ECDomainParameters parameters = new ECDomainParameters(sm2p256v1.Curve, sm2p256v1.G, sm2p256v1.N);
KeyGenerationParameters kgp = new ECKeyGenerationParameters(parameters, new SecureRandom());
ECKeyPairGenerator ecKeyPairGenerator = new ECKeyPairGenerator();
ecKeyPairGenerator.Init(kgp);
ECPrivateKeyParameters ecpriv = null;
ECPublicKeyParameters ecpub = null;
// int count = 0;
do
{
AsymmetricCipherKeyPair keypair = ecKeyPairGenerator.GenerateKeyPair();
ecpriv = (ECPrivateKeyParameters)keypair.Private;
ecpub = (ECPublicKeyParameters)keypair.Public;
} while (ecpriv == null || ecpriv.D.Equals(BigInteger.Zero)
|| ecpriv.D.CompareTo(sm2p256v1.N) >= 0 || ecpriv.D.SignValue <= 0);
byte[] privKey = FormartBigNum(ecpriv.D, 32);
return new SM2KeyPair(privKey, ecpub.Q.GetEncoded());
}
/**
* 格式化BigIntegerbg.toByteArray()获取到的字节数据长度不固定,因此需要格式化为固定长度
* @param bg 大数
* @param needLength 所需要的长度
* @return
*/
private static byte[] FormartBigNum(BigInteger bg, int needLength)
{
byte[] tmp = new byte[needLength];
byte[] bgByte = bg.ToByteArray();
if (bgByte == null)
{
return null;
}
if (bgByte.Length > needLength)
{
Buffer.BlockCopy(bgByte, bgByte.Length - needLength, tmp, 0, needLength);
}
else if (bgByte.Length == needLength)
{
tmp = bgByte;
}
else
{
Buffer.BlockCopy(bgByte, 0, tmp, needLength - bgByte.Length, bgByte.Length);
}
return tmp;
}
/**
* sm2加密
*
*/
public static byte[] Encrypt(byte[] pubkey, byte[] srcData)
{
X9ECParameters sm2p256v1 = GMNamedCurves.GetByName("sm2p256v1");
SecureRandom random = new SecureRandom();
ECDomainParameters parameters = new ECDomainParameters(sm2p256v1.Curve, sm2p256v1.G, sm2p256v1.N);
ECPublicKeyParameters pubKeyParameters = new ECPublicKeyParameters(sm2p256v1.Curve.DecodePoint(pubkey), parameters);
SM2Engine engine = new SM2Engine();
ParametersWithRandom pwr = new ParametersWithRandom(pubKeyParameters, new SecureRandom());
engine.Init(true, pwr);
return encodeSM2CipherToDER(engine.ProcessBlock(srcData, 0, srcData.Length));
}
/**
* sm2解密
*/
public static byte[] Decrypt(byte[] privkey, byte[] srcData)
{
X9ECParameters sm2p256v1 = GMNamedCurves.GetByName("sm2p256v1");
SecureRandom random = new SecureRandom();
ECDomainParameters parameters = new ECDomainParameters(sm2p256v1.Curve, sm2p256v1.G, sm2p256v1.N);
ECPrivateKeyParameters priKeyParameters = new ECPrivateKeyParameters(new BigInteger(1, privkey), parameters);
SM2Engine engine = new SM2Engine();
ParametersWithRandom pwr = new ParametersWithRandom(priKeyParameters, new SecureRandom());
engine.Init(false, priKeyParameters);
byte[] c1c2c3 = decodeDERSM2Cipher(srcData);
return engine.ProcessBlock(c1c2c3, 0, c1c2c3.Length);
}
/**
* sm2签名
* <p>userId使用默认1234567812345678
* @param privateKey 私钥,二进制数据
* @param sourceData 待签名数据
* @return 返回der编码的签名值
* @throws CryptoException
*/
public static byte[] Sign(byte[] privateKey, byte[] sourceData)
{
return Sign(defaultUserID, privateKey, sourceData);
}
/**
* sm2签名
* @param userId ID值若无约定使用默认1234567812345678
* @param privateKey 私钥,二进制数据
* @param sourceData 待签名数据
* @return 返回der编码的签名值
* @throws CryptoException
*/
public static byte[] Sign(byte[] userId, byte[] privateKey, byte[] sourceData)
{
X9ECParameters sm2p256v1 = GMNamedCurves.GetByName("sm2p256v1");
ECDomainParameters parameters = new ECDomainParameters(sm2p256v1.Curve, sm2p256v1.G, sm2p256v1.N);
ECPrivateKeyParameters priKeyParameters = new ECPrivateKeyParameters(new BigInteger(1,privateKey),parameters);
SM2Signer signer = new SM2Signer();
ICipherParameters param = null;
ParametersWithRandom pwr = new ParametersWithRandom(priKeyParameters, new SecureRandom());
if (userId != null) {
param = new ParametersWithID(pwr, userId);
} else {
param = pwr;
}
signer.Init(true, param);
signer.BlockUpdate(sourceData, 0, sourceData.Length);
return signer.GenerateSignature();
}
/**
* sm2验签
* <p>userId使用默认1234567812345678
* @param publicKey 公钥,二进制数据
* @param sourceData 待验签数据
* @param signData 签名值
* @return 返回是否成功
*/
public static Boolean VerifySign(byte[] publicKey, byte[] sourceData, byte[] signData)
{
return VerifySign(defaultUserID, publicKey, sourceData, signData);
}
/**
* sm2验签
* @param userId ID值若无约定使用默认1234567812345678
* @param publicKey 公钥,二进制数据
* @param sourceData 待验签数据
* @param signData 签名值
* @return 返回是否成功
*/
public static Boolean VerifySign(byte[] userId, byte[] publicKey, byte[] sourceData, byte[] signData)
{
if (publicKey.Length == 64)
{
byte[] tmp = new byte[65];
Buffer.BlockCopy(publicKey, 0, tmp, 1, publicKey.Length);
tmp[0] = 0x04;
publicKey = tmp;
}
X9ECParameters sm2p256v1 = GMNamedCurves.GetByName("sm2p256v1");
ECDomainParameters parameters = new ECDomainParameters(sm2p256v1.Curve, sm2p256v1.G, sm2p256v1.N);
ECPublicKeyParameters pubKeyParameters = new ECPublicKeyParameters(sm2p256v1.Curve.DecodePoint(publicKey), parameters);
SM2Signer signer = new SM2Signer();
ICipherParameters param;
if (userId != null)
{
param = new ParametersWithID(pubKeyParameters, userId);
}
else
{
param = pubKeyParameters;
}
signer.Init(false, param);
signer.BlockUpdate(sourceData, 0, sourceData.Length);
return signer.VerifySignature(signData);
}
public static byte[] encodeSM2CipherToDER(byte[] cipher)
{
int startPos = 1;
int curveLength = 32;
int digestLength = 32;
byte[] c1x = new byte[curveLength];
Buffer.BlockCopy(cipher, startPos, c1x, 0, c1x.Length);
startPos += c1x.Length;
byte[] c1y = new byte[curveLength];
Buffer.BlockCopy(cipher, startPos, c1y, 0, c1y.Length);
startPos += c1y.Length;
byte[] c2 = new byte[cipher.Length - c1x.Length - c1y.Length - 1 - digestLength];
Buffer.BlockCopy(cipher, startPos, c2, 0, c2.Length);
startPos += c2.Length;
byte[] c3 = new byte[digestLength];
Buffer.BlockCopy(cipher, startPos, c3, 0, c3.Length);
Asn1Encodable[] arr = new Asn1Encodable[4];
arr[0] = new DerInteger(new BigInteger(1, c1x));//
arr[1] = new DerInteger(new BigInteger(1, c1y));//
arr[2] = new DerOctetString(c3);
arr[3] = new DerOctetString(c2);
DerSequence ds = new DerSequence(arr);
return ds.GetEncoded(Asn1Encodable.Der);
}
public static byte[] decodeDERSM2Cipher(byte[] derCipher)
{
Asn1Sequence ds = DerSequence.GetInstance(derCipher);
byte[] c1x = ((DerInteger)ds[0]).Value.ToByteArray();
byte[] c1y = ((DerInteger)ds[1]).Value.ToByteArray();
byte[] c3 = ((DerOctetString)ds[2]).GetOctets();
byte[] c2 = ((DerOctetString)ds[3]).GetOctets();
int pos = 0;
int cureLength = 32;
byte[] cipherText = new byte[1 + c2.Length + cureLength * 2 + c3.Length];
byte uncompressedFlag = 0x04;
cipherText[0] = uncompressedFlag;
pos += 1;
if (c1x.Length >= cureLength)
{
Buffer.BlockCopy(c1x, c1x.Length - cureLength, cipherText, pos, cureLength);
}
else
{
Buffer.BlockCopy(c1x, 0, cipherText, pos + cureLength - c1x.Length, c1x.Length);
}
pos += cureLength;
if (c1y.Length >= cureLength)
{
Buffer.BlockCopy(c1y, c1y.Length - cureLength, cipherText, pos, cureLength);
}
else
{
Buffer.BlockCopy(c1y, 0, cipherText, pos + cureLength - c1y.Length, c1y.Length);
}
pos += cureLength;
Buffer.BlockCopy(c2, 0, cipherText, pos, c2.Length);
pos += c2.Length;
Buffer.BlockCopy(c3, 0, cipherText, pos, c3.Length);
return cipherText;
}
}
}