别再手动造轮子了!用BouncyCastle 1.9.0在C#里快速搞定国密SM2/SM3/SM4
2026/6/2 3:54:56 网站建设 项目流程

国密算法实战:用BouncyCastle在C#中快速集成SM2/SM3/SM4

当项目需要符合国密标准时,大多数开发者面临的第一个难题是如何快速实现SM2非对称加密、SM3摘要算法和SM4对称加密。从头实现这些算法不仅耗时,还可能引入安全隐患。本文将展示如何利用成熟的BouncyCastle密码库,在C#项目中快速搭建国密算法支持。

1. 环境准备与基础配置

在开始之前,我们需要准备好开发环境。对于C#项目来说,BouncyCastle是最受欢迎的密码学库之一,它提供了对国密算法的完整支持。

首先通过NuGet安装BouncyCastle:

Install-Package Portable.BouncyCastle -Version 1.9.0

安装完成后,我们需要定义一些基础参数和常量:

// SM4加密固定IV private const string SM4_IV = "zhjy-essa-ABCDEF"; // SM2曲线参数(使用GMNamedCurves确保国密标准) private static readonly X9ECParameters Sm2EcParams = GMNamedCurves.GetByName("SM2P256V1"); private static readonly ECDomainParameters Sm2DomainParams = new ECDomainParameters( Sm2EcParams.Curve, Sm2EcParams.G, Sm2EcParams.N, Sm2EcParams.H);

2. SM2密钥管理与加密解密

SM2是基于椭圆曲线的非对称加密算法,我们首先需要生成密钥对。

2.1 生成SM2密钥对

public static Dictionary<string, string> GenerateSm2KeyPair() { var gen = new ECKeyPairGenerator(); var keyGenParams = new ECKeyGenerationParameters(Sm2DomainParams, new SecureRandom()); gen.Init(keyGenParams); var keyPair = gen.GenerateKeyPair(); var privKey = (ECPrivateKeyParameters)keyPair.Private; var pubKey = (ECPublicKeyParameters)keyPair.Public; string priKeyHex = privKey.D.ToString(16).ToLower(); string pubKeyHex = Hex.ToHexString(pubKey.Q.GetEncoded(false)).ToLower(); return new Dictionary<string, string> { { "pubkey", pubKeyHex }, { "prikey", priKeyHex } }; }

2.2 SM2加密实现

SM2加密需要注意密文格式问题,国标推荐使用C1C3C2格式:

public static string Sm2Encrypt(string publicKeyHex, byte[] data, Sm2Mode mode = Sm2Mode.C1C3C2) { try { byte[] pubBytes = Hex.Decode(publicKeyHex); var pubPoint = Sm2DomainParams.Curve.DecodePoint(pubBytes); var pubKeyParams = new ECPublicKeyParameters(pubPoint, Sm2DomainParams); var engine = new SM2Engine(new SM3Digest()); engine.Init(true, new ParametersWithRandom(pubKeyParams, new SecureRandom())); byte[] cipher = engine.ProcessBlock(data, 0, data.Length); if (mode == Sm2Mode.C1C2C3) cipher = ChangeC1C3C2ToC1C2C3(cipher); return Convert.ToBase64String(cipher); } catch (Exception ex) { throw new Exception("SM2加密失败:" + ex.Message, ex); } }

2.3 SM2解密实现

解密时需要确保使用与加密时相同的密文格式:

public static byte[] Sm2Decrypt(string privateKeyHex, string cipherBase64, Sm2Mode mode = Sm2Mode.C1C3C2) { try { byte[] cipher = Convert.FromBase64String(cipherBase64); if (mode == Sm2Mode.C1C2C3) cipher = ChangeC1C2C3ToC1C3C2(cipher); BigInteger privD = new BigInteger(privateKeyHex, 16); var privKeyParams = new ECPrivateKeyParameters(privD, Sm2DomainParams); var engine = new SM2Engine(new SM3Digest()); engine.Init(false, privKeyParams); return engine.ProcessBlock(cipher, 0, cipher.Length); } catch (Exception ex) { throw new Exception("SM2解密失败:" + ex.Message, ex); } }

3. SM3摘要算法实现

SM3是国密标准的哈希算法,输出为256位(32字节)的摘要值:

public static string Sm3ComputeDigest(string data) { byte[] dataBytes = Encoding.UTF8.GetBytes(data); return Sm3ComputeDigest(dataBytes); } public static string Sm3ComputeDigest(byte[] data) { SM3Digest sm3 = new SM3Digest(); sm3.BlockUpdate(data, 0, data.Length); byte[] digest = new byte[sm3.GetDigestSize()]; sm3.DoFinal(digest, 0); return Hex.ToHexString(digest).ToLower(); }

4. SM4对称加密实战

SM4是国密标准的对称加密算法,密钥长度为128位。

4.1 生成SM4密钥

public static string Sm4GenerateKey() { byte[] key = new byte[16]; using (var rng = RandomNumberGenerator.Create()) rng.GetBytes(key); return Hex.ToHexString(key).ToLower(); }

4.2 SM4加密实现

public static string Sm4Encrypt(string sm4KeyHex, string plainText) { byte[] key = Hex.Decode(sm4KeyHex); byte[] iv = Encoding.UTF8.GetBytes(SM4_IV); byte[] plainBytes = Encoding.UTF8.GetBytes(plainText); SM4Engine engine = new SM4Engine(); CbcBlockCipher cbc = new CbcBlockCipher(engine); PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(cbc, new Pkcs7Padding()); cipher.Init(true, new ParametersWithIV(new KeyParameter(key), iv)); byte[] cipherBytes = cipher.DoFinal(plainBytes); return Convert.ToBase64String(cipherBytes); }

4.3 SM4解密实现

public static string Sm4Decrypt(string sm4KeyHex, string cipherBase64) { byte[] key = Hex.Decode(sm4KeyHex); byte[] iv = Encoding.UTF8.GetBytes(SM4_IV); byte[] cipherBytes = Convert.FromBase64String(cipherBase64); SM4Engine engine = new SM4Engine(); CbcBlockCipher cbc = new CbcBlockCipher(engine); PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(cbc, new Pkcs7Padding()); cipher.Init(false, new ParametersWithIV(new KeyParameter(key), iv)); byte[] plainBytes = cipher.DoFinal(cipherBytes); return Encoding.UTF8.GetString(plainBytes); }

5. 实战技巧与常见问题

在实际项目中集成国密算法时,有几个关键点需要注意:

  1. 密钥管理

    • SM2公私钥建议存储在安全的位置
    • SM4密钥应该定期更换
    • 生产环境应该使用硬件安全模块(HSM)保护密钥
  2. 性能优化

    • SM2加密速度较慢,适合加密小数据或加密SM4密钥
    • 大数据加密应该使用SM4
    • 可以考虑缓存SM2密钥对象避免重复解析
  3. 跨平台兼容性

    • 不同系统对国密算法的实现可能有差异
    • 特别注意密文格式(C1C2C3 vs C1C3C2)
    • 测试时应该在不同平台验证加解密结果
  4. 错误处理

    • 加解密操作应该放在try-catch块中
    • 记录详细的错误日志便于排查问题
    • 提供有意义的错误信息给调用方

在实际项目中,我们通常会将这些功能封装成工具类,提供统一的接口给业务代码调用。这样可以降低使用复杂度,提高代码的可维护性。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询