You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用RSACryptoServiceProvider生成验证许可证密钥,验证始终返回False求排查

许可证密钥验证失败问题排查与修复

我正在为一款新的.NET服务器应用开发许可证密钥生成与验证的POC,设计思路是:

  • 安装服务器时,通过Winform应用基于硬件属性生成ComputerId
  • 以ComputerId为基础生成许可证密钥
  • 后续在Winform中输入许可证密钥,验证是否为本服务器生成

我编写了控制台应用测试,但验证始终返回False,代码如下:

private static (string privateKeyParameters, string publicKeyParameters) GenerateKeyPair(int keySize)
{
    string PrivateRsaKey;
    string PublicRsaKey;

    using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
    {
        rsa.KeySize = keySize;

        PrivateRsaKey = Convert.ToBase64String(rsa.ExportRSAPrivateKey());
        PublicRsaKey = Convert.ToBase64String(rsa.ExportRSAPublicKey());
    }

    return (PrivateRsaKey, PublicRsaKey);
}
private static string CreateLicense(string computerId)
{
    byte[] SignedLicense;
    byte[] UnsignedComputerId = Encoding.UTF8.GetBytes(computerId);
    int i = 0;
    var rsaKeys = GenerateKeyPair(2048);
    string license;

    using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
    {
        rsa.ImportRSAPrivateKey(Convert.FromBase64String(rsaKeys.privateKeyParameters), out i);

        SignedLicense = rsa.SignData(UnsignedComputerId, "SHA1");
        license = Convert.ToBase64String(SignedLicense);
    }

    return license;
}
private static bool VerifyLicense(string license)
{
    int i;
    byte[] UnsignedComputerId = Encoding.UTF8.GetBytes(computerId);
    byte[] SignedLicense = Convert.FromBase64String(license);
    bool VerifOK = false;
    var rsaKeys = GenerateKeyPair(2048);

    using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
    {
        rsa.ImportRSAPublicKey(Convert.FromBase64String(rsaKeys.publicKeyParameters), out i);
        VerifOK = rsa.VerifyData(UnsignedComputerId, "SHA1", SignedLicense);
    }

        return VerifOK;
}
static void Main(string[] args)
{
    var (privateKeyParameters, publicKeyParameters) = GenerateKeyPair(1024);
    var license = CreateLicense(computerId);

    Console.WriteLine("Privatekey: " + privateKeyParameters);
    Console.WriteLine();
    Console.WriteLine("Publickey: " + publicKeyParameters);

    Console.WriteLine();
    Console.WriteLine("License: " + license);

    Console.WriteLine();
    Console.WriteLine("License is verified: " + VerifyLicense(license));

    Console.ReadLine();
}

核心错误原因

  • 密钥对完全不匹配:CreateLicense和VerifyLicense方法内部都会调用GenerateKeyPair,每次调用都会生成全新的RSA密钥对。签名用的是临时生成的A密钥对私钥,验证却用另一个临时生成的B密钥对公钥,两者毫无关联,必然验证失败。
  • Main方法生成的密钥未被实际使用:Main里生成的密钥对仅用于打印,签名和验证过程完全没用到这组密钥。
  • 哈希算法不安全:使用已被证明存在安全漏洞的SHA1进行签名,应替换为SHA256及以上版本。
  • API过时:RSACryptoServiceProvider是.NET Framework旧版API,在.NET Core/.NET 5+环境下兼容性差,推荐使用现代的RSA.Create()。

修正后的代码实现

我们需要保证签名和验证使用同一组密钥对,私钥由授权方保管,公钥嵌入到验证端。以下是修正后的完整代码:

using System;
using System.Security.Cryptography;
using System.Text;

namespace LicenseKeyDemo
{
    class Program
    {
        // 仅生成一次密钥对,私钥由授权方保存,公钥分发到验证端
        private static (string privateKey, string publicKey) GenerateKeyPair(int keySize = 2048)
        {
            using var rsa = RSA.Create(keySize);
            var privateKey = Convert.ToBase64String(rsa.ExportRSAPrivateKey());
            var publicKey = Convert.ToBase64String(rsa.ExportRSAPublicKey());
            return (privateKey, publicKey);
        }

        // 使用指定私钥签名ComputerId生成许可证
        private static string CreateLicense(string computerId, string privateKey)
        {
            var computerIdBytes = Encoding.UTF8.GetBytes(computerId);
            using var rsa = RSA.Create();
            rsa.ImportRSAPrivateKey(Convert.FromBase64String(privateKey), out _);
            
            // 使用安全的SHA256哈希算法签名
            var signatureBytes = rsa.SignData(computerIdBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
            return Convert.ToBase64String(signatureBytes);
        }

        // 使用指定公钥验证许可证
        private static bool VerifyLicense(string computerId, string license, string publicKey)
        {
            var computerIdBytes = Encoding.UTF8.GetBytes(computerId);
            var signatureBytes = Convert.FromBase64String(license);
            
            using var rsa = RSA.Create();
            rsa.ImportRSAPublicKey(Convert.FromBase64String(publicKey), out _);
            
            // 与签名使用一致的哈希算法验证
            return rsa.VerifyData(computerIdBytes, signatureBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
        }

        static void Main(string[] args)
        {
            // 模拟授权方生成密钥对
            var (privateKey, publicKey) = GenerateKeyPair();
            string computerId = "SampleHardwareId123"; // 实际为硬件生成的唯一ID

            // 生成许可证
            var license = CreateLicense(computerId, privateKey);

            // 打印信息
            Console.WriteLine("私钥: " + privateKey);
            Console.WriteLine();
            Console.WriteLine("公钥: " + publicKey);
            Console.WriteLine();
            Console.WriteLine("许可证密钥: " + license);
            Console.WriteLine();

            // 验证许可证
            bool isVerified = VerifyLicense(computerId, license, publicKey);
            Console.WriteLine("许可证验证结果: " + isVerified);

            Console.ReadLine();
        }
    }
}

关键改进点

  • 密钥对仅生成一次,签名和验证严格使用同一组密钥
  • 替换SHA1为安全的SHA256哈希算法
  • 使用现代RSA.Create()API替代过时的RSACryptoServiceProvider
  • 方法参数明确传递密钥,避免内部生成无关密钥导致的不匹配问题

内容的提问来源于stack exchange,提问作者Anders Pedersen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 14:08:10