92 lines
3.3 KiB
C#
92 lines
3.3 KiB
C#
using Newtonsoft.Json;
|
||
using Org.BouncyCastle.Asn1.GM;
|
||
using Org.BouncyCastle.Asn1.Sec;
|
||
using Org.BouncyCastle.Asn1.X9;
|
||
using Org.BouncyCastle.Crypto;
|
||
using Org.BouncyCastle.Crypto.Engines;
|
||
using Org.BouncyCastle.Crypto.Modes;
|
||
using Org.BouncyCastle.Crypto.Paddings;
|
||
using Org.BouncyCastle.Crypto.Parameters;
|
||
using Org.BouncyCastle.Security;
|
||
using System.Security.Cryptography;
|
||
using System.Text;
|
||
|
||
namespace YD_AllHeartRates.Api.Utilities
|
||
{
|
||
public static class DataEncryptHelper
|
||
{
|
||
/// <summary>
|
||
/// SM2 公钥加密(C1C3C2 顺序,输出十六进制)
|
||
/// </summary>
|
||
/// <param name="plainText">明文字符串</param>
|
||
/// <param name="pubKeyHex">公钥十六进制(压缩或非压缩)</param>
|
||
/// <returns>加密后的十六进制密文</returns>
|
||
public static string EncryptSm2(string plainText, string pubKeyHex)
|
||
{
|
||
if (string.IsNullOrEmpty(plainText))
|
||
throw new ArgumentException("plainText 不能为空");
|
||
if (string.IsNullOrEmpty(pubKeyHex))
|
||
throw new ArgumentException("pubKeyHex 不能为空");
|
||
|
||
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
|
||
|
||
// 获取 SM2 曲线参数
|
||
var sm2Curve = GMNamedCurves.GetByName("sm2p256v1");
|
||
var curve = sm2Curve.Curve;
|
||
var ecParams = new ECDomainParameters(curve, sm2Curve.G, sm2Curve.N);
|
||
|
||
// 解析公钥
|
||
byte[] pubKeyBytes = HexStringToBytes(pubKeyHex);
|
||
if (pubKeyBytes.Length != 33 && pubKeyBytes.Length != 65)
|
||
throw new ArgumentException("公钥长度错误,应为 33(压缩)或 65(非压缩)字节");
|
||
|
||
Org.BouncyCastle.Math.EC.ECPoint q;
|
||
try
|
||
{
|
||
q = curve.DecodePoint(pubKeyBytes);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
throw new ArgumentException("公钥解析失败,请确认是有效 SM2 公钥(压缩或非压缩)", ex);
|
||
}
|
||
|
||
var pubKey = new ECPublicKeyParameters(q, ecParams);
|
||
|
||
// SM2 加密(C1C3C2)
|
||
var engine = new SM2Engine(SM2Engine.Mode.C1C3C2);
|
||
engine.Init(true, new ParametersWithRandom(pubKey, new SecureRandom()));
|
||
|
||
byte[] cipherBytes = engine.ProcessBlock(plainBytes, 0, plainBytes.Length);
|
||
|
||
return BytesToHex(cipherBytes);
|
||
}
|
||
|
||
#region 辅助方法
|
||
/// <summary>
|
||
/// 十六进制字符串转字节数组
|
||
/// </summary>
|
||
private static byte[] HexStringToBytes(string hex)
|
||
{
|
||
if (hex.Length % 2 != 0)
|
||
throw new ArgumentException("Hex string 必须为偶数长度");
|
||
|
||
byte[] bytes = new byte[hex.Length / 2];
|
||
for (int i = 0; i < hex.Length; i += 2)
|
||
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
|
||
return bytes;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 字节数组转十六进制字符串
|
||
/// </summary>
|
||
private static string BytesToHex(byte[] bytes)
|
||
{
|
||
StringBuilder sb = new StringBuilder(bytes.Length * 2);
|
||
foreach (var b in bytes)
|
||
sb.AppendFormat("{0:x2}", b);
|
||
return sb.ToString();
|
||
}
|
||
#endregion
|
||
}
|
||
}
|