使用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
相关产品推荐
相关产品推荐

