using System.Security.Cryptography; using System.Text; using System.Text.Json.Serialization; var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); // Static key material for simulations (not for production use). using var ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256); var ecdsaPublic = ecdsa.ExportSubjectPublicKeyInfo(); byte[] Sign(string message, string algorithm) { var data = Encoding.UTF8.GetBytes(message); var lower = algorithm.Trim().ToLowerInvariant(); var upper = algorithm.Trim().ToUpperInvariant(); if (lower is "pq.dilithium3" or "pq.falcon512" or "pq.sim" || upper is "DILITHIUM3" or "FALCON512") { return HMACSHA256.HashData(Encoding.UTF8.GetBytes("pq-sim-key"), data); } if (lower is "ru.magma.sim" or "ru.kuznyechik.sim" || upper is "GOST12-256" or "GOST12-512") { return HMACSHA256.HashData(Encoding.UTF8.GetBytes("gost-sim-key"), data); } if (lower is "sm.sim" or "sm2.sim" || upper is "SM2") { return HMACSHA256.HashData(Encoding.UTF8.GetBytes("sm-sim-key"), data); } return ecdsa.SignData(data, HashAlgorithmName.SHA256); } bool Verify(string message, string algorithm, byte[] signature) { var data = Encoding.UTF8.GetBytes(message); var lower = algorithm.Trim().ToLowerInvariant(); var upper = algorithm.Trim().ToUpperInvariant(); if (lower is "pq.dilithium3" or "pq.falcon512" or "pq.sim" || upper is "DILITHIUM3" or "FALCON512") { return CryptographicOperations.FixedTimeEquals(HMACSHA256.HashData(Encoding.UTF8.GetBytes("pq-sim-key"), data), signature); } if (lower is "ru.magma.sim" or "ru.kuznyechik.sim" || upper is "GOST12-256" or "GOST12-512") { return CryptographicOperations.FixedTimeEquals(HMACSHA256.HashData(Encoding.UTF8.GetBytes("gost-sim-key"), data), signature); } if (lower is "sm.sim" or "sm2.sim" || upper is "SM2") { return CryptographicOperations.FixedTimeEquals(HMACSHA256.HashData(Encoding.UTF8.GetBytes("sm-sim-key"), data), signature); } return ecdsa.VerifyData(data, signature, HashAlgorithmName.SHA256); } app.MapPost("/sign", (SignRequest request) => { if (string.IsNullOrWhiteSpace(request.Algorithm) || string.IsNullOrWhiteSpace(request.Message)) { return Results.BadRequest("Algorithm and message are required."); } var sig = Sign(request.Message, request.Algorithm); return Results.Json(new SignResponse(Convert.ToBase64String(sig), request.Algorithm)); }); app.MapPost("/verify", (VerifyRequest request) => { if (string.IsNullOrWhiteSpace(request.Algorithm) || string.IsNullOrWhiteSpace(request.Message) || string.IsNullOrWhiteSpace(request.SignatureBase64)) { return Results.BadRequest("Algorithm, message, and signature are required."); } var sig = Convert.FromBase64String(request.SignatureBase64); var ok = Verify(request.Message, request.Algorithm, sig); return Results.Json(new VerifyResponse(ok, request.Algorithm)); }); app.MapGet("/keys", () => { return Results.Json(new KeysResponse( Convert.ToBase64String(ecdsaPublic), "nistp256", new[] { "pq.sim", "DILITHIUM3", "FALCON512", "ru.magma.sim", "ru.kuznyechik.sim", "GOST12-256", "GOST12-512", "sm.sim", "SM2", "fips.sim", "eidas.sim", "kcmvp.sim", "world.sim" })); }); app.Run(); public record SignRequest( [property: JsonPropertyName("message")] string Message, [property: JsonPropertyName("algorithm")] string Algorithm); public record SignResponse( [property: JsonPropertyName("signature_b64")] string SignatureBase64, [property: JsonPropertyName("algorithm")] string Algorithm); public record VerifyRequest( [property: JsonPropertyName("message")] string Message, [property: JsonPropertyName("signature_b64")] string SignatureBase64, [property: JsonPropertyName("algorithm")] string Algorithm); public record VerifyResponse( [property: JsonPropertyName("ok")] bool Ok, [property: JsonPropertyName("algorithm")] string Algorithm); public record KeysResponse( [property: JsonPropertyName("public_key_b64")] string PublicKeyBase64, [property: JsonPropertyName("curve")] string Curve, [property: JsonPropertyName("simulated_providers")] IEnumerable Providers);