Files
git.stella-ops.org/src/__Libraries/StellaOps.Cryptography.Plugin.CryptoPro/CryptoProGostCryptoProvider.cs
master cef4cb2c5a Add support for ГОСТ Р 34.10 digital signatures
- Implemented the GostKeyValue class for handling public key parameters in ГОСТ Р 34.10 digital signatures.
- Created the GostSignedXml class to manage XML signatures using ГОСТ 34.10, including methods for computing and checking signatures.
- Developed the GostSignedXmlImpl class to encapsulate the signature computation logic and public key retrieval.
- Added specific key value classes for ГОСТ Р 34.10-2001, ГОСТ Р 34.10-2012/256, and ГОСТ Р 34.10-2012/512 to support different signature algorithms.
- Ensured compatibility with existing XML signature standards while integrating ГОСТ cryptography.
2025-11-09 21:59:57 +02:00

106 lines
4.0 KiB
C#

using System;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Runtime.Versioning;
using StellaOps.Cryptography;
namespace StellaOps.Cryptography.Plugin.CryptoPro;
[SupportedOSPlatform("windows")]
public sealed class CryptoProGostCryptoProvider : ICryptoProvider, ICryptoProviderDiagnostics
{
private readonly ILogger<CryptoProGostCryptoProvider>? logger;
private readonly IReadOnlyDictionary<string, CryptoProGostKeyEntry> entries;
public CryptoProGostCryptoProvider(
IOptions<CryptoProGostProviderOptions>? optionsAccessor = null,
ILogger<CryptoProGostCryptoProvider>? logger = null)
{
this.logger = logger;
var options = optionsAccessor?.Value ?? new CryptoProGostProviderOptions();
var map = new Dictionary<string, CryptoProGostKeyEntry>(StringComparer.OrdinalIgnoreCase);
foreach (var key in options.Keys)
{
var certificate = CryptoProCertificateResolver.Resolve(key);
var entry = new CryptoProGostKeyEntry(
key.KeyId,
key.Algorithm,
certificate,
key.ProviderName,
key.ContainerName,
key.UseMachineKeyStore,
key.SignatureFormat);
map[key.KeyId] = entry;
}
entries = map;
}
public string Name => "ru.cryptopro.csp";
public bool Supports(CryptoCapability capability, string algorithmId)
=> capability is CryptoCapability.Signing or CryptoCapability.Verification
&& (string.Equals(algorithmId, SignatureAlgorithms.GostR3410_2012_256, StringComparison.OrdinalIgnoreCase)
|| string.Equals(algorithmId, SignatureAlgorithms.GostR3410_2012_512, StringComparison.OrdinalIgnoreCase));
public IPasswordHasher GetPasswordHasher(string algorithmId)
=> throw new NotSupportedException("CryptoPro provider does not expose password hashing.");
public ICryptoSigner GetSigner(string algorithmId, CryptoKeyReference keyReference)
{
ArgumentNullException.ThrowIfNull(keyReference);
var entry = ResolveKey(keyReference.KeyId);
if (!string.Equals(entry.AlgorithmId, algorithmId, StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException(
$"Signing key '{keyReference.KeyId}' is registered for algorithm '{entry.AlgorithmId}', not '{algorithmId}'.");
}
logger?.LogDebug("Using CryptoPro key {Key} ({Algorithm})", entry.KeyId, entry.AlgorithmId);
return new CryptoProGostSigner(entry);
}
public void UpsertSigningKey(CryptoSigningKey signingKey)
=> throw new NotSupportedException("CryptoPro keys are managed externally.");
public bool RemoveSigningKey(string keyId) => false;
public IReadOnlyCollection<CryptoSigningKey> GetSigningKeys()
=> Array.Empty<CryptoSigningKey>();
public IEnumerable<CryptoProviderKeyDescriptor> DescribeKeys()
{
foreach (var entry in entries.Values)
{
yield return new CryptoProviderKeyDescriptor(
Name,
entry.KeyId,
entry.AlgorithmId,
new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase)
{
["provider"] = entry.ProviderName,
["container"] = entry.ContainerName,
["thumbprint"] = entry.Certificate.Thumbprint,
["subject"] = entry.Certificate.Subject
});
}
}
private CryptoProGostKeyEntry ResolveKey(string? keyId)
{
if (string.IsNullOrWhiteSpace(keyId))
{
throw new ArgumentException("Crypto key reference must include KeyId.", nameof(keyId));
}
if (entries.TryGetValue(keyId, out var entry))
{
return entry;
}
throw new KeyNotFoundException($"CryptoPro key '{keyId}' is not registered.");
}
}