| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- using System;
- using System.Text;
- using System.Security.Cryptography;
- using Newtonsoft.Json.Linq;
- using Org.BouncyCastle.Crypto;
- using Org.BouncyCastle.Crypto.Digests;
- using Org.BouncyCastle.Crypto.Engines;
- using Org.BouncyCastle.Crypto.Macs;
- using Org.BouncyCastle.Crypto.Parameters;
- using Org.BouncyCastle.Crypto.Generators;
- using Org.BouncyCastle.Crypto.Prng;
- using Org.BouncyCastle.Security;
- using Org.BouncyCastle.Crypto.Paddings;
- using Org.BouncyCastle.Crypto.Modes;
- using Org.BouncyCastle.Math;
- using Org.BouncyCastle.Asn1.Sec;
- using Org.BouncyCastle.Asn1.X9;
- using Org.BouncyCastle.Asn1.X509;
- using Org.BouncyCastle.Asn1.Pkcs;
- using Org.BouncyCastle.Pkcs;
- using Org.BouncyCastle.Utilities.Encoders;
- namespace MySystem
- {
- public class SMUtil
- {
- private const string KEY_ALGORITHM = "AES";
- public const string SM4_ECB_PKCS5PADDING = "SM4/ECB/PKCS5Padding";
- public const string ALGORITHM_NAME = "SM4";
- static SMUtil()
- {
- // 在 .NET 中不需要像 Java 那样显式注册提供者,BouncyCastle 通过 NuGet 引用即可使用
- }
- // 生成一个对称秘钥(返回字符串,行为与 Java 版保持一致:base64 后取前 16 个字符)
- public static string GetSymmetrickey()
- {
- try
- {
- byte[] keyBytes = new byte[32]; // 256 bits
- using (var rng = new RNGCryptoServiceProvider())
- {
- rng.GetBytes(keyBytes);
- }
- string key = Convert.ToBase64String(keyBytes);
- if (key.Length >= 16)
- key = key.Substring(0, 16);
- return key;
- }
- catch
- {
- return string.Empty;
- }
- }
- // 生成 SM2 公私钥对,返回 { publicKeyBase64, privateKeyBase64 }
- public static string[] GenerateSmKey()
- {
- try
- {
- X9ECParameters ecP = ECNamedCurveTable.GetByName("sm2p256v1");
- ECDomainParameters domainParams = new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H);
- var gen = new ECKeyPairGenerator();
- var secureRandom = new SecureRandom();
- var keyGenParam = new ECKeyGenerationParameters(domainParams, secureRandom);
- gen.Init(keyGenParam);
- AsymmetricCipherKeyPair pair = gen.GenerateKeyPair();
- // 构造 X.509 SubjectPublicKeyInfo(使用公钥点),以及 PKCS#8 PrivateKeyInfo
- var pubParam = pair.Public as ECPublicKeyParameters;
- var privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(pair.Private);
- // AlgorithmIdentifier: id-ecPublicKey + named curve OID
- var curveOid = ECNamedCurveTable.GetOid("sm2p256v1");
- var algId = new Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier(X9ObjectIdentifiers.IdECPublicKey, curveOid);
- var spki = new SubjectPublicKeyInfo(algId, pubParam.Q.GetEncoded(false));
- byte[] pubBytes = spki.ToAsn1Object().GetEncoded();
- byte[] privBytes = privInfo.ToAsn1Object().GetEncoded();
- return new string[] { Convert.ToBase64String(pubBytes), Convert.ToBase64String(privBytes) };
- }
- catch (Exception)
- {
- return null;
- }
- }
- // 从 base64 字符串恢复公钥参数(AsymmetricKeyParameter)
- public static AsymmetricKeyParameter CreatePublicKey(string publicKeyBase64)
- {
- try
- {
- byte[] data = Convert.FromBase64String(publicKeyBase64);
- return PublicKeyFactory.CreateKey(data);
- }
- catch (Exception)
- {
- return null;
- }
- }
- // 从 base64 字符串恢复私钥参数
- public static AsymmetricKeyParameter CreatePrivateKey(string privateKeyBase64)
- {
- try
- {
- byte[] data = Convert.FromBase64String(privateKeyBase64);
- return PrivateKeyFactory.CreateKey(data);
- }
- catch (Exception)
- {
- return null;
- }
- }
- // SM2 加密(对称秘钥字符串使用 SM2 公钥加密,返回 base64)
- public static string Sm2Encrypt(string symmetrickey, string pubKeyBase64)
- {
- try
- {
- var pubParam = CreatePublicKey(pubKeyBase64) as ECPublicKeyParameters;
- if (pubParam == null) return null;
- var engine = new SM2Engine();
- engine.Init(true, new ParametersWithRandom(pubParam, new SecureRandom()));
- byte[] inBytes = Encoding.UTF8.GetBytes(symmetrickey);
- byte[] outBytes = engine.ProcessBlock(inBytes, 0, inBytes.Length);
- return Convert.ToBase64String(outBytes);
- }
- catch (Exception)
- {
- return null;
- }
- }
- // SM2 解密(传入 base64 密文和私钥 base64)
- public static string Sm2Decrypt(string cipherBase64, string priKeyBase64)
- {
- try
- {
- var priParam = CreatePrivateKey(priKeyBase64) as ECPrivateKeyParameters;
- if (priParam == null) return null;
- var engine = new SM2Engine();
- engine.Init(false, priParam);
- byte[] inBytes = Convert.FromBase64String(cipherBase64);
- byte[] outBytes = engine.ProcessBlock(inBytes, 0, inBytes.Length);
- return Encoding.UTF8.GetString(outBytes);
- }
- catch (Exception)
- {
- return null;
- }
- }
- // SM3 摘要
- public static byte[] Sm3(byte[] srcData)
- {
- var digest = new SM3Digest();
- digest.BlockUpdate(srcData, 0, srcData.Length);
- byte[] result = new byte[digest.GetDigestSize()];
- digest.DoFinal(result, 0);
- return result;
- }
- public static string Sm3Hex(string srcData)
- {
- byte[] hash = Sm3(Encoding.UTF8.GetBytes(srcData));
- return Hex.ToHexString(hash);
- }
- // HMAC-SM3
- public static byte[] HmacSm3(byte[] key, byte[] srcData)
- {
- var mac = new HMac(new SM3Digest());
- mac.Init(new KeyParameter(key));
- mac.BlockUpdate(srcData, 0, srcData.Length);
- byte[] result = new byte[mac.GetMacSize()];
- mac.DoFinal(result, 0);
- return result;
- }
- public static string HmacSm3Hex(string key, string srcData)
- {
- byte[] hash = HmacSm3(Encoding.UTF8.GetBytes(key), Encoding.UTF8.GetBytes(srcData));
- return Hex.ToHexString(hash);
- }
- // 另一种调用 MessageDigest 的 SM3 实现(使用 BouncyCastle 的 Digest 就足够了)
- public static byte[] Sm3Bc(byte[] srcData)
- {
- return Sm3(srcData);
- }
- public static string Sm3BcHex(string srcData)
- {
- return Sm3Hex(srcData);
- }
- // SM4 加解密(使用 BouncyCastle 的块加密器和填充)
- public static string Sm4Encrypt(string symmetrickey, string data)
- {
- string algorithmName = SM4_ECB_PKCS5PADDING;
- byte[] key = Encoding.UTF8.GetBytes(symmetrickey);
- byte[] iv = Encoding.UTF8.GetBytes(symmetrickey);
- byte[] cipher = Sm4Core(algorithmName, true, key, iv, Encoding.UTF8.GetBytes(data));
- return Convert.ToBase64String(cipher);
- }
- public static string Sm4Decrypt(string symmetrickey, string data)
- {
- string algorithmName = SM4_ECB_PKCS5PADDING;
- byte[] key = Encoding.UTF8.GetBytes(symmetrickey);
- byte[] iv = Encoding.UTF8.GetBytes(symmetrickey);
- byte[] plain = Sm4Core(algorithmName, false, key, iv, Convert.FromBase64String(data));
- return Encoding.UTF8.GetString(plain);
- }
- private static byte[] Sm4Core(string algorithmName, bool forEncrypt, byte[] key, byte[] iv, byte[] input)
- {
- try
- {
- // 将 Java 的 "SM4/ECB/PKCS5Padding" 换为 BouncyCastle 可识别的形式
- string bcName = algorithmName.Replace("PKCS5Padding", "PKCS7Padding");
- var cipher = CipherUtilities.GetCipher(bcName);
- ICipherParameters parameters = null;
- if (algorithmName.Contains("/ECB/"))
- {
- parameters = new KeyParameter(key);
- }
- else
- {
- parameters = new ParametersWithIV(new KeyParameter(key), iv);
- }
- cipher.Init(forEncrypt, parameters);
- byte[] outBytes = cipher.DoFinal(input);
- return outBytes;
- }
- catch (Exception ex)
- {
- throw new Exception("SM4 operation failed", ex);
- }
- }
- // 将 JObject 的 key 转为小写(null 或空值替换为 "")
- public static JObject DealJSONObj(JObject jsonObj)
- {
- var result = new JObject();
- foreach (var prop in jsonObj.Properties())
- {
- JToken val = prop.Value;
- if (!HasValue(val))
- val = "";
- result[prop.Name.ToLower()] = val;
- }
- return result;
- }
- public static JArray DealJSONArray(JArray jsonArray)
- {
- var arr = new JArray();
- foreach (var item in jsonArray)
- {
- if (item is JObject jo)
- {
- arr.Add(DealJSONObj(jo));
- }
- else
- {
- arr.Add(item);
- }
- }
- return arr;
- }
- private static bool HasValue(JToken token)
- {
- if (token == null) return false;
- if (token.Type == JTokenType.Null) return false;
- if (token.Type == JTokenType.String)
- {
- var s = token.ToString();
- return !string.IsNullOrWhiteSpace(s);
- }
- return true;
- }
- }
- }
|