using Microsoft.Extensions.Options; using Org.BouncyCastle.Utilities.Encoders; using SharpAbp.Abp.Crypto.SM2; using SharpAbp.Abp.Crypto.SM3; using SharpAbp.Abp.Crypto.SM4; using System.Security.Cryptography; using System.Text; using static Org.BouncyCastle.Crypto.Engines.SM2Engine; namespace YourCompany.GmCrypto; /// <summary> /// 国密 SM2 / SM3 / SM4 静态帮助类(基于 SharpAbp.Abp.Crypto) /// </summary> public static class SmHelper { private static readonly ISm2EncryptionService Sm2 = new Sm2EncryptionService( Options.Create(new AbpSm2EncryptionOptions { DefaultCurve = Sm2EncryptionNames.CurveSm2p256v1 })); private static readonly ISm3EncryptionService Sm3 = new Sm3EncryptionService(); private static readonly ISm4EncryptionService Sm4 = new Sm4EncryptionService( Options.Create(new AbpSm4EncryptionOptions { DefaultMode = Sm4EncryptionNames.ModeCBC, DefaultPadding = Sm4EncryptionNames.PKCS7Padding, DefaultIv = Encoding.UTF8.GetBytes("1234567890123456") // 16 字节 })); #region SM2 /// <summary>生成 SM2 密钥对(十六进制)</summary> public static Sm2KeyPairResult GenerateSm2KeyPair() { var keyPair = Sm2.GenerateSm2KeyPair(); return new Sm2KeyPairResult { PublicKeyHex = keyPair.ExportPublicKey(), PrivateKeyHex = keyPair.ExportPrivateKey() }; } /// <summary>SM2 公钥加密,返回十六进制密文</summary> public static string Sm2Encrypt(string plainText, string publicKeyHex) => Sm2.Encrypt(publicKeyHex, plainText, Encoding.UTF8, mode: Mode.C1C2C3); /// <summary>SM2 私钥解密</summary> public static string Sm2Decrypt(string cipherTextHex, string privateKeyHex) => Sm2.Decrypt(privateKeyHex, cipherTextHex, Encoding.UTF8, mode: Mode.C1C2C3); /// <summary>SM2 私钥签名,返回十六进制签名</summary> public static string Sm2Sign(string plainText, string privateKeyHex) => Sm2.Sign(privateKeyHex, plainText, Encoding.UTF8); /// <summary>SM2 公钥验签</summary> public static bool Sm2Verify(string plainText, string signatureHex, string publicKeyHex) => Sm2.VerifySign(publicKeyHex, plainText, signatureHex, Encoding.UTF8); /// <summary>C1C2C3 转 C1C3C2(对接 Java/前端时可能需要)</summary> public static byte[] Sm2C123ToC132(byte[] c1c2c3) => Sm2.C123ToC132(c1c2c3); /// <summary>C1C3C2 转 C1C2C3</summary> public static byte[] Sm2C132ToC123(byte[] c1c3c2) => Sm2.C132ToC123(c1c3c2); #endregion #region SM3 /// <summary>SM3 哈希,返回十六进制</summary> public static string Sm3Hash(string plainText) => Sm3.GetHash(plainText, Encoding.UTF8); /// <summary>SM3 哈希(字节数组)</summary> public static byte[] Sm3Hash(byte[] plainBytes) => Sm3.GetHash(plainBytes); #endregion #region SM4 /// <summary>生成 SM4 密钥(16 字节,32 位十六进制)</summary> public static string GenerateSm4KeyHex() => Hex.ToHexString(RandomNumberGenerator.GetBytes(16)).ToLowerInvariant(); /// <summary>生成 SM4 IV(16 字节,32 位十六进制)</summary> public static string GenerateSm4IvHex() => Hex.ToHexString(RandomNumberGenerator.GetBytes(16)).ToLowerInvariant(); /// <summary>SM4 加密(CBC + PKCS7),返回十六进制密文</summary> public static string Sm4Encrypt(string plainText, string keyHex, string? ivHex = null) { ivHex ??= GenerateSm4IvHex(); return Sm4.Encrypt( plainText, keyHex, ivHex, Sm4EncryptionNames.ModeCBC, Sm4EncryptionNames.PKCS7Padding, Encoding.UTF8); } /// <summary>SM4 解密(CBC + PKCS7)</summary> public static string Sm4Decrypt(string cipherTextHex, string keyHex, string ivHex) => Sm4.Decrypt( cipherTextHex, keyHex, ivHex, Sm4EncryptionNames.ModeCBC, Sm4EncryptionNames.PKCS7Padding, Encoding.UTF8); #endregion } /// <summary>SM2 密钥对</summary> public sealed class Sm2KeyPairResult { public required string PublicKeyHex { get; init; } public required string PrivateKeyHex { get; init; } }
使用示例
using YourCompany.GmCrypto; // ============================================================ // SM2:非对称加密(公钥加密 / 私钥解密)+ 数字签名 / 验签 // 适用:密钥交换、小数据加密、身份认证、防篡改 // ============================================================ // 1. 生成一对 SM2 密钥(公钥给别人加密/验签,私钥自己保管) var keys = SmHelper.GenerateSm2KeyPair(); // keys.PublicKeyHex → 公钥(可公开) // keys.PrivateKeyHex → 私钥(务必保密) // 2. 用【公钥】加密明文(只有对应私钥能解开) var cipher = SmHelper.Sm2Encrypt("hello", keys.PublicKeyHex); // cipher 是十六进制密文字符串 // 3. 用【私钥】解密密文,还原明文 var plain = SmHelper.Sm2Decrypt(cipher, keys.PrivateKeyHex); // plain 应等于 "hello" // 4. 用【私钥】对数据签名(证明“是我签的、没被改过”) var sign = SmHelper.Sm2Sign("hello", keys.PrivateKeyHex); // sign 是十六进制签名字符串 // 5. 用【公钥】验签(确认签名是否有效、数据是否被篡改) var ok = SmHelper.Sm2Verify("hello", sign, keys.PublicKeyHex); // ok == true 表示验签通过 // ============================================================ // SM3:哈希(摘要),不可逆 // 适用:密码摘要、数据完整性校验、配合 SM2 签名前的预处理等 // ============================================================ // 对字符串做 SM3 哈希,得到固定长度的十六进制摘要 var hash = SmHelper.Sm3Hash("hello"); // 同样输入永远得到同样输出;无法从 hash 反推原文 // ============================================================ // SM4:对称加密(同一个密钥加解密) // 适用:大批量数据加密、本地存储加密、报文加密等 // 模式:CBC + PKCS7(类库内默认配置) // ============================================================ // 1. 生成 16 字节(128 位)密钥,32 位十六进制 var key = SmHelper.GenerateSm4KeyHex(); // 2. 生成 16 字节 IV(初始化向量),CBC 模式必须 var iv = SmHelper.GenerateSm4IvHex(); // 3. 用 key + iv 加密明文 var sm4Cipher = SmHelper.Sm4Encrypt("hello", key, iv); // 若 iv 传 null,会自动生成;解密时必须用【同一个 iv】 // 4. 用【相同 key + iv】解密密文 var sm4Plain = SmHelper.Sm4Decrypt(sm4Cipher, key, iv); // sm4Plain 应等于 "hello" // ============================================================ // 典型组合场景(注释说明,按需选用) // ============================================================ // 场景 A:传输敏感小数据 // → SM2 加密(对方公钥加密,己方私钥解密) // 场景 B:接口防篡改 // → 发送方 Sm2Sign,接收方 Sm2Verify // 场景 C:存密码 / 做指纹 // → Sm3Hash(不要明文存密码) // 场景 D:加密较长内容或文件内容 // → 用 SM4;SM2 只用来加密 SM4 的 key(混合加密,需自行封装) // 场景 E:与 Java / 前端对接 SM2 密文格式不一致时 // → 可能需要 C1C2C3 ↔ C1C3C2 转换: // // var converted = SmHelper.Sm2C123ToC132(cipherBytes);
对应关系 原来 国密替代 用途 MD5 SM3 数据摘要、完整性校验、指纹 SHA-1 / SHA-256 SM3 同上(国密场景优先 SM3) AES / DES SM4 对称加密 RSA SM2 非对称加密、签名
--------------------------------------------------
只有对写程序充满热情,才能写出好的程序!
只有对写程序充满热情,才能写出好的程序!
浙公网安备 33010602011771号