Add migrated to .NET 8.0 variant of Hcs.Client

This commit is contained in:
2025-09-26 19:48:32 +09:00
parent da127df8f6
commit 6cd2fb82e9
503 changed files with 223796 additions and 0 deletions

View File

@ -0,0 +1,38 @@
using System;
namespace GostXades.Helpers
{
public static class ArrayHelper
{
public static bool AreEquals(byte[] first, byte[] second)
{
return AreEquals(first, second, (x, y) => x.Equals(y));
}
public static bool AreEquals(string[] first, string[] second)
{
return AreEquals(first, second, (x, y) => string.Equals(x, y, StringComparison.InvariantCultureIgnoreCase));
}
private static bool AreEquals<T>(T[] first, T[] second, Func<T, T, bool> comparator)
{
if (first == second)
{
return true;
}
if (first.Length != second.Length)
{
return false;
}
for (var i = 0; i < first.Length; i++)
{
var equals = comparator.Invoke(first[i], second[i]);
if (!equals)
{
return false;
}
}
return true;
}
}
}

View File

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
namespace GostXades.Helpers
{
public static class CertificateHelper
{
/// <summary>
/// Получение сертификата из личного локального хранилища по отпечатку
/// </summary>
/// <param name="thumbprint">Отпечаток требуемого сертификата</param>
/// <returns>Сертификат с нужным отпечатком</returns>
public static X509Certificate2 GetCertificateByThumbprint(string thumbprint)
{
var certificateStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
try
{
certificateStore.Open(OpenFlags.ReadOnly);
var certificateCollection = certificateStore.Certificates
.Cast<X509Certificate2>()
.Where(i => string.Equals(i.Thumbprint, thumbprint, StringComparison.InvariantCultureIgnoreCase))
.ToArray();
if (!certificateCollection.Any())
{
throw new ArgumentException("Некорректный отпечаток сертификата");
}
var activeCertificates = certificateCollection.Where(i => DateTime.Parse(i.GetEffectiveDateString()) <= DateTime.Now &&
DateTime.Now <= DateTime.Parse(i.GetExpirationDateString()))
.ToArray();
if (activeCertificates.Any())
{
return activeCertificates[0];
}
throw new ArgumentException($"Сертификат с указанным отпечатком {thumbprint} недействителен");
}
finally
{
certificateStore.Close();
}
}
/// <summary>
/// Получение сертификатов из локального хранилища текущего пользователя
/// </summary>
/// <returns>Сертификаты из локального хранилища текущего пользователя</returns>
public static IEnumerable<X509Certificate2> GetCertificates()
{
var certificateStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
try
{
certificateStore.Open(OpenFlags.ReadOnly);
return certificateStore.Certificates.OfType<X509Certificate2>();
}
finally
{
certificateStore.Close();
}
}
}
}

View File

@ -0,0 +1,13 @@
using System.Collections;
using System.Linq;
namespace GostXades.Helpers
{
public static class CollectionHelper
{
public static bool IsNotEmpty(this IEnumerable enumerable)
{
return enumerable != null && enumerable.OfType<object>().Any();
}
}
}

View File

@ -0,0 +1,12 @@
using System.Numerics;
namespace GostXades.Helpers
{
public static class ConvertHelper
{
public static string BigIntegerToHex(string str)
{
return BigInteger.Parse(str).ToString("X");
}
}
}

View File

@ -0,0 +1,14 @@
using System;
namespace GostXades.Helpers
{
public static class DateTimeHelper
{
public static DateTimeOffset ToDateTimeOffset(this DateTime dateTime, int timeZoneOffsetMinutes = 0)
{
var shiftedDateTime = dateTime.AddMinutes(timeZoneOffsetMinutes);
var unspecifiedDateTime = DateTime.SpecifyKind(shiftedDateTime, DateTimeKind.Unspecified);
return new DateTimeOffset(unspecifiedDateTime, new TimeSpan(0, timeZoneOffsetMinutes, 0));
}
}
}

View File

@ -0,0 +1,15 @@
using System.Collections.Generic;
using System.Linq;
namespace GostXades.Helpers
{
public static class EnumerableHelper
{
public static bool AreSequenceEquals(IEnumerable<string> first, IEnumerable<string> second)
{
var sortedFirst = first.OrderBy(x => x).ToArray();
var sortedSecond = second.OrderBy(x => x).ToArray();
return ArrayHelper.AreEquals(sortedFirst, sortedSecond);
}
}
}

View File

@ -0,0 +1,23 @@
using GostCryptography.Config;
using System;
namespace GostXades.Helpers
{
public static class GostHashAlgorithmHelper
{
/// <summary>
/// Рассчитать хэш
/// </summary>
/// <param name="cryptoProviderType">Тип криптопровайдера</param>
/// <param name="bytes"></param>
/// <returns></returns>
public static string ComputeHash(CryptoProviderTypeEnum cryptoProviderType, byte[] bytes)
{
byte[] hashValue;
GostCryptoConfig.ProviderType = (GostCryptography.Base.ProviderType)cryptoProviderType;
var hashAlgorithm = new GostCryptography.Gost_R3411.Gost_R3411_2012_512_HashAlgorithm();
hashValue = hashAlgorithm.ComputeHash(bytes);
return BitConverter.ToString(hashValue).Replace("-", "");
}
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
using System.Xml;
namespace GostXades.Helpers
{
public static class KeyInfoHelper
{
public static KeyInfo Create(X509Certificate2 certificate)
{
var xmlDocument = new XmlDocument();
var x509DataElement = xmlDocument.CreateElement("ds", "X509Data", KeyInfoNamespace);
var x509CertificateElement = xmlDocument.CreateElement("ds", "X509Certificate", KeyInfoNamespace);
x509CertificateElement.InnerText = Convert.ToBase64String(certificate.GetRawCertData());
x509DataElement.AppendChild(x509CertificateElement);
var keyInfo = new KeyInfo();
keyInfo.AddClause(new KeyInfoNode(x509DataElement));
return keyInfo;
}
private const string KeyInfoNamespace = "http://www.w3.org/2000/09/xmldsig#";
}
}

View File

@ -0,0 +1,74 @@
using Org.BouncyCastle.Asn1.X509;
using System.Linq;
using System.Text;
namespace GostXades.Helpers
{
public static class X509NameHelper
{
/// <summary>
/// Исправить строку X509IssuerName для рукожопых пейсателей из Ланита
/// </summary>
/// <param name="x509Name">Исходная строка из сертификата</param>
/// <returns>Исправленная строка, чтобы ее понимал сервер ГИС ЖКХ</returns>
public static string ToX509IssuerName(this X509Name x509Name)
{
string x509IssuerName = x509Name.ToString();
var pairs = x509IssuerName
.Replace("\\,", "^_^")
.Split(',')
.Select(part => part.Split('='))
.Select(lrParts => new ReplacementPair
{
Key = lrParts[0],
Value = lrParts.Length == 2 ? lrParts[1] : string.Empty
}).ToList();
var nCount = pairs.Count;
var result = new StringBuilder();
var i = 0;
foreach (var pair in pairs)
{
switch (pair.Key.ToLower())
{
case "t":
case "title":
pair.Key = "2.5.4.12";
break;
case "g":
case "givenname":
pair.Key = "2.5.4.42";
break;
case "e":
pair.Key = "1.2.840.113549.1.9.1";
break;
case "sn":
case "surname":
pair.Key = "2.5.4.4";
break;
case "ou":
case "orgunit":
pair.Key = "2.5.4.11";
break;
case "unstructured-name":
case "unstructuredname":
pair.Key = "1.2.840.113549.1.9.2";
break;
}
result.Append($"{pair.Key}={pair.Value}{(i != (nCount - 1) ? ", " : string.Empty)}");
i++;
}
return result.ToString().Replace("^_^", "\\,");
}
}
internal class ReplacementPair
{
public string Key { get; set; }
public string Value { get; set; }
}
}

View File

@ -0,0 +1,16 @@
using Microsoft.Xades;
using System.Xml;
namespace GostXades.Helpers
{
public static class XadesSignedXmlHelper
{
public static void InjectSignatureTo(this XadesSignedXml signedXml, XmlDocument originalDoc)
{
var signatureElement = signedXml.GetXml();
var importSignatureElement = originalDoc.ImportNode(signatureElement, true);
var signedDataContainer = signedXml.GetIdElement(originalDoc, signedXml.SignedElementId);
signedDataContainer.InsertBefore(importSignatureElement, signedDataContainer.FirstChild);
}
}
}

View File

@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
namespace GostXades.Helpers
{
public static class XmlDocumentHelper
{
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> XmlDocument <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
public static XmlDocument Create(string xmlData)
{
var xmlDocument = new XmlDocument { PreserveWhitespace = true };
try
{
xmlDocument.LoadXml(xmlData);
}
catch (XmlException xmlEx)
{
throw new InvalidOperationException($"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> xml <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: {xmlEx.Message}", xmlEx);
}
return xmlDocument;
}
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> XmlDocument <20><> <20><><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
public static XmlDocument Load(string pathName)
{
var xmlDocument = new XmlDocument { PreserveWhitespace = true };
try
{
xmlDocument.Load(pathName);
}
catch (XmlException xmlEx)
{
throw new InvalidOperationException($"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> xml <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>: {xmlEx.Message}", xmlEx);
}
return xmlDocument;
}
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> XmlDocument
/// </summary>
public static XmlNamespaceManager CreateNamespaceManager(this XmlDocument xml)
{
var manager = new XmlNamespaceManager(xml.NameTable);
foreach (var name in GetNamespaceDictionary(xml))
{
manager.AddNamespace(name.Key, name.Value);
}
return manager;
}
private static IDictionary<string, string> GetNamespaceDictionary(this XmlDocument xml)
{
var nameSpaceList = xml.SelectNodes(@"//namespace::*[not(. = ../../namespace::*)]").OfType<XmlNode>();
return nameSpaceList.Distinct(new LocalNameComparer()).ToDictionary(xmlNode => xmlNode.LocalName, xmlNode => xmlNode.Value);
}
private class LocalNameComparer : IEqualityComparer<XmlNode>
{
public bool Equals(XmlNode x, XmlNode y)
{
return x.LocalName == y.LocalName;
}
public int GetHashCode(XmlNode obj)
{
return obj.LocalName.GetHashCode();
}
}
}
}