diff --git a/DotnetSampleProject.csproj b/DotnetSampleProject.csproj
new file mode 100644
index 0000000..9cc998e
--- /dev/null
+++ b/DotnetSampleProject.csproj
@@ -0,0 +1,20 @@
+
+
+ Exe
+ netcoreapp3.1
+ win-x64
+
+ Microsoft.Private.CoreFx.NETCoreApp;runtime.win-x64.Microsoft.Private.CoreFx.NETCoreApp;$(PackageConflictPreferredPackages)
+
+
+
+
+
+
+ ..\corefx\artifacts\bin\runtime\netcoreapp-Windows_NT-Debug-x64\System.Security.Cryptography.Pkcs.dll
+
+
+ ..\corefx\artifacts\bin\runtime\netcoreapp-Windows_NT-Debug-x64\System.Security.Cryptography.Xml.dll
+
+
+
\ No newline at end of file
diff --git a/DotnetSampleProject.sln b/DotnetSampleProject.sln
new file mode 100644
index 0000000..41a26d7
--- /dev/null
+++ b/DotnetSampleProject.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29709.97
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotnetSampleProject", "DotnetSampleProject.csproj", "{8D81D66D-892A-46E4-B058-DAF52F5840CA}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {8D81D66D-892A-46E4-B058-DAF52F5840CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8D81D66D-892A-46E4-B058-DAF52F5840CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8D81D66D-892A-46E4-B058-DAF52F5840CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8D81D66D-892A-46E4-B058-DAF52F5840CA}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {7101067E-48BD-4F7C-8AF2-2299E6C596F6}
+ EndGlobalSection
+EndGlobal
diff --git a/Program.cs b/Program.cs
new file mode 100644
index 0000000..8cd3344
--- /dev/null
+++ b/Program.cs
@@ -0,0 +1,225 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
+using System.Xml;
+using System.Security.Cryptography.Xml;
+
+namespace DotnetSample
+{
+ class Program
+ {
+ private static readonly byte[] bytesToHash =
+ new byte[]
+ {
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+ };
+
+ static void Main(string[] args)
+ {
+ var hash = HashAlgorithmName.Gost3411_2012_256;
+ Program.MakeMeCert();
+ var gostCert = new X509Certificate2(@"MyCert.pfx", "1");
+ var gostSk = gostCert.PrivateKey as Gost3410_2012_256CryptoServiceProvider;
+ var signed = gostSk.SignData(bytesToHash, hash);
+
+ var gostPk = gostCert.GetGost3410_2012_256PublicKey();
+ var dataValidationResult = gostPk.VerifyData(bytesToHash, signed, hash);
+
+ Console.WriteLine($"Validation result: {dataValidationResult}");
+
+ Program.CreateSomeXml("test.txml");
+ Program.SignXmlFile("test.txml", "test.xml.sig", gostSk, gostCert);
+ Program.ValidateXmlFIle("test.xml.sig");
+ }
+
+ ///
+ /// Создать сертификат ГОСТ 34.10.2012 256
+ ///
+ private static void MakeMeCert()
+ {
+ using (var parent = new Gost3410_2012_256CryptoServiceProvider())
+ {
+ var parentReq = new CertificateRequest(
+ "CN=Experimental Issuing Authority",
+ parent,
+ HashAlgorithmName.Gost3411_2012_256);
+
+ parentReq.CertificateExtensions.Add(
+ new X509BasicConstraintsExtension(true, false, 0, true));
+
+ parentReq.CertificateExtensions.Add(
+ new X509SubjectKeyIdentifierExtension(parentReq.PublicKey, false));
+
+ using (var parentCert = parentReq.CreateSelfSigned(
+ DateTimeOffset.UtcNow.AddDays(-45),
+ DateTimeOffset.UtcNow.AddDays(365)))
+ {
+ byte[] certData = parentCert.Export(X509ContentType.Pfx, "1");
+ File.WriteAllBytes(@"MyCert.pfx", certData);
+ }
+ }
+ }
+
+ static void CreateSomeXml(string FileName)
+ {
+ string SourceDocument = "" +
+ "" +
+ " " +
+ "Here is some data to sign." +
+ "";
+
+ // Создать документ по строке
+ XmlDocument document = new XmlDocument();
+ document.LoadXml(SourceDocument);
+
+ // Сохранить подписываемый документ в файле.
+ using (XmlTextWriter xmltw = new XmlTextWriter(FileName,
+ new UTF8Encoding(false)))
+ {
+ xmltw.WriteStartDocument();
+ document.WriteTo(xmltw);
+ }
+ }
+
+ ///
+ /// Подпись xml файла
+ ///
+ static void SignXmlFile(string FileName,
+ string SignedFileName, AsymmetricAlgorithm Key,
+ X509Certificate Certificate)
+ {
+ // Создаем новый XML документ.
+ XmlDocument doc = new XmlDocument();
+
+ // Пробельные символы участвуют в вычислении подписи и должны быть сохранены для совместимости с другими реализациями.
+ doc.PreserveWhitespace = true;
+
+ // Читаем документ из файла.
+ doc.Load(new XmlTextReader(FileName));
+
+ // Создаем объект SignedXml по XML документу.
+ SignedXml signedXml = new SignedXml(doc);
+
+ // Добавляем ключ в SignedXml документ.
+ signedXml.SigningKey = Key;
+
+ // Создаем ссылку на node для подписи.
+ // При подписи всего документа проставляем "".
+ Reference reference = new Reference();
+ reference.Uri = "";
+
+ // Явно проставляем алгоритм хэширования,
+ // по умолчанию SHA1.
+ reference.DigestMethod =
+ SignedXml.XmlDsigGost3411_2012_256Url;
+
+ // Добавляем transform на подписываемые данные
+ // для удаления вложенной подписи.
+ XmlDsigEnvelopedSignatureTransform env =
+ new XmlDsigEnvelopedSignatureTransform();
+ reference.AddTransform(env);
+
+ // Добавляем СМЭВ трансформ.
+ // начиная с .NET 4.5.1 для проверки подписи, необходимо добавить этот трансформ в довернные:
+ // signedXml.SafeCanonicalizationMethods.Add("urn://smev-gov-ru/xmldsig/transform");
+ XmlDsigSmevTransform smev =
+ new XmlDsigSmevTransform();
+ reference.AddTransform(smev);
+
+ // Добавляем transform для канонизации.
+ XmlDsigC14NTransform c14 = new XmlDsigC14NTransform();
+ reference.AddTransform(c14);
+
+ // Добавляем ссылку на подписываемые данные
+ signedXml.AddReference(reference);
+
+ // Создаем объект KeyInfo.
+ KeyInfo keyInfo = new KeyInfo();
+
+ // Добавляем сертификат в KeyInfo
+ keyInfo.AddClause(new KeyInfoX509Data(Certificate));
+
+ // Добавляем KeyInfo в SignedXml.
+ signedXml.KeyInfo = keyInfo;
+
+ // Вычисляем подпись.
+ signedXml.ComputeSignature();
+
+ // Получаем XML представление подписи и сохраняем его
+ // в отдельном node.
+ XmlElement xmlDigitalSignature = signedXml.GetXml();
+
+ // Добавляем node подписи в XML документ.
+ doc.DocumentElement.AppendChild(doc.ImportNode(
+ xmlDigitalSignature, true));
+
+ // При наличии стартовой XML декларации ее удаляем
+ // (во избежание повторного сохранения)
+ if (doc.FirstChild is XmlDeclaration)
+ {
+ doc.RemoveChild(doc.FirstChild);
+ }
+
+ // Сохраняем подписанный документ в файле.
+ using (XmlTextWriter xmltw = new XmlTextWriter(SignedFileName,
+ new UTF8Encoding(false)))
+ {
+ xmltw.WriteStartDocument();
+ doc.WriteTo(xmltw);
+ }
+ }
+
+ ///
+ /// Проверка xml файла
+ ///
+ ///
+ static void ValidateXmlFIle(string path)
+ {
+ // Создаем новый XML документ в памяти.
+ XmlDocument xmlDocument = new XmlDocument();
+
+ // Сохраняем все пробельные символы, они важны при проверке
+ // подписи.
+ xmlDocument.PreserveWhitespace = true;
+
+ // Загружаем подписанный документ из файла.
+ xmlDocument.Load(path);
+
+ // Ищем все node "Signature" и сохраняем их в объекте XmlNodeList
+ XmlNodeList nodeList = xmlDocument.GetElementsByTagName(
+ "Signature", SignedXml.XmlDsigNamespaceUrl);
+
+ Console.WriteLine("Найдено:{0} подпис(ей).", nodeList.Count);
+
+ // Проверяем все подписи.
+ for (int curSignature = 0; curSignature < nodeList.Count; curSignature++)
+ {
+ // Создаем объект SignedXml для проверки подписи документа.
+ SignedXml signedXml = new SignedXml(xmlDocument);
+
+ // начиная с .NET 4.5.1 для проверки подписи, необходимо добавить СМЭВ transform в довернные:
+
+ signedXml.SafeCanonicalizationMethods.Add("urn://smev-gov-ru/xmldsig/transform");
+
+ // Загружаем узел с подписью.
+ signedXml.LoadXml((XmlElement)nodeList[curSignature]);
+
+ // Проверяем подпись и выводим результат.
+ bool result = signedXml.CheckSignature();
+
+ // Выводим результат проверки подписи в консоль.
+ if (result)
+ {
+ Console.WriteLine("XML подпись[{0}] верна.", curSignature + 1);
+ }
+ else
+ {
+ Console.WriteLine("XML подпись[{0}] не верна.", curSignature + 1);
+ }
+ }
+ }
+ }
+}