Add post-quantum cryptography support with PqSoftCryptoProvider
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
wine-csp-build / Build Wine CSP Image (push) Has been cancelled

- Implemented PqSoftCryptoProvider for software-only post-quantum algorithms (Dilithium3, Falcon512) using BouncyCastle.
- Added PqSoftProviderOptions and PqSoftKeyOptions for configuration.
- Created unit tests for Dilithium3 and Falcon512 signing and verification.
- Introduced EcdsaPolicyCryptoProvider for compliance profiles (FIPS/eIDAS) with explicit allow-lists.
- Added KcmvpHashOnlyProvider for KCMVP baseline compliance.
- Updated project files and dependencies for new libraries and testing frameworks.
This commit is contained in:
StellaOps Bot
2025-12-07 15:04:19 +02:00
parent 862bb6ed80
commit 98e6b76584
119 changed files with 11436 additions and 1732 deletions

View File

@@ -0,0 +1,73 @@
using System;
using System.Security.Cryptography;
using System.Text;
using FluentAssertions;
using StellaOps.Cryptography;
using Xunit;
namespace StellaOps.Cryptography.Tests;
public class PolicyProvidersTests
{
[Fact]
public async Task FipsSoft_Signs_And_Verifies_Es256()
{
Environment.SetEnvironmentVariable("FIPS_SOFT_ALLOWED", "1");
var provider = new FipsSoftCryptoProvider();
using var ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256);
var key = new CryptoSigningKey(
new CryptoKeyReference("fips-es256"),
SignatureAlgorithms.Es256,
ecdsa.ExportParameters(true),
DateTimeOffset.UtcNow);
provider.UpsertSigningKey(key);
var signer = provider.GetSigner(SignatureAlgorithms.Es256, new CryptoKeyReference("fips-es256"));
var data = Encoding.UTF8.GetBytes("fips-soft-provider");
var signature = await signer.SignAsync(data);
(await signer.VerifyAsync(data, signature)).Should().BeTrue();
provider.GetHasher(HashAlgorithms.Sha256).ComputeHash(data).Length.Should().Be(32);
}
[Fact]
public async Task EidasSoft_Signs_And_Verifies_Es384()
{
Environment.SetEnvironmentVariable("EIDAS_SOFT_ALLOWED", "1");
var provider = new EidasSoftCryptoProvider();
using var ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP384);
var key = new CryptoSigningKey(
new CryptoKeyReference("eidas-es384"),
SignatureAlgorithms.Es384,
ecdsa.ExportParameters(true),
DateTimeOffset.UtcNow);
provider.UpsertSigningKey(key);
var signer = provider.GetSigner(SignatureAlgorithms.Es384, new CryptoKeyReference("eidas-es384"));
var data = Encoding.UTF8.GetBytes("eidas-soft-provider");
var signature = await signer.SignAsync(data);
(await signer.VerifyAsync(data, signature)).Should().BeTrue();
provider.GetHasher(HashAlgorithms.Sha384).ComputeHash(data).Length.Should().Be(48);
}
[Fact]
public void KcmvpHashOnly_Computes_Hash()
{
Environment.SetEnvironmentVariable("KCMVP_HASH_ALLOWED", "1");
var provider = new KcmvpHashOnlyProvider();
var data = Encoding.UTF8.GetBytes("kcmvp-hash-only");
provider.Supports(CryptoCapability.ContentHashing, HashAlgorithms.Sha256).Should().BeTrue();
var digest = provider.GetHasher(HashAlgorithms.Sha256).ComputeHash(data);
digest.Length.Should().Be(32);
provider.Invoking(p => p.GetSigner(SignatureAlgorithms.Es256, new CryptoKeyReference("none")))
.Should().Throw<NotSupportedException>();
}
}

View File

@@ -0,0 +1,77 @@
using System;
using System.Text;
using FluentAssertions;
using Microsoft.Extensions.Options;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium;
using Org.BouncyCastle.Pqc.Crypto.Falcon;
using StellaOps.Cryptography;
using StellaOps.Cryptography.Plugin.PqSoft;
using Xunit;
namespace StellaOps.Cryptography.Tests;
public class PqSoftCryptoProviderTests
{
[Fact]
public async Task Dilithium3_Signs_And_Verifies()
{
var provider = CreateProvider();
var generator = new DilithiumKeyPairGenerator();
generator.Init(new DilithiumKeyGenerationParameters(new SecureRandom(), DilithiumParameters.Dilithium3));
var keyPair = generator.GenerateKeyPair();
var priv = ((DilithiumPrivateKeyParameters)keyPair.Private).GetEncoded();
var pub = ((DilithiumPublicKeyParameters)keyPair.Public).GetEncoded();
provider.UpsertSigningKey(new CryptoSigningKey(
new CryptoKeyReference("pq-dil3"),
SignatureAlgorithms.Dilithium3,
priv,
DateTimeOffset.UtcNow,
publicKey: pub));
var signer = provider.GetSigner(SignatureAlgorithms.Dilithium3, new CryptoKeyReference("pq-dil3"));
var data = Encoding.UTF8.GetBytes("dilithium-soft");
var signature = await signer.SignAsync(data);
(await signer.VerifyAsync(data, signature)).Should().BeTrue();
}
[Fact]
public async Task Falcon512_Signs_And_Verifies()
{
var provider = CreateProvider();
var generator = new FalconKeyPairGenerator();
generator.Init(new FalconKeyGenerationParameters(new SecureRandom(), FalconParameters.falcon_512));
var keyPair = generator.GenerateKeyPair();
var priv = ((FalconPrivateKeyParameters)keyPair.Private).GetEncoded();
var pub = ((FalconPublicKeyParameters)keyPair.Public).GetEncoded();
provider.UpsertSigningKey(new CryptoSigningKey(
new CryptoKeyReference("pq-falcon"),
SignatureAlgorithms.Falcon512,
priv,
DateTimeOffset.UtcNow,
publicKey: pub));
var signer = provider.GetSigner(SignatureAlgorithms.Falcon512, new CryptoKeyReference("pq-falcon"));
var data = Encoding.UTF8.GetBytes("falcon-soft");
var signature = await signer.SignAsync(data);
(await signer.VerifyAsync(data, signature)).Should().BeTrue();
}
private static PqSoftCryptoProvider CreateProvider()
{
var options = Options.Create(new PqSoftProviderOptions
{
RequireEnvironmentGate = false
});
return new PqSoftCryptoProvider(options);
}
}

View File

@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>preview</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BouncyCastle.Cryptography" Version="2.5.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="coverlet.collector" Version="6.0.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\StellaOps.Cryptography\StellaOps.Cryptography.csproj" />
<ProjectReference Include="..\StellaOps.Cryptography.Plugin.PqSoft\StellaOps.Cryptography.Plugin.PqSoft.csproj" />
</ItemGroup>
</Project>