.NET 平台 SM2 国密算法 License 证书生成深度解析

本文涉及的产品
应用实时监控服务-可观测链路OpenTelemetry版,每月50GB免费额度
可观测监控 Prometheus 版,每月50GB免费额度
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
简介: 授权证书文件的后缀通常取决于其编码格式和具体用途。本文档通过一个示例程序展示了如何在 .NET 平台上使用国密 SM2 算法生成和验证许可证(License)文件。该示例不仅详细演示了 SM2 国密算法的实际应用场景,还提供了关于如何高效处理大规模许可证文件生成任务的技术参考。通过对不同并发策略的性能测试,开发者可以更好地理解如何优化许可证生成流程,以满足高并发和大数据量的需求。希望这段描述更清晰地传达了程序的功能和技术亮点。

License 授权机制构思

.NET 中实现 License 授权机制,可以通过以下步骤进行:

1.确定授权方式

  • 基于时间的授权:限制软件的使用时间。
  • 基于功能的授权:根据用户购买的版本,开放不同的功能。
  • 基于并发数的授权:限制同时使用软件的用户或设备数量。

2.生成许可证文件

  • 包含信息:用户信息、授权类型、有效期、签名等。
  • 使用加密算法:采用非对称加密算法(如RSA)对许可证文件进行签名,防止改。

3.验证许可证

  • 解析许可证文件:读取并解析许可证中的信息。
  • 验证签名:使用公钥验证许可证的签名,确保其合法性。
  • 检查授权条件:根据许可证中的信息,检查授权是否有效。

4.集成到应用程序

  • 启动时验证:在应用程序启动时验证许可证,如果无效则提示用户或限制功能。
  • 提供管理界面:允许用户输入许可证密钥或查看授权信息。

注意事项

  • 安全性:确保许可证文件的安全性,防止被非法获取或算改。
  • 用户体验:在授权验证失败时,提供友好的提示信息,避免影响用户体验。
  • 灵活性:根据实际需求,设计灵活的授权机制,方便后续扩展和维护。

通过以上步骤,可以在 .NET 应用程序中实现一个基本的 License 授权机制,确保软件的合法使用。

继续完善授权机制

为了完善 .NET 中的 License 授权机制,使其包含时间效期、应用功能和并发数限制等,您可以按照以下步骤进行:

说明:实际业务场景请具体问题考虑,这里只是抛砖引玉。

1.许可证文件结构

设计一个包含以下信息的许可证文件格式:

  • 时间效期:许可证的有效开始日期和结束日期。
  • 应用功能:列出可用的功能模块或权限级别。
  • 并发数限制:允许同时使用的最大用户数或设备数。

2.生成许可证文件

在生成许可证文件时,将这些信息嵌入到文件中,并使用加密算法进行签名。

3.验证许可证

在验证许可证时,除了检查签名和时间效期外,还需要检查功能和并发数限制:

  • 功能验证:根据许可证中的功能列表,检查用户是否有权限使用特定功能。
  • 并发数验证:维护一个计数器或记录,跟踪当前使用的用户或设备数量,确保不超过许可证允许的并发数。

4.集成到应用程序

  • 启动时验证:在应用程序启动时,验证许可证的时间效期和并发数限制。
  • 功能访问控制:在用户尝试访问特定功能时,验证其是否在许可证允许的功能列表中。
  • 并发数管理:在用户登录或启动新实例时,检查并发数限制,并在用户注销或实例关闭时更新计数器。

注意事项

  • 同步和并发管理:确保在多用户或多线程环境中,并发数的计数和管理是同步和准确的。
  • 动态更新:考虑实现许可证的动态更新机制,允许在不影响用户使用的情况下更新许可证信。
  • 息日志记录:记录许可证验证和使用的日志,便于追踪和审计。

通过以上步骤,您可以实现一个包含时间效期、应用功能和并发数限制的完整 License 授权机制。

授权证书文件格式介绍

授权证书生成文件的后缀通常取决于其编码格式和用途。
以下是一些常见的授权证书文件后缀:

  • .pemPrivacy Enhanced Mail 的缩写,采用 Base64 编码的ASCIl 文本格式,可包含证书.私钥或两者皆有。
  • .derDistinguished Encoding Rules 的缩写,二进制编码格式,常用于存储 X.509 证书。
  • .crtCertificate 的缩写,常用于存储公钥证书,格式可以是PEMDER
  • .cer:与 .crt 类似,用于存储证书,编码格式通常为 DER
  • .pfxPersonal Information Exchange 的缩写,包含证书和私钥的二进制格式,常用于 Windows 平台,可通过密码保护。
  • .p12:与 .pfx 相同,是 PKCS #12 标准的另一种扩展名。
  • .jksJava KeyStore 的缩写,用于存储证书和私钥,常用于Java 平台。
  • .licLicense 的缩写,特定软件或系统的授权证书文件,格式和内容自定义。

这些后缀代表了不同的证书格式和编码方式,在实际应用中,应根据具体需求和场景选择合适的文件格式。

BouncyCastle.Cryptography 包介绍

一个开源的密码学库,提供广泛的加密算法和协议实现,支持 .NET 平台。
BouncyCastle.Cryptography

核心功能

1.算法支持

  • 对称加密(如 AES、DES
  • 非对称加密(如 RSA、SM2
  • 数字签名(如 ECDSA、SM3WithSM2
  • 哈希算法(如 SHA-256、SM3
  • 国密算法(如 SM2、SM3、SM4

    2.证书与密钥管理

  • X.509 证书解析/生成

  • 密钥对(AsymmetricCipherKeyPair)生成与存储
  • PKCS#1/PKCS#8 密钥格式支持

    3.协议支持

  • TLS/SSL 相关功能

  • CMS(加密消息语法)

    4.适用场景

  • 需要兼容国密算法(如 SM2/SM3/SM4)的项目

  • 自定义证书签名/验证流程(如您代码中的 License 签名)
  • 低层级密码学操作(如手动处理密钥与加密流程)

在项目中安装使用:

# 通过 NuGet 安装
Install-Package BouncyCastle.Cryptography

注意事项

  • 版本兼容性:确保选择与目标 .NET 版本兼容的包版本(当前最新为 2.2.1+)。
  • 性能:相比 .NET 内置加密库(如 System.Security.Cryptography),某些场景可能性能较低。
  • 文档:官方文档较少,建议参考 源码示例

为啥选择 SM2 国密算法?

在选择签名算法时,此处本人采用 SM2 国密算法,原因如下:

安全性

  • 基于椭圆曲线密码学:SM2 算法的安全性基于椭圆曲线离散对数问题,具有较高的安全强度。256 位的 SM2 密码强度已经比2048 位的 RSA 密码强度要高。
  • 国家密码管理局认可:SM2 算法是中国国家密码管理局批准的公钥密码算法,经过严格的审查和测试,符合国家安全标准。

效率

  • 签名速度快:相较于 RSA 算法,SM2 算法在签名和密钥生成速度上更快,特别是在处理大量数据时,效率优势明显。
  • 密钥长度短: SM2 算法使用较短的密钥长度(256位),减少了存储和传输的开销。

适用性

  • 广泛应用:SM2 算法适用于数字签名、密钥交换和数据加密等多种场景,满足多种密码应用的安全需求。
  • 支持国密标准:SM2 算法与 SM3 哈希算法结合使用,符合中国国密标准,适用于需要遵循国内安全标准的系统和应用。

兼容性

  • 开源支持:许多开源密码学库(如 BouncyCastle )已经支持 SM2 算法,便于集成和开发。
  • 硬件支持:国内许多加密芯片和硬件设备支持 SM2 算法,提供硬件级的加速和安全保障。

综上所述,SM2 算法在安全性、效率和适用性方面都表现出色,是签名国密算法的理想选择。

基于 SM2 国密算法如何使用 .net 实现 License 证书?

为了方便演示,本人此处使用新建 .net9 控制台应用程序,并添加依赖包:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="BouncyCastle.Cryptography" Version="2.5.1" />
  </ItemGroup>

</Project>

项目(LicenseDemo)结构如下所示:

LicenseDemo

为了使用 SM2 算法完善签名并生成 .lic 授权证书,您可以按照以下步骤进行:

1. 生成 SM2 密钥对

首先,您需要生成 SM2 算法的公钥和私钥。可以使用 C# 中的BouncyCastle.Cryptography 库来实现。

C# 中,ECKeyGenerationParameters 类用于生成椭圆曲线密钥对时指定参数。选择椭圆曲线参数集,这里使用的是 "sm2p256v1",然后创建一个安全的随机数生成器 SecureRandom(),接着实例化 ECKeyGenerationParameters

创建 ECKeyPairGenerator 实例,初始化密钥生成器,然后调用 GenerateKeyPair()方法,即可生成 SM2 算法的密钥对。

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Asn1.GM;
using System.Text;

namespace LicenseDemo.Licenses;

/// <summary>
/// 生成SM2密钥对
/// </summary>
class Sm2KeyPairGenerator
{
   
    #region 单例模式
    // 使用 Lazy<T> 实现懒加载
    private static readonly Lazy<Sm2KeyPairGenerator> _instance = new(() => new Sm2KeyPairGenerator());

    // 私有构造函数,防止外部实例化
    private Sm2KeyPairGenerator() {
    }

    // 公共静态属性,用于访问单例实例
    public static Sm2KeyPairGenerator Instance => _instance.Value;
    #endregion

    #region 密钥对生成算法
    // 使用【sm2p256v1】曲线,获取SM2曲线的X9ECParameters对象
    private static readonly X9ECParameters x9ECParameters = GMNamedCurves.GetByName("sm2p256v1");

    // 使用X9ECParameters对象创建ECDomainParameters对象
    private static readonly ECDomainParameters domainParams = new(
        x9ECParameters.Curve,
        x9ECParameters.G,
        x9ECParameters.N,
        x9ECParameters.H,
        x9ECParameters.GetSeed()
    );

    private static readonly ECKeyPairGenerator generator = new();

    /// <summary>
    /// 生成SM2密钥对(公钥,私钥)
    /// </summary>
    /// <returns></returns>
    public AsymmetricCipherKeyPair GenerateKeyPair()
    {
   
        generator.Init(new ECKeyGenerationParameters(domainParams, new SecureRandom()));
        return generator.GenerateKeyPair();
    }
    #endregion

    /// <summary>
    /// 测试,输出SM2密钥对信息
    /// </summary>
    public void KeyPairInfo()
    {
   
        StringBuilder strBuilder = new(128);

        strBuilder.AppendLine("Hello, SM2KeyPairGenerator!");
        // 输出曲线名称
        strBuilder.AppendLine("Curve Name: sm2p256v1");

        // 输出曲线参数
        strBuilder.AppendLine($"Curve: {x9ECParameters.Curve}");
        strBuilder.AppendLine($"G:{x9ECParameters.G}");
        strBuilder.AppendLine($"N:{x9ECParameters.N}");
        strBuilder.AppendLine($"H:{x9ECParameters.H}");

        byte[]? seed = x9ECParameters.GetSeed();
        if (seed != null)
        {
   
            strBuilder.AppendLine($"Seed:{BitConverter.ToString(seed)}");
        }

        // 输出ECDomainParameters对象
        strBuilder.AppendLine($"ECDomainParameters: {domainParams}");
        Console.WriteLine(strBuilder.ToString());
    }
}

2. 生成 SM2 签名/验签 & 加密/解密

  • 签名 & 验签

在生成密钥对后,您可以使用私钥对数据进行签名,

// 使用SM2私钥对数据进行签名
public byte[] SignData(byte[] data, AsymmetricKeyParameter privateKey)
{
   
    var signer = SignerUtilities.GetSigner("SM3WITHSM2");
    signer.Init(true, privateKey);
    signer.BlockUpdate(data, 0, data.Length);
    return signer.GenerateSignature();
}

验证签名时,使用对应的公钥:

// 使用SM2公钥对数据进行验签
public bool VerifyData(byte[] data, byte[] signature, AsymmetricKeyParameter publicKey)
{
   
    var verifier = SignerUtilities.GetSigner("SM3WITHSM2");
    verifier.Init(false, publicKey);
    verifier.BlockUpdate(data, 0, data.Length);
    return verifier.VerifySignature(signature);
}
  • 加密 & 解密

除了上面的签名和验签之外,我们还可以利用公钥加密,私钥解密。

// 使用SM2公钥加密
public string Encrypt(string plainText, AsymmetricKeyParameter publicKey)
{
   
    SM2Engine engine = new();
    engine.Init(true, new ParametersWithRandom(publicKey, new SecureRandom()));
    byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
    byte[] encryptedBytes = engine.ProcessBlock(plainTextBytes, 0, plainTextBytes.Length);
    return Convert.ToBase64String(encryptedBytes);
}

// 使用SM2私钥解密
public string Decrypt(string encryptedText, AsymmetricKeyParameter privateKey)
{
   
    SM2Engine engine = new();
    engine.Init(false, privateKey);
    byte[] encryptedBytes = Convert.FromBase64String(encryptedText);
    byte[] decryptedBytes = engine.ProcessBlock(encryptedBytes, 0, encryptedBytes.Length);
    return Encoding.UTF8.GetString(decryptedBytes);
}

3. 定义 License 数据结构

License 数据结构是针对应用授权的定义,根据自己实际业务情况,可以自定义扩展定义。

/// <summary>
/// License 数据
/// </summary>
class LicenseData
{
   
    public string Id => Guid.NewGuid().ToString();
    public string AppName {
    get; set; } = null!;
    public string AppVersion {
    get; set; } = null!;
    public string AuthCode {
    get; set; } = null!;
    public string UserName {
    get; set; } = null!;
    public string CompanyName {
    get; set; } = null!;
    public DateTimeOffset StartDate {
    get; set; }
    public DateTimeOffset ExpirationDate {
    get; set; }
    public List<string> AllowedFeatures {
    get; set; } = [];
}

4. 定义 License 上下文对象

上下文对象用于承载证书数据的形态,但为了安全性保障,该上下文对象会被再次加密,然后将密文写入 .lic 文件中。

/// <summary>
/// License 上下文
/// </summary>
internal class LicenseContent
{
   
    /// <summary>
    /// 数据
    /// </summary>
    public string Data {
    get; set; } = null!;

    /// <summary>
    /// 签名
    /// </summary>
    public string Signature {
    get; set; } = null!;
}

上面基本信息铺垫后,接下来我们开始实现 License 证书的生成与校验。

5. 实现 License 授权助手

  • 在生成 .lic 授权证书时,您可以将签名数据和其他相关信息(如用户信息、授权类型、时间限制等)一起包含在证书中;
  • 在生成 .lic 授权证书时,您需要提取数据和签名,然后使用公钥进行验证;
using Org.BouncyCastle.Crypto;
using System.Text.Json;
using System.Text;

namespace LicenseDemo.Licenses;

/// <summary>
/// license 授权助手
/// </summary>
/// <param name="publicKey">公钥</param>
/// <param name="privateKey">私钥</param>
class LicenseAssistant(AsymmetricCipherKeyPair keyPair)
{
   
    private readonly Sm2Assistant _sm2Assistant = new();

    private AsymmetricKeyParameter PublicKey => keyPair.Public;
    private AsymmetricKeyParameter PrivateKey => keyPair.Private;

    /// <summary>
    /// 生成License文件(.lic授权证书)
    /// </summary>
    /// <param name="licenseData"></param>
    /// <param name="outputFile"></param>
    /// <returns></returns>
    public async Task GenerateLicenseFileAsync(LicenseData licenseData, string outputFile)
    {
   
        // 序列化数据
        string jsonString = await JsonSerializeAsync(licenseData);

        // 对数据进行签名
        byte[] dataToSign = Encoding.UTF8.GetBytes(jsonString);
        byte[] signature = _sm2Assistant.SignData(dataToSign, PrivateKey);

        // 组合数据和签名
        LicenseContent licenseContent = new()
        {
   
            Data = jsonString,
            Signature = Convert.ToBase64String(signature)
        };

        // 异步序列化 JSON 数据
        string license = await JsonSerializeAsync(licenseContent);

        // 公钥加密
        string licenseCiphertext = _sm2Assistant.Encrypt(license, PublicKey);

        // 写入文件
        await File.WriteAllTextAsync(outputFile, licenseCiphertext);
    }

    /// <summary>
    /// 验证License文件(.lic授权证书)
    /// </summary>
    /// <param name="licenseFilePath"></param>
    /// <returns></returns>
    public async Task<bool> VerifyLicenseFileAsync(string licenseFilePath)
    {
   
        // 读取文件内容
        string licenseCiphertext = await File.ReadAllTextAsync(licenseFilePath);

        // 私钥解密
        string licenseContent = _sm2Assistant.Decrypt(licenseCiphertext, PrivateKey);

        // 异步反序列化 JSON 数据
        var licenseData = await JsonDeserializeAsync<LicenseContent>(licenseContent);

        // 解析数据和签名
        string data = licenseData.Data;
        byte[] signature = Convert.FromBase64String(licenseData.Signature);

        // 验证签名
        byte[] verify = Encoding.UTF8.GetBytes(data);
        return _sm2Assistant.VerifyData(verify, signature, PublicKey);
    }

    /// <summary>
    /// 序列化数据
    /// </summary>
    /// <typeparam name="TData"></typeparam>
    /// <param name="data"></param>
    /// <returns></returns>
    private async Task<string> JsonSerializeAsync<TData>(TData data)
    {
   
        using var stream = new MemoryStream();
        await JsonSerializer.SerializeAsync(stream, data);

        stream.Position = 0;
        using var reader = new StreamReader(stream);
        return await reader.ReadToEndAsync();
    }

    /// <summary>
    /// 反序列化数据
    /// </summary>
    /// <typeparam name="TData"></typeparam>
    /// <param name="data"></param>
    /// <returns></returns>
    private async Task<TData> JsonDeserializeAsync<TData>(string data)
    {
   
        if (string.IsNullOrWhiteSpace(data))
            return default!;

        // 解析数据和签名
        byte[] jsonBytes = Encoding.UTF8.GetBytes(data);
        using var stream = new MemoryStream(jsonBytes);

        // 将 JSON 字符串写入内存流
        //await stream.WriteAsync(jsonBytes, 0, jsonBytes.Length);
        //stream.Position = 0;

        // 异步反序列化 JSON 数据
        return await JsonSerializer.DeserializeAsync<TData>(stream);
    }
}

应用程序中如何使用?

Program.cs 文件中添加如下代码:

// See https://aka.ms/new-console-template for more information
using LicenseDemo.Licenses;
using System.Diagnostics;
using System.Text;

{
   
    // 1.生成SM2密钥对
    var sm2KeyPairGenerator = Sm2KeyPairGenerator.Instance;
    sm2KeyPairGenerator.KeyPairInfo();
    var keyPair = sm2KeyPairGenerator.GenerateKeyPair();
    Console.WriteLine($"public => {keyPair.Public}");
    Console.WriteLine($"private => {keyPair.Private}");

    // 2.使用SM2签名数据 & 验证签名
    Sm2Assistant sm2Assistant = new();
    var data = Encoding.UTF8.GetBytes("hello");
    var signature = sm2Assistant.SignData(data, keyPair.Private);
    Console.WriteLine($"sign => {signature}");
    var verify = sm2Assistant.VerifyData(data, signature, keyPair.Public);
    Console.WriteLine($"verify => {verify}");

    // 3.创建许可证数据
    var licenseData = new LicenseData
    {
   
        AppName = "MyApp",
        AppVersion = "1.0.0",
        AuthCode = "1234567890",
        UserName = "John Doe",
        CompanyName = "ACME Corp",
        StartDate = DateTime.UtcNow,
        ExpirationDate = DateTime.UtcNow.AddDays(30),
        AllowedFeatures = ["PremiumFeature1", "PremiumFeature2"]
    };

    // 4. 实例化 License 助手
    LicenseAssistant licenseAssistant = new(keyPair);

    // 4.1 设置 .lic 证书存放路径
    string targetDirectory = "lics";
    Directory.CreateDirectory(targetDirectory);
    Console.WriteLine($"Project Folder Path: {targetDirectory}");
    string outputFilePath = Path.Combine(targetDirectory, "license.lic");

    // 4.2 生成许可证文件
    await licenseAssistant.GenerateLicenseFileAsync(licenseData, outputFilePath);

    // 4.3 验证许可证文件
    bool isValid = await licenseAssistant.VerifyLicenseFileAsync(outputFilePath);
    Console.WriteLine($"License is valid: {isValid}");  
}

注意事项

  • 密钥管理:确保私钥的安全存储,避免泄露。
  • 安全性:考虑使用其他安全措施,如加密数据、添加时间戳等,增强证书的安全性。
  • 可读性:虽然加密和签名增加了安全性,但也要确保生成的。

通过上述步骤,您可以使用 SM2 算法完善签名并生成 .lic 授权证书,确保数据和签名的安全性和完整性。

生成 License 证书性能测试

为了更好的利用计算机资源,此处使用异步多线程方式生成多个 .lic 文件。

说明:性能测试基准,生成 10000 个许可证文件,记录生成耗时。

方法一:使用 Parallel.For

这里使用了 async 关键字,但 Parallel.For 是为同步代码设计的。虽然它支持 async,但可能会导致一些潜在的问题,比如任务调度不当或资源浪费。

int licenseCount = 10000; // 指定 10000 个许可证文件
{
   
    Stopwatch stopwatch = Stopwatch.StartNew();
    await Task.Run(() =>
    {
   
        Parallel.For(0, licenseCount, async i =>
        {
   
            LicenseData licenseData = new()
            {
   
                AppName = "MyApp",
                AppVersion = "1.0.0",
                AuthCode = "123456",
                UserName = "John Doe",
                CompanyName = "Acme Inc.",
                StartDate = DateTimeOffset.Now,
                ExpirationDate = DateTimeOffset.Now.AddDays(365),
                AllowedFeatures = ["Feature1", "Feature2"]
            };
            string licenseFile = Path.Combine(targetDirectory, $"license1-{i}.lic");
            await licenseAssistant.GenerateLicenseFileAsync(licenseData, licenseFile);
        });
    });
    stopwatch.Stop();
    Console.WriteLine($"方法 1:使用 Parallel.For,Generated {licenseCount} license files in {stopwatch.ElapsedMilliseconds} ms");
}

方法 2:使用 Task.WhenAll

这种方式更符合现代化 .net 异步编程的最佳实践,能够更好地利用 I/O 并发的优势,避免阻塞主线程。

{
   
    Stopwatch stopwatch2 = Stopwatch.StartNew();
    List<Task> tasks = [];
    for (int i = 0; i < licenseCount; i++)
    {
   
        int index = i; // 捕获循环变量
        tasks.Add(Task.Run(async () =>
        {
   
            LicenseData licenseData = new()
            {
   
                AppName = "MyApp",
                AppVersion = "1.0.0",
                AuthCode = "123456",
                UserName = "John Doe",
                CompanyName = "Acme Inc.",
                StartDate = DateTimeOffset.Now,
                ExpirationDate = DateTimeOffset.Now.AddDays(365),
                AllowedFeatures = ["Feature1", "Feature2"]
            };
            string licenseFile = Path.Combine(targetDirectory, $"license2-{index}.lic");
            await licenseAssistant.GenerateLicenseFileAsync(licenseData, licenseFile);
        }));
    }
    await Task.WhenAll(tasks);
    stopwatch2.Stop();
    Console.WriteLine($"方法 2:使用 Task.WhenAll,Generated {licenseCount} license files in {stopwatch2.ElapsedMilliseconds} ms");
}

本人测试电脑配置比较差,信息如下:

cpu

  • 执行命令:
dotnet run
  • 输出信息:
Hello, SM2KeyPairGenerator!
Curve Name: sm2p256v1
Curve: Org.BouncyCastle.Math.EC.FpCurve
G:(32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7,bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0,1,fffffffefffffffG:(32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7,bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0,1,fffffffeffffffG:(32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7,bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0,1,fffffffeffffffG:(32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7,bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0,1,fffffffeffffffffffffG:(32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7,bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0,1,fffffffeffffG:(32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7,bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0,1,fffffffeffffG:(32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7,bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0,1,fffffffeffff
ffffffffffffffffffffffffffff00000000fffffffffffffffc)
N:115792089210356248756420345214020892766061623724957744567843809356293439045923
H:1
ECDomainParameters: Org.BouncyCastle.Crypto.Parameters.ECDomainParameters

public => Org.BouncyCastle.Crypto.Parameters.ECPublicKeyParameters
private => Org.BouncyCastle.Crypto.Parameters.ECPrivateKeyParameters
sign => System.Byte[]
verify => True
Project Folder Path: lics
License is valid: True

方法 1:使用 Parallel.For,Generated 10000 license files in 81969 ms
方法 2:使用 Task.WhenAll,Generated 10000 license files in 73862 ms

说明,依据电脑配置情况,生成文件耗时会有差异,此处大概参考。
电脑配置规格: cpu:intel i7-12650h,内存:16g ddr4,硬盘:1 t ssd
生成 10000.lic 文件,大概耗时 18-19 秒左右。
感兴趣的下伙伴请自行测试哟。

  • License 证书文件如下:

在这里插入图片描述

关于 Parallel.For & Task.WhenAll 的对比

1.工作原理

  • Parallel.For
- 使用 TPL (Task Parallel Library) 来并行执行循环体。
- 内部管理线程池,自动分配任务到多个线程。
- 更适合 CPU 密集型任务。
  • Task.WhenAll
- 创建多个异步任务,并等待所有任务完成。
- 每个任务可以独立运行,适用于 I/O 密集型任务(如文件操作、网络请求)。
- 提供更好的控制和灵活性,可以组合不同的异步操作。

2.适用场景

  • Parallel.For
- 适用于需要并行处理大量数据的场景。
- 例如:计算密集型任务,如矩阵运算、图像处理等。
  • Task.WhenAll
- 适用于需要并发执行多个异步操作的场景。
- 例如:并发读写文件、发起多个 HTTP 请求等。

3.性能对比

  • Parallel.For
对于 CPU 密集型任务,性能较好。
对于 I/O 密集型任务,可能因为线程切换频繁而降低性能。
  • Task.WhenAll
对于 I/O 密集型任务,性能更好,因为它不会阻塞线程,而是让线程去执行其他任务。
在你的例子中,生成许可证文件是 I/O 密集型任务,因此 Task.WhenAll 更合适。

4.结论

如果你需要处理 I/O 密集型任务(如文件操作、网络请求),建议使用 Task.WhenAll。
如果你需要处理 CPU 密集型任务(如大量计算),可以考虑使用 Parallel.For。

在上述的代码中,生成 .lic 许可证文件属于 I/O 密集型任务,因此推荐使用 Task.WhenAll 方式来提高性能和稳定性。

目录
相关文章
|
2月前
|
安全 算法 网络协议
解析:HTTPS通过SSL/TLS证书加密的原理与逻辑
HTTPS通过SSL/TLS证书加密,结合对称与非对称加密及数字证书验证实现安全通信。首先,服务器发送含公钥的数字证书,客户端验证其合法性后生成随机数并用公钥加密发送给服务器,双方据此生成相同的对称密钥。后续通信使用对称加密确保高效性和安全性。同时,数字证书验证服务器身份,防止中间人攻击;哈希算法和数字签名确保数据完整性,防止篡改。整个流程保障了身份认证、数据加密和完整性保护。
|
2月前
|
Web App开发 数据采集 开发者
某查”平台请求头反爬技术解析与应对
某查”平台请求头反爬技术解析与应对
|
1月前
|
弹性计算 运维 安全
优化管理与服务:操作系统控制平台的订阅功能解析
本文介绍了如何通过操作系统控制平台提升系统效率,优化资源利用。首先,通过阿里云官方平台开通服务并安装SysOM组件,体验操作系统控制平台的功能。接着,详细讲解了订阅管理功能,包括创建订阅、查看和管理ECS实例的私有YUM仓库权限。订阅私有YUM仓库能够集中管理软件包版本、提升安全性,并提供灵活的配置选项。最后总结指出,使用阿里云的订阅和私有YUM仓库功能,可以提高系统可靠性和运维效率,确保业务顺畅运行。
|
9天前
|
存储 监控 算法
基于 C++ 哈希表算法的局域网如何监控电脑技术解析
当代数字化办公与生活环境中,局域网的广泛应用极大地提升了信息交互的效率与便捷性。然而,出于网络安全管理、资源合理分配以及合规性要求等多方面的考量,对局域网内计算机进行有效监控成为一项至关重要的任务。实现局域网内计算机监控,涉及多种数据结构与算法的运用。本文聚焦于 C++ 编程语言中的哈希表算法,深入探讨其在局域网计算机监控场景中的应用,并通过详尽的代码示例进行阐释。
30 4
|
11天前
|
机器学习/深度学习 存储 Kubernetes
【重磅发布】AllData数据中台核心功能:机器学习算法平台
杭州奥零数据科技有限公司成立于2023年,专注于数据中台业务,维护开源项目AllData并提供商业版解决方案。AllData提供数据集成、存储、开发、治理及BI展示等一站式服务,支持AI大模型应用,助力企业高效利用数据价值。
|
12天前
|
存储 监控 算法
员工电脑监控场景下 Python 红黑树算法的深度解析
在当代企业管理范式中,员工电脑监控业已成为一种广泛采用的策略性手段,其核心目标在于维护企业信息安全、提升工作效能并确保合规性。借助对员工电脑操作的实时监测机制,企业能够敏锐洞察潜在风险,诸如数据泄露、恶意软件侵袭等威胁。而员工电脑监控系统的高效运作,高度依赖于底层的数据结构与算法架构。本文旨在深入探究红黑树(Red - Black Tree)这一数据结构在员工电脑监控领域的应用,并通过 Python 代码实例详尽阐释其实现机制。
37 6
|
1月前
|
开发框架 .NET 中间件
.net8 使用 license 证书授权案例解析
本文介绍了如何使用 `.NET CLI` 创建并改造一个 `ASP.NET Core Web API` 项目,以实现基于许可证的授权机制。具体步骤包括创建项目、添加必要的 NuGet 包(如 `Standard.Licensing` 和 `Swashbuckle.AspNetCore`),以及修改 `Program.cs` 文件以集成自定义的许可证验证中间件。项目结构中新增了 `LicenseController` 接口用于处理授权相关操作,并通过测试流程验证了默认天气接口在未授权和授权状态下的响应情况。整个过程确保了应用程序能够在启动时正确验证许可证,保障系统的安全性与可控性。
90 8
.net8 使用 license 证书授权案例解析
|
23天前
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
|
30天前
|
监控 算法 安全
基于 C# 的内网行为管理软件入侵检测算法解析
当下数字化办公环境中,内网行为管理软件已成为企业维护网络安全、提高办公效率的关键工具。它宛如一位恪尽职守的网络守护者,持续监控内网中的各类活动,以确保数据安全及网络稳定。在其诸多功能实现的背后,先进的数据结构与算法发挥着至关重要的作用。本文将深入探究一种应用于内网行为管理软件的 C# 算法 —— 基于二叉搜索树的入侵检测算法,并借助具体代码例程予以解析。
43 4
|
1月前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

推荐镜像

更多