.net实现SM2算法

1:添加正确的 NuGet 包

<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />

2: 生成 SM2 密钥对

using Org.BouncyCastle.Asn1.GM;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;

public static (string publicKeyHex, string privateKeyHex) GenerateSm2KeyPair()
{
    // 1. 获取国密标准曲线
    var curve = GMNamedCurves.GetByName("sm2p256v1");
    // 2. 创建曲线域参数
    var domainParams = new ECDomainParameters(curve.Curve, curve.G, curve.N);

    // 3. 初始化密钥生成器
    var generator = new ECKeyPairGenerator();
    generator.Init(new ECKeyGenerationParameters(domainParams, new SecureRandom()));

    // 4. 生成密钥对
    AsymmetricCipherKeyPair keyPair = generator.GenerateKeyPair();

    // 5. 提取并编码公私钥(通常转为十六进制字符串存储)
    var pubKey = (ECPublicKeyParameters)keyPair.Public;
    var privKey = (ECPrivateKeyParameters)keyPair.Private;

    // 公钥使用非压缩格式 (04 | X | Y)
    string publicKeyHex = Hex.ToHexString(pubKey.Q.GetEncoded(false));
    string privateKeyHex = Hex.ToHexString(privKey.D.ToByteArrayUnsigned());

    return (publicKeyHex, privateKeyHex);
}

3: 使用私钥进行 SM2 签名

public static byte[] SignData(byte[] data, string privateKeyHex)
{
    // 1. 获取曲线和域参数
    var curve = GMNamedCurves.GetByName("sm2p256v1");
    var domainParams = new ECDomainParameters(curve.Curve, curve.G, curve.N);

    // 2. 从十六进制字符串还原私钥
    var privateKey = new ECPrivateKeyParameters(
        new BigInteger(1, Hex.Decode(privateKeyHex)), domainParams);

    // 3. 创建签名器实例,算法指定为 SM3withSM2
    var signer = SignerUtilities.GetSigner("SM3withSM2");

    // 4. 初始化签名器(true表示签名模式),并绑定随机数
    signer.Init(true, new ParametersWithRandom(privateKey, new SecureRandom()));

    // 5. 传入待签名数据并生成签名
    signer.BlockUpdate(data, 0, data.Length);
    byte[] signature = signer.GenerateSignature();

    return signature;
}

4: 使用公钥验证签名

public static bool VerifySignature(byte[] data, byte[] signature, string publicKeyHex)
{
    // 1. 获取曲线和域参数
    var curve = GMNamedCurves.GetByName("sm2p256v1");
    var domainParams = new ECDomainParameters(curve.Curve, curve.G, curve.N);

    // 2. 从十六进制字符串还原公钥
    var q = curve.Curve.DecodePoint(Hex.Decode(publicKeyHex));
    var publicKey = new ECPublicKeyParameters(q, domainParams);

    // 3. 创建签名器实例
    var signer = SignerUtilities.GetSigner("SM3withSM2");

    // 4. 初始化签名器为验证模式
    signer.Init(false, publicKey);

    // 5. 传入数据和签名进行验证
    signer.BlockUpdate(data, 0, data.Length);
    return signer.VerifySignature(signature);
}
说明:
  • Z值计算:SM2 验签时,需要计算一个 Z 值,它包含了用户身份、曲线参数等信息。Bouncy Castle 的 SM2Signer 在调用 Init 后会自动处理这部分,不要手写 Z 值计算逻辑,否则很容易因为 ID 长度、编码格式不一致导致验签失败。
  • 公钥格式:以上示例中的公钥字符串采用了非压缩格式(以 04 开头,后跟 X 和 Y 坐标),这是最常见的一种格式。如果你的密钥是其他格式(如压缩格式),需要使用对应的解码方式。
  • 版本影响:根据 Bouncy Castle 的历史版本迭代,较早的 1.8.x 版本可能不支持 SM2 相关的命名空间或 API。使用 2.0.0+ 版本是避免这类问题的有效方式
posted @ 2026-09-02 09:26  七星飘虫  阅读(7)  评论(0)    收藏  举报