# BugFree.Security **Repository Path**: BugFree_1/BugFree.Security ## Basic Information - **Project Name**: BugFree.Security - **Description**: 面向 .NET 的现代安全加密库,统一封装对称/非对称加密、密码哈希、密钥管理及国密算法(SM2/SM3/SM4),支持依赖注入,安全优先,开箱即用。 - **Primary Language**: C# - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-08-16 - **Last Updated**: 2026-09-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # BugFree.Security ![.NET](https://img.shields.io/badge/.NET-net8.0%20%7C%20net10.0-512BD4) ![License](https://img.shields.io/badge/license-MIT-green) ![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-blue) **BugFree.Security** 是面向 .NET 的实例化密码学库,覆盖对称与非对称密码、格式保持加密、密码哈希、摘要、HMAC、校验和、非密码学哈希,以及独立配置的密钥生命周期管理。 ## 特性 - 8 个可直接构造、也可通过依赖注入使用的公开 facade - AES、RSA、ECDSA、ECDH、Ed25519、X25519,以及 SM2、SM3、SM4 等算法 - NIST FF1-AES 格式保持加密和历史兼容构造 - Argon2id、BCrypt、scrypt、PBKDF2 密码哈希及验证资源上限 - 异步、基于不透明 revision 的 compare-and-swap 密钥存储合约 - 使用调用方主密钥的 AES-256-GCM 受保护文件 envelope - 构造期 provider 快照、严格验证、冻结和精确算法路由 ## 安装 ```shell dotnet add package BugFree.Security ``` 目标框架:`net8.0`、`net10.0`。 ## 公开 facade 与依赖注入 库只公开以下 8 个实例 facade;它们都具有无参构造函数: | 功能 | Facade | 主要操作 | |------|--------|----------| | 非对称密码 | `AsymmetricCryptography` | `GenerateKeyPair`、`Encrypt`、`Decrypt`、`Sign`、`Verify`、`DeriveKey` | | 对称密码 | `SymmetricCryptography` | `CreateKey`、`Encrypt`、`Decrypt`、`TryIsValidKey` | | 格式保持加密 | `FormatPreservingCryptography` | `Protect`、`Unprotect`、`TryIsValidKey` | | 密码学哈希 | `CryptographicHashing` | `ComputeHash`、`VerifyHash` | | HMAC | `HmacCryptography` | `ComputeHmac`、`VerifyHmac` | | 密码哈希 | `PasswordHashing` | `Hash`、`Verify` | | 校验和 | `ChecksumHashing` | `ComputeChecksum`、`VerifyChecksum` | | 非密码学哈希 | `NonCryptographicHashing` | `ComputeHash`、`VerifyHash` | 聚合注册入口恰好注册这 8 个 facade: ```csharp using BugFree.Security; using Microsoft.Extensions.DependencyInjection; var services = new ServiceCollection(); services.AddBugFreeCryptography(); ``` 也可以按功能注册: ```csharp services.AddAsymmetricCryptography(); services.AddSymmetricCryptography(); services.AddFormatPreservingCryptography(); services.AddCryptographicHashing(); services.AddHmacCryptography(); services.AddPasswordHashing(); services.AddChecksumHashing(); services.AddNonCryptographicHashing(); ``` `AddBugFreeCryptography()` 不会隐式注册 KeyManagement。密钥存储与轮换策略必须由应用单独提供,详见“密钥管理”一节。 ### Provider 注册与路由保证 8 个 facade 都先注册内置 provider,再在构造期间将第三方 provider 恰好物化一次,验证后冻结注册表。第三方 provider: - 不能覆盖内置算法 ID,也不能覆盖更早注册的自定义 ID; - 自定义算法 ID 必须使用规范的 `vendor/name`; - 由请求中的算法 ID 精确选择,不进行 probing、fallback、provider substitution、retry 或 downgrade; - facade 构造完成后不能再改变其 provider 集合。 密码验证还要求每种编码格式具有唯一前缀。`PasswordHashing.Verify` 只选择与 encoded prefix 匹配的一个 provider;未知、冲突或无效格式不会触发其他 provider 探测。 ## 使用示例 ### 对称加密 AES 与 SM4 的算法描述符默认模式均为 GCM;加密时省略 `Mode` 会使用该默认模式并返回 nonce 与 tag。需要固定协议参数时仍建议显式选择 GCM,并在解密时传回 nonce、tag 和完全相同的 AAD: ```csharp using System.Text; using BugFree.Security.Symmetric; var crypto = new SymmetricCryptography(); var key = crypto.CreateKey(SymmetricAlgorithm.Aes); var plaintext = Encoding.UTF8.GetBytes("secret message"); var aad = Encoding.UTF8.GetBytes("message-metadata"); var encrypted = crypto.Encrypt( SymmetricAlgorithm.Aes, plaintext, key, new SymmetricEncryptionOptions { Mode = SymmetricCipherMode.Gcm, AAD = aad }); var decrypted = crypto.Decrypt( SymmetricAlgorithm.Aes, encrypted.Ciphertext, key, new SymmetricDecryptionOptions { Mode = SymmetricCipherMode.Gcm, Nonce = encrypted.Nonce, Tag = encrypted.Tag, AAD = encrypted.AAD }); ``` AES 支持 16/24/32-byte 密钥,SM4 使用 16-byte 密钥。CBC、CFB 和 CTR 不提供认证;若因兼容协议而使用,必须由协议另行提供可靠的完整性保护。解密历史 CBC/CFB/CTR 密文时必须显式提供原模式以及对应的 IV、nonce 或反馈大小;实现不会根据参数或密文推断模式,也不会回退到其他模式。 ### 非对称加密与签名 ```csharp using System.Text; using BugFree.Security.Asymmetric; var crypto = new AsymmetricCryptography(); var keyPair = crypto.GenerateKeyPair(AsymmetricAlgorithm.Rsa); var data = Encoding.UTF8.GetBytes("message"); var ciphertext = crypto.Encrypt( AsymmetricAlgorithm.Rsa, data, keyPair.PublicKey); var plaintext = crypto.Decrypt( AsymmetricAlgorithm.Rsa, ciphertext, keyPair.PrivateKey); var signature = crypto.Sign( AsymmetricAlgorithm.Rsa, data, keyPair.PrivateKey); var verified = crypto.Verify( AsymmetricAlgorithm.Rsa, data, signature, keyPair.PublicKey); ``` `AsymmetricKeyPair.PublicKey` 是 SubjectPublicKeyInfo DER,`PrivateKey` 是 PKCS#8 DER。RSA 加密默认使用 OAEP-SHA256,RSA 签名默认使用 PSS + SHA-256;需要固定协议参数时应显式传入 `RsaEncryptionOptions` 或 `RsaSignatureOptions`。 SM2 使用相同 facade 和 `AsymmetricAlgorithm.Sm2`,支持加解密、签名验签与 key agreement。当前选项类型为 `Sm2EncryptionOptions`、`Sm2SignatureOptions`、`Sm2KeyAgreementOptions`;密文格式通过 `Sm2EncryptionOptions.CiphertextFormat` 选择 `Sm2CiphertextFormat.C1C3C2` 或 `Sm2CiphertextFormat.C1C2C3`,密钥协商角色使用 `Sm2KeyAgreementRole.Initiator` / `Responder`。 ### 格式保持加密(FPE) ```csharp using BugFree.Security.FormatPreserving; var fpe = new FormatPreservingCryptography(); const string alphabet = "0123456789"; const string rawData = "012345678901"; var key = Convert.FromHexString("00112233445566778899AABBCCDDEEFF"); byte[] tweak = [1, 2, 3, 4]; var protectedData = fpe.Protect( FormatPreservingAlgorithm.Ff1Aes, rawData, alphabet, key, tweak); var unprotectedData = fpe.Unprotect( FormatPreservingAlgorithm.Ff1Aes, protectedData, alphabet, key, tweak); ``` FPE 对相同算法、输入、字符表、密钥和 tweak 是确定性的,因此会泄露长度、格式域及重复值信息。内置实现要求 ASCII 字符表和输入,radix 为 2–128,字符表字符唯一,且格式域满足 `radix^length >= 1,000,000`。 FPE 只提供机密性,不提供认证或完整性,密文也不是自描述格式。必须在密文之外保留: - 规范算法 ID; - 字符表和格式域定义; - tweak 值或确定的派生规则; - key ID 与 key version。 还原时必须使用这些精确参数,不允许回退到其他算法或密钥。只有 `FormatPreservingAlgorithm.Ff1Aes`(`nist/ff1-aes`)是 NIST 标准;`CustomFeistelHmacSha256` 与 `CustomFeistelAesCmac` 是本仓库的历史兼容构造,不是 FF1,不应用于新协议。 ### 哈希、HMAC、校验和与非密码学哈希 ```csharp using System.Text; using BugFree.Security.Hashing; using BugFree.Security.Hashing.Cryptographic; using BugFree.Security.Hashing.Hmac; var data = Encoding.UTF8.GetBytes("message"); var hashing = new CryptographicHashing(); var digest = hashing.ComputeHash( CryptographicHashAlgorithm.Sha256, data); var digestIsValid = hashing.VerifyHash( CryptographicHashAlgorithm.Sha256, digest, data); var hmac = new HmacCryptography(); var hmacKey = Convert.FromHexString( "00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF"); var tag = hmac.ComputeHmac(HmacAlgorithm.Sha256, data, hmacKey); var tagIsValid = hmac.VerifyHmac( HmacAlgorithm.Sha256, tag, data, hmacKey); var checksums = new ChecksumHashing(); var crc32 = checksums.ComputeChecksum(ChecksumAlgorithmId.CRC32, data); var distributionHashes = new NonCryptographicHashing(); var xxHash = distributionHashes.ComputeHash( NonCryptographicHashAlgorithmId.XxHash3, data); ``` 密码学哈希不能替代带密钥的消息认证。CRC、Adler 和非密码学哈希只适合检测意外损坏、散列表、分片或内容分布,不能用于安全决策或抵抗恶意篡改。 ### 密码哈希 ```csharp using BugFree.Security.Hashing.Password; var hashing = new PasswordHashing(); var encodedHash = hashing.Hash( PasswordHashAlgorithm.Argon2id, "myPassword"); var result = hashing.Verify("myPassword", encodedHash); if (result.IsValid && result.NeedsRehash) { encodedHash = hashing.Hash( PasswordHashAlgorithm.Argon2id, "myPassword"); } ``` `Verify` 返回 `PasswordHashVerificationResult`,包含 `IsValid`、`NeedsRehash`、识别出的 `Algorithm` 和非敏感 `Parameters`。可在 DI 注册时传入不可变资源上限: ```csharp var limits = new PasswordHashVerificationLimits( maximumArgon2MemorySizeInKibibytes: 65_536, maximumPbkdf2Iterations: 600_000); services.AddPasswordHashing(limits); ``` ## 算法与安全用途 ### 对称密码 | 算法 | 模式 / 密钥 | 用途 | |------|-------------|------| | AES | CBC/CFB/CTR/GCM;16/24/32 bytes | 新协议优先 GCM | | SM4 | CBC/CFB/CTR/GCM;16 bytes | 国密场景;新协议优先 GCM | | DES | CBC;8 bytes | 仅历史互操作 | | TripleDES | CBC;16/24 bytes | 仅历史互操作 | | RC2 | CBC;5–16 bytes | 仅历史互操作 | ### 非对称密码 | 算法 | 密钥生成 | 加解密 | 签名验签 | Key agreement | 用途 | |------|----------|--------|----------|---------------|------| | RSA | 是 | 是 | 是 | 否 | 通用公钥密码 | | DSA | 是 | 否 | 是 | 否 | 仅历史互操作 | | ECDSA | 是 | 否 | 是 | 否 | 椭圆曲线签名 | | ECDH | 是 | 否 | 否 | 是 | 椭圆曲线密钥协商 | | Ed25519 | 是 | 否 | 是 | 否 | 现代签名 | | X25519 | 是 | 否 | 否 | 是 | 现代密钥协商 | | SM2 | 是 | 是 | 是 | 是 | 国密公钥密码 | ### 密码哈希 | 算法 | 用途 | |------|------| | Argon2id | 新密码首选 | | BCrypt、scrypt、PBKDF2 | 受支持的替代方案;参数应按部署环境制定 | | Argon2i、Argon2d | 仅验证历史编码;成功后重新哈希为 Argon2id | ### 摘要、HMAC 与快速哈希 - 新协议优先使用 SHA-256/384/512、SHA3-256/384/512、SM3 或合适的 BLAKE2/BLAKE3 变体。 - 还支持 SHA-224、SHA-512/224、SHA-512/256、Whirlpool、Tiger、SHAKE128-256、SHAKE256-512。 - MD2、MD4、MD5、SHA-1、RIPEMD-160/256/320 仅为历史互操作保留,不能用于新的安全协议。 - HMAC-SHA-256/384/512 与 HMAC-SM3 可用;HMAC-MD5 和 HMAC-SHA-1 仅为历史互操作保留。 - CRC32、CRC64、Adler32 以及 FNV-1a、xxHash 家族不提供密码学安全性。 ## 密钥管理 KeyManagement 与 8 个密码 facade 独立。`IKeyStore` 是用于可导出密钥记录的异步 CAS 合约: | 操作 | 公开 API | 语义 | |------|----------|------| | 精确读取 | `ReadAsync(KeyIdentity, CancellationToken)` | 读取指定 key version | | 最新读取 | `ReadLatestAsync(string, CancellationToken)` | 读取逻辑 key 的最高版本 | | 元数据列表 | `ListAsync(CancellationToken)` | 返回稳定、完整物化的快照 | | 条件创建 | `CreateAsync(KeyRecord, CancellationToken)` | 仅在 identity 不存在时创建 | | 条件替换 | `ReplaceAsync(KeyRecord, KeyRevision, CancellationToken)` | 仅在不透明 revision 相等时替换 | | 条件删除 | `DeleteAsync(KeyIdentity, KeyRevision, CancellationToken)` | 仅在不透明 revision 相等时删除 | `KeyRevision` 只能作为相等性 token,不能解析或排序。mutation 通过 `KeyStoreMutationStatus.Applied`、`Conflict`、`NotFound` 报告结果。进程内场景可使用 `InMemoryKeyStore`;需要文件持久化时应显式配置 `ProtectedFileKeyStore`。 ### 受保护文件存储与 DI `ProtectedFileKeyStore` 强制要求 `IKeyMaterialProtector`。构造函数不执行文件系统 I/O,所有使用前都必须显式调用 `InitializeAsync`: ```csharp using System.Security.Cryptography; using BugFree.Security; using BugFree.Security.DependencyInjection; using BugFree.Security.KeyManagement; using Microsoft.Extensions.DependencyInjection; // 固定值仅用于文档演示;生产环境应从外部秘密存储载入并自行轮换。 var masterKey = Convert.FromHexString( "00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF"); using var protector = new AesGcmKeyMaterialProtector(masterKey); CryptographicOperations.ZeroMemory(masterKey); var keyStore = new ProtectedFileKeyStore( Path.Combine(AppContext.BaseDirectory, "protected-keys"), protector); await keyStore.InitializeAsync(); var rotationPolicy = new KeyRotationPolicySnapshot( rotationInterval: TimeSpan.FromDays(90), maxUsageCount: 1_000_000, enableAutoRotation: true); var services = new ServiceCollection(); services.AddBugFreeCryptography(); services.AddBugFreeKeyManagement( keyStore, rotationPolicy, TimeProvider.System); ``` `AddBugFreeKeyManagement(IServiceCollection, IKeyStore, KeyRotationPolicySnapshot, TimeProvider?)` 不创建或初始化 store,也不会由 `AddBugFreeCryptography()` 间接调用。 `AesGcmKeyMaterialProtector` 只接受调用方提供并保管的精确 32-byte master key。它以 AES-256-GCM 加密 key material,并将 envelope 的算法标识与规范元数据作为 authenticated data;文件篡改、元数据篡改或错误 master key 会以格式或完整性错误明确失败。解密只使用当前配置的 exact protector 和 master key,不进行 alternate-key probing 或 fallback。 这是一种应用管理的加密文件方案,不是 HSM。它不能防御: - master-key compromise; - live-process compromise; - 文件删除和其他可用性攻击; - 将文件替换为旧的、仍可通过认证的 envelope 所造成的回滚。 应用必须负责 master key custody 与 rotation、备份和恢复、host ACL,以及 caller memory 中原始 master key 和导出密钥材料的生命周期。`AesGcmKeyMaterialProtector.Dispose()` 会清除其私有副本,但不会替调用方清除原始缓冲区。 ### 旧明文 JSON 的显式迁移 `LegacyPlaintextKeyStoreMigrator` 只用于调用方明确发起的一次性迁移。destination 必须已完成 `InitializeAsync`: ```csharp var legacyDirectory = Path.Combine( AppContext.BaseDirectory, "legacy-plaintext-keys"); var migrator = new LegacyPlaintextKeyStoreMigrator( legacyDirectory, KeyMaterialKind.Symmetric, keyStore); LegacyPlaintextKeyMigrationReport report = await migrator.MigrateAsync(); foreach (var item in report.Items) { Console.WriteLine($"{item.SourcePath}: {item.Status} {item.Error}"); } ``` 迁移器按稳定文件名顺序逐个读取 canonical 历史 JSON,条件写入后立即回读并进行精确验证。每项状态严格为: - `LegacyPlaintextKeyMigrationStatus.Migrated` - `LegacyPlaintextKeyMigrationStatus.AlreadyMigrated` - `LegacyPlaintextKeyMigrationStatus.Conflict` - `LegacyPlaintextKeyMigrationStatus.Invalid` - `LegacyPlaintextKeyMigrationStatus.Unsupported` - `LegacyPlaintextKeyMigrationStatus.Failed` 相同记录可安全重跑并报告 `AlreadyMigrated`,不同记录报告 `Conflict`,绝不覆盖。写入后验证失败时迁移器会尝试按 revision 回滚新记录,因此中断或失败后可以恢复并再次运行。源文件默认保留,并且迁移器始终不会修改或删除源文件。 ## 架构概览 生产项目按垂直 feature 组织: ```text BugFree.Security/ ├── ServiceCollectionExtensions.cs ├── Symmetric/ │ ├── SymmetricCryptography.cs │ ├── ISymmetricProvider.cs │ └── Providers/ ├── Asymmetric/ │ ├── AsymmetricCryptography.cs │ ├── ProviderContracts.cs │ └── Internal/ ├── Hashing/ │ ├── Cryptographic/ │ ├── Hmac/ │ ├── Password/ │ ├── Checksum/ │ └── NonCryptographic/ ├── FormatPreserving/ │ ├── FormatPreservingCryptography.cs │ └── FormatPreservingAlgorithmRegistry.cs ├── KeyManagement/ │ ├── IKeyStore.cs │ ├── KeyLifecycleCoordinator.cs │ ├── ProtectedFileKeyStore.cs │ └── LegacyPlaintextKeyStoreMigrator.cs └── DependencyInjection/ └── KeyManagementServiceCollectionExtensions.cs ``` 通用 8-facade 注册位于项目根部的 `ServiceCollectionExtensions.cs`;KeyManagement 的独立注册位于 `DependencyInjection/KeyManagementServiceCollectionExtensions.cs`。 ## 测试 `BugFree.Security.Tests` 覆盖 facade 路由、provider 注册冲突、安全边界、算法已知答案、历史格式兼容、密码验证资源限制、受保护 envelope、CAS 密钥生命周期与依赖注入。 ```shell dotnet test ``` ## 参与贡献 欢迎提交 Issue 和 Pull Request: 1. Fork 本仓库。 2. 创建特性分支:`git checkout -b feat/your-feature`。 3. 提交代码:`git commit -m "feat: add xxx"`。 4. 推送分支:`git push origin feat/your-feature`。 5. 创建 Pull Request。 ## 许可证 本项目基于 MIT 许可证开源。