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.
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<MyXml>
|
||||
<SomeElement Encrypt="false">
|
||||
Here is public data.
|
||||
</SomeElement>
|
||||
<SomeElement Encrypt="true">
|
||||
Here is private data.
|
||||
</SomeElement>
|
||||
<SomeElement Encrypt="true">
|
||||
Here is private data.
|
||||
</SomeElement>
|
||||
<SomeElement Encrypt="true">
|
||||
Here is private data.
|
||||
</SomeElement>
|
||||
</MyXml>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<MyXml>
|
||||
<SomeElement Id="Id1">
|
||||
Here is some data to sign.
|
||||
</SomeElement>
|
||||
</MyXml>
|
||||
53
third_party/forks/AlexMAS.GostCryptography/Source/GostCryptography.Tests/Data/SmevExample.xml
vendored
Normal file
53
third_party/forks/AlexMAS.GostCryptography/Source/GostCryptography.Tests/Data/SmevExample.xml
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
|
||||
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
|
||||
>
|
||||
<S:Header>
|
||||
<wsse:Security S:actor="http://smev.gosuslugi.ru/actors/smev">
|
||||
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
||||
<ds:KeyInfo>
|
||||
<wsse:SecurityTokenReference>
|
||||
<wsse:Reference URI="#SenderCertificate"/>
|
||||
</wsse:SecurityTokenReference>
|
||||
</ds:KeyInfo>
|
||||
</ds:Signature>
|
||||
<wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"
|
||||
ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"
|
||||
wsu:Id="SenderCertificate"
|
||||
>
|
||||
</wsse:BinarySecurityToken>
|
||||
</wsse:Security>
|
||||
</S:Header>
|
||||
<S:Body wsu:Id="body">
|
||||
<ws:queryINNFL xmlns:ws="http://ws.unisoft/">
|
||||
<smev:Message xmlns:smev="http://smev.gosuslugi.ru/rev110801">
|
||||
<smev:Sender>
|
||||
<smev:Code>MINECONOMSK_SYS_1</smev:Code>
|
||||
<smev:Name>Минэкономразвития СК</smev:Name>
|
||||
</smev:Sender>
|
||||
<smev:Recipient>
|
||||
<smev:Code>13312</smev:Code>
|
||||
<smev:Name>ФНС</smev:Name>
|
||||
</smev:Recipient>
|
||||
<smev:Originator>
|
||||
<smev:Code>MINECONOMSK_SYS_1</smev:Code>
|
||||
<smev:Name>Минэкономразвития СК</smev:Name>
|
||||
</smev:Originator>
|
||||
<smev:TypeCode>2</smev:TypeCode>
|
||||
<smev:Date>2012-03-13T11:10:54.54Z</smev:Date>
|
||||
</smev:Message>
|
||||
<smev:MessageData xmlns:smev="http://smev.gosuslugi.ru/rev110801">
|
||||
<smev:AppData wsu:Id="fns-AppData">
|
||||
<Документ xmlns="http://ws.unisoft/FNSINN/queryINNFL" ВерсФорм="4.01" ИдЗапрос="AB324006-978B-44D4-933D-C5E6DFA8A576">
|
||||
<СвЮЛ ИННЮЛ="7825497650" НаимОрг="Нагрузочное тестирование" ОГРН="1037843048880"/>
|
||||
<СвФЛ ДатаРожд="12.07.1954" МестоРожд="РОССИЯ,,ГОРЬКОВСКАЯ ОБЛ.,АРЗАМАССКИЙ Р-Н,,НИКОЛЬСКОЕ С., ,,,">
|
||||
<ФИО Имя="ПЕТР" Отчество="АЛЕКСЕЕВИЧ" Фамилия="ЧАХЛОВ"/>
|
||||
<УдЛичнФЛ ВыдДок="АРОВД" ДатаДок="16.11.2002" КодВидДок="21" СерНомДок="22 02 919928"/>
|
||||
</СвФЛ>
|
||||
</Документ>
|
||||
</smev:AppData>
|
||||
</smev:MessageData>
|
||||
</ws:queryINNFL>
|
||||
</S:Body>
|
||||
</S:Envelope>
|
||||
@@ -0,0 +1,37 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net40;net452</TargetFrameworks>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Security" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="nunit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0-preview.2" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GostCryptography\GostCryptography.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,103 @@
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_28147_89
|
||||
{
|
||||
/// <summary>
|
||||
/// Шифрование и дешифрование данных с использованием случайного сессионного ключа.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест имитирует обмен данными между условным отправителем, который шифрует заданный поток байт, и условным получателем, который дешифрует
|
||||
/// зашифрованный поток байт. Шифрация осуществляется с использованием случайного симметричного ключа, который в свою очередь шифруется
|
||||
/// с использованием открытого ключа получателя. Соответственно для дешифрации данных сначала расшифровывается случайный симметричный ключ
|
||||
/// с использованием закрытого ключа получателя.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Шифрование и дешифрование данных с использованием случайного сессионного ключа")]
|
||||
public class EncryptDecryptSessionKeyTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_Certificates))]
|
||||
public void ShouldEncryptAndDecrypt(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var privateKey = (GostAsymmetricAlgorithm)certificate.GetPrivateKeyAlgorithm();
|
||||
var publicKey = (GostAsymmetricAlgorithm)certificate.GetPublicKeyAlgorithm();
|
||||
var dataStream = CreateDataStream();
|
||||
|
||||
// When
|
||||
var encryptedDataStream = SendEncryptedDataStream(publicKey, dataStream, out var iv, out var sessionKey);
|
||||
var decryptedDataStream = ReceiveEncryptedDataStream(privateKey, encryptedDataStream, iv, sessionKey);
|
||||
|
||||
// Then
|
||||
Assert.That(dataStream, Is.EqualTo(decryptedDataStream));
|
||||
}
|
||||
|
||||
private static Stream CreateDataStream()
|
||||
{
|
||||
// Некоторый поток байт
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes("Some data to encrypt..."));
|
||||
}
|
||||
|
||||
private static Stream SendEncryptedDataStream(GostAsymmetricAlgorithm publicKey, Stream dataStream, out byte[] iv, out byte[] sessionKey)
|
||||
{
|
||||
var encryptedDataStream = new MemoryStream();
|
||||
|
||||
// Отправитель создает случайный сессионный ключ для шифрации данных
|
||||
using (var senderSessionKey = new Gost_28147_89_SymmetricAlgorithm(publicKey.ProviderType))
|
||||
{
|
||||
// Отправитель передает получателю вектор инициализации
|
||||
iv = senderSessionKey.IV;
|
||||
|
||||
// Отправитель шифрует сессионный ключ и передает его получателю
|
||||
var formatter = publicKey.CreateKeyExchangeFormatter();
|
||||
sessionKey = formatter.CreateKeyExchangeData(senderSessionKey);
|
||||
|
||||
// Отправитель шифрует данные с использованием сессионного ключа
|
||||
using (var encryptor = senderSessionKey.CreateEncryptor())
|
||||
{
|
||||
var cryptoStream = new CryptoStream(encryptedDataStream, encryptor, CryptoStreamMode.Write);
|
||||
dataStream.CopyTo(cryptoStream);
|
||||
cryptoStream.FlushFinalBlock();
|
||||
}
|
||||
}
|
||||
|
||||
encryptedDataStream.Position = 0;
|
||||
|
||||
return encryptedDataStream;
|
||||
}
|
||||
|
||||
private static Stream ReceiveEncryptedDataStream(GostAsymmetricAlgorithm privateKey, Stream encryptedDataStream, byte[] iv, byte[] sessionKey)
|
||||
{
|
||||
var decryptedDataStream = new MemoryStream();
|
||||
|
||||
var deformatter = privateKey.CreateKeyExchangeDeformatter();
|
||||
|
||||
// Получатель принимает от отправителя зашифрованный сессионный ключ и дешифрует его
|
||||
using (var receiverSessionKey = deformatter.DecryptKeyExchangeAlgorithm(sessionKey))
|
||||
{
|
||||
// Получатель принимает от отправителя вектор инициализации
|
||||
receiverSessionKey.IV = iv;
|
||||
|
||||
// Получатель дешифрует данные с использованием сессионного ключа
|
||||
using (var decryptor = receiverSessionKey.CreateDecryptor())
|
||||
{
|
||||
var cryptoStream = new CryptoStream(encryptedDataStream, decryptor, CryptoStreamMode.Read);
|
||||
cryptoStream.CopyTo(decryptedDataStream);
|
||||
}
|
||||
}
|
||||
|
||||
decryptedDataStream.Position = 0;
|
||||
|
||||
return decryptedDataStream;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_28147_89
|
||||
{
|
||||
/// <summary>
|
||||
/// Вычисление имитовставки на базе общего симметричного ключа ГОСТ 28147-89.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест выполняет подпись и проверку подписи потока байт с использованием имитовставки.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Вычисление имитовставки на базе общего симметричного ключа ГОСТ 28147-89")]
|
||||
public class Gost_28147_89_ImitHashAlgorithmTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldComputeImitHash(ProviderType providerType)
|
||||
{
|
||||
// Given
|
||||
var dataStream = CreateDataStream();
|
||||
var sharedKey = new Gost_28147_89_SymmetricAlgorithm(providerType);
|
||||
|
||||
// When
|
||||
var imitDataStream = CreateImitDataStream(sharedKey, dataStream);
|
||||
var isValidImitDataStream = VerifyImitDataStream(sharedKey, imitDataStream);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(isValidImitDataStream);
|
||||
}
|
||||
|
||||
private static Stream CreateDataStream()
|
||||
{
|
||||
// Некоторый поток байт
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes("Some data for imit..."));
|
||||
}
|
||||
|
||||
private static Stream CreateImitDataStream(Gost_28147_89_SymmetricAlgorithmBase sharedKey, Stream dataStream)
|
||||
{
|
||||
// Создание объекта для вычисления имитовставки
|
||||
using (var imitHash = new Gost_28147_89_ImitHashAlgorithm(sharedKey))
|
||||
{
|
||||
// Вычисление имитовставки для потока данных
|
||||
var imitHashValue = imitHash.ComputeHash(dataStream);
|
||||
|
||||
// Запись имитовставки в начало выходного потока данных
|
||||
var imitDataStream = new MemoryStream();
|
||||
imitDataStream.Write(imitHashValue, 0, imitHashValue.Length);
|
||||
|
||||
// Копирование исходного потока данных в выходной поток
|
||||
dataStream.Position = 0;
|
||||
dataStream.CopyTo(imitDataStream);
|
||||
|
||||
imitDataStream.Position = 0;
|
||||
|
||||
return imitDataStream;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool VerifyImitDataStream(Gost_28147_89_SymmetricAlgorithmBase sharedKey, Stream imitDataStream)
|
||||
{
|
||||
// Создание объекта для вычисления имитовставки
|
||||
using (var imitHash = new Gost_28147_89_ImitHashAlgorithm(sharedKey))
|
||||
{
|
||||
// Считывание имитовставки из потока данных
|
||||
var imitHashValue = new byte[imitHash.HashSize / 8];
|
||||
imitDataStream.Read(imitHashValue, 0, imitHashValue.Length);
|
||||
|
||||
// Вычисление реального значения имитовставки для потока данных
|
||||
var expectedImitHashValue = imitHash.ComputeHash(imitDataStream);
|
||||
|
||||
// Сравнение исходной имитовставки с ожидаемой
|
||||
return imitHashValue.SequenceEqual(expectedImitHashValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_28147_89
|
||||
{
|
||||
/// <summary>
|
||||
/// Шифрование и дешифрование данных с использованием общего симметричного ключа ГОСТ 28147-89.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает поток байт, шифрует его с использованием общего симметричного ключа,
|
||||
/// а затем дешифрует зашифрованные данные и проверяет корректность дешифрации.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Шифрование и дешифрование данных с использованием общего симметричного ключа ГОСТ 28147-89")]
|
||||
public class Gost_28147_89_SymmetricAlgorithmTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldEncryptAndDecrypt(ProviderType providerType)
|
||||
{
|
||||
// Given
|
||||
var sharedKey = new Gost_28147_89_SymmetricAlgorithm(providerType);
|
||||
var dataStream = CreateDataStream();
|
||||
|
||||
// When
|
||||
var encryptedDataStream = EncryptDataStream(sharedKey, dataStream);
|
||||
var decryptedDataStream = DecryptDataStream(sharedKey, encryptedDataStream);
|
||||
|
||||
// Then
|
||||
Assert.That(dataStream, Is.EqualTo(decryptedDataStream));
|
||||
}
|
||||
|
||||
private static Stream CreateDataStream()
|
||||
{
|
||||
// Некоторый поток байт
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes("Some data to encrypt..."));
|
||||
}
|
||||
|
||||
private static Stream EncryptDataStream(SymmetricAlgorithm sharedKey, Stream dataStream)
|
||||
{
|
||||
var encryptedDataStream = new MemoryStream();
|
||||
|
||||
using (var encryptor = sharedKey.CreateEncryptor())
|
||||
{
|
||||
var cryptoStream = new CryptoStream(encryptedDataStream, encryptor, CryptoStreamMode.Write);
|
||||
dataStream.CopyTo(cryptoStream);
|
||||
cryptoStream.FlushFinalBlock();
|
||||
}
|
||||
|
||||
encryptedDataStream.Position = 0;
|
||||
|
||||
return encryptedDataStream;
|
||||
}
|
||||
|
||||
private static Stream DecryptDataStream(SymmetricAlgorithm sharedKey, Stream encryptedDataStream)
|
||||
{
|
||||
var decryptedDataStream = new MemoryStream();
|
||||
|
||||
using (var decryptor = sharedKey.CreateDecryptor())
|
||||
{
|
||||
var cryptoStream = new CryptoStream(encryptedDataStream, decryptor, CryptoStreamMode.Read);
|
||||
cryptoStream.CopyTo(decryptedDataStream);
|
||||
decryptedDataStream.Flush();
|
||||
}
|
||||
|
||||
decryptedDataStream.Position = 0;
|
||||
|
||||
return decryptedDataStream;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_28147_89
|
||||
{
|
||||
/// <summary>
|
||||
/// Шифрование и дешифрование данных с использованием случайного сессионного ключа ГОСТ Р 34.12-2015 Кузнечик.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест имитирует обмен данными между условным отправителем, который шифрует заданный поток байт, и условным получателем, который дешифрует
|
||||
/// зашифрованный поток байт. Шифрация осуществляется с использованием случайного симметричного ключа, который в свою очередь шифруется
|
||||
/// с использованием открытого ключа получателя. Соответственно для дешифрации данных сначала расшифровывается случайный симметричный ключ
|
||||
/// с использованием закрытого ключа получателя.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Шифрование и дешифрование данных с использованием случайного сессионного ключа ГОСТ Р 34.12-2015 Кузнечик")]
|
||||
public class KuznyechikEncryptDecryptSessionKeyTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_Certificates))]
|
||||
public void ShouldEncryptAndDecrypt(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var privateKey = (GostAsymmetricAlgorithm)certificate.GetPrivateKeyAlgorithm();
|
||||
var publicKey = (GostAsymmetricAlgorithm)certificate.GetPublicKeyAlgorithm();
|
||||
var dataStream = CreateDataStream();
|
||||
|
||||
// When
|
||||
var encryptedDataStream = SendEncryptedDataStream(publicKey, dataStream, out var iv, out var sessionKey);
|
||||
var decryptedDataStream = ReceiveEncryptedDataStream(privateKey, encryptedDataStream, iv, sessionKey);
|
||||
|
||||
// Then
|
||||
Assert.That(dataStream, Is.EqualTo(decryptedDataStream));
|
||||
}
|
||||
|
||||
private static Stream CreateDataStream()
|
||||
{
|
||||
// Некоторый поток байт
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes("Some data to encrypt..."));
|
||||
}
|
||||
|
||||
private static Stream SendEncryptedDataStream(GostAsymmetricAlgorithm publicKey, Stream dataStream, out byte[] iv, out byte[] sessionKey)
|
||||
{
|
||||
var encryptedDataStream = new MemoryStream();
|
||||
|
||||
// Отправитель создает случайный сессионный ключ для шифрации данных
|
||||
using (var senderSessionKey = new Gost_3412_K_SymmetricAlgorithm(publicKey.ProviderType))
|
||||
{
|
||||
// Отправитель передает получателю вектор инициализации
|
||||
iv = senderSessionKey.IV;
|
||||
|
||||
// Отправитель шифрует сессионный ключ и передает его получателю
|
||||
var formatter = publicKey.CreateKeyExchangeFormatter();
|
||||
sessionKey = formatter.CreateKeyExchangeData(senderSessionKey);
|
||||
|
||||
// Отправитель шифрует данные с использованием сессионного ключа
|
||||
using (var encryptor = senderSessionKey.CreateEncryptor())
|
||||
{
|
||||
var cryptoStream = new CryptoStream(encryptedDataStream, encryptor, CryptoStreamMode.Write);
|
||||
dataStream.CopyTo(cryptoStream);
|
||||
cryptoStream.FlushFinalBlock();
|
||||
}
|
||||
}
|
||||
|
||||
encryptedDataStream.Position = 0;
|
||||
|
||||
return encryptedDataStream;
|
||||
}
|
||||
|
||||
private static Stream ReceiveEncryptedDataStream(GostAsymmetricAlgorithm privateKey, Stream encryptedDataStream, byte[] iv, byte[] sessionKey)
|
||||
{
|
||||
var decryptedDataStream = new MemoryStream();
|
||||
|
||||
var deformatter = privateKey.CreateKeyExchangeDeformatter();
|
||||
|
||||
// Получатель принимает от отправителя зашифрованный сессионный ключ и дешифрует его
|
||||
using (var receiverSessionKey = deformatter.DecryptKeyExchangeAlgorithm(sessionKey))
|
||||
{
|
||||
// Получатель принимает от отправителя вектор инициализации
|
||||
receiverSessionKey.IV = iv;
|
||||
|
||||
// Получатель дешифрует данные с использованием сессионного ключа
|
||||
using (var decryptor = receiverSessionKey.CreateDecryptor())
|
||||
{
|
||||
var cryptoStream = new CryptoStream(encryptedDataStream, decryptor, CryptoStreamMode.Read);
|
||||
cryptoStream.CopyTo(decryptedDataStream);
|
||||
}
|
||||
}
|
||||
|
||||
decryptedDataStream.Position = 0;
|
||||
|
||||
return decryptedDataStream;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_28147_89
|
||||
{
|
||||
/// <summary>
|
||||
/// Вычисление имитовставки на базе общего симметричного ключа ГОСТ Р 34.12-2015 Кузнечик.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест выполняет подпись и проверку подписи потока байт с использованием имитовставки.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Вычисление имитовставки на базе общего симметричного ключа ГОСТ Р 34.12-2015 Кузнечик")]
|
||||
public class KuznyechikImitHashAlgorithmTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldComputeImitHash(ProviderType providerType)
|
||||
{
|
||||
// Given
|
||||
var dataStream = CreateDataStream();
|
||||
var sharedKey = new Gost_3412_K_SymmetricAlgorithm(providerType);
|
||||
|
||||
// When
|
||||
var imitDataStream = CreateImitDataStream(sharedKey, dataStream);
|
||||
var isValidImitDataStream = VerifyImitDataStream(sharedKey, imitDataStream);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(isValidImitDataStream);
|
||||
}
|
||||
|
||||
private static Stream CreateDataStream()
|
||||
{
|
||||
// Некоторый поток байт
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes("Some data for imit..."));
|
||||
}
|
||||
|
||||
private static Stream CreateImitDataStream(Gost_3412_K_SymmetricAlgorithm sharedKey, Stream dataStream)
|
||||
{
|
||||
// Создание объекта для вычисления имитовставки
|
||||
using (var imitHash = new Gost_3412_K_ImitHashAlgorithm(sharedKey))
|
||||
{
|
||||
// Вычисление имитовставки для потока данных
|
||||
var imitHashValue = imitHash.ComputeHash(dataStream);
|
||||
|
||||
// Запись имитовставки в начало выходного потока данных
|
||||
var imitDataStream = new MemoryStream();
|
||||
imitDataStream.Write(imitHashValue, 0, imitHashValue.Length);
|
||||
|
||||
// Копирование исходного потока данных в выходной поток
|
||||
dataStream.Position = 0;
|
||||
dataStream.CopyTo(imitDataStream);
|
||||
|
||||
imitDataStream.Position = 0;
|
||||
|
||||
return imitDataStream;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool VerifyImitDataStream(Gost_3412_K_SymmetricAlgorithm sharedKey, Stream imitDataStream)
|
||||
{
|
||||
// Создание объекта для вычисления имитовставки
|
||||
using (var imitHash = new Gost_3412_K_ImitHashAlgorithm(sharedKey))
|
||||
{
|
||||
// Считывание имитовставки из потока данных
|
||||
var imitHashValue = new byte[imitHash.HashSize / 8];
|
||||
imitDataStream.Read(imitHashValue, 0, imitHashValue.Length);
|
||||
|
||||
// Вычисление реального значения имитовставки для потока данных
|
||||
var expectedImitHashValue = imitHash.ComputeHash(imitDataStream);
|
||||
|
||||
// Сравнение исходной имитовставки с ожидаемой
|
||||
return imitHashValue.SequenceEqual(expectedImitHashValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_28147_89
|
||||
{
|
||||
/// <summary>
|
||||
/// Шифрование и дешифрование данных с использованием общего симметричного ключа ГОСТ Р 34.12-2015 Кузнечик.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает поток байт, шифрует его с использованием общего симметричного ключа,
|
||||
/// а затем дешифрует зашифрованные данные и проверяет корректность дешифрации.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Шифрование и дешифрование данных с использованием общего симметричного ключа ГОСТ Р 34.12-2015 Кузнечик")]
|
||||
public class KuznyechikSymmetricAlgorithmTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldEncryptAndDecrypt(ProviderType providerType)
|
||||
{
|
||||
// Given
|
||||
var sharedKey = new Gost_3412_K_SymmetricAlgorithm(providerType);
|
||||
var dataStream = CreateDataStream();
|
||||
|
||||
// When
|
||||
var encryptedDataStream = EncryptDataStream(sharedKey, dataStream);
|
||||
var decryptedDataStream = DecryptDataStream(sharedKey, encryptedDataStream);
|
||||
|
||||
// Then
|
||||
Assert.That(dataStream, Is.EqualTo(decryptedDataStream));
|
||||
}
|
||||
|
||||
private static Stream CreateDataStream()
|
||||
{
|
||||
// Некоторый поток байт
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes("Some data to encrypt..."));
|
||||
}
|
||||
|
||||
private static Stream EncryptDataStream(SymmetricAlgorithm sharedKey, Stream dataStream)
|
||||
{
|
||||
var encryptedDataStream = new MemoryStream();
|
||||
|
||||
using (var encryptor = sharedKey.CreateEncryptor())
|
||||
{
|
||||
var cryptoStream = new CryptoStream(encryptedDataStream, encryptor, CryptoStreamMode.Write);
|
||||
dataStream.CopyTo(cryptoStream);
|
||||
cryptoStream.FlushFinalBlock();
|
||||
}
|
||||
|
||||
encryptedDataStream.Position = 0;
|
||||
|
||||
return encryptedDataStream;
|
||||
}
|
||||
|
||||
private static Stream DecryptDataStream(SymmetricAlgorithm sharedKey, Stream encryptedDataStream)
|
||||
{
|
||||
var decryptedDataStream = new MemoryStream();
|
||||
|
||||
using (var decryptor = sharedKey.CreateDecryptor())
|
||||
{
|
||||
var cryptoStream = new CryptoStream(encryptedDataStream, decryptor, CryptoStreamMode.Read);
|
||||
cryptoStream.CopyTo(decryptedDataStream);
|
||||
decryptedDataStream.Flush();
|
||||
}
|
||||
|
||||
decryptedDataStream.Position = 0;
|
||||
|
||||
return decryptedDataStream;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_28147_89
|
||||
{
|
||||
/// <summary>
|
||||
/// Шифрование и дешифрование данных с использованием случайного сессионного ключа ГОСТ Р 34.12-2015 Магма.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест имитирует обмен данными между условным отправителем, который шифрует заданный поток байт, и условным получателем, который дешифрует
|
||||
/// зашифрованный поток байт. Шифрация осуществляется с использованием случайного симметричного ключа, который в свою очередь шифруется
|
||||
/// с использованием открытого ключа получателя. Соответственно для дешифрации данных сначала расшифровывается случайный симметричный ключ
|
||||
/// с использованием закрытого ключа получателя.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Шифрование и дешифрование данных с использованием случайного сессионного ключа ГОСТ Р 34.12-2015 Магма")]
|
||||
public class MagmaEncryptDecryptSessionKeyTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_Certificates))]
|
||||
public void ShouldEncryptAndDecrypt(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var privateKey = (GostAsymmetricAlgorithm)certificate.GetPrivateKeyAlgorithm();
|
||||
var publicKey = (GostAsymmetricAlgorithm)certificate.GetPublicKeyAlgorithm();
|
||||
var dataStream = CreateDataStream();
|
||||
|
||||
// When
|
||||
var encryptedDataStream = SendEncryptedDataStream(publicKey, dataStream, out var iv, out var sessionKey);
|
||||
var decryptedDataStream = ReceiveEncryptedDataStream(privateKey, encryptedDataStream, iv, sessionKey);
|
||||
|
||||
// Then
|
||||
Assert.That(dataStream, Is.EqualTo(decryptedDataStream));
|
||||
}
|
||||
|
||||
private static Stream CreateDataStream()
|
||||
{
|
||||
// Некоторый поток байт
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes("Some data to encrypt..."));
|
||||
}
|
||||
|
||||
private static Stream SendEncryptedDataStream(GostAsymmetricAlgorithm publicKey, Stream dataStream, out byte[] iv, out byte[] sessionKey)
|
||||
{
|
||||
var encryptedDataStream = new MemoryStream();
|
||||
|
||||
// Отправитель создает случайный сессионный ключ для шифрации данных
|
||||
using (var senderSessionKey = new Gost_3412_M_SymmetricAlgorithm(publicKey.ProviderType))
|
||||
{
|
||||
// Отправитель передает получателю вектор инициализации
|
||||
iv = senderSessionKey.IV;
|
||||
|
||||
// Отправитель шифрует сессионный ключ и передает его получателю
|
||||
var formatter = publicKey.CreateKeyExchangeFormatter();
|
||||
sessionKey = formatter.CreateKeyExchangeData(senderSessionKey);
|
||||
|
||||
// Отправитель шифрует данные с использованием сессионного ключа
|
||||
using (var encryptor = senderSessionKey.CreateEncryptor())
|
||||
{
|
||||
var cryptoStream = new CryptoStream(encryptedDataStream, encryptor, CryptoStreamMode.Write);
|
||||
dataStream.CopyTo(cryptoStream);
|
||||
cryptoStream.FlushFinalBlock();
|
||||
}
|
||||
}
|
||||
|
||||
encryptedDataStream.Position = 0;
|
||||
|
||||
return encryptedDataStream;
|
||||
}
|
||||
|
||||
private static Stream ReceiveEncryptedDataStream(GostAsymmetricAlgorithm privateKey, Stream encryptedDataStream, byte[] iv, byte[] sessionKey)
|
||||
{
|
||||
var decryptedDataStream = new MemoryStream();
|
||||
|
||||
var deformatter = privateKey.CreateKeyExchangeDeformatter();
|
||||
|
||||
// Получатель принимает от отправителя зашифрованный сессионный ключ и дешифрует его
|
||||
using (var receiverSessionKey = deformatter.DecryptKeyExchangeAlgorithm(sessionKey))
|
||||
{
|
||||
// Получатель принимает от отправителя вектор инициализации
|
||||
receiverSessionKey.IV = iv;
|
||||
|
||||
// Получатель дешифрует данные с использованием сессионного ключа
|
||||
using (var decryptor = receiverSessionKey.CreateDecryptor())
|
||||
{
|
||||
var cryptoStream = new CryptoStream(encryptedDataStream, decryptor, CryptoStreamMode.Read);
|
||||
cryptoStream.CopyTo(decryptedDataStream);
|
||||
}
|
||||
}
|
||||
|
||||
decryptedDataStream.Position = 0;
|
||||
|
||||
return decryptedDataStream;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_28147_89
|
||||
{
|
||||
/// <summary>
|
||||
/// Вычисление имитовставки на базе общего симметричного ключа ГОСТ Р 34.12-2015 Магма.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест выполняет подпись и проверку подписи потока байт с использованием имитовставки.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Вычисление имитовставки на базе общего симметричного ключа ГОСТ Р 34.12-2015 Магма")]
|
||||
public class MagmaImitHashAlgorithmTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldComputeImitHash(ProviderType providerType)
|
||||
{
|
||||
// Given
|
||||
var dataStream = CreateDataStream();
|
||||
var sharedKey = new Gost_3412_M_SymmetricAlgorithm(providerType);
|
||||
|
||||
// When
|
||||
var imitDataStream = CreateImitDataStream(sharedKey, dataStream);
|
||||
var isValidImitDataStream = VerifyImitDataStream(sharedKey, imitDataStream);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(isValidImitDataStream);
|
||||
}
|
||||
|
||||
private static Stream CreateDataStream()
|
||||
{
|
||||
// Некоторый поток байт
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes("Some data for imit..."));
|
||||
}
|
||||
|
||||
private static Stream CreateImitDataStream(Gost_3412_M_SymmetricAlgorithm sharedKey, Stream dataStream)
|
||||
{
|
||||
// Создание объекта для вычисления имитовставки
|
||||
using (var imitHash = new Gost_3412_M_ImitHashAlgorithm(sharedKey))
|
||||
{
|
||||
// Вычисление имитовставки для потока данных
|
||||
var imitHashValue = imitHash.ComputeHash(dataStream);
|
||||
|
||||
// Запись имитовставки в начало выходного потока данных
|
||||
var imitDataStream = new MemoryStream();
|
||||
imitDataStream.Write(imitHashValue, 0, imitHashValue.Length);
|
||||
|
||||
// Копирование исходного потока данных в выходной поток
|
||||
dataStream.Position = 0;
|
||||
dataStream.CopyTo(imitDataStream);
|
||||
|
||||
imitDataStream.Position = 0;
|
||||
|
||||
return imitDataStream;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool VerifyImitDataStream(Gost_3412_M_SymmetricAlgorithm sharedKey, Stream imitDataStream)
|
||||
{
|
||||
// Создание объекта для вычисления имитовставки
|
||||
using (var imitHash = new Gost_3412_M_ImitHashAlgorithm(sharedKey))
|
||||
{
|
||||
// Считывание имитовставки из потока данных
|
||||
var imitHashValue = new byte[imitHash.HashSize / 8];
|
||||
imitDataStream.Read(imitHashValue, 0, imitHashValue.Length);
|
||||
|
||||
// Вычисление реального значения имитовставки для потока данных
|
||||
var expectedImitHashValue = imitHash.ComputeHash(imitDataStream);
|
||||
|
||||
// Сравнение исходной имитовставки с ожидаемой
|
||||
return imitHashValue.SequenceEqual(expectedImitHashValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_28147_89
|
||||
{
|
||||
/// <summary>
|
||||
/// Шифрование и дешифрование данных с использованием общего симметричного ключа ГОСТ Р 34.12-2015 Магма.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает поток байт, шифрует его с использованием общего симметричного ключа,
|
||||
/// а затем дешифрует зашифрованные данные и проверяет корректность дешифрации.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Шифрование и дешифрование данных с использованием общего симметричного ключа ГОСТ Р 34.12-2015 Магма")]
|
||||
public class MagmaSymmetricAlgorithmTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldEncryptAndDecrypt(ProviderType providerType)
|
||||
{
|
||||
// Given
|
||||
var sharedKey = new Gost_3412_M_SymmetricAlgorithm(providerType);
|
||||
var dataStream = CreateDataStream();
|
||||
|
||||
// When
|
||||
var encryptedDataStream = EncryptDataStream(sharedKey, dataStream);
|
||||
var decryptedDataStream = DecryptDataStream(sharedKey, encryptedDataStream);
|
||||
|
||||
// Then
|
||||
Assert.That(dataStream, Is.EqualTo(decryptedDataStream));
|
||||
}
|
||||
|
||||
private static Stream CreateDataStream()
|
||||
{
|
||||
// Некоторый поток байт
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes("Some data to encrypt..."));
|
||||
}
|
||||
|
||||
private static Stream EncryptDataStream(SymmetricAlgorithm sharedKey, Stream dataStream)
|
||||
{
|
||||
var encryptedDataStream = new MemoryStream();
|
||||
|
||||
using (var encryptor = sharedKey.CreateEncryptor())
|
||||
{
|
||||
var cryptoStream = new CryptoStream(encryptedDataStream, encryptor, CryptoStreamMode.Write);
|
||||
dataStream.CopyTo(cryptoStream);
|
||||
cryptoStream.FlushFinalBlock();
|
||||
}
|
||||
|
||||
encryptedDataStream.Position = 0;
|
||||
|
||||
return encryptedDataStream;
|
||||
}
|
||||
|
||||
private static Stream DecryptDataStream(SymmetricAlgorithm sharedKey, Stream encryptedDataStream)
|
||||
{
|
||||
var decryptedDataStream = new MemoryStream();
|
||||
|
||||
using (var decryptor = sharedKey.CreateDecryptor())
|
||||
{
|
||||
var cryptoStream = new CryptoStream(encryptedDataStream, decryptor, CryptoStreamMode.Read);
|
||||
cryptoStream.CopyTo(decryptedDataStream);
|
||||
decryptedDataStream.Flush();
|
||||
}
|
||||
|
||||
decryptedDataStream.Position = 0;
|
||||
|
||||
return decryptedDataStream;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.Security;
|
||||
|
||||
using GostCryptography.Gost_R3410;
|
||||
|
||||
using NUnit.Framework;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
using GostCryptography.Base;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_R3410
|
||||
{
|
||||
[TestFixture(Description = "Проверка возможности установки пароля для контейнера ключей")]
|
||||
public class SetContainerPasswordTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_2001_Certificates))]
|
||||
public void ShouldSetContainerPassword_R3410_2001(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var data = GetSomeData();
|
||||
var certificate = testCase.Certificate;
|
||||
var securePassword = CreateSecureString(TestConfig.ContainerPassword);
|
||||
|
||||
// When
|
||||
|
||||
var privateKeyInfo = certificate.GetPrivateKeyInfo();
|
||||
var privateKey = new Gost_R3410_2001_AsymmetricAlgorithm(privateKeyInfo);
|
||||
privateKey.SetContainerPassword(securePassword);
|
||||
|
||||
var signature = CreateSignature(privateKey, data);
|
||||
var isValidSignature = VerifySignature(privateKey, data, signature);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(isValidSignature);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_2012_256_Certificates))]
|
||||
public void ShouldSetContainerPassword_R3410_2012_256(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var data = GetSomeData();
|
||||
var certificate = testCase.Certificate;
|
||||
var securePassword = CreateSecureString(TestConfig.ContainerPassword);
|
||||
|
||||
// When
|
||||
|
||||
var privateKeyInfo = certificate.GetPrivateKeyInfo();
|
||||
var privateKey = new Gost_R3410_2012_256_AsymmetricAlgorithm(privateKeyInfo);
|
||||
privateKey.SetContainerPassword(securePassword);
|
||||
|
||||
var signature = CreateSignature(privateKey, data);
|
||||
var isValidSignature = VerifySignature(privateKey, data, signature);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(isValidSignature);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_2012_512_Certificates))]
|
||||
public void ShouldSetContainerPassword_R3410_2012_512(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var data = GetSomeData();
|
||||
var certificate = testCase.Certificate;
|
||||
var securePassword = CreateSecureString(TestConfig.ContainerPassword);
|
||||
|
||||
// When
|
||||
|
||||
var privateKeyInfo = certificate.GetPrivateKeyInfo();
|
||||
var privateKey = new Gost_R3410_2012_512_AsymmetricAlgorithm(privateKeyInfo);
|
||||
privateKey.SetContainerPassword(securePassword);
|
||||
|
||||
var signature = CreateSignature(privateKey, data);
|
||||
var isValidSignature = VerifySignature(privateKey, data, signature);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(isValidSignature);
|
||||
}
|
||||
|
||||
|
||||
private static byte[] CreateSignature(GostAsymmetricAlgorithm privateKey, byte[] data)
|
||||
{
|
||||
byte[] hash;
|
||||
|
||||
using (var hashAlg = privateKey.CreateHashAlgorithm())
|
||||
{
|
||||
hash = hashAlg.ComputeHash(data);
|
||||
}
|
||||
|
||||
return privateKey.CreateSignature(hash);
|
||||
}
|
||||
|
||||
private static bool VerifySignature(GostAsymmetricAlgorithm publicKey, byte[] data, byte[] signature)
|
||||
{
|
||||
byte[] hash;
|
||||
|
||||
using (var hashAlg = publicKey.CreateHashAlgorithm())
|
||||
{
|
||||
hash = hashAlg.ComputeHash(data);
|
||||
}
|
||||
|
||||
return publicKey.VerifySignature(hash, signature);
|
||||
}
|
||||
|
||||
private static SecureString CreateSecureString(string value)
|
||||
{
|
||||
var result = new SecureString();
|
||||
|
||||
foreach (var c in value)
|
||||
{
|
||||
result.AppendChar(c);
|
||||
}
|
||||
|
||||
result.MakeReadOnly();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static byte[] GetSomeData()
|
||||
{
|
||||
var random = new Random();
|
||||
var data = new byte[1024];
|
||||
random.NextBytes(data);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
using GostCryptography.Gost_R3411;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_R3411
|
||||
{
|
||||
/// <summary>
|
||||
/// Вычисление HMAC на базе алгоритма хэширования ГОСТ Р 34.11-2012/256 и общего симметричного ключа ГОСТ 28147-89.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест выполняет подпись и проверку подписи потока байт с использованием HMAC.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Вычисление HMAC на базе алгоритма хэширования ГОСТ Р 34.11-2012/256 и общего симметричного ключа ГОСТ 28147-89")]
|
||||
public class Gost_R3411_2012_256_HMACTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldComputeHMAC(ProviderType providerType)
|
||||
{
|
||||
// Given
|
||||
var dataStream = CreateDataStream();
|
||||
var sharedKey = new Gost_28147_89_SymmetricAlgorithm(providerType);
|
||||
|
||||
// When
|
||||
var hmacDataStream = CreateHmacDataStream(sharedKey, dataStream);
|
||||
var isValidHmacDataStream = VerifyHmacDataStream(sharedKey, hmacDataStream);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(isValidHmacDataStream);
|
||||
}
|
||||
|
||||
private static Stream CreateDataStream()
|
||||
{
|
||||
// Некоторый поток байт
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes("Some data to HMAC..."));
|
||||
}
|
||||
|
||||
private static Stream CreateHmacDataStream(GostSymmetricAlgorithm sharedKey, Stream dataStream)
|
||||
{
|
||||
// Создание объекта для вычисления HMAC
|
||||
using (var hmac = new Gost_R3411_2012_256_HMAC(sharedKey))
|
||||
{
|
||||
// Вычисление HMAC для потока данных
|
||||
var hmacValue = hmac.ComputeHash(dataStream);
|
||||
|
||||
// Запись HMAC в начало выходного потока данных
|
||||
var hmacDataStream = new MemoryStream();
|
||||
hmacDataStream.Write(hmacValue, 0, hmacValue.Length);
|
||||
|
||||
// Копирование исходного потока данных в выходной поток
|
||||
dataStream.Position = 0;
|
||||
dataStream.CopyTo(hmacDataStream);
|
||||
|
||||
hmacDataStream.Position = 0;
|
||||
|
||||
return hmacDataStream;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool VerifyHmacDataStream(GostSymmetricAlgorithm sharedKey, Stream hmacDataStream)
|
||||
{
|
||||
// Создание объекта для вычисления HMAC
|
||||
using (var hmac = new Gost_R3411_2012_256_HMAC(sharedKey))
|
||||
{
|
||||
// Считывание HMAC из потока данных
|
||||
var hmacValue = new byte[hmac.HashSize / 8];
|
||||
hmacDataStream.Read(hmacValue, 0, hmacValue.Length);
|
||||
|
||||
// Вычисление реального значения HMAC для потока данных
|
||||
var expectedHmacValue = hmac.ComputeHash(hmacDataStream);
|
||||
|
||||
// Сравнение исходного HMAC с ожидаемым
|
||||
return hmacValue.SequenceEqual(expectedHmacValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_R3411;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_R3411
|
||||
{
|
||||
/// <summary>
|
||||
/// Вычисление хэша в соответствии с ГОСТ Р 34.11-2012/256.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает поток байт, вычисляет хэш в соответствии с ГОСТ Р 34.11-2012/256 и проверяет его корректность.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Вычисление хэша в соответствии с ГОСТ Р 34.11-2012/256")]
|
||||
public class Gost_R3411_2012_256_HashAlgorithmTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldComputeHash(ProviderType providerType)
|
||||
{
|
||||
// Given
|
||||
var dataStream = CreateDataStream();
|
||||
|
||||
// When
|
||||
|
||||
byte[] hashValue;
|
||||
|
||||
using (var hash = new Gost_R3411_2012_256_HashAlgorithm(providerType))
|
||||
{
|
||||
hashValue = hash.ComputeHash(dataStream);
|
||||
}
|
||||
|
||||
// Then
|
||||
Assert.IsNotNull(hashValue);
|
||||
Assert.AreEqual(256, 8 * hashValue.Length);
|
||||
}
|
||||
|
||||
private static Stream CreateDataStream()
|
||||
{
|
||||
// Некоторый поток байт
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes("Some data to hash..."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
using GostCryptography.Gost_R3411;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_R3411
|
||||
{
|
||||
/// <summary>
|
||||
/// Использование PRF на базе алгоритма хэширования ГОСТ Р 34.11-2012/256.
|
||||
/// </summary>
|
||||
[TestFixture(Description = "Использование PRF на базе алгоритма хэширования ГОСТ Р 34.11-2012/256")]
|
||||
public class Gost_R3411_2012_256_PRFTest
|
||||
{
|
||||
private static readonly byte[] Label = { 1, 2, 3, 4, 5 };
|
||||
private static readonly byte[] Seed = { 6, 7, 8, 9, 0 };
|
||||
private static readonly byte[] TestData = Encoding.UTF8.GetBytes("Some data to encrypt...");
|
||||
|
||||
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldDeriveBytes(ProviderType providerType)
|
||||
{
|
||||
// Given
|
||||
var initKey = new Gost_28147_89_SymmetricAlgorithm(providerType);
|
||||
|
||||
// When
|
||||
|
||||
byte[] randomBytes1;
|
||||
byte[] randomBytes2;
|
||||
byte[] randomBytes3;
|
||||
|
||||
using (var prf = new Gost_R3411_2012_256_PRF(initKey, Label, Seed))
|
||||
{
|
||||
randomBytes1 = prf.DeriveBytes();
|
||||
randomBytes2 = prf.DeriveBytes();
|
||||
randomBytes3 = prf.DeriveBytes();
|
||||
}
|
||||
|
||||
// Then
|
||||
Assert.IsNotNull(randomBytes1);
|
||||
Assert.IsNotNull(randomBytes2);
|
||||
Assert.IsNotNull(randomBytes3);
|
||||
Assert.AreEqual(256, 8 * randomBytes1.Length);
|
||||
Assert.AreEqual(256, 8 * randomBytes2.Length);
|
||||
Assert.AreEqual(256, 8 * randomBytes3.Length);
|
||||
CollectionAssert.AreNotEqual(randomBytes1, randomBytes2);
|
||||
CollectionAssert.AreNotEqual(randomBytes1, randomBytes3);
|
||||
CollectionAssert.AreNotEqual(randomBytes2, randomBytes3);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldDeriveKey(ProviderType providerType)
|
||||
{
|
||||
// TODO: VipNet does not support this feature - https://infotecs.ru/forum/topic/10142-oshibka-pri-sozdanii-klyucha-shifrovaniya-na-osnove-dannyih-polzovatelya-cryptderivekey/
|
||||
if (providerType.IsVipNet())
|
||||
{
|
||||
Assert.Ignore("VipNet does not support this feature");
|
||||
}
|
||||
|
||||
// Given
|
||||
var initKey = new Gost_28147_89_SymmetricAlgorithm(providerType);
|
||||
|
||||
// When
|
||||
|
||||
GostSymmetricAlgorithm randomKey1;
|
||||
GostSymmetricAlgorithm randomKey2;
|
||||
GostSymmetricAlgorithm randomKey3;
|
||||
|
||||
using (var prf = new Gost_R3411_2012_256_PRF(initKey, Label, Seed))
|
||||
{
|
||||
randomKey1 = prf.DeriveKey();
|
||||
randomKey2 = prf.DeriveKey();
|
||||
randomKey3 = prf.DeriveKey();
|
||||
}
|
||||
|
||||
// Then
|
||||
Assert.IsNotNull(randomKey1);
|
||||
Assert.IsNotNull(randomKey2);
|
||||
Assert.IsNotNull(randomKey3);
|
||||
AssertKeyIsValid(randomKey1);
|
||||
AssertKeyIsValid(randomKey2);
|
||||
AssertKeyIsValid(randomKey3);
|
||||
AssertKeysAreNotEqual(randomKey1, randomKey2);
|
||||
AssertKeysAreNotEqual(randomKey1, randomKey3);
|
||||
AssertKeysAreNotEqual(randomKey2, randomKey3);
|
||||
}
|
||||
|
||||
|
||||
public static void AssertKeyIsValid(GostSymmetricAlgorithm key)
|
||||
{
|
||||
var encryptedData = EncryptData(key, TestData);
|
||||
var decryptedData = DecryptData(key, encryptedData);
|
||||
CollectionAssert.AreEqual(TestData, decryptedData);
|
||||
}
|
||||
|
||||
public static void AssertKeysAreNotEqual(GostSymmetricAlgorithm key1, GostSymmetricAlgorithm key2)
|
||||
{
|
||||
var encryptedData1 = EncryptData(key1, TestData);
|
||||
var encryptedData2 = EncryptData(key2, TestData);
|
||||
CollectionAssert.AreNotEqual(encryptedData1, encryptedData2);
|
||||
}
|
||||
|
||||
|
||||
public static byte[] EncryptData(GostSymmetricAlgorithm key, byte[] data)
|
||||
{
|
||||
var transform = key.CreateEncryptor();
|
||||
return transform.TransformFinalBlock(data, 0, data.Length);
|
||||
}
|
||||
|
||||
public static byte[] DecryptData(GostSymmetricAlgorithm key, byte[] data)
|
||||
{
|
||||
var transform = key.CreateDecryptor();
|
||||
return transform.TransformFinalBlock(data, 0, data.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
using GostCryptography.Gost_R3411;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_R3411
|
||||
{
|
||||
/// <summary>
|
||||
/// Вычисление HMAC на базе алгоритма хэширования ГОСТ Р 34.11-2012/512 и общего симметричного ключа ГОСТ 28147-89.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест выполняет подпись и проверку подписи потока байт с использованием HMAC.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Вычисление HMAC на базе алгоритма хэширования ГОСТ Р 34.11-2012/512 и общего симметричного ключа ГОСТ 28147-89")]
|
||||
public class Gost_R3411_2012_512_HMACTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldComputeHMAC(ProviderType providerType)
|
||||
{
|
||||
// Given
|
||||
var dataStream = CreateDataStream();
|
||||
var sharedKey = new Gost_28147_89_SymmetricAlgorithm(providerType);
|
||||
|
||||
// When
|
||||
var hmacDataStream = CreateHmacDataStream(sharedKey, dataStream);
|
||||
var isValidHmacDataStream = VerifyHmacDataStream(sharedKey, hmacDataStream);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(isValidHmacDataStream);
|
||||
}
|
||||
|
||||
private static Stream CreateDataStream()
|
||||
{
|
||||
// Некоторый поток байт
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes("Some data to HMAC..."));
|
||||
}
|
||||
|
||||
private static Stream CreateHmacDataStream(GostSymmetricAlgorithm sharedKey, Stream dataStream)
|
||||
{
|
||||
// Создание объекта для вычисления HMAC
|
||||
using (var hmac = new Gost_R3411_2012_512_HMAC(sharedKey))
|
||||
{
|
||||
// Вычисление HMAC для потока данных
|
||||
var hmacValue = hmac.ComputeHash(dataStream);
|
||||
|
||||
// Запись HMAC в начало выходного потока данных
|
||||
var hmacDataStream = new MemoryStream();
|
||||
hmacDataStream.Write(hmacValue, 0, hmacValue.Length);
|
||||
|
||||
// Копирование исходного потока данных в выходной поток
|
||||
dataStream.Position = 0;
|
||||
dataStream.CopyTo(hmacDataStream);
|
||||
|
||||
hmacDataStream.Position = 0;
|
||||
|
||||
return hmacDataStream;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool VerifyHmacDataStream(GostSymmetricAlgorithm sharedKey, Stream hmacDataStream)
|
||||
{
|
||||
// Создание объекта для вычисления HMAC
|
||||
using (var hmac = new Gost_R3411_2012_512_HMAC(sharedKey))
|
||||
{
|
||||
// Считывание HMAC из потока данных
|
||||
var hmacValue = new byte[hmac.HashSize / 8];
|
||||
hmacDataStream.Read(hmacValue, 0, hmacValue.Length);
|
||||
|
||||
// Вычисление реального значения HMAC для потока данных
|
||||
var expectedHmacValue = hmac.ComputeHash(hmacDataStream);
|
||||
|
||||
// Сравнение исходного HMAC с ожидаемым
|
||||
return hmacValue.SequenceEqual(expectedHmacValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_R3411;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_R3411
|
||||
{
|
||||
/// <summary>
|
||||
/// Вычисление хэша в соответствии с ГОСТ Р 34.11-2012/512.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает поток байт, вычисляет хэш в соответствии с ГОСТ Р 34.11-2012/512 и проверяет его корректность.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Вычисление хэша в соответствии с ГОСТ Р 34.11-2012/512")]
|
||||
public class Gost_R3411_2012_512_HashAlgorithmTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldComputeHash(ProviderType providerType)
|
||||
{
|
||||
// Given
|
||||
var dataStream = CreateDataStream();
|
||||
|
||||
// When
|
||||
|
||||
byte[] hashValue;
|
||||
|
||||
using (var hash = new Gost_R3411_2012_512_HashAlgorithm(providerType))
|
||||
{
|
||||
hashValue = hash.ComputeHash(dataStream);
|
||||
}
|
||||
|
||||
// Then
|
||||
Assert.IsNotNull(hashValue);
|
||||
Assert.AreEqual(512, 8 * hashValue.Length);
|
||||
}
|
||||
|
||||
private static Stream CreateDataStream()
|
||||
{
|
||||
// Некоторый поток байт
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes("Some data to hash..."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
using GostCryptography.Gost_R3411;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_R3411
|
||||
{
|
||||
/// <summary>
|
||||
/// Использование PRF на базе алгоритма хэширования ГОСТ Р 34.11-2012/512.
|
||||
/// </summary>
|
||||
[TestFixture(Description = "Использование PRF на базе алгоритма хэширования ГОСТ Р 34.11-2012/512")]
|
||||
public class Gost_R3411_2012_512_PRFTest
|
||||
{
|
||||
private static readonly byte[] Label = { 1, 2, 3, 4, 5 };
|
||||
private static readonly byte[] Seed = { 6, 7, 8, 9, 0 };
|
||||
private static readonly byte[] TestData = Encoding.UTF8.GetBytes("Some data to encrypt...");
|
||||
|
||||
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldDeriveBytes(ProviderType providerType)
|
||||
{
|
||||
// Given
|
||||
var initKey = new Gost_28147_89_SymmetricAlgorithm(providerType);
|
||||
|
||||
// When
|
||||
|
||||
byte[] randomBytes1;
|
||||
byte[] randomBytes2;
|
||||
byte[] randomBytes3;
|
||||
|
||||
using (var prf = new Gost_R3411_2012_512_PRF(initKey, Label, Seed))
|
||||
{
|
||||
randomBytes1 = prf.DeriveBytes();
|
||||
randomBytes2 = prf.DeriveBytes();
|
||||
randomBytes3 = prf.DeriveBytes();
|
||||
}
|
||||
|
||||
// Then
|
||||
Assert.IsNotNull(randomBytes1);
|
||||
Assert.IsNotNull(randomBytes2);
|
||||
Assert.IsNotNull(randomBytes3);
|
||||
Assert.AreEqual(512, 8 * randomBytes1.Length);
|
||||
Assert.AreEqual(512, 8 * randomBytes2.Length);
|
||||
Assert.AreEqual(512, 8 * randomBytes3.Length);
|
||||
CollectionAssert.AreNotEqual(randomBytes1, randomBytes2);
|
||||
CollectionAssert.AreNotEqual(randomBytes1, randomBytes3);
|
||||
CollectionAssert.AreNotEqual(randomBytes2, randomBytes3);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldDeriveKey(ProviderType providerType)
|
||||
{
|
||||
// TODO: VipNet does not support this feature - https://infotecs.ru/forum/topic/10142-oshibka-pri-sozdanii-klyucha-shifrovaniya-na-osnove-dannyih-polzovatelya-cryptderivekey/
|
||||
if (providerType.IsVipNet())
|
||||
{
|
||||
Assert.Ignore("VipNet does not support this feature");
|
||||
}
|
||||
|
||||
// Given
|
||||
var initKey = new Gost_28147_89_SymmetricAlgorithm(providerType);
|
||||
|
||||
// When
|
||||
|
||||
GostSymmetricAlgorithm randomKey1;
|
||||
GostSymmetricAlgorithm randomKey2;
|
||||
GostSymmetricAlgorithm randomKey3;
|
||||
|
||||
using (var prf = new Gost_R3411_2012_512_PRF(initKey, Label, Seed))
|
||||
{
|
||||
randomKey1 = prf.DeriveKey();
|
||||
randomKey2 = prf.DeriveKey();
|
||||
randomKey3 = prf.DeriveKey();
|
||||
}
|
||||
|
||||
// Then
|
||||
Assert.IsNotNull(randomKey1);
|
||||
Assert.IsNotNull(randomKey2);
|
||||
Assert.IsNotNull(randomKey3);
|
||||
AssertKeyIsValid(randomKey1);
|
||||
AssertKeyIsValid(randomKey2);
|
||||
AssertKeyIsValid(randomKey3);
|
||||
AssertKeysAreNotEqual(randomKey1, randomKey2);
|
||||
AssertKeysAreNotEqual(randomKey1, randomKey3);
|
||||
AssertKeysAreNotEqual(randomKey2, randomKey3);
|
||||
}
|
||||
|
||||
|
||||
public static void AssertKeyIsValid(GostSymmetricAlgorithm key)
|
||||
{
|
||||
var encryptedData = EncryptData(key, TestData);
|
||||
var decryptedData = DecryptData(key, encryptedData);
|
||||
CollectionAssert.AreEqual(TestData, decryptedData);
|
||||
}
|
||||
|
||||
public static void AssertKeysAreNotEqual(GostSymmetricAlgorithm key1, GostSymmetricAlgorithm key2)
|
||||
{
|
||||
var encryptedData1 = EncryptData(key1, TestData);
|
||||
var encryptedData2 = EncryptData(key2, TestData);
|
||||
CollectionAssert.AreNotEqual(encryptedData1, encryptedData2);
|
||||
}
|
||||
|
||||
|
||||
public static byte[] EncryptData(GostSymmetricAlgorithm key, byte[] data)
|
||||
{
|
||||
var transform = key.CreateEncryptor();
|
||||
return transform.TransformFinalBlock(data, 0, data.Length);
|
||||
}
|
||||
|
||||
public static byte[] DecryptData(GostSymmetricAlgorithm key, byte[] data)
|
||||
{
|
||||
var transform = key.CreateDecryptor();
|
||||
return transform.TransformFinalBlock(data, 0, data.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
using GostCryptography.Gost_R3411;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_R3411
|
||||
{
|
||||
/// <summary>
|
||||
/// Вычисление HMAC на базе алгоритма хэширования ГОСТ Р 34.11-94 и общего симметричного ключа ГОСТ 28147-89.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест выполняет подпись и проверку подписи потока байт с использованием HMAC.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Вычисление HMAC на базе алгоритма хэширования ГОСТ Р 34.11-94 и общего симметричного ключа ГОСТ 28147-89")]
|
||||
public class Gost_R3411_94_HMACTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldComputeHMAC(ProviderType providerType)
|
||||
{
|
||||
// Given
|
||||
var dataStream = CreateDataStream();
|
||||
var sharedKey = new Gost_28147_89_SymmetricAlgorithm(providerType);
|
||||
|
||||
// When
|
||||
var hmacDataStream = CreateHmacDataStream(sharedKey, dataStream);
|
||||
var isValidHmacDataStream = VerifyHmacDataStream(sharedKey, hmacDataStream);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(isValidHmacDataStream);
|
||||
}
|
||||
|
||||
private static Stream CreateDataStream()
|
||||
{
|
||||
// Некоторый поток байт
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes("Some data to HMAC..."));
|
||||
}
|
||||
|
||||
private static Stream CreateHmacDataStream(GostSymmetricAlgorithm sharedKey, Stream dataStream)
|
||||
{
|
||||
// Создание объекта для вычисления HMAC
|
||||
using (var hmac = new Gost_R3411_94_HMAC(sharedKey))
|
||||
{
|
||||
// Вычисление HMAC для потока данных
|
||||
var hmacValue = hmac.ComputeHash(dataStream);
|
||||
|
||||
// Запись HMAC в начало выходного потока данных
|
||||
var hmacDataStream = new MemoryStream();
|
||||
hmacDataStream.Write(hmacValue, 0, hmacValue.Length);
|
||||
|
||||
// Копирование исходного потока данных в выходной поток
|
||||
dataStream.Position = 0;
|
||||
dataStream.CopyTo(hmacDataStream);
|
||||
|
||||
hmacDataStream.Position = 0;
|
||||
|
||||
return hmacDataStream;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool VerifyHmacDataStream(GostSymmetricAlgorithm sharedKey, Stream hmacDataStream)
|
||||
{
|
||||
// Создание объекта для вычисления HMAC
|
||||
using (var hmac = new Gost_R3411_94_HMAC(sharedKey))
|
||||
{
|
||||
// Считывание HMAC из потока данных
|
||||
var hmacValue = new byte[hmac.HashSize / 8];
|
||||
hmacDataStream.Read(hmacValue, 0, hmacValue.Length);
|
||||
|
||||
// Вычисление реального значения HMAC для потока данных
|
||||
var expectedHmacValue = hmac.ComputeHash(hmacDataStream);
|
||||
|
||||
// Сравнение исходного HMAC с ожидаемым
|
||||
return hmacValue.SequenceEqual(expectedHmacValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_R3411;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_R3411
|
||||
{
|
||||
/// <summary>
|
||||
/// Вычисление хэша в соответствии с ГОСТ Р 34.11-94.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает поток байт, вычисляет хэш в соответствии с ГОСТ Р 34.11-94 и проверяет его корректность.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Вычисление хэша в соответствии с ГОСТ Р 34.11-94")]
|
||||
public class Gost_R3411_94_HashAlgorithmTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldComputeHash(ProviderType providerType)
|
||||
{
|
||||
// Given
|
||||
var dataStream = CreateDataStream();
|
||||
|
||||
// When
|
||||
|
||||
byte[] hashValue;
|
||||
|
||||
using (var hash = new Gost_R3411_94_HashAlgorithm(providerType))
|
||||
{
|
||||
hashValue = hash.ComputeHash(dataStream);
|
||||
}
|
||||
|
||||
// Then
|
||||
Assert.IsNotNull(hashValue);
|
||||
Assert.AreEqual(256, 8 * hashValue.Length);
|
||||
}
|
||||
|
||||
private static Stream CreateDataStream()
|
||||
{
|
||||
// Некоторый поток байт
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes("Some data to hash..."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
using GostCryptography.Gost_R3411;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Gost_R3411
|
||||
{
|
||||
/// <summary>
|
||||
/// Использование PRF на базе алгоритма хэширования ГОСТ Р 34.11-94.
|
||||
/// </summary>
|
||||
[TestFixture(Description = "Использование PRF на базе алгоритма хэширования ГОСТ Р 34.11-94")]
|
||||
public class Gost_R3411_94_PRFTest
|
||||
{
|
||||
private static readonly byte[] Label = { 1, 2, 3, 4, 5 };
|
||||
private static readonly byte[] Seed = { 6, 7, 8, 9, 0 };
|
||||
private static readonly byte[] TestData = Encoding.UTF8.GetBytes("Some data to encrypt...");
|
||||
|
||||
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldDeriveBytes(ProviderType providerType)
|
||||
{
|
||||
// Given
|
||||
var initKey = new Gost_28147_89_SymmetricAlgorithm(providerType);
|
||||
|
||||
// When
|
||||
|
||||
byte[] randomBytes1;
|
||||
byte[] randomBytes2;
|
||||
byte[] randomBytes3;
|
||||
|
||||
using (var prf = new Gost_R3411_94_PRF(initKey, Label, Seed))
|
||||
{
|
||||
randomBytes1 = prf.DeriveBytes();
|
||||
randomBytes2 = prf.DeriveBytes();
|
||||
randomBytes3 = prf.DeriveBytes();
|
||||
}
|
||||
|
||||
// Then
|
||||
Assert.IsNotNull(randomBytes1);
|
||||
Assert.IsNotNull(randomBytes2);
|
||||
Assert.IsNotNull(randomBytes3);
|
||||
Assert.AreEqual(256, 8 * randomBytes1.Length);
|
||||
Assert.AreEqual(256, 8 * randomBytes2.Length);
|
||||
Assert.AreEqual(256, 8 * randomBytes3.Length);
|
||||
CollectionAssert.AreNotEqual(randomBytes1, randomBytes2);
|
||||
CollectionAssert.AreNotEqual(randomBytes1, randomBytes3);
|
||||
CollectionAssert.AreNotEqual(randomBytes2, randomBytes3);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldDeriveKey(ProviderType providerType)
|
||||
{
|
||||
// Given
|
||||
var initKey = new Gost_28147_89_SymmetricAlgorithm(providerType);
|
||||
|
||||
// When
|
||||
|
||||
GostSymmetricAlgorithm randomKey1;
|
||||
GostSymmetricAlgorithm randomKey2;
|
||||
GostSymmetricAlgorithm randomKey3;
|
||||
|
||||
using (var prf = new Gost_R3411_94_PRF(initKey, Label, Seed))
|
||||
{
|
||||
randomKey1 = prf.DeriveKey();
|
||||
randomKey2 = prf.DeriveKey();
|
||||
randomKey3 = prf.DeriveKey();
|
||||
}
|
||||
|
||||
// Then
|
||||
Assert.IsNotNull(randomKey1);
|
||||
Assert.IsNotNull(randomKey2);
|
||||
Assert.IsNotNull(randomKey3);
|
||||
AssertKeyIsValid(randomKey1);
|
||||
AssertKeyIsValid(randomKey2);
|
||||
AssertKeyIsValid(randomKey3);
|
||||
AssertKeysAreNotEqual(randomKey1, randomKey2);
|
||||
AssertKeysAreNotEqual(randomKey1, randomKey3);
|
||||
AssertKeysAreNotEqual(randomKey2, randomKey3);
|
||||
}
|
||||
|
||||
|
||||
public static void AssertKeyIsValid(GostSymmetricAlgorithm key)
|
||||
{
|
||||
var encryptedData = EncryptData(key, TestData);
|
||||
var decryptedData = DecryptData(key, encryptedData);
|
||||
CollectionAssert.AreEqual(TestData, decryptedData);
|
||||
}
|
||||
|
||||
public static void AssertKeysAreNotEqual(GostSymmetricAlgorithm key1, GostSymmetricAlgorithm key2)
|
||||
{
|
||||
var encryptedData1 = EncryptData(key1, TestData);
|
||||
var encryptedData2 = EncryptData(key2, TestData);
|
||||
CollectionAssert.AreNotEqual(encryptedData1, encryptedData2);
|
||||
}
|
||||
|
||||
|
||||
public static byte[] EncryptData(GostSymmetricAlgorithm key, byte[] data)
|
||||
{
|
||||
var transform = key.CreateEncryptor();
|
||||
return transform.TransformFinalBlock(data, 0, data.Length);
|
||||
}
|
||||
|
||||
public static byte[] DecryptData(GostSymmetricAlgorithm key, byte[] data)
|
||||
{
|
||||
var transform = key.CreateDecryptor();
|
||||
return transform.TransformFinalBlock(data, 0, data.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography.Pkcs;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Pkcs
|
||||
{
|
||||
/// <summary>
|
||||
/// Шифрация и дешифрация сообщения CMS/PKCS#7.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает сообщение, шифрует его в формате CMS/PKCS#7, а затем дешифрует зашифрованное сообщение.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Шифрация и дешифрация сообщения CMS/PKCS#7")]
|
||||
public class EnvelopedCmsEncryptTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_Certificates))]
|
||||
public void ShouldEncryptAndDecrypt(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var message = CreateMessage();
|
||||
|
||||
// When
|
||||
var encryptedMessage = EncryptMessage(certificate, message);
|
||||
var decryptedMessage = DecryptMessage(encryptedMessage);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(message.SequenceEqual(decryptedMessage));
|
||||
}
|
||||
|
||||
private static byte[] CreateMessage()
|
||||
{
|
||||
// Некоторое сообщение для подписи
|
||||
|
||||
return Encoding.UTF8.GetBytes("Some message to sign...");
|
||||
}
|
||||
|
||||
private static byte[] EncryptMessage(X509Certificate2 certificate, byte[] message)
|
||||
{
|
||||
// Создание объекта для шифрования сообщения
|
||||
var envelopedCms = new EnvelopedCms(new ContentInfo(message));
|
||||
|
||||
// Создание объект с информацией о получателе
|
||||
var recipient = new CmsRecipient(SubjectIdentifierType.IssuerAndSerialNumber, certificate);
|
||||
|
||||
// Шифрование сообщения CMS/PKCS#7
|
||||
envelopedCms.Encrypt(recipient);
|
||||
|
||||
// Создание сообщения CMS/PKCS#7
|
||||
return envelopedCms.Encode();
|
||||
}
|
||||
|
||||
private static byte[] DecryptMessage(byte[] encryptedMessage)
|
||||
{
|
||||
// Создание объекта для расшифровки сообщения
|
||||
var envelopedCms = new EnvelopedCms();
|
||||
|
||||
// Чтение сообщения CMS/PKCS#7
|
||||
envelopedCms.Decode(encryptedMessage);
|
||||
|
||||
// Расшифровка сообщения CMS/PKCS#7
|
||||
envelopedCms.Decrypt(envelopedCms.RecipientInfos[0]);
|
||||
|
||||
return envelopedCms.ContentInfo.Content;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System.Security.Cryptography.Pkcs;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Pkcs;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Pkcs
|
||||
{
|
||||
/// <summary>
|
||||
/// Подпись и проверка отсоединенной подписи сообщения CMS/PKCS#7.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает сообщение, формирует отсоединенную подпись сообщения в формате CMS/PKCS#7,
|
||||
/// а затем проверяет подпись полученную цифровую подпись.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Подпись и проверка отсоединенной подписи сообщения CMS/PKCS#7")]
|
||||
public class SignedCmsDetachedSignTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_Certificates))]
|
||||
public void ShouldSign(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var message = CreateMessage();
|
||||
|
||||
// When
|
||||
var detachedSignature = SignMessage(certificate, message);
|
||||
var isValidDetachedSignature = VerifyMessage(message, detachedSignature);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(isValidDetachedSignature);
|
||||
}
|
||||
|
||||
private static byte[] CreateMessage()
|
||||
{
|
||||
// Некоторое сообщение для подписи
|
||||
|
||||
return Encoding.UTF8.GetBytes("Some message to sign...");
|
||||
}
|
||||
|
||||
private static byte[] SignMessage(X509Certificate2 certificate, byte[] message)
|
||||
{
|
||||
// Создание объекта для подписи сообщения
|
||||
var signedCms = new GostSignedCms(new ContentInfo(message), true);
|
||||
|
||||
// Создание объект с информацией о подписчике
|
||||
var signer = new CmsSigner(certificate);
|
||||
|
||||
// Включение информации только о конечном сертификате (только для теста)
|
||||
signer.IncludeOption = X509IncludeOption.EndCertOnly;
|
||||
|
||||
// Создание подписи для сообщения CMS/PKCS#7
|
||||
signedCms.ComputeSignature(signer);
|
||||
|
||||
// Создание подписи CMS/PKCS#7
|
||||
return signedCms.Encode();
|
||||
}
|
||||
|
||||
private static bool VerifyMessage(byte[] message, byte[] detachedSignature)
|
||||
{
|
||||
// Создание объекта для проверки подписи сообщения
|
||||
var signedCms = new GostSignedCms(new ContentInfo(message), true);
|
||||
|
||||
// Чтение подписи CMS/PKCS#7
|
||||
signedCms.Decode(detachedSignature);
|
||||
|
||||
try
|
||||
{
|
||||
// Проверка подписи CMS/PKCS#7
|
||||
signedCms.CheckSignature(true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
using System.Security.Cryptography.Pkcs;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Pkcs;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Pkcs
|
||||
{
|
||||
/// <summary>
|
||||
/// Подпись и проверка подписи сообщения CMS/PKCS#7.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает сообщение, формирует подписанное сообщение в формате CMS/PKCS#7,
|
||||
/// исключая информацию о сертификате подписчика с целью минимизации размера сообщения,
|
||||
/// а затем проверяет подпись полученную цифровую подпись.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Подпись и проверка подписи сообщения CMS/PKCS#7")]
|
||||
public class SignedCmsSignAndExcludeCertificates
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_Certificates))]
|
||||
public void ShouldSign(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var message = CreateMessage();
|
||||
|
||||
// When
|
||||
var signedMessage = SignMessage(certificate, message);
|
||||
var isValidSignedMessage = VerifyMessage(certificate, signedMessage);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(isValidSignedMessage);
|
||||
}
|
||||
|
||||
private static byte[] CreateMessage()
|
||||
{
|
||||
// Некоторое сообщение для подписи
|
||||
|
||||
return Encoding.UTF8.GetBytes("Some message to sign...");
|
||||
}
|
||||
|
||||
private static byte[] SignMessage(X509Certificate2 certificate, byte[] message)
|
||||
{
|
||||
// Создание объекта для подписи сообщения
|
||||
var signedCms = new GostSignedCms(new ContentInfo(message));
|
||||
|
||||
// Создание объект с информацией о подписчике
|
||||
var signer = new CmsSigner(certificate);
|
||||
|
||||
// Включение информации только о конечном сертификате (только для теста)
|
||||
signer.IncludeOption = X509IncludeOption.EndCertOnly;
|
||||
|
||||
// Создание подписи для сообщения CMS/PKCS#7
|
||||
signedCms.ComputeSignature(signer);
|
||||
|
||||
// Исключение сертификатов для уменьшения размера сообщения
|
||||
signedCms.RemoveCertificates();
|
||||
|
||||
// Создание сообщения CMS/PKCS#7
|
||||
return signedCms.Encode();
|
||||
}
|
||||
|
||||
private static bool VerifyMessage(X509Certificate2 certificate, byte[] signedMessage)
|
||||
{
|
||||
// Создание объекта для проверки подписи сообщения
|
||||
var signedCms = new GostSignedCms();
|
||||
|
||||
// Чтение сообщения CMS/PKCS#7
|
||||
signedCms.Decode(signedMessage);
|
||||
|
||||
// Список сертификатов подписчика
|
||||
var signerCerts = new X509Certificate2Collection(certificate);
|
||||
|
||||
try
|
||||
{
|
||||
// Проверка подписи сообщения CMS/PKCS#7
|
||||
signedCms.CheckSignature(signerCerts, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System.Security.Cryptography.Pkcs;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Pkcs;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Pkcs
|
||||
{
|
||||
/// <summary>
|
||||
/// Подпись и проверка подписи сообщения CMS/PKCS#7.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает сообщение, формирует подписанное сообщение в формате CMS/PKCS#7,
|
||||
/// а затем проверяет подпись полученную цифровую подпись.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Подпись и проверка подписи сообщения CMS/PKCS#7")]
|
||||
public class SignedCmsSignTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_Certificates))]
|
||||
public void ShouldSign(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var message = CreateMessage();
|
||||
|
||||
// When
|
||||
var signedMessage = SignMessage(certificate, message);
|
||||
var isValidSignedMessage = VerifyMessage(signedMessage);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(isValidSignedMessage);
|
||||
}
|
||||
|
||||
private static byte[] CreateMessage()
|
||||
{
|
||||
// Некоторое сообщение для подписи
|
||||
|
||||
return Encoding.UTF8.GetBytes("Some message to sign...");
|
||||
}
|
||||
|
||||
private static byte[] SignMessage(X509Certificate2 certificate, byte[] message)
|
||||
{
|
||||
// Создание объекта для подписи сообщения
|
||||
var signedCms = new GostSignedCms(new ContentInfo(message));
|
||||
|
||||
// Создание объект с информацией о подписчике
|
||||
var signer = new CmsSigner(certificate);
|
||||
|
||||
// Включение информации только о конечном сертификате (только для теста)
|
||||
signer.IncludeOption = X509IncludeOption.EndCertOnly;
|
||||
|
||||
// Создание подписи для сообщения CMS/PKCS#7
|
||||
signedCms.ComputeSignature(signer);
|
||||
|
||||
// Создание сообщения CMS/PKCS#7
|
||||
return signedCms.Encode();
|
||||
}
|
||||
|
||||
private static bool VerifyMessage(byte[] signedMessage)
|
||||
{
|
||||
// Создание объекта для проверки подписи сообщения
|
||||
var signedCms = new GostSignedCms();
|
||||
|
||||
// Чтение сообщения CMS/PKCS#7
|
||||
signedCms.Decode(signedMessage);
|
||||
|
||||
try
|
||||
{
|
||||
// Проверка подписи сообщения CMS/PKCS#7
|
||||
signedCms.CheckSignature(true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
118
third_party/forks/AlexMAS.GostCryptography/Source/GostCryptography.Tests/Properties/Resources.Designer.cs
generated
vendored
Normal file
118
third_party/forks/AlexMAS.GostCryptography/Source/GostCryptography.Tests/Properties/Resources.Designer.cs
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace GostCryptography.Tests.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GostCryptography.Tests.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?>
|
||||
///<MyXml>
|
||||
/// <SomeElement Encrypt="false">
|
||||
/// Here is public data.
|
||||
/// </SomeElement>
|
||||
/// <SomeElement Encrypt="true">
|
||||
/// Here is private data.
|
||||
/// </SomeElement>
|
||||
/// <SomeElement Encrypt="true">
|
||||
/// Here is private data.
|
||||
/// </SomeElement>
|
||||
/// <SomeElement Encrypt="true">
|
||||
/// Here is private data.
|
||||
/// </SomeElement>
|
||||
///</MyXml>.
|
||||
/// </summary>
|
||||
internal static string EncryptedXmlExample {
|
||||
get {
|
||||
return ResourceManager.GetString("EncryptedXmlExample", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8" ?>
|
||||
///<MyXml>
|
||||
/// <SomeElement Id="Id1">
|
||||
/// Here is some data to sign.
|
||||
/// </SomeElement>
|
||||
///</MyXml>.
|
||||
/// </summary>
|
||||
internal static string SignedXmlExample {
|
||||
get {
|
||||
return ResourceManager.GetString("SignedXmlExample", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
///<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"
|
||||
/// xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
|
||||
/// xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
|
||||
/// >
|
||||
/// <S:Header>
|
||||
/// <wsse:Security S:actor="http://smev.gosuslugi.ru/actors/smev">
|
||||
/// <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
||||
/// <ds:KeyInfo>
|
||||
/// <wsse:SecurityTokenR [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string SmevExample {
|
||||
get {
|
||||
return ResourceManager.GetString("SmevExample", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
130
third_party/forks/AlexMAS.GostCryptography/Source/GostCryptography.Tests/Properties/Resources.resx
vendored
Normal file
130
third_party/forks/AlexMAS.GostCryptography/Source/GostCryptography.Tests/Properties/Resources.resx
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="EncryptedXmlExample" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\data\encryptedxmlexample.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
|
||||
</data>
|
||||
<data name="SignedXmlExample" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\data\signedxmlexample.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
|
||||
</data>
|
||||
<data name="SmevExample" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\data\smevexample.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,74 @@
|
||||
using System.IO;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Sign
|
||||
{
|
||||
/// <summary>
|
||||
/// Подпись и проверка подписи потока байт с помощью сертификата.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает поток байт, вычисляет цифровую подпись потока байт с использованием закрытого ключа сертификата,
|
||||
/// а затем с помощью открытого ключа сертификата проверяет полученную подпись.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Подпись и проверка подписи потока байт с помощью сертификата")]
|
||||
public class SignDataStreamCertificateTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_Certificates))]
|
||||
public void ShouldSignDataStream(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var privateKey = (GostAsymmetricAlgorithm)certificate.GetPrivateKeyAlgorithm();
|
||||
var publicKey = (GostAsymmetricAlgorithm)certificate.GetPublicKeyAlgorithm();
|
||||
var dataStream = CreateDataStream();
|
||||
|
||||
// When
|
||||
|
||||
dataStream.Seek(0, SeekOrigin.Begin);
|
||||
var signature = CreateSignature(privateKey, dataStream);
|
||||
|
||||
dataStream.Seek(0, SeekOrigin.Begin);
|
||||
var isValidSignature = VerifySignature(publicKey, dataStream, signature);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(isValidSignature);
|
||||
}
|
||||
|
||||
private static Stream CreateDataStream()
|
||||
{
|
||||
// Некоторый поток байт для подписи
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes("Some data to sign..."));
|
||||
}
|
||||
|
||||
private static byte[] CreateSignature(GostAsymmetricAlgorithm privateKey, Stream dataStream)
|
||||
{
|
||||
byte[] hash;
|
||||
|
||||
using (var hashAlg = privateKey.CreateHashAlgorithm())
|
||||
{
|
||||
hash = hashAlg.ComputeHash(dataStream);
|
||||
}
|
||||
|
||||
return privateKey.CreateSignature(hash);
|
||||
}
|
||||
|
||||
private static bool VerifySignature(GostAsymmetricAlgorithm publicKey, Stream dataStream, byte[] signature)
|
||||
{
|
||||
byte[] hash;
|
||||
|
||||
using (var hashAlg = publicKey.CreateHashAlgorithm())
|
||||
{
|
||||
hash = hashAlg.ComputeHash(dataStream);
|
||||
}
|
||||
|
||||
return publicKey.VerifySignature(hash, signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Config;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Sign
|
||||
{
|
||||
/// <summary>
|
||||
/// Подпись и проверка подписи потока байт с помощью сертификата и информации об алгоритме цифровой подписи
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает поток байт, вычисляет цифровую подпись потока байт с использованием закрытого ключа сертификата,
|
||||
/// а затем с помощью открытого ключа сертификата проверяет полученную подпись. Для вычисления цифровой подписи
|
||||
/// и ее проверки используется информация об алгоритме цифровой подписи <see cref="SignatureDescription"/>,
|
||||
/// получаемая с помощью метода <see cref="GostCryptoConfig.CreateFromName"/>.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Подпись и проверка подписи потока байт с помощью сертификата и информации об алгоритме цифровой подписи")]
|
||||
public class SignDataStreamSignatureDescriptionTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_Certificates))]
|
||||
public void ShouldSignDataStream(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var privateKey = (GostAsymmetricAlgorithm)certificate.GetPrivateKeyAlgorithm();
|
||||
var publicKey = (GostAsymmetricAlgorithm)certificate.GetPublicKeyAlgorithm();
|
||||
var dataStream = CreateDataStream();
|
||||
|
||||
// When
|
||||
|
||||
dataStream.Seek(0, SeekOrigin.Begin);
|
||||
var signature = CreateSignature(privateKey, dataStream);
|
||||
|
||||
dataStream.Seek(0, SeekOrigin.Begin);
|
||||
var isValidSignature = VerifySignature(publicKey, dataStream, signature);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(isValidSignature);
|
||||
}
|
||||
|
||||
private static Stream CreateDataStream()
|
||||
{
|
||||
// Некоторый поток байт для подписи
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes("Some data to sign..."));
|
||||
}
|
||||
|
||||
private static byte[] CreateSignature(AsymmetricAlgorithm privateKey, Stream dataStream)
|
||||
{
|
||||
var signatureDescription = (SignatureDescription)GostCryptoConfig.CreateFromName(privateKey.SignatureAlgorithm);
|
||||
|
||||
byte[] hash;
|
||||
|
||||
using (var hashAlg = signatureDescription.CreateDigest())
|
||||
{
|
||||
hash = hashAlg.ComputeHash(dataStream);
|
||||
}
|
||||
|
||||
var formatter = signatureDescription.CreateFormatter(privateKey);
|
||||
formatter.SetHashAlgorithm(signatureDescription.DigestAlgorithm);
|
||||
|
||||
return formatter.CreateSignature(hash);
|
||||
}
|
||||
|
||||
private static bool VerifySignature(AsymmetricAlgorithm publicKey, Stream dataStream, byte[] signature)
|
||||
{
|
||||
var signatureDescription = (SignatureDescription)GostCryptoConfig.CreateFromName(publicKey.SignatureAlgorithm);
|
||||
|
||||
byte[] hash;
|
||||
|
||||
using (var hashAlg = signatureDescription.CreateDigest())
|
||||
{
|
||||
hash = hashAlg.ComputeHash(dataStream);
|
||||
}
|
||||
|
||||
var deformatter = signatureDescription.CreateDeformatter(publicKey);
|
||||
deformatter.SetHashAlgorithm(signatureDescription.DigestAlgorithm);
|
||||
|
||||
return deformatter.VerifySignature(hash, signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using System.IO;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
|
||||
using GostCryptography.Base;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Sign
|
||||
{
|
||||
/// <summary>
|
||||
/// Подпись и проверка подписи потока байт с помощью сертификата и классов форматирования.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает поток байт, вычисляет цифровую подпись потока байт с использованием закрытого ключа сертификата,
|
||||
/// а затем с помощью открытого ключа сертификата проверяет полученную подпись. Для вычисления цифровой подписи
|
||||
/// используется класс <see cref="GostSignatureFormatter"/>, для проверки цифровой подписи используется класс
|
||||
/// <see cref="GostSignatureDeformatter"/>.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Подпись и проверка подписи потока байт с помощью сертификата и классов форматирования")]
|
||||
public class SignDataStreamSignatureFormatterTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_Certificates))]
|
||||
public void ShouldSignDataStream(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var privateKey = (GostAsymmetricAlgorithm)certificate.GetPrivateKeyAlgorithm();
|
||||
var publicKey = (GostAsymmetricAlgorithm)certificate.GetPublicKeyAlgorithm();
|
||||
var dataStream = CreateDataStream();
|
||||
|
||||
// When
|
||||
|
||||
dataStream.Seek(0, SeekOrigin.Begin);
|
||||
var signature = CreateSignature(privateKey, dataStream);
|
||||
|
||||
dataStream.Seek(0, SeekOrigin.Begin);
|
||||
var isValidSignature = VerifySignature(publicKey, dataStream, signature);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(isValidSignature);
|
||||
}
|
||||
|
||||
private static Stream CreateDataStream()
|
||||
{
|
||||
// Некоторый поток байт для подписи
|
||||
|
||||
return new MemoryStream(Encoding.UTF8.GetBytes("Some data to sign..."));
|
||||
}
|
||||
|
||||
private static byte[] CreateSignature(GostAsymmetricAlgorithm privateKey, Stream dataStream)
|
||||
{
|
||||
byte[] hash;
|
||||
|
||||
using (var hashAlg = privateKey.CreateHashAlgorithm())
|
||||
{
|
||||
hash = hashAlg.ComputeHash(dataStream);
|
||||
}
|
||||
|
||||
var formatter = new GostSignatureFormatter(privateKey);
|
||||
|
||||
return formatter.CreateSignature(hash);
|
||||
}
|
||||
|
||||
private static bool VerifySignature(GostAsymmetricAlgorithm publicKey, Stream dataStream, byte[] signature)
|
||||
{
|
||||
byte[] hash;
|
||||
|
||||
using (var hashAlg = publicKey.CreateHashAlgorithm())
|
||||
{
|
||||
hash = hashAlg.ComputeHash(dataStream);
|
||||
}
|
||||
|
||||
var deformatter = new GostSignatureDeformatter(publicKey);
|
||||
|
||||
return deformatter.VerifySignature(hash, signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
21
third_party/forks/AlexMAS.GostCryptography/Source/GostCryptography.Tests/TestCertificateInfo.cs
vendored
Normal file
21
third_party/forks/AlexMAS.GostCryptography/Source/GostCryptography.Tests/TestCertificateInfo.cs
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
namespace GostCryptography.Tests
|
||||
{
|
||||
public class TestCertificateInfo
|
||||
{
|
||||
public TestCertificateInfo(string name, X509Certificate2 certificate)
|
||||
{
|
||||
Name = name;
|
||||
Certificate = certificate;
|
||||
}
|
||||
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public X509Certificate2 Certificate { get; }
|
||||
|
||||
|
||||
public override string ToString() => Name;
|
||||
}
|
||||
}
|
||||
79
third_party/forks/AlexMAS.GostCryptography/Source/GostCryptography.Tests/TestConfig.cs
vendored
Normal file
79
third_party/forks/AlexMAS.GostCryptography/Source/GostCryptography.Tests/TestConfig.cs
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Config;
|
||||
|
||||
namespace GostCryptography.Tests
|
||||
{
|
||||
public static class TestConfig
|
||||
{
|
||||
static TestConfig()
|
||||
{
|
||||
Providers = new[] { GostCryptoConfig.ProviderType, GostCryptoConfig.ProviderType_2012_512, GostCryptoConfig.ProviderType_2012_1024 };
|
||||
|
||||
var gost_R3410_2001 = new TestCertificateInfo("ГОСТ Р 34.10-2001", FindGostCertificate(filter: c => c.IsGost_R3410_2001()));
|
||||
var gost_R3410_2012_256 = new TestCertificateInfo("ГОСТ Р 34.10-2012/256", FindGostCertificate(filter: c => c.IsGost_R3410_2012_256()));
|
||||
var gost_R3410_2012_512 = new TestCertificateInfo("ГОСТ Р 34.10-2012/512", FindGostCertificate(filter: c => c.IsGost_R3410_2012_512()));
|
||||
|
||||
var gost_R3410_Certificates = new List<TestCertificateInfo> { gost_R3410_2001, gost_R3410_2012_256, gost_R3410_2012_512 };
|
||||
var gost_R3410_2001_Certificates = new List<TestCertificateInfo> { gost_R3410_2001 };
|
||||
var gost_R3410_2012_256_Certificates = new List<TestCertificateInfo> { gost_R3410_2012_256 };
|
||||
var gost_R3410_2012_512_Certificates = new List<TestCertificateInfo> { gost_R3410_2012_512 };
|
||||
|
||||
gost_R3410_Certificates.RemoveAll(c => c.Certificate == null);
|
||||
gost_R3410_2001_Certificates.RemoveAll(c => c.Certificate == null);
|
||||
gost_R3410_2012_256_Certificates.RemoveAll(c => c.Certificate == null);
|
||||
gost_R3410_2012_512_Certificates.RemoveAll(c => c.Certificate == null);
|
||||
|
||||
Gost_R3410_Certificates = gost_R3410_Certificates;
|
||||
Gost_R3410_2001_Certificates = gost_R3410_2001_Certificates;
|
||||
Gost_R3410_2012_256_Certificates = gost_R3410_2012_256_Certificates;
|
||||
Gost_R3410_2012_512_Certificates = gost_R3410_2012_512_Certificates;
|
||||
}
|
||||
|
||||
|
||||
public const StoreName DefaultStoreName = StoreName.My;
|
||||
|
||||
public const StoreLocation DefaultStoreLocation = StoreLocation.LocalMachine;
|
||||
|
||||
public static IEnumerable<ProviderType> Providers { get; }
|
||||
|
||||
public static IEnumerable<TestCertificateInfo> Gost_R3410_Certificates { get; }
|
||||
|
||||
public static IEnumerable<TestCertificateInfo> Gost_R3410_2001_Certificates { get; }
|
||||
|
||||
public static IEnumerable<TestCertificateInfo> Gost_R3410_2012_256_Certificates { get; }
|
||||
|
||||
public static IEnumerable<TestCertificateInfo> Gost_R3410_2012_512_Certificates { get; }
|
||||
|
||||
public const string ContainerPassword = "GostCryptography";
|
||||
|
||||
|
||||
[SecuritySafeCritical]
|
||||
public static X509Certificate2 FindGostCertificate(StoreName storeName = DefaultStoreName, StoreLocation storeLocation = DefaultStoreLocation, Predicate<X509Certificate2> filter = null)
|
||||
{
|
||||
var store = new X509Store(storeName, storeLocation);
|
||||
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var certificate in store.Certificates)
|
||||
{
|
||||
if (certificate.HasPrivateKey && certificate.IsGost() && (filter == null || filter(certificate)))
|
||||
{
|
||||
return certificate;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
store.Close();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Security.Cryptography.Xml;
|
||||
using System.Xml;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
using GostCryptography.Tests.Properties;
|
||||
using GostCryptography.Xml;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Xml.Encrypt
|
||||
{
|
||||
/// <summary>
|
||||
/// Шифрация и дешифрация XML для широковещательной рассылки.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает XML-документ, выборочно шифрует элементы данного документа, а затем дешифрует полученный зашифрованный документ.
|
||||
/// Элементы шифруются с использованием случайного сессионного ключа, который в свою очередь кодируется (экспортируется)
|
||||
/// с использованием публичного ключа сертификата получателя. Расшифровка документа происходит с использованием первого
|
||||
/// найденного секретного ключа сертификата получателя.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Шифрация и дешифрация XML для широковещательной рассылки")]
|
||||
public sealed class EncryptedXmlBroadcastTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_Certificates))]
|
||||
public void ShouldEncryptXml(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var certificates = new[] { certificate };
|
||||
var xmlDocument = CreateXmlDocument();
|
||||
var expectedXml = xmlDocument.OuterXml;
|
||||
|
||||
// When
|
||||
var encryptedXmlDocument = EncryptXmlDocument(xmlDocument, certificates);
|
||||
var decryptedXmlDocument = DecryptXmlDocument(encryptedXmlDocument);
|
||||
var actualXml = decryptedXmlDocument.OuterXml;
|
||||
|
||||
// Then
|
||||
Assert.AreEqual(expectedXml, actualXml);
|
||||
}
|
||||
|
||||
private static XmlDocument CreateXmlDocument()
|
||||
{
|
||||
var document = new XmlDocument();
|
||||
document.LoadXml(Resources.EncryptedXmlExample);
|
||||
return document;
|
||||
}
|
||||
|
||||
private static XmlDocument EncryptXmlDocument(XmlDocument xmlDocument, IEnumerable<X509Certificate2> certificates)
|
||||
{
|
||||
// Создание объекта для шифрации XML
|
||||
var encryptedXml = new GostEncryptedXml();
|
||||
|
||||
// Поиск элементов для шифрации
|
||||
var elements = xmlDocument.SelectNodes("//SomeElement[@Encrypt='true']");
|
||||
|
||||
if (elements != null)
|
||||
{
|
||||
var elementIndex = 0;
|
||||
|
||||
foreach (XmlElement element in elements)
|
||||
{
|
||||
// Формирование элемента EncryptedData
|
||||
var elementEncryptedData = new EncryptedData();
|
||||
elementEncryptedData.Id = "EncryptedElement" + elementIndex++;
|
||||
elementEncryptedData.Type = EncryptedXml.XmlEncElementUrl;
|
||||
elementEncryptedData.KeyInfo = new KeyInfo();
|
||||
|
||||
using (var sessionKey = new Gost_28147_89_SymmetricAlgorithm())
|
||||
{
|
||||
elementEncryptedData.EncryptionMethod = new EncryptionMethod(sessionKey.AlgorithmName);
|
||||
|
||||
// Шифрация элемента с использованием симметричного ключа
|
||||
var encryptedElement = encryptedXml.EncryptData(element, sessionKey, false);
|
||||
|
||||
foreach (var certificate in certificates)
|
||||
{
|
||||
// Шифрация сессионного ключа с использованием открытого ключа сертификата
|
||||
var encryptedSessionKeyData = GostEncryptedXml.EncryptKey(sessionKey, (GostAsymmetricAlgorithm)certificate.GetPublicKeyAlgorithm());
|
||||
|
||||
// Формирование информации о зашифрованном сессионном ключе
|
||||
var encryptedSessionKey = new EncryptedKey();
|
||||
encryptedSessionKey.CipherData = new CipherData(encryptedSessionKeyData);
|
||||
encryptedSessionKey.EncryptionMethod = new EncryptionMethod(GostEncryptedXml.XmlEncGostCryptoProKeyExportUrl);
|
||||
encryptedSessionKey.AddReference(new DataReference { Uri = "#" + elementEncryptedData.Id });
|
||||
encryptedSessionKey.KeyInfo.AddClause(new KeyInfoX509Data(certificate));
|
||||
|
||||
// Добавление ссылки на зашифрованный ключ, используемый при шифровании данных
|
||||
elementEncryptedData.KeyInfo.AddClause(new KeyInfoEncryptedKey(encryptedSessionKey));
|
||||
}
|
||||
|
||||
// Установка зашифрованных данных у объекта EncryptedData
|
||||
elementEncryptedData.CipherData.CipherValue = encryptedElement;
|
||||
}
|
||||
|
||||
// Замена элемента его зашифрованным представлением
|
||||
GostEncryptedXml.ReplaceElement(element, elementEncryptedData, false);
|
||||
}
|
||||
}
|
||||
|
||||
return xmlDocument;
|
||||
}
|
||||
|
||||
private static XmlDocument DecryptXmlDocument(XmlDocument encryptedXmlDocument)
|
||||
{
|
||||
// Создание объекта для дешифрации XML
|
||||
var encryptedXml = new GostEncryptedXml(encryptedXmlDocument);
|
||||
|
||||
var nsManager = new XmlNamespaceManager(encryptedXmlDocument.NameTable);
|
||||
nsManager.AddNamespace("enc", EncryptedXml.XmlEncNamespaceUrl);
|
||||
|
||||
// Поиск всех зашифрованных XML-элементов
|
||||
var encryptedDataList = encryptedXmlDocument.SelectNodes("//enc:EncryptedData", nsManager);
|
||||
|
||||
if (encryptedDataList != null)
|
||||
{
|
||||
foreach (XmlElement encryptedData in encryptedDataList)
|
||||
{
|
||||
// Загрузка элемента EncryptedData
|
||||
var elementEncryptedData = new EncryptedData();
|
||||
elementEncryptedData.LoadXml(encryptedData);
|
||||
|
||||
// Извлечение симметричный ключ для расшифровки элемента EncryptedData
|
||||
var sessionKey = GetDecryptionKey(elementEncryptedData);
|
||||
|
||||
if (sessionKey != null)
|
||||
{
|
||||
// Расшифровка элемента EncryptedData
|
||||
var decryptedData = encryptedXml.DecryptData(elementEncryptedData, sessionKey);
|
||||
|
||||
// Замена элемента EncryptedData его расшифрованным представлением
|
||||
encryptedXml.ReplaceData(encryptedData, decryptedData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return encryptedXmlDocument;
|
||||
}
|
||||
|
||||
private static SymmetricAlgorithm GetDecryptionKey(EncryptedData encryptedData)
|
||||
{
|
||||
SymmetricAlgorithm sessionKey = null;
|
||||
|
||||
foreach (var keyInfo in encryptedData.KeyInfo)
|
||||
{
|
||||
if (keyInfo is KeyInfoEncryptedKey)
|
||||
{
|
||||
var encryptedKey = ((KeyInfoEncryptedKey)keyInfo).EncryptedKey;
|
||||
|
||||
if (encryptedKey != null)
|
||||
{
|
||||
foreach (var ekKeyInfo in encryptedKey.KeyInfo)
|
||||
{
|
||||
if (ekKeyInfo is KeyInfoX509Data)
|
||||
{
|
||||
var certificates = ((KeyInfoX509Data)ekKeyInfo).Certificates;
|
||||
|
||||
// Поиск закрытого ключа для дешифрации сессионного ключа
|
||||
var privateKey = FindPrivateKey(certificates);
|
||||
|
||||
if (privateKey != null)
|
||||
{
|
||||
// Дешифрация сессионного ключа с использованием закрытого ключа сертификата
|
||||
sessionKey = GostEncryptedXml.DecryptKey(encryptedKey.CipherData.CipherValue, privateKey);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sessionKey;
|
||||
}
|
||||
|
||||
private static GostAsymmetricAlgorithm FindPrivateKey(IEnumerable certificates)
|
||||
{
|
||||
// Какая-то логика поиска закрытого ключа
|
||||
|
||||
GostAsymmetricAlgorithm privateKey = null;
|
||||
|
||||
var store = new X509Store(TestConfig.DefaultStoreName, TestConfig.DefaultStoreLocation);
|
||||
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
|
||||
var storeCertificates = store.Certificates;
|
||||
store.Close();
|
||||
|
||||
foreach (X509Certificate2 certificate in certificates)
|
||||
{
|
||||
var index = storeCertificates.IndexOf(certificate);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
privateKey = storeCertificates[index].GetPrivateKeyAlgorithm() as GostAsymmetricAlgorithm;
|
||||
|
||||
if (privateKey != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return privateKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Xml;
|
||||
|
||||
using GostCryptography.Tests.Properties;
|
||||
using GostCryptography.Xml;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Xml.Encrypt
|
||||
{
|
||||
/// <summary>
|
||||
/// Шифрация и дешифрация XML документа с использованием сертификата.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает XML-документ, выборочно шифрует элементы данного документа с использованием сертификата,
|
||||
/// а затем дешифрует полученный зашифрованный документ.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Шифрация и дешифрация XML документа с использованием сертификата")]
|
||||
public sealed class EncryptedXmlCertificateTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_Certificates))]
|
||||
public void ShouldEncryptXml(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var xmlDocument = CreateXmlDocument();
|
||||
var expectedXml = xmlDocument.OuterXml;
|
||||
|
||||
// When
|
||||
var encryptedXmlDocument = EncryptXmlDocument(xmlDocument, certificate);
|
||||
var decryptedXmlDocument = DecryptXmlDocument(encryptedXmlDocument);
|
||||
var actualXml = decryptedXmlDocument.OuterXml;
|
||||
|
||||
// Then
|
||||
Assert.AreEqual(expectedXml, actualXml);
|
||||
}
|
||||
|
||||
private static XmlDocument CreateXmlDocument()
|
||||
{
|
||||
var document = new XmlDocument();
|
||||
document.LoadXml(Resources.EncryptedXmlExample);
|
||||
return document;
|
||||
}
|
||||
|
||||
private static XmlDocument EncryptXmlDocument(XmlDocument xmlDocument, X509Certificate2 certificate)
|
||||
{
|
||||
// Создание объекта для шифрации XML
|
||||
var encryptedXml = new GostEncryptedXml();
|
||||
|
||||
// Поиск элементов для шифрации
|
||||
var elements = xmlDocument.SelectNodes("//SomeElement[@Encrypt='true']");
|
||||
|
||||
if (elements != null)
|
||||
{
|
||||
foreach (XmlElement element in elements)
|
||||
{
|
||||
// Шифрация элемента
|
||||
var elementEncryptedData = encryptedXml.Encrypt(element, certificate);
|
||||
|
||||
// Замена элемента его зашифрованным представлением
|
||||
GostEncryptedXml.ReplaceElement(element, elementEncryptedData, false);
|
||||
}
|
||||
}
|
||||
|
||||
return xmlDocument;
|
||||
}
|
||||
|
||||
private static XmlDocument DecryptXmlDocument(XmlDocument encryptedXmlDocument)
|
||||
{
|
||||
// Создание объекта для дешифрации XML
|
||||
var encryptedXml = new GostEncryptedXml(encryptedXmlDocument);
|
||||
|
||||
// Расшифровка зашифрованных элементов документа
|
||||
encryptedXml.DecryptDocument();
|
||||
|
||||
return encryptedXmlDocument;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Security.Cryptography.Xml;
|
||||
using System.Xml;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
using GostCryptography.Gost_R3410;
|
||||
using GostCryptography.Tests.Properties;
|
||||
using GostCryptography.Xml;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Xml.Encrypt
|
||||
{
|
||||
/// <summary>
|
||||
/// Шифрация и дешифрация XML с использованием контейнера ключей.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест имитирует обмен данными между условным отправителем, который шифрует заданный XML-документ, и условным получателем, который дешифрует
|
||||
/// зашифрованный XML-документ. Шифрация и дешифрация осуществляется без использования сертификатов. Шифрация осуществляется с использованием
|
||||
/// случайного симметричного ключа, который в свою очередь шифруется с использованием открытого ключа получателя. Соответственно для дешифрации
|
||||
/// данных сначала расшифровывается случайный симметричный ключ с использованием закрытого ключа получателя.
|
||||
///
|
||||
/// Перед началом теста имитируется передача получателем своего открытого ключа отправителю. Для этого получатель извлекает информацию о закрытом
|
||||
/// ключе из контейнера ключей, формирует закрытый ключ для дешифрации XML и условно передает (экспортирует) отправителю информацию о своем открытом
|
||||
/// ключе. Отправитель в свою очередь принимает (импортирует) от получателя информацию о его открытом ключе и формирует открытый ключ для шифрации XML.
|
||||
///
|
||||
/// Тест создает XML-документ, выборочно шифрует элементы данного документа с использованием случайного симметричного ключа, а затем дешифрует
|
||||
/// полученный зашифрованный документ. Случайный симметричного ключ в свою очередь шифруется открытым асимметричным ключом получателя и в зашифрованном
|
||||
/// виде добавляется в зашифрованный документ.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Шифрация и дешифрация XML с использованием контейнера ключей")]
|
||||
public class EncryptedXmlKeyContainerTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_2001_Certificates))]
|
||||
public void ShouldEncryptXmlWithGost_R3410_2001(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
|
||||
var certificate = testCase.Certificate;
|
||||
|
||||
// Получатель экспортирует отправителю информацию о своем открытом ключе
|
||||
var keyContainer = certificate.GetPrivateKeyInfo();
|
||||
var privateKey = new Gost_R3410_2001_AsymmetricAlgorithm(keyContainer);
|
||||
var publicKeyInfo = privateKey.ExportParameters(false);
|
||||
|
||||
// Отправитель импортирует от получателя информацию о его открытом ключе
|
||||
var publicKey = new Gost_R3410_2001_AsymmetricAlgorithm();
|
||||
publicKey.ImportParameters(publicKeyInfo);
|
||||
|
||||
var xmlDocument = CreateXmlDocument();
|
||||
var expectedXml = xmlDocument.OuterXml;
|
||||
|
||||
// When
|
||||
var encryptedXmlDocument = EncryptXmlDocument(xmlDocument, publicKey);
|
||||
var decryptedXmlDocument = DecryptXmlDocument(encryptedXmlDocument, privateKey);
|
||||
var actualXml = decryptedXmlDocument.OuterXml;
|
||||
|
||||
// Then
|
||||
Assert.AreEqual(expectedXml, actualXml);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_2012_256_Certificates))]
|
||||
public void ShouldEncryptXmlWithGost_R3410_2012_256(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
|
||||
var certificate = testCase.Certificate;
|
||||
|
||||
// Получатель экспортирует отправителю информацию о своем открытом ключе
|
||||
var keyContainer = certificate.GetPrivateKeyInfo();
|
||||
var privateKey = new Gost_R3410_2012_256_AsymmetricAlgorithm(keyContainer);
|
||||
var publicKeyInfo = privateKey.ExportParameters(false);
|
||||
|
||||
// Отправитель импортирует от получателя информацию о его открытом ключе
|
||||
var publicKey = new Gost_R3410_2012_256_AsymmetricAlgorithm();
|
||||
publicKey.ImportParameters(publicKeyInfo);
|
||||
|
||||
var xmlDocument = CreateXmlDocument();
|
||||
var expectedXml = xmlDocument.OuterXml;
|
||||
|
||||
// When
|
||||
var encryptedXmlDocument = EncryptXmlDocument(xmlDocument, publicKey);
|
||||
var decryptedXmlDocument = DecryptXmlDocument(encryptedXmlDocument, privateKey);
|
||||
var actualXml = decryptedXmlDocument.OuterXml;
|
||||
|
||||
// Then
|
||||
Assert.AreEqual(expectedXml, actualXml);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_2012_512_Certificates))]
|
||||
public void ShouldEncryptXmlWithGost_R3410_2012_512(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
|
||||
var certificate = testCase.Certificate;
|
||||
|
||||
// Получатель экспортирует отправителю информацию о своем открытом ключе
|
||||
var keyContainer = certificate.GetPrivateKeyInfo();
|
||||
var privateKey = new Gost_R3410_2012_512_AsymmetricAlgorithm(keyContainer);
|
||||
var publicKeyInfo = privateKey.ExportParameters(false);
|
||||
|
||||
// Отправитель импортирует от получателя информацию о его открытом ключе
|
||||
var publicKey = new Gost_R3410_2012_512_AsymmetricAlgorithm();
|
||||
publicKey.ImportParameters(publicKeyInfo);
|
||||
|
||||
var xmlDocument = CreateXmlDocument();
|
||||
var expectedXml = xmlDocument.OuterXml;
|
||||
|
||||
// When
|
||||
var encryptedXmlDocument = EncryptXmlDocument(xmlDocument, publicKey);
|
||||
var decryptedXmlDocument = DecryptXmlDocument(encryptedXmlDocument, privateKey);
|
||||
var actualXml = decryptedXmlDocument.OuterXml;
|
||||
|
||||
// Then
|
||||
Assert.AreEqual(expectedXml, actualXml);
|
||||
}
|
||||
|
||||
private static XmlDocument CreateXmlDocument()
|
||||
{
|
||||
var document = new XmlDocument();
|
||||
document.LoadXml(Resources.EncryptedXmlExample);
|
||||
return document;
|
||||
}
|
||||
|
||||
private static XmlDocument EncryptXmlDocument(XmlDocument xmlDocument, GostAsymmetricAlgorithm publicKey)
|
||||
{
|
||||
// Создание объекта для шифрации XML
|
||||
var encryptedXml = new GostEncryptedXml(publicKey.ProviderType);
|
||||
|
||||
// Поиск элементов для шифрации
|
||||
var elements = xmlDocument.SelectNodes("//SomeElement[@Encrypt='true']");
|
||||
|
||||
if (elements != null)
|
||||
{
|
||||
var elementIndex = 0;
|
||||
|
||||
foreach (XmlElement element in elements)
|
||||
{
|
||||
// Создание случайного сессионного ключа
|
||||
using (var sessionKey = new Gost_28147_89_SymmetricAlgorithm(publicKey.ProviderType))
|
||||
{
|
||||
// Шифрация элемента
|
||||
var encryptedData = encryptedXml.EncryptData(element, sessionKey, false);
|
||||
|
||||
// Шифрация сессионного ключа с использованием публичного асимметричного ключа
|
||||
var encryptedSessionKeyData = GostEncryptedXml.EncryptKey(sessionKey, publicKey);
|
||||
|
||||
// Формирование элемента EncryptedData
|
||||
var elementEncryptedData = new EncryptedData();
|
||||
elementEncryptedData.Id = "EncryptedElement" + elementIndex++;
|
||||
elementEncryptedData.Type = EncryptedXml.XmlEncElementUrl;
|
||||
elementEncryptedData.EncryptionMethod = new EncryptionMethod(sessionKey.AlgorithmName);
|
||||
elementEncryptedData.CipherData.CipherValue = encryptedData;
|
||||
elementEncryptedData.KeyInfo = new KeyInfo();
|
||||
|
||||
// Формирование информации о зашифрованном сессионном ключе
|
||||
var encryptedSessionKey = new EncryptedKey();
|
||||
encryptedSessionKey.CipherData = new CipherData(encryptedSessionKeyData);
|
||||
encryptedSessionKey.EncryptionMethod = new EncryptionMethod(publicKey.KeyExchangeAlgorithm);
|
||||
encryptedSessionKey.AddReference(new DataReference { Uri = "#" + elementEncryptedData.Id });
|
||||
encryptedSessionKey.KeyInfo.AddClause(new KeyInfoName { Value = "KeyName1" });
|
||||
|
||||
// Добавление ссылки на зашифрованный ключ, используемый при шифровании данных
|
||||
elementEncryptedData.KeyInfo.AddClause(new KeyInfoEncryptedKey(encryptedSessionKey));
|
||||
|
||||
// Замена элемента его зашифрованным представлением
|
||||
GostEncryptedXml.ReplaceElement(element, elementEncryptedData, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return xmlDocument;
|
||||
}
|
||||
|
||||
private static XmlDocument DecryptXmlDocument(XmlDocument encryptedXmlDocument, GostAsymmetricAlgorithm privateKey)
|
||||
{
|
||||
// Создание объекта для дешифрации XML
|
||||
var encryptedXml = new GostEncryptedXml(privateKey.ProviderType, encryptedXmlDocument);
|
||||
|
||||
// Добавление ссылки на приватный асимметричный ключ
|
||||
encryptedXml.AddKeyNameMapping("KeyName1", privateKey);
|
||||
|
||||
// Расшифровка зашифрованных элементов документа
|
||||
encryptedXml.DecryptDocument();
|
||||
|
||||
return encryptedXmlDocument;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
using System.Security.Cryptography.Xml;
|
||||
using System.Xml;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
using GostCryptography.Tests.Properties;
|
||||
using GostCryptography.Xml;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Xml.Encrypt
|
||||
{
|
||||
/// <summary>
|
||||
/// Шифрация и дешифрация XML с использованием случайного сессионного ключа.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает XML-документ, выборочно шифрует элементы данного документа с использованием случайного симметричного ключа,
|
||||
/// а затем дешифрует полученный зашифрованный документ. Случайный симметричного ключ в свою очередь шифруется общим симметричным
|
||||
/// ключом и в зашифрованном виде добавляется в зашифрованный документ.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Шифрация и дешифрация XML с использованием случайного сессионного ключа")]
|
||||
public class EncryptedXmlSessionKey
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldEncryptXml(ProviderType providerType)
|
||||
{
|
||||
// Given
|
||||
var sharedKey = new Gost_28147_89_SymmetricAlgorithm(providerType);
|
||||
var xmlDocument = CreateXmlDocument();
|
||||
var expectedXml = xmlDocument.OuterXml;
|
||||
|
||||
// When
|
||||
var encryptedXmlDocument = EncryptXmlDocument(xmlDocument, sharedKey);
|
||||
var decryptedXmlDocument = DecryptXmlDocument(encryptedXmlDocument, sharedKey);
|
||||
var actualXml = decryptedXmlDocument.OuterXml;
|
||||
|
||||
// Then
|
||||
Assert.AreEqual(expectedXml, actualXml);
|
||||
}
|
||||
|
||||
private static XmlDocument CreateXmlDocument()
|
||||
{
|
||||
var document = new XmlDocument();
|
||||
document.LoadXml(Resources.EncryptedXmlExample);
|
||||
return document;
|
||||
}
|
||||
|
||||
private static XmlDocument EncryptXmlDocument(XmlDocument xmlDocument, GostSymmetricAlgorithm sharedKey)
|
||||
{
|
||||
// Создание объекта для шифрации XML
|
||||
var encryptedXml = new GostEncryptedXml(sharedKey.ProviderType);
|
||||
|
||||
// Поиск элементов для шифрации
|
||||
var elements = xmlDocument.SelectNodes("//SomeElement[@Encrypt='true']");
|
||||
|
||||
if (elements != null)
|
||||
{
|
||||
var elementIndex = 0;
|
||||
|
||||
foreach (XmlElement element in elements)
|
||||
{
|
||||
// Создание случайного сессионного ключа
|
||||
using (var sessionKey = new Gost_28147_89_SymmetricAlgorithm(sharedKey.ProviderType))
|
||||
{
|
||||
// Шифрация элемента
|
||||
var encryptedData = encryptedXml.EncryptData(element, sessionKey, false);
|
||||
|
||||
// Шифрация сессионного ключа с использованием общего симметричного ключа
|
||||
var encryptedSessionKeyData = GostEncryptedXml.EncryptKey(sessionKey, sharedKey, GostKeyExchangeExportMethod.CryptoProKeyExport);
|
||||
|
||||
// Формирование элемента EncryptedData
|
||||
var elementEncryptedData = new EncryptedData();
|
||||
elementEncryptedData.Id = "EncryptedElement" + elementIndex++;
|
||||
elementEncryptedData.Type = EncryptedXml.XmlEncElementUrl;
|
||||
elementEncryptedData.EncryptionMethod = new EncryptionMethod(sessionKey.AlgorithmName);
|
||||
elementEncryptedData.CipherData.CipherValue = encryptedData;
|
||||
elementEncryptedData.KeyInfo = new KeyInfo();
|
||||
|
||||
// Формирование информации о зашифрованном сессионном ключе
|
||||
var encryptedSessionKey = new EncryptedKey();
|
||||
encryptedSessionKey.CipherData = new CipherData(encryptedSessionKeyData);
|
||||
encryptedSessionKey.EncryptionMethod = new EncryptionMethod(GostEncryptedXml.XmlEncGostCryptoProKeyExportUrl);
|
||||
encryptedSessionKey.AddReference(new DataReference { Uri = "#" + elementEncryptedData.Id });
|
||||
encryptedSessionKey.KeyInfo.AddClause(new KeyInfoName { Value = "SharedKey1" });
|
||||
|
||||
// Добавление ссылки на зашифрованный ключ, используемый при шифровании данных
|
||||
elementEncryptedData.KeyInfo.AddClause(new KeyInfoEncryptedKey(encryptedSessionKey));
|
||||
|
||||
// Замена элемента его зашифрованным представлением
|
||||
GostEncryptedXml.ReplaceElement(element, elementEncryptedData, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return xmlDocument;
|
||||
}
|
||||
|
||||
private static XmlDocument DecryptXmlDocument(XmlDocument encryptedXmlDocument, GostSymmetricAlgorithm sharedKey)
|
||||
{
|
||||
// Создание объекта для дешифрации XML
|
||||
var encryptedXml = new GostEncryptedXml(sharedKey.ProviderType, encryptedXmlDocument);
|
||||
|
||||
// Добавление ссылки на общий симметричный ключ
|
||||
encryptedXml.AddKeyNameMapping("SharedKey1", sharedKey);
|
||||
|
||||
// Расшифровка зашифрованных элементов документа
|
||||
encryptedXml.DecryptDocument();
|
||||
|
||||
return encryptedXmlDocument;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
using System.Security.Cryptography.Xml;
|
||||
using System.Xml;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
using GostCryptography.Tests.Properties;
|
||||
using GostCryptography.Xml;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Xml.Encrypt
|
||||
{
|
||||
/// <summary>
|
||||
/// Шифрация и дешифрация XML с использованием общего симметричного ключа.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает XML-документ, выборочно шифрует элементы данного документа с использованием общего симметричного ключа,
|
||||
/// а затем дешифрует полученный зашифрованный документ.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Шифрация и дешифрация XML с использованием общего симметричного ключа")]
|
||||
public sealed class EncryptedXmlSharedKeyTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Providers))]
|
||||
public void ShouldEncryptXml(ProviderType providerType)
|
||||
{
|
||||
// Given
|
||||
var sharedKey = new Gost_28147_89_SymmetricAlgorithm(providerType);
|
||||
var xmlDocument = CreateXmlDocument();
|
||||
var expectedXml = xmlDocument.OuterXml;
|
||||
|
||||
// When
|
||||
var encryptedXmlDocument = EncryptXmlDocument(xmlDocument, sharedKey);
|
||||
var decryptedXmlDocument = DecryptXmlDocument(encryptedXmlDocument, sharedKey);
|
||||
var actualXml = decryptedXmlDocument.OuterXml;
|
||||
|
||||
// Then
|
||||
Assert.AreEqual(expectedXml, actualXml);
|
||||
}
|
||||
|
||||
private static XmlDocument CreateXmlDocument()
|
||||
{
|
||||
var document = new XmlDocument();
|
||||
document.LoadXml(Resources.EncryptedXmlExample);
|
||||
return document;
|
||||
}
|
||||
|
||||
private static XmlDocument EncryptXmlDocument(XmlDocument xmlDocument, Gost_28147_89_SymmetricAlgorithm sharedKey)
|
||||
{
|
||||
// Создание объекта для шифрации XML
|
||||
var encryptedXml = new GostEncryptedXml(sharedKey.ProviderType);
|
||||
|
||||
// Поиск элементов для шифрации
|
||||
var elements = xmlDocument.SelectNodes("//SomeElement[@Encrypt='true']");
|
||||
|
||||
if (elements != null)
|
||||
{
|
||||
foreach (XmlElement element in elements)
|
||||
{
|
||||
// Шифрация элемента
|
||||
var encryptedData = encryptedXml.EncryptData(element, sharedKey, false);
|
||||
|
||||
// Формирование элемента EncryptedData
|
||||
var elementEncryptedData = new EncryptedData();
|
||||
elementEncryptedData.Type = EncryptedXml.XmlEncElementUrl;
|
||||
elementEncryptedData.EncryptionMethod = new EncryptionMethod(sharedKey.AlgorithmName);
|
||||
elementEncryptedData.CipherData.CipherValue = encryptedData;
|
||||
|
||||
// Замена элемента его зашифрованным представлением
|
||||
GostEncryptedXml.ReplaceElement(element, elementEncryptedData, false);
|
||||
}
|
||||
}
|
||||
|
||||
return xmlDocument;
|
||||
}
|
||||
|
||||
private static XmlDocument DecryptXmlDocument(XmlDocument encryptedXmlDocument, Gost_28147_89_SymmetricAlgorithm sharedKey)
|
||||
{
|
||||
// Создание объекта для дешифрации XML
|
||||
var encryptedXml = new GostEncryptedXml(sharedKey.ProviderType, encryptedXmlDocument);
|
||||
|
||||
var nsManager = new XmlNamespaceManager(encryptedXmlDocument.NameTable);
|
||||
nsManager.AddNamespace("enc", EncryptedXml.XmlEncNamespaceUrl);
|
||||
|
||||
// Поиск всех зашифрованных XML-элементов
|
||||
var encryptedDataList = encryptedXmlDocument.SelectNodes("//enc:EncryptedData", nsManager);
|
||||
|
||||
if (encryptedDataList != null)
|
||||
{
|
||||
foreach (XmlElement encryptedData in encryptedDataList)
|
||||
{
|
||||
// Загрузка элемента EncryptedData
|
||||
var elementEncryptedData = new EncryptedData();
|
||||
elementEncryptedData.LoadXml(encryptedData);
|
||||
|
||||
// Расшифровка элемента EncryptedData
|
||||
var decryptedData = encryptedXml.DecryptData(elementEncryptedData, sharedKey);
|
||||
|
||||
// Замена элемента EncryptedData его расшифрованным представлением
|
||||
encryptedXml.ReplaceData(encryptedData, decryptedData);
|
||||
}
|
||||
}
|
||||
|
||||
return encryptedXmlDocument;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Security.Cryptography.Xml;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
using GostCryptography.Tests.Properties;
|
||||
using GostCryptography.Xml;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Xml.Encrypt
|
||||
{
|
||||
/// <summary>
|
||||
/// Шифрация и дешифрация XML документа с использованием сертификата и алгоритма ГОСТ Р 34.12-2015 Кузнечик.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает XML-документ, шифрует его целиком с использованием сертификата, а затем дешифрует зашифрованный документ.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Шифрация и дешифрация XML документа с использованием сертификата и алгоритма ГОСТ Р 34.12-2015 Кузнечик")]
|
||||
public sealed class KuznyechikEncryptedXmlCertificateTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_Certificates))]
|
||||
public void ShouldEncryptXml(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var xmlDocument = CreateXmlDocument();
|
||||
var expectedXml = xmlDocument.OuterXml.Replace("\r\n", "\n");
|
||||
|
||||
// When
|
||||
var encryptedXmlDocument = EncryptXmlDocument(xmlDocument, certificate);
|
||||
var decryptedXmlDocument = DecryptXmlDocument(encryptedXmlDocument);
|
||||
var actualXml = decryptedXmlDocument.OuterXml.Replace("\r\n", "\n");
|
||||
|
||||
// Then
|
||||
Assert.AreEqual(expectedXml, actualXml);
|
||||
}
|
||||
|
||||
private static XmlDocument CreateXmlDocument()
|
||||
{
|
||||
var document = new XmlDocument();
|
||||
document.LoadXml(Resources.EncryptedXmlExample);
|
||||
return document;
|
||||
}
|
||||
|
||||
private static XmlDocument EncryptXmlDocument(XmlDocument xmlDocument, X509Certificate2 certificate)
|
||||
{
|
||||
var publicKeyAlgorithm = (GostAsymmetricAlgorithm)certificate.GetPublicKeyAlgorithm();
|
||||
|
||||
using (var sessionKey = new Gost_3412_K_SymmetricAlgorithm(publicKeyAlgorithm.ProviderType))
|
||||
{
|
||||
var encryptedSessionKeyData = GostEncryptedXml.EncryptKey(sessionKey, publicKeyAlgorithm);
|
||||
|
||||
var encryptedSessionKey = new EncryptedKey
|
||||
{
|
||||
CipherData = new CipherData(encryptedSessionKeyData),
|
||||
EncryptionMethod = new EncryptionMethod(publicKeyAlgorithm.KeyExchangeAlgorithm),
|
||||
};
|
||||
|
||||
encryptedSessionKey.KeyInfo.AddClause(new KeyInfoX509Data(certificate));
|
||||
|
||||
var elementEncryptedData = new EncryptedData
|
||||
{
|
||||
EncryptionMethod = new EncryptionMethod(sessionKey.AlgorithmName),
|
||||
};
|
||||
|
||||
var encryptedXml = new GostEncryptedXml();
|
||||
var xmlBytes = Encoding.UTF8.GetBytes(xmlDocument.OuterXml);
|
||||
var encryptedData = encryptedXml.EncryptData(xmlBytes, sessionKey);
|
||||
|
||||
elementEncryptedData.CipherData.CipherValue = encryptedData;
|
||||
elementEncryptedData.KeyInfo.AddClause(new KeyInfoEncryptedKey(encryptedSessionKey));
|
||||
|
||||
GostEncryptedXml.ReplaceElement(xmlDocument.DocumentElement, elementEncryptedData, false);
|
||||
}
|
||||
|
||||
return xmlDocument;
|
||||
}
|
||||
|
||||
private static XmlDocument DecryptXmlDocument(XmlDocument encryptedXmlDocument)
|
||||
{
|
||||
// Создание объекта для дешифрации XML
|
||||
var encryptedXml = new GostEncryptedXml(encryptedXmlDocument);
|
||||
|
||||
// Расшифровка зашифрованных элементов документа
|
||||
encryptedXml.DecryptDocument();
|
||||
|
||||
return encryptedXmlDocument;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Security.Cryptography.Xml;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_28147_89;
|
||||
using GostCryptography.Tests.Properties;
|
||||
using GostCryptography.Xml;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Xml.Encrypt
|
||||
{
|
||||
/// <summary>
|
||||
/// Шифрация и дешифрация XML документа с использованием сертификата и алгоритма ГОСТ Р 34.12-2015 Магма.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает XML-документ, шифрует его целиком с использованием сертификата, а затем дешифрует зашифрованный документ.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Шифрация и дешифрация XML документа с использованием сертификата и алгоритма ГОСТ Р 34.12-2015 Магма")]
|
||||
public sealed class MagmaEncryptedXmlCertificateTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_Certificates))]
|
||||
public void ShouldEncryptXml(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var xmlDocument = CreateXmlDocument();
|
||||
var expectedXml = xmlDocument.OuterXml.Replace("\r\n", "\n");
|
||||
|
||||
// When
|
||||
var encryptedXmlDocument = EncryptXmlDocument(xmlDocument, certificate);
|
||||
var decryptedXmlDocument = DecryptXmlDocument(encryptedXmlDocument);
|
||||
var actualXml = decryptedXmlDocument.OuterXml.Replace("\r\n", "\n");
|
||||
|
||||
// Then
|
||||
Assert.AreEqual(expectedXml, actualXml);
|
||||
}
|
||||
|
||||
private static XmlDocument CreateXmlDocument()
|
||||
{
|
||||
var document = new XmlDocument();
|
||||
document.LoadXml(Resources.EncryptedXmlExample);
|
||||
return document;
|
||||
}
|
||||
|
||||
private static XmlDocument EncryptXmlDocument(XmlDocument xmlDocument, X509Certificate2 certificate)
|
||||
{
|
||||
var publicKeyAlgorithm = (GostAsymmetricAlgorithm)certificate.GetPublicKeyAlgorithm();
|
||||
|
||||
using (var sessionKey = new Gost_3412_M_SymmetricAlgorithm(publicKeyAlgorithm.ProviderType))
|
||||
{
|
||||
var encryptedSessionKeyData = GostEncryptedXml.EncryptKey(sessionKey, publicKeyAlgorithm);
|
||||
|
||||
var encryptedSessionKey = new EncryptedKey
|
||||
{
|
||||
CipherData = new CipherData(encryptedSessionKeyData),
|
||||
EncryptionMethod = new EncryptionMethod(publicKeyAlgorithm.KeyExchangeAlgorithm),
|
||||
};
|
||||
|
||||
encryptedSessionKey.KeyInfo.AddClause(new KeyInfoX509Data(certificate));
|
||||
|
||||
var elementEncryptedData = new EncryptedData
|
||||
{
|
||||
EncryptionMethod = new EncryptionMethod(sessionKey.AlgorithmName),
|
||||
};
|
||||
|
||||
var encryptedXml = new GostEncryptedXml();
|
||||
var xmlBytes = Encoding.UTF8.GetBytes(xmlDocument.OuterXml);
|
||||
var encryptedData = encryptedXml.EncryptData(xmlBytes, sessionKey);
|
||||
|
||||
elementEncryptedData.CipherData.CipherValue = encryptedData;
|
||||
elementEncryptedData.KeyInfo.AddClause(new KeyInfoEncryptedKey(encryptedSessionKey));
|
||||
|
||||
GostEncryptedXml.ReplaceElement(xmlDocument.DocumentElement, elementEncryptedData, false);
|
||||
}
|
||||
|
||||
return xmlDocument;
|
||||
}
|
||||
|
||||
private static XmlDocument DecryptXmlDocument(XmlDocument encryptedXmlDocument)
|
||||
{
|
||||
// Создание объекта для дешифрации XML
|
||||
var encryptedXml = new GostEncryptedXml(encryptedXmlDocument);
|
||||
|
||||
// Расшифровка зашифрованных элементов документа
|
||||
encryptedXml.DecryptDocument();
|
||||
|
||||
return encryptedXmlDocument;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Security.Cryptography.Xml;
|
||||
using System.Xml;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Tests.Properties;
|
||||
using GostCryptography.Xml;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Xml.Sign
|
||||
{
|
||||
/// <summary>
|
||||
/// Подпись и проверка подписи XML-документа с использованием сертификата.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает XML-документ, подписывает определенную часть данного документа с использованием сертификата,
|
||||
/// а затем проверяет полученную цифровую подпись.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Подпись и проверка подписи XML-документа с использованием сертификата")]
|
||||
public class SignedXmlCertificateTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_Certificates))]
|
||||
public void ShouldSignXml(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var xmlDocument = CreateXmlDocument();
|
||||
|
||||
// When
|
||||
var signedXmlDocument = SignXmlDocument(xmlDocument, certificate);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(VerifyXmlDocumentSignature(signedXmlDocument));
|
||||
}
|
||||
|
||||
private static XmlDocument CreateXmlDocument()
|
||||
{
|
||||
var document = new XmlDocument();
|
||||
document.LoadXml(Resources.SignedXmlExample);
|
||||
return document;
|
||||
}
|
||||
|
||||
private static XmlDocument SignXmlDocument(XmlDocument xmlDocument, X509Certificate2 certificate)
|
||||
{
|
||||
// Создание подписчика XML-документа
|
||||
var signedXml = new GostSignedXml(xmlDocument);
|
||||
|
||||
// Установка ключа для создания подписи
|
||||
signedXml.SetSigningCertificate(certificate);
|
||||
|
||||
// Ссылка на узел, который нужно подписать, с указанием алгоритма хэширования
|
||||
var dataReference = new Reference { Uri = "#Id1", DigestMethod = GetDigestMethod(certificate) };
|
||||
|
||||
// Установка ссылки на узел
|
||||
signedXml.AddReference(dataReference);
|
||||
|
||||
// Установка информации о сертификате, который использовался для создания подписи
|
||||
var keyInfo = new KeyInfo();
|
||||
keyInfo.AddClause(new KeyInfoX509Data(certificate));
|
||||
signedXml.KeyInfo = keyInfo;
|
||||
|
||||
// Вычисление подписи
|
||||
signedXml.ComputeSignature();
|
||||
|
||||
// Получение XML-представления подписи
|
||||
var signatureXml = signedXml.GetXml();
|
||||
|
||||
// Добавление подписи в исходный документ
|
||||
xmlDocument.DocumentElement.AppendChild(xmlDocument.ImportNode(signatureXml, true));
|
||||
|
||||
return xmlDocument;
|
||||
}
|
||||
|
||||
private static bool VerifyXmlDocumentSignature(XmlDocument signedXmlDocument)
|
||||
{
|
||||
// Создание подписчика XML-документа
|
||||
var signedXml = new GostSignedXml(signedXmlDocument);
|
||||
|
||||
// Поиск узла с подписью
|
||||
var nodeList = signedXmlDocument.GetElementsByTagName("Signature", SignedXml.XmlDsigNamespaceUrl);
|
||||
|
||||
// Загрузка найденной подписи
|
||||
signedXml.LoadXml((XmlElement)nodeList[0]);
|
||||
|
||||
// Проверка подписи
|
||||
return signedXml.CheckSignature();
|
||||
}
|
||||
|
||||
private static string GetDigestMethod(X509Certificate2 certificate)
|
||||
{
|
||||
// Имя алгоритма вычисляем динамически, чтобы сделать код теста универсальным
|
||||
|
||||
using (var publicKey = (GostAsymmetricAlgorithm)certificate.GetPublicKeyAlgorithm())
|
||||
using (var hashAlgorithm = publicKey.CreateHashAlgorithm())
|
||||
{
|
||||
return hashAlgorithm.AlgorithmName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Security.Cryptography.Xml;
|
||||
using System.Xml;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Tests.Properties;
|
||||
using GostCryptography.Xml;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Xml.Sign
|
||||
{
|
||||
/// <summary>
|
||||
/// Подпись и проверка подписи всего XML документа с использованием сертификата
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает XML-документ, подписывает весь документ с использованием сертификата,
|
||||
/// а затем проверяет полученную цифровую подпись.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Подпись и проверка подписи всего XML документа с использованием сертификата")]
|
||||
public class SignedXmlDocumentTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_Certificates))]
|
||||
public void ShouldSignXml(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var xmlDocument = CreateXmlDocument();
|
||||
|
||||
// When
|
||||
var signedXmlDocument = SignXmlDocument(xmlDocument, certificate);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(VerifyXmlDocumentSignature(signedXmlDocument));
|
||||
}
|
||||
|
||||
private static XmlDocument CreateXmlDocument()
|
||||
{
|
||||
var document = new XmlDocument();
|
||||
document.LoadXml(Resources.SignedXmlExample);
|
||||
return document;
|
||||
}
|
||||
|
||||
private static XmlDocument SignXmlDocument(XmlDocument xmlDocument, X509Certificate2 certificate)
|
||||
{
|
||||
// Создание подписчика XML-документа
|
||||
var signedXml = new GostSignedXml(xmlDocument);
|
||||
|
||||
// Установка ключа для создания подписи
|
||||
signedXml.SetSigningCertificate(certificate);
|
||||
|
||||
// Ссылка на весь документ и указание алгоритма хэширования
|
||||
var dataReference = new Reference { Uri = "", DigestMethod = GetDigestMethod(certificate) };
|
||||
|
||||
// Метод преобразования для подписи всего документа
|
||||
dataReference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
|
||||
|
||||
// Установка ссылки на узел
|
||||
signedXml.AddReference(dataReference);
|
||||
|
||||
// Установка информации о сертификате, который использовался для создания подписи
|
||||
var keyInfo = new KeyInfo();
|
||||
keyInfo.AddClause(new KeyInfoX509Data(certificate));
|
||||
signedXml.KeyInfo = keyInfo;
|
||||
|
||||
// Вычисление подписи
|
||||
signedXml.ComputeSignature();
|
||||
|
||||
// Получение XML-представления подписи
|
||||
var signatureXml = signedXml.GetXml();
|
||||
|
||||
// Добавление подписи в исходный документ
|
||||
xmlDocument.DocumentElement.AppendChild(xmlDocument.ImportNode(signatureXml, true));
|
||||
|
||||
return xmlDocument;
|
||||
}
|
||||
|
||||
private static bool VerifyXmlDocumentSignature(XmlDocument signedXmlDocument)
|
||||
{
|
||||
// Создание подписчика XML-документа
|
||||
var signedXml = new GostSignedXml(signedXmlDocument);
|
||||
|
||||
// Поиск узла с подписью
|
||||
var nodeList = signedXmlDocument.GetElementsByTagName("Signature", SignedXml.XmlDsigNamespaceUrl);
|
||||
|
||||
// Загрузка найденной подписи
|
||||
signedXml.LoadXml((XmlElement)nodeList[0]);
|
||||
|
||||
// Проверка подписи
|
||||
return signedXml.CheckSignature();
|
||||
}
|
||||
|
||||
private static string GetDigestMethod(X509Certificate2 certificate)
|
||||
{
|
||||
// Имя алгоритма вычисляем динамически, чтобы сделать код теста универсальным
|
||||
|
||||
using (var publicKey = (GostAsymmetricAlgorithm)certificate.GetPublicKeyAlgorithm())
|
||||
using (var hashAlgorithm = publicKey.CreateHashAlgorithm())
|
||||
{
|
||||
return hashAlgorithm.AlgorithmName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Security.Cryptography.Xml;
|
||||
using System.Xml;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Gost_R3410;
|
||||
using GostCryptography.Tests.Properties;
|
||||
using GostCryptography.Xml;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Xml.Sign
|
||||
{
|
||||
/// <summary>
|
||||
/// Подпись и проверка подписи XML-документа с использованием контейнера ключей.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает XML-документ, подписывает определенную часть данного документа с использованием контейнера ключей,
|
||||
/// а затем проверяет полученную цифровую подпись.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Подпись и проверка подписи XML-документа с использованием контейнера ключей")]
|
||||
public class SignedXmlKeyContainerTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_2001_Certificates))]
|
||||
public void ShouldSignXmlWithGost_R3410_2001(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var keyContainer = certificate.GetPrivateKeyInfo();
|
||||
var signingKey = new Gost_R3410_2001_AsymmetricAlgorithm(keyContainer);
|
||||
var xmlDocument = CreateXmlDocument();
|
||||
|
||||
// When
|
||||
var signedXmlDocument = SignXmlDocument(xmlDocument, new Gost_R3410_2001_KeyValue(signingKey));
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(VerifyXmlDocumentSignature(signedXmlDocument));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_2012_256_Certificates))]
|
||||
public void ShouldSignXmlWithGost_R3410_2012_256(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var keyContainer = certificate.GetPrivateKeyInfo();
|
||||
var signingKey = new Gost_R3410_2012_256_AsymmetricAlgorithm(keyContainer);
|
||||
var xmlDocument = CreateXmlDocument();
|
||||
|
||||
// When
|
||||
var signedXmlDocument = SignXmlDocument(xmlDocument, new Gost_R3410_2012_256_KeyValue(signingKey));
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(VerifyXmlDocumentSignature(signedXmlDocument));
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_2012_512_Certificates))]
|
||||
public void ShouldSignXmlWithGost_R3410_2012_512(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var keyContainer = certificate.GetPrivateKeyInfo();
|
||||
var signingKey = new Gost_R3410_2012_512_AsymmetricAlgorithm(keyContainer);
|
||||
var xmlDocument = CreateXmlDocument();
|
||||
|
||||
// When
|
||||
var signedXmlDocument = SignXmlDocument(xmlDocument, new Gost_R3410_2012_512_KeyValue(signingKey));
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(VerifyXmlDocumentSignature(signedXmlDocument));
|
||||
}
|
||||
|
||||
private static XmlDocument CreateXmlDocument()
|
||||
{
|
||||
var document = new XmlDocument();
|
||||
document.LoadXml(Resources.SignedXmlExample);
|
||||
return document;
|
||||
}
|
||||
|
||||
private static XmlDocument SignXmlDocument(XmlDocument xmlDocument, GostKeyValue keyValue)
|
||||
{
|
||||
var signingKey = keyValue.PublicKey;
|
||||
|
||||
// Создание подписчика XML-документа
|
||||
var signedXml = new GostSignedXml(xmlDocument);
|
||||
|
||||
// Установка ключа для создания подписи
|
||||
signedXml.SigningKey = signingKey;
|
||||
|
||||
// Ссылка на узел, который нужно подписать, с указанием алгоритма хэширования
|
||||
var dataReference = new Reference { Uri = "#Id1", DigestMethod = GetDigestMethod(signingKey) };
|
||||
|
||||
// Установка ссылки на узел
|
||||
signedXml.AddReference(dataReference);
|
||||
|
||||
// Установка информации о ключе, который использовался для создания подписи
|
||||
var keyInfo = new KeyInfo();
|
||||
keyInfo.AddClause(keyValue);
|
||||
signedXml.KeyInfo = keyInfo;
|
||||
|
||||
// Вычисление подписи
|
||||
signedXml.ComputeSignature();
|
||||
|
||||
// Получение XML-представления подписи
|
||||
var signatureXml = signedXml.GetXml();
|
||||
|
||||
// Добавление подписи в исходный документ
|
||||
xmlDocument.DocumentElement.AppendChild(xmlDocument.ImportNode(signatureXml, true));
|
||||
|
||||
return xmlDocument;
|
||||
}
|
||||
|
||||
private static bool VerifyXmlDocumentSignature(XmlDocument signedXmlDocument)
|
||||
{
|
||||
// Создание подписчика XML-документа
|
||||
var signedXml = new GostSignedXml(signedXmlDocument);
|
||||
|
||||
// Поиск узла с подписью
|
||||
var nodeList = signedXmlDocument.GetElementsByTagName("Signature", SignedXml.XmlDsigNamespaceUrl);
|
||||
|
||||
// Загрузка найденной подписи
|
||||
signedXml.LoadXml((XmlElement)nodeList[0]);
|
||||
|
||||
// Проверка подписи
|
||||
return signedXml.CheckSignature();
|
||||
}
|
||||
|
||||
private static string GetDigestMethod(GostAsymmetricAlgorithm signingKey)
|
||||
{
|
||||
// Имя алгоритма вычисляем динамически, чтобы сделать код теста универсальным
|
||||
|
||||
using (var hashAlgorithm = signingKey.CreateHashAlgorithm())
|
||||
{
|
||||
return hashAlgorithm.AlgorithmName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Security.Cryptography.Xml;
|
||||
using System.Xml;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Tests.Properties;
|
||||
using GostCryptography.Xml;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Xml.Sign
|
||||
{
|
||||
/// <summary>
|
||||
/// Подпись и проверка подписи запроса к сервису СМЭВ (Система межведомственного электронного взаимодействия).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает запрос к сервису СМЭВ, подписывает определенную часть данного запроса с использованием сертификата,
|
||||
/// а затем проверяет полученную цифровую подпись.
|
||||
/// </remarks>
|
||||
[TestFixture(Description = "Подпись и проверка подписи запроса к сервису СМЭВ (Система межведомственного электронного взаимодействия)")]
|
||||
public sealed class SignedXmlSmevTest
|
||||
{
|
||||
private const string WsSecurityExtNamespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
|
||||
private const string WsSecurityUtilityNamespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
|
||||
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_Certificates))]
|
||||
public void ShouldSignXml(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var smevRequest = CreateSmevRequest();
|
||||
|
||||
// When
|
||||
var signedXmlDocument = SignSmevRequest(smevRequest, certificate);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(VerifySmevRequestSignature(signedXmlDocument));
|
||||
}
|
||||
|
||||
private static XmlDocument CreateSmevRequest()
|
||||
{
|
||||
var document = new XmlDocument();
|
||||
document.LoadXml(Resources.SmevExample);
|
||||
return document;
|
||||
}
|
||||
|
||||
private static XmlDocument SignSmevRequest(XmlDocument smevRequest, X509Certificate2 certificate)
|
||||
{
|
||||
// Создание подписчика XML-документа
|
||||
var signedXml = new GostSignedXml(smevRequest) { GetIdElementHandler = GetSmevIdElement };
|
||||
|
||||
// Установка ключа для создания подписи
|
||||
signedXml.SetSigningCertificate(certificate);
|
||||
|
||||
// Ссылка на узел, который нужно подписать, с указанием алгоритма хэширования
|
||||
var dataReference = new Reference { Uri = "#body", DigestMethod = GetDigestMethod(certificate) };
|
||||
|
||||
// Метод преобразования, применяемый к данным перед их подписью (в соответствии с методическими рекомендациями СМЭВ)
|
||||
var dataTransform = new XmlDsigExcC14NTransform();
|
||||
dataReference.AddTransform(dataTransform);
|
||||
|
||||
// Установка ссылки на узел
|
||||
signedXml.AddReference(dataReference);
|
||||
|
||||
// Установка алгоритма нормализации узла SignedInfo (в соответствии с методическими рекомендациями СМЭВ)
|
||||
signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
|
||||
|
||||
// Установка алгоритма хэширования (в соответствии с методическими рекомендациями СМЭВ)
|
||||
signedXml.SignedInfo.SignatureMethod = GetSignatureMethod(certificate);
|
||||
|
||||
// Вычисление подписи
|
||||
signedXml.ComputeSignature();
|
||||
|
||||
// Получение XML-представления подписи
|
||||
var signatureXml = signedXml.GetXml();
|
||||
|
||||
// Добавление подписи в исходный документ
|
||||
smevRequest.GetElementsByTagName("ds:Signature")[0].PrependChild(smevRequest.ImportNode(signatureXml.GetElementsByTagName("SignatureValue")[0], true));
|
||||
smevRequest.GetElementsByTagName("ds:Signature")[0].PrependChild(smevRequest.ImportNode(signatureXml.GetElementsByTagName("SignedInfo")[0], true));
|
||||
smevRequest.GetElementsByTagName("wsse:BinarySecurityToken")[0].InnerText = Convert.ToBase64String(certificate.RawData);
|
||||
|
||||
return smevRequest;
|
||||
}
|
||||
|
||||
private static bool VerifySmevRequestSignature(XmlDocument signedSmevRequest)
|
||||
{
|
||||
// Создание подписчика XML-документа
|
||||
var signedXml = new GostSignedXml(signedSmevRequest) { GetIdElementHandler = GetSmevIdElement };
|
||||
|
||||
// Поиск узла с подписью
|
||||
var nodeList = signedSmevRequest.GetElementsByTagName("Signature", SignedXml.XmlDsigNamespaceUrl);
|
||||
|
||||
// Загрузка найденной подписи
|
||||
signedXml.LoadXml((XmlElement)nodeList[0]);
|
||||
|
||||
// Поиск ссылки на BinarySecurityToken
|
||||
var references = signedXml.KeyInfo.GetXml().GetElementsByTagName("Reference", WsSecurityExtNamespace);
|
||||
|
||||
if (references.Count > 0)
|
||||
{
|
||||
// Определение ссылки на сертификат (ссылка на узел документа)
|
||||
var binaryTokenReference = ((XmlElement)references[0]).GetAttribute("URI");
|
||||
|
||||
if (!string.IsNullOrEmpty(binaryTokenReference) && binaryTokenReference[0] == '#')
|
||||
{
|
||||
// Поиск элемента с закодированным в Base64 сертификатом
|
||||
var binaryTokenElement = signedXml.GetIdElement(signedSmevRequest, binaryTokenReference.Substring(1));
|
||||
|
||||
if (binaryTokenElement != null)
|
||||
{
|
||||
// Загрузка сертификата, который был использован для подписи
|
||||
var certificate = new X509Certificate2(Convert.FromBase64String(binaryTokenElement.InnerText));
|
||||
|
||||
// Проверка подписи
|
||||
return signedXml.CheckSignature(certificate.GetPublicKeyAlgorithm());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static XmlElement GetSmevIdElement(XmlDocument document, string idValue)
|
||||
{
|
||||
var namespaceManager = new XmlNamespaceManager(document.NameTable);
|
||||
namespaceManager.AddNamespace("wsu", WsSecurityUtilityNamespace);
|
||||
|
||||
return document.SelectSingleNode("//*[@wsu:Id='" + idValue + "']", namespaceManager) as XmlElement;
|
||||
}
|
||||
|
||||
private static string GetSignatureMethod(X509Certificate2 certificate)
|
||||
{
|
||||
// Имя алгоритма вычисляем динамически, чтобы сделать код теста универсальным
|
||||
|
||||
using (var publicKey = (GostAsymmetricAlgorithm)certificate.GetPublicKeyAlgorithm())
|
||||
{
|
||||
return publicKey.SignatureAlgorithm;
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetDigestMethod(X509Certificate2 certificate)
|
||||
{
|
||||
// Имя алгоритма вычисляем динамически, чтобы сделать код теста универсальным
|
||||
|
||||
using (var publicKey = (GostAsymmetricAlgorithm)certificate.GetPublicKeyAlgorithm())
|
||||
using (var hashAlgorithm = publicKey.CreateHashAlgorithm())
|
||||
{
|
||||
return hashAlgorithm.AlgorithmName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Security.Cryptography.Xml;
|
||||
using System.Xml;
|
||||
|
||||
using GostCryptography.Base;
|
||||
using GostCryptography.Tests.Properties;
|
||||
using GostCryptography.Xml;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace GostCryptography.Tests.Xml.Sign
|
||||
{
|
||||
/// <summary>
|
||||
/// Подпись и проверка подписи XML-документа с предварительным XSLT-преобразованием подписываемых данных.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Тест создает XML-документ, подписывает определенную часть данного документа с использованием сертификата,
|
||||
/// предварительно осуществляя XSLT-преобразование подписываемых данных, а затем проверяет полученную цифровую подпись.
|
||||
/// </remarks>
|
||||
[Ignore("TODO: Нужно произвести диагностику с подключением логирования")]
|
||||
[TestFixture(Description = "Подпись и проверка подписи XML-документа с предварительным XSLT-преобразованием подписываемых данных")]
|
||||
public sealed class SignedXmlTransformTest
|
||||
{
|
||||
[Test]
|
||||
[TestCaseSource(typeof(TestConfig), nameof(TestConfig.Gost_R3410_Certificates))]
|
||||
public void ShouldSignXml(TestCertificateInfo testCase)
|
||||
{
|
||||
// Given
|
||||
var certificate = testCase.Certificate;
|
||||
var xmlDocument = CreateXmlDocument();
|
||||
|
||||
// When
|
||||
var signedXmlDocument = SignXmlDocument(xmlDocument, certificate);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(VerifyXmlDocumentSignature(signedXmlDocument));
|
||||
}
|
||||
|
||||
private static XmlDocument CreateXmlDocument()
|
||||
{
|
||||
var document = new XmlDocument();
|
||||
document.LoadXml(Resources.SignedXmlExample);
|
||||
return document;
|
||||
}
|
||||
|
||||
private static XmlDocument SignXmlDocument(XmlDocument xmlDocument, X509Certificate2 certificate)
|
||||
{
|
||||
// Создание подписчика XML-документа
|
||||
var signedXml = new GostSignedXml(xmlDocument);
|
||||
|
||||
// Установка ключа для создания подписи
|
||||
signedXml.SetSigningCertificate(certificate);
|
||||
|
||||
// Ссылка на узел, который нужно подписать, с указанием алгоритма хэширования
|
||||
var dataReference = new Reference { Uri = "#Id1", DigestMethod = GetDigestMethod(certificate) };
|
||||
|
||||
// Метод преобразования, применяемый к данным перед их подписью
|
||||
var dataTransform = CreateDataTransform();
|
||||
dataReference.AddTransform(dataTransform);
|
||||
|
||||
// Установка ссылки на узел
|
||||
signedXml.AddReference(dataReference);
|
||||
|
||||
// Установка информации о сертификате, который использовался для создания подписи
|
||||
var keyInfo = new KeyInfo();
|
||||
keyInfo.AddClause(new KeyInfoX509Data(certificate));
|
||||
signedXml.KeyInfo = keyInfo;
|
||||
|
||||
// Вычисление подписи
|
||||
signedXml.ComputeSignature();
|
||||
|
||||
// Получение XML-представления подписи
|
||||
var signatureXml = signedXml.GetXml();
|
||||
|
||||
// Добавление подписи в исходный документ
|
||||
xmlDocument.DocumentElement.AppendChild(xmlDocument.ImportNode(signatureXml, true));
|
||||
|
||||
return xmlDocument;
|
||||
}
|
||||
|
||||
private static XmlDsigXsltTransform CreateDataTransform()
|
||||
{
|
||||
var dataTransformDocument = new XmlDocument();
|
||||
|
||||
dataTransformDocument.LoadXml(@"
|
||||
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:ds='http://www.w3.org/2000/09/xmldsig#'>
|
||||
<xsl:template match='/'>
|
||||
<xsl:apply-templates />
|
||||
</xsl:template>
|
||||
<xsl:template match='*'>
|
||||
<xsl:copy>
|
||||
<xsl:copy-of select='@*' />
|
||||
<xsl:apply-templates />
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
<xsl:template match='ds:Signature' />
|
||||
</xsl:stylesheet>");
|
||||
|
||||
var dataTransform = new XmlDsigXsltTransform();
|
||||
dataTransform.LoadInnerXml(dataTransformDocument.ChildNodes);
|
||||
|
||||
return dataTransform;
|
||||
}
|
||||
|
||||
private static bool VerifyXmlDocumentSignature(XmlDocument signedXmlDocument)
|
||||
{
|
||||
// Создание подписчика XML-документа
|
||||
var signedXml = new GostSignedXml(signedXmlDocument);
|
||||
|
||||
// Поиск узла с подписью
|
||||
var nodeList = signedXmlDocument.GetElementsByTagName("Signature", SignedXml.XmlDsigNamespaceUrl);
|
||||
|
||||
// Загрузка найденной подписи
|
||||
signedXml.LoadXml((XmlElement)nodeList[0]);
|
||||
|
||||
// Проверка подписи
|
||||
return signedXml.CheckSignature();
|
||||
}
|
||||
|
||||
private static string GetDigestMethod(X509Certificate2 certificate)
|
||||
{
|
||||
// Имя алгоритма вычисляем динамически, чтобы сделать код теста универсальным
|
||||
|
||||
using (var publicKey = (GostAsymmetricAlgorithm)certificate.GetPublicKeyAlgorithm())
|
||||
using (var hashAlgorithm = publicKey.CreateHashAlgorithm())
|
||||
{
|
||||
return hashAlgorithm.AlgorithmName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user