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:
master
2025-11-09 21:59:57 +02:00
parent 75c2bcafce
commit cef4cb2c5a
486 changed files with 32952 additions and 801 deletions

View File

@@ -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>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<MyXml>
<SomeElement Id="Id1">
Here is some data to sign.
</SomeElement>
</MyXml>

View 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>

View File

@@ -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>

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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..."));
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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..."));
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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..."));
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View 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 &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
///&lt;MyXml&gt;
/// &lt;SomeElement Encrypt=&quot;false&quot;&gt;
/// Here is public data.
/// &lt;/SomeElement&gt;
/// &lt;SomeElement Encrypt=&quot;true&quot;&gt;
/// Here is private data.
/// &lt;/SomeElement&gt;
/// &lt;SomeElement Encrypt=&quot;true&quot;&gt;
/// Here is private data.
/// &lt;/SomeElement&gt;
/// &lt;SomeElement Encrypt=&quot;true&quot;&gt;
/// Here is private data.
/// &lt;/SomeElement&gt;
///&lt;/MyXml&gt;.
/// </summary>
internal static string EncryptedXmlExample {
get {
return ResourceManager.GetString("EncryptedXmlExample", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
///&lt;MyXml&gt;
/// &lt;SomeElement Id=&quot;Id1&quot;&gt;
/// Here is some data to sign.
/// &lt;/SomeElement&gt;
///&lt;/MyXml&gt;.
/// </summary>
internal static string SignedXmlExample {
get {
return ResourceManager.GetString("SignedXmlExample", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
///&lt;S:Envelope xmlns:S=&quot;http://schemas.xmlsoap.org/soap/envelope/&quot;
/// xmlns:wsse=&quot;http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd&quot;
/// xmlns:wsu=&quot;http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd&quot;
/// &gt;
/// &lt;S:Header&gt;
/// &lt;wsse:Security S:actor=&quot;http://smev.gosuslugi.ru/actors/smev&quot;&gt;
/// &lt;ds:Signature xmlns:ds=&quot;http://www.w3.org/2000/09/xmldsig#&quot;&gt;
/// &lt;ds:KeyInfo&gt;
/// &lt;wsse:SecurityTokenR [rest of string was truncated]&quot;;.
/// </summary>
internal static string SmevExample {
get {
return ResourceManager.GetString("SmevExample", resourceCulture);
}
}
}
}

View 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>

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View 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;
}
}

View 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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -0,0 +1,21 @@
using System;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public abstract class Asn18BitCharString : Asn1CharString
{
public const int BitsPerCharA = 8;
public const int BitsPerCharU = 7;
protected internal Asn18BitCharString(short typeCode)
: base(typeCode)
{
}
protected internal Asn18BitCharString(string data, short typeCode)
: base(data, typeCode)
{
}
}
}

View File

@@ -0,0 +1,401 @@
using System;
using System.IO;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
public class Asn1BerDecodeBuffer : Asn1DecodeBuffer
{
private readonly IntHolder _lenHolder;
private readonly Asn1Tag _tagHolder;
private Asn1Tag _lastParsedTag;
private MemoryStream _openTypeCaptureBuffer;
private MemoryStream _parserCaptureBuffer;
public Asn1BerDecodeBuffer(byte[] msgdata)
: base(msgdata)
{
_tagHolder = new Asn1Tag();
_lenHolder = new IntHolder();
}
public Asn1BerDecodeBuffer(Stream inputStream)
: base(inputStream)
{
_tagHolder = new Asn1Tag();
_lenHolder = new IntHolder();
}
public virtual Asn1Tag LastTag
{
get { return _lastParsedTag; }
}
public static int CalcIndefLen(byte[] data, int offset, int len)
{
Asn1BerDecodeBuffer buffer;
if ((offset == 0) && (len == data.Length))
{
buffer = new Asn1BerDecodeBuffer(data);
}
else
{
var destinationArray = new byte[len];
Array.Copy(data, offset, destinationArray, 0, len);
buffer = new Asn1BerDecodeBuffer(destinationArray);
}
var tag = new Asn1Tag();
var num = buffer.DecodeTagAndLength(tag);
if (num == Asn1Status.IndefiniteLength)
{
var num2 = 1;
num = 0;
while (num2 > 0)
{
var byteCount = buffer.ByteCount;
var num4 = buffer.DecodeTagAndLength(tag);
num += buffer.ByteCount - byteCount;
if (num4 > 0)
{
buffer.Skip(num4);
num += num4;
}
else
{
if (num4 == Asn1Status.IndefiniteLength)
{
num2++;
continue;
}
if (tag.IsEoc() && (num4 == 0))
{
num2--;
}
}
}
}
return num;
}
public virtual int DecodeLength()
{
var num3 = 0;
var num2 = Read();
if (num2 < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, ByteCount);
}
if (num2 <= 0x80)
{
if (num2 == 0x80)
{
return Asn1Status.IndefiniteLength;
}
return num2;
}
var num = num2 & 0x7f;
if (num > 4)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidLengthException);
}
while (num > 0)
{
num2 = Read();
if (num2 < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, ByteCount);
}
num3 = (num3 * 0x100) + num2;
num--;
}
return num3;
}
public virtual byte[] DecodeOpenType()
{
return DecodeOpenType(true);
}
public virtual byte[] DecodeOpenType(bool saveData)
{
if (saveData)
{
if (_openTypeCaptureBuffer == null)
{
_openTypeCaptureBuffer = new MemoryStream(0x100);
}
else
{
_openTypeCaptureBuffer.Seek(0L, SeekOrigin.Begin);
_openTypeCaptureBuffer.SetLength(0L);
}
AddCaptureBuffer(_openTypeCaptureBuffer);
}
DecodeOpenTypeElement(_tagHolder, _lenHolder, saveData);
if (saveData)
{
var buffer = _openTypeCaptureBuffer.ToArray();
RemoveCaptureBuffer(_openTypeCaptureBuffer);
return buffer;
}
return null;
}
private void DecodeOpenTypeElement(Asn1Tag tag, IntHolder len, bool saveData)
{
var nbytes = DecodeTagAndLength(tag);
var byteCount = base.ByteCount;
if (nbytes > 0)
{
if (saveData)
{
Capture(nbytes);
}
else
{
Skip(nbytes);
}
}
else if (nbytes == Asn1Status.IndefiniteLength)
{
MovePastEoc(saveData);
}
len.Value = base.ByteCount - byteCount;
}
public virtual void DecodeTag(Asn1Tag tag)
{
var num = Read();
if (num < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, ByteCount);
}
tag.Class = (short)(num & 0xc0);
tag.Form = (short)(num & 0x20);
tag.IdCode = num & 0x1f;
if (tag.IdCode == 0x1f)
{
var num2 = 0L;
var num3 = 0;
do
{
num = Read();
if (num < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, ByteCount);
}
num2 = (num2 * 0x80L) + (num & 0x7f);
if ((num2 > 0x7fffffffL) || (num3++ > 8))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidTagValue);
}
}
while ((num & 0x80) != 0);
tag.IdCode = (int)num2;
}
_lastParsedTag = tag;
}
public virtual int DecodeTagAndLength(Asn1Tag tag)
{
DecodeTag(tag);
return DecodeLength();
}
public virtual bool MatchTag(Asn1Tag tag)
{
return MatchTag(tag.Class, tag.Form, tag.IdCode, null, null);
}
public virtual bool MatchTag(Asn1Tag tag, Asn1Tag parsedTag, IntHolder parsedLen)
{
return MatchTag(tag.Class, tag.Form, tag.IdCode, parsedTag, parsedLen);
}
public virtual bool MatchTag(short tagClass, short tagForm, int tagIdCode, Asn1Tag parsedTag, IntHolder parsedLen)
{
Mark();
var tag = parsedTag ?? _tagHolder;
var holder = parsedLen ?? _lenHolder;
holder.Value = DecodeTagAndLength(tag);
if (!tag.Equals(tagClass, tagForm, tagIdCode))
{
Reset();
return false;
}
return true;
}
protected void MovePastEoc(bool saveData)
{
var tag = new Asn1Tag();
var num = 1;
while (num > 0)
{
var nbytes = DecodeTagAndLength(tag);
if (nbytes > 0)
{
if (saveData)
{
Capture(nbytes);
}
else
{
Skip(nbytes);
}
}
else if (nbytes == Asn1Status.IndefiniteLength)
{
num++;
}
else if (tag.IsEoc() && (nbytes == 0))
{
num--;
}
}
}
public virtual void Parse(IAsn1TaggedEventHandler handler)
{
if (_parserCaptureBuffer == null)
{
RemoveCaptureBuffer(_parserCaptureBuffer);
}
if (_parserCaptureBuffer == null)
{
_parserCaptureBuffer = new MemoryStream(0x100);
AddCaptureBuffer(_parserCaptureBuffer);
}
else
{
_parserCaptureBuffer.Seek(0L, SeekOrigin.Begin);
_parserCaptureBuffer.SetLength(0L);
}
ParseElement(handler, _tagHolder, _lenHolder);
}
private void ParseCons(IAsn1TaggedEventHandler handler, int len)
{
var tag2 = new Asn1Tag();
var holder = new IntHolder();
var byteCount = base.ByteCount;
while (true)
{
ParseElement(handler, tag2, holder);
if (len == Asn1Status.IndefiniteLength)
{
if (tag2.IsEoc() && (holder.Value == 0))
{
return;
}
continue;
}
if ((base.ByteCount - byteCount) >= len)
{
return;
}
}
}
private void ParseElement(IAsn1TaggedEventHandler handler, Asn1Tag tag, IntHolder len)
{
_parserCaptureBuffer.Seek(0L, SeekOrigin.Begin);
_parserCaptureBuffer.SetLength(0L);
len.Value = DecodeTagAndLength(tag);
if (!tag.IsEoc() || (len.Value != 0))
{
handler.StartElement(tag, len.Value, _parserCaptureBuffer.ToArray());
_parserCaptureBuffer.Seek(0L, SeekOrigin.Begin);
_parserCaptureBuffer.SetLength(0L);
if ((len.Value > 0) || (len.Value == Asn1Status.IndefiniteLength))
{
if (tag.Constructed)
{
ParseCons(handler, len.Value);
}
else
{
ParsePrim(handler, len.Value);
}
}
handler.EndElement(tag);
}
}
private void ParsePrim(IAsn1TaggedEventHandler handler, int len)
{
var buffer = new byte[len];
Read(buffer);
handler.Contents(buffer);
}
public virtual Asn1Tag PeekTag()
{
var parsedTag = new Asn1Tag();
PeekTag(parsedTag);
return parsedTag;
}
public virtual void PeekTag(Asn1Tag parsedTag)
{
Mark();
DecodeTag(parsedTag);
Reset();
}
public override int ReadByte()
{
return Read();
}
}
}

View File

@@ -0,0 +1,72 @@
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
public class Asn1BerDecodeContext
{
private readonly int _decBufByteCount;
private readonly Asn1BerDecodeBuffer _decodeBuffer;
private readonly int _elemLength;
private readonly Asn1Tag _tagHolder;
public Asn1BerDecodeContext(Asn1BerDecodeBuffer decodeBuffer, int elemLength)
{
_decodeBuffer = decodeBuffer;
_decBufByteCount = decodeBuffer.ByteCount;
_elemLength = elemLength;
_tagHolder = new Asn1Tag();
}
public virtual bool Expired()
{
if (_elemLength == Asn1Status.IndefiniteLength)
{
var parsedLen = new IntHolder();
var flag = _decodeBuffer.MatchTag(0, 0, 0, null, parsedLen);
if (flag)
{
_decodeBuffer.Reset();
}
return flag;
}
var num = _decodeBuffer.ByteCount - _decBufByteCount;
return (num >= _elemLength);
}
public virtual bool MatchElemTag(Asn1Tag tag, IntHolder parsedLen, bool advance)
{
return MatchElemTag(tag.Class, tag.Form, tag.IdCode, parsedLen, advance);
}
public virtual bool MatchElemTag(short tagClass, short tagForm, int tagIdCode, IntHolder parsedLen, bool advance)
{
if (Expired())
{
return false;
}
var flag = _decodeBuffer.MatchTag(tagClass, tagForm, tagIdCode, _tagHolder, parsedLen);
if ((_elemLength != Asn1Status.IndefiniteLength) && (parsedLen.Value != Asn1Status.IndefiniteLength))
{
var num = _decodeBuffer.ByteCount - _decBufByteCount;
if ((parsedLen.Value < 0) || (parsedLen.Value > (_elemLength - num)))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidLengthException);
}
}
if (flag && !advance)
{
_decodeBuffer.Reset();
}
return flag;
}
}
}

View File

@@ -0,0 +1,305 @@
using System;
using System.IO;
using System.Text;
namespace GostCryptography.Asn1.Ber
{
public class Asn1BerEncodeBuffer : Asn1EncodeBuffer
{
public Asn1BerEncodeBuffer()
{
ByteIndex = SizeIncrement - 1;
}
public Asn1BerEncodeBuffer(int sizeIncrement)
: base(sizeIncrement)
{
ByteIndex = SizeIncrement - 1;
}
public virtual MemoryStream ByteArrayInputStream
{
get
{
var index = ByteIndex + 1;
return new MemoryStream(Data, index, Data.Length - index);
}
}
public override byte[] MsgCopy
{
get
{
var sourceIndex = ByteIndex + 1;
var length = Data.Length - sourceIndex;
var destinationArray = new byte[length];
Array.Copy(Data, sourceIndex, destinationArray, 0, length);
return destinationArray;
}
}
public override int MsgLength
{
get
{
var num = ByteIndex + 1;
return (Data.Length - num);
}
}
public virtual void BinDump()
{
BinDump(null);
}
public override void BinDump(StreamWriter outs, string varName)
{
var buffer = new Asn1BerDecodeBuffer(ByteArrayInputStream);
try
{
buffer.Parse(new Asn1BerMessageDumpHandler(outs));
}
catch (Exception exception)
{
Console.Out.WriteLine(exception.Message);
Console.Error.Write(exception.StackTrace);
Console.Error.Flush();
}
}
protected internal override void CheckSize(int bytesRequired)
{
if (bytesRequired > (ByteIndex + 1))
{
var num = ((bytesRequired - 1) / SizeIncrement) + 1;
var num2 = num * SizeIncrement;
var destinationArray = new byte[Data.Length + num2];
var destinationIndex = (ByteIndex + num2) + 1;
var length = Data.Length - (ByteIndex + 1);
Array.Copy(Data, ByteIndex + 1, destinationArray, destinationIndex, length);
Data = destinationArray;
ByteIndex = destinationIndex - 1;
}
}
public override void Copy(byte data)
{
if (ByteIndex < 0)
{
CheckSize(1);
}
Data[ByteIndex--] = data;
}
public override void Copy(byte[] data)
{
CheckSize(data.Length);
ByteIndex -= data.Length;
Array.Copy(data, 0, Data, ByteIndex + 1, data.Length);
}
public virtual void Copy(string data)
{
var length = data.Length;
CheckSize(length);
ByteIndex -= length;
for (var i = 0; i < length; ++i)
{
Data[(ByteIndex + i) + 1] = (byte)data[i];
}
}
public virtual void Copy(byte[] data, int startOffset, int length)
{
CheckSize(length);
ByteIndex -= length;
Array.Copy(data, startOffset, Data, ByteIndex + 1, length);
}
public virtual int EncodeIdentifier(int ident)
{
var flag = true;
var num = 0;
var num2 = ident;
do
{
if (ByteIndex < 0)
{
CheckSize(1);
}
Data[ByteIndex] = (byte)(num2 % 0x80);
if (!flag)
{
Data[ByteIndex] = (byte)(Data[ByteIndex] | 0x80);
}
else
{
flag = false;
}
ByteIndex--;
num2 /= 0x80;
num++;
}
while (num2 > 0);
return num;
}
public virtual int EncodeIntValue(long ivalue)
{
long num2;
long num = ivalue;
var num3 = 0;
do
{
num2 = num % 0x100L;
num /= 0x100L;
if ((num < 0L) && (num2 != 0L))
{
num -= 1L;
}
Copy((byte)num2);
num3++;
}
while ((num != 0L) && (num != -1L));
if ((ivalue > 0L) && ((num2 & 0x80L) == 0x80L))
{
Copy(0);
num3++;
return num3;
}
if ((ivalue < 0L) && ((num2 & 0x80L) == 0L))
{
Copy(0xff);
num3++;
}
return num3;
}
public virtual int EncodeLength(int len)
{
var num = 0;
bool flag;
if (len >= 0)
{
flag = len > 0x7f;
var num2 = len;
do
{
if (ByteIndex < 0)
{
CheckSize(1);
}
Data[ByteIndex--] = (byte)(num2 % 0x100);
num++;
num2 /= 0x100;
}
while (num2 > 0);
}
else
{
flag = len == Asn1Status.IndefiniteLength;
}
if (flag)
{
if (ByteIndex < 0)
{
CheckSize(1);
}
Data[ByteIndex--] = (byte)(num | 0x80);
num++;
}
return num;
}
public virtual int EncodeTag(Asn1Tag tag)
{
var num = (byte)(((byte)tag.Class) | ((byte)tag.Form));
var num2 = 0;
if (tag.IdCode < 0x1f)
{
Copy((byte)(num | tag.IdCode));
num2++;
return num2;
}
num2 += EncodeIdentifier(tag.IdCode);
Copy((byte)(num | 0x1f));
num2++;
return num2;
}
public virtual int EncodeTagAndLength(Asn1Tag tag, int len)
{
return (EncodeLength(len) + EncodeTag(tag));
}
public virtual int EncodeTagAndLength(short tagClass, short tagForm, int tagIdCode, int len)
{
var tag = new Asn1Tag(tagClass, tagForm, tagIdCode);
return EncodeTagAndLength(tag, len);
}
public override Stream GetInputStream()
{
return ByteArrayInputStream;
}
public override void Reset()
{
ByteIndex = Data.Length - 1;
}
public override string ToString()
{
var num = ByteIndex + 1;
var num2 = Data.Length - num;
var str = new StringBuilder("").ToString();
for (var i = 0; i < num2; ++i)
{
str = str + Asn1Util.ToHexString(Data[i + num]);
}
return str;
}
public override void Write(Stream outs)
{
var offset = ByteIndex + 1;
outs.Write(Data, offset, Data.Length - offset);
}
}
}

View File

@@ -0,0 +1,41 @@
using System.IO;
namespace GostCryptography.Asn1.Ber
{
public class Asn1BerInputStream : Asn1BerDecodeBuffer, IAsn1InputStream
{
public Asn1BerInputStream(Stream inputStream)
: base(inputStream)
{
}
public virtual int Available()
{
var inputStream = GetInputStream();
if (inputStream != null)
{
var num = inputStream.Length - inputStream.Position;
return (int)num;
}
return 0;
}
public virtual void Close()
{
var inputStream = GetInputStream();
if (inputStream != null)
{
inputStream.Close();
}
}
public virtual bool MarkSupported()
{
var inputStream = GetInputStream();
return ((inputStream != null) && inputStream.CanSeek);
}
}
}

View File

@@ -0,0 +1,135 @@
using System;
using System.IO;
using System.Text;
namespace GostCryptography.Asn1.Ber
{
public class Asn1BerMessageDumpHandler : IAsn1TaggedEventHandler
{
private const int MaxBytesPerLine = 12;
private int _offset;
private readonly StreamWriter _printStream;
public Asn1BerMessageDumpHandler()
{
_printStream = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = true };
_offset = 0;
}
public Asn1BerMessageDumpHandler(StreamWriter outs)
{
_printStream = outs;
_offset = 0;
}
public virtual void Contents(byte[] data)
{
if (data.Length != 0)
{
PrintOffset();
var flag = true;
var builder = new StringBuilder(100);
var builder2 = new StringBuilder(100);
for (var i = 0; i < data.Length; ++i)
{
builder.Append(Asn1Util.ToHexString(data[i]));
builder.Append(' ');
int num2 = data[i];
if ((num2 >= 0x20) && (num2 <= 0x7f))
{
builder2.Append((char)num2);
}
else
{
builder2.Append('.');
}
if (((i + 1) % MaxBytesPerLine) == 0)
{
if (!flag)
{
_printStream.Write(" : ");
}
else
{
flag = false;
}
_printStream.WriteLine(builder + ": " + builder2);
builder.Length = 0;
builder2.Length = 0;
}
}
if (builder.Length > 0)
{
while (builder.Length < 0x24)
{
builder.Append(' ');
}
if (!flag)
{
_printStream.Write(" : ");
}
_printStream.WriteLine(builder + ": " + builder2);
}
_offset += data.Length;
}
}
public virtual void EndElement(Asn1Tag tag)
{
}
public virtual void StartElement(Asn1Tag tag, int len, byte[] tagLenBytes)
{
PrintOffset();
new StringBuilder(40); // WTF?
var index = 0;
while (index < tagLenBytes.Length)
{
_printStream.Write(Asn1Util.ToHexString(tagLenBytes[index]));
_printStream.Write(' ');
index++;
}
while (index < MaxBytesPerLine)
{
_printStream.Write(" ");
index++;
}
_printStream.Write(": ");
_printStream.Write(tag.Constructed ? "C " : "P ");
_printStream.Write(tag + " ");
_printStream.WriteLine(Convert.ToString(len));
_offset += tagLenBytes.Length;
}
private void PrintOffset()
{
var str = Convert.ToString(_offset);
var num = 4 - str.Length;
for (var i = 0; i < num; ++i)
{
_printStream.Write('0');
}
_printStream.Write(str);
_printStream.Write(" : ");
}
}
}

View File

@@ -0,0 +1,277 @@
using System.IO;
namespace GostCryptography.Asn1.Ber
{
public class Asn1BerOutputStream : Asn1OutputStream
{
private static readonly byte[] Eoc = new byte[2];
public Asn1BerOutputStream(Stream outputStream)
: base(new BufferedStream(outputStream))
{
}
public Asn1BerOutputStream(Stream outputStream, int bufSize)
: base((bufSize == 0) ? outputStream : new BufferedStream(outputStream, bufSize))
{
}
public virtual void Encode(Asn1Type type, bool explicitTagging)
{
type.Encode(this, explicitTagging);
}
public virtual void EncodeBitString(byte[] data, int numbits, bool explicitTagging, Asn1Tag tag)
{
if (explicitTagging)
{
EncodeTag(tag);
}
var count = (numbits + 7) / 8;
EncodeLength(count + 1);
var num2 = numbits % 8;
if (num2 != 0)
{
num2 = 8 - num2;
data[count - 1] = (byte)(data[count - 1] & ((byte)~((1 << num2) - 1)));
}
OutputStream.WriteByte((byte)num2);
if (count > 0)
{
OutputStream.Write(data, 0, count);
}
}
public virtual void EncodeBmpString(string data, bool explicitTagging, Asn1Tag tag)
{
if (explicitTagging)
{
EncodeTag(tag);
}
if (data == null)
{
EncodeLength(0);
}
else
{
EncodeLength(data.Length * 2);
var length = data.Length;
for (var i = 0; i < length; i++)
{
var num3 = data[i];
var num2 = num3 / 0x100;
var num = num3 % 0x100;
OutputStream.WriteByte((byte)num2);
OutputStream.WriteByte((byte)num);
}
}
}
public virtual void EncodeCharString(string data, bool explicitTagging, Asn1Tag tag)
{
if (explicitTagging)
{
EncodeTag(tag);
}
if (data == null)
{
EncodeLength(0);
}
else
{
EncodeLength(data.Length);
var buffer = Asn1Util.ToByteArray(data);
OutputStream.Write(buffer, 0, buffer.Length);
}
}
public virtual void EncodeEoc()
{
OutputStream.Write(Eoc, 0, Eoc.Length);
}
public virtual void EncodeIdentifier(long ident)
{
var number = 0x7fL;
var identBytesCount = Asn1RunTime.GetIdentBytesCount(ident);
number = number << (7 * identBytesCount);
if (identBytesCount > 0)
{
while (identBytesCount > 0)
{
number = Asn1Util.UrShift(number, 7);
identBytesCount--;
var num3 = Asn1Util.UrShift(ident & number, identBytesCount * 7);
if (identBytesCount != 0)
{
num3 |= 0x80L;
}
OutputStream.WriteByte((byte)num3);
}
}
else
{
OutputStream.WriteByte(0);
}
}
public virtual void EncodeIntValue(long data, bool encodeLen)
{
long num2;
var num = data;
var buffer = new byte[9];
var len = 0;
var length = buffer.Length;
do
{
num2 = num % 0x100L;
num /= 0x100L;
if ((num < 0L) && (num2 != 0L))
{
num -= 1L;
}
buffer[--length] = (byte)num2;
len++;
}
while ((num != 0L) && (num != -1L));
if ((data > 0L) && ((num2 & 0x80L) == 0x80L))
{
buffer[--length] = 0;
len++;
}
else if ((data < 0L) && ((num2 & 0x80L) == 0L))
{
buffer[--length] = 0xff;
len++;
}
if (encodeLen)
{
EncodeLength(len);
}
OutputStream.Write(buffer, length, len);
}
public virtual void EncodeLength(int len)
{
if (len >= 0)
{
var bytesCount = Asn1Util.GetBytesCount(len);
if (len > 0x7f)
{
OutputStream.WriteByte((byte)(bytesCount | 0x80));
}
for (var i = (8 * bytesCount) - 8; i >= 0; i -= 8)
{
var num3 = (byte)((len >> i) & 0xff);
OutputStream.WriteByte(num3);
}
}
else if (len == Asn1Status.IndefiniteLength)
{
OutputStream.WriteByte(0x80);
}
}
public virtual void EncodeOctetString(byte[] data, bool explicitTagging, Asn1Tag tag)
{
if (explicitTagging)
{
EncodeTag(tag);
}
if (data == null)
{
EncodeLength(0);
}
else
{
EncodeLength(data.Length);
OutputStream.Write(data, 0, data.Length);
}
}
public virtual void EncodeTag(Asn1Tag tag)
{
var num = (byte)(((byte)tag.Class) | ((byte)tag.Form));
if (tag.IdCode < 0x1f)
{
OutputStream.WriteByte((byte)(num | tag.IdCode));
}
else
{
OutputStream.WriteByte((byte)(num | 0x1f));
EncodeIdentifier(tag.IdCode);
}
}
public virtual void EncodeTag(short tagClass, short tagForm, int tagIdCode)
{
EncodeTag(new Asn1Tag(tagClass, tagForm, tagIdCode));
}
public virtual void EncodeTagAndIndefLen(Asn1Tag tag)
{
EncodeTag(tag);
OutputStream.WriteByte(0x80);
}
public virtual void EncodeTagAndIndefLen(short tagClass, short tagForm, int tagIdCode)
{
EncodeTag(new Asn1Tag(tagClass, tagForm, tagIdCode));
OutputStream.WriteByte(0x80);
}
public virtual void EncodeTagAndLength(Asn1Tag tag, int len)
{
EncodeTag(tag);
EncodeLength(len);
}
public virtual void EncodeUnivString(int[] data, bool explicitTagging, Asn1Tag tag)
{
if (explicitTagging)
{
EncodeTag(tag);
}
if (data == null)
{
EncodeLength(0);
}
else
{
EncodeLength(data.Length * 4);
var length = data.Length;
for (var i = 0; i < length; ++i)
{
var number = data[i];
OutputStream.WriteByte((byte)(Asn1Util.UrShift(number, 0x18) & 0xff));
OutputStream.WriteByte((byte)(Asn1Util.UrShift(number, 0x10) & 0xff));
OutputStream.WriteByte((byte)(Asn1Util.UrShift(number, 8) & 0xff));
OutputStream.WriteByte((byte)(number & 0xff));
}
}
}
}
}

View File

@@ -0,0 +1,137 @@
using System;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1BigInteger : Asn1Type
{
private const int MaxBigIntLen = 0x186a0;
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, BigIntegerTypeCode);
public static readonly BigInteger Zero = new BigInteger();
private BigInteger _value;
public Asn1BigInteger()
{
_value = new BigInteger();
}
public Asn1BigInteger(BigInteger value)
{
_value = value;
}
public Asn1BigInteger(string value)
{
_value = new BigInteger(value);
}
public Asn1BigInteger(string value, int radix)
{
_value = new BigInteger(value, radix);
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
var length = explicitTagging ? MatchTag(buffer, Tag) : implicitLength;
_value = DecodeValue(buffer, length);
buffer.TypeCode = 2;
}
public BigInteger DecodeValue(Asn1DecodeBuffer buffer, int length)
{
var ivalue = new byte[length];
if (length > MaxBigIntLen)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1TooBigIntegerValue, length);
}
for (var i = 0; i < length; ++i)
{
ivalue[i] = (byte)buffer.ReadByte();
}
var integer = new BigInteger();
if (length > 0)
{
integer.SetData(ivalue);
}
return integer;
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
var len = EncodeValue(buffer, _value, true);
if (explicitTagging)
{
len += buffer.EncodeTagAndLength(Tag, len);
}
return len;
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
if (explicitTagging)
{
outs.EncodeTag(Tag);
}
var buffer = new Asn1BerEncodeBuffer();
var len = EncodeValue(buffer, _value, true);
outs.EncodeLength(len);
outs.Write(buffer.MsgCopy);
}
private static int EncodeValue(Asn1EncodeBuffer buffer, BigInteger ivalue, bool doCopy)
{
var data = ivalue.GetData();
var length = data.Length;
for (var i = length - 1; i >= 0; --i)
{
if (doCopy)
{
buffer.Copy(data[i]);
}
}
return length;
}
public virtual bool Equals(long value)
{
return _value.Equals(value);
}
public override bool Equals(object value)
{
var integer = value as Asn1BigInteger;
if (integer == null)
{
return false;
}
return _value.Equals(integer._value);
}
public override int GetHashCode()
{
return _value.GetHashCode();
}
public override string ToString()
{
return _value.ToString(10);
}
}
}

View File

@@ -0,0 +1,455 @@
using System;
using System.Collections;
using System.Text;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1BitString : Asn1Type
{
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, BitStringTypeCode);
[NonSerialized]
public byte[] Value;
[NonSerialized]
public int NumBits;
public Asn1BitString()
{
NumBits = 0;
Value = null;
}
public Asn1BitString(bool[] bitValues)
{
AllocBitArray(bitValues.Length);
var index = 0;
var num4 = 0x80;
var num = 0;
var num2 = 0;
while (num < bitValues.Length)
{
if (bitValues[num])
{
num2 |= num4;
}
num4 = num4 >> 1;
if (num4 == 0)
{
Value[index++] = (byte)num2;
num4 = 0x80;
num2 = 0;
}
num++;
}
if (num4 != 0x80)
{
Value[index] = (byte)num2;
}
}
public Asn1BitString(BitArray bitArray)
{
AllocBitArray(bitArray.Length);
var index = 0;
var num4 = 0x80;
var num = 0;
var num2 = 0;
while (num < bitArray.Length)
{
if (bitArray.Get(num))
{
num2 |= num4;
}
num4 = num4 >> 1;
if (num4 == 0)
{
Value[index++] = (byte)num2;
num4 = 0x80;
num2 = 0;
}
num++;
}
if (num4 != 0x80)
{
Value[index] = (byte)num2;
}
}
public Asn1BitString(string value)
{
var numbits = new IntHolder();
Value = Asn1Value.ParseString(value, numbits);
NumBits = numbits.Value;
}
public Asn1BitString(int numBits, byte[] data)
{
NumBits = numBits;
Value = data;
}
private void AllocBitArray(int numbits)
{
NumBits = numbits;
var num = (NumBits + 7) / 8;
if ((Value == null) || (Value.Length < num))
{
Value = new byte[num];
}
}
public virtual void Clear(int bitIndex)
{
this[bitIndex] = false;
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
var elemLength = explicitTagging ? MatchTag(buffer, Tag) : implicitLength;
var lastTag = buffer.LastTag;
if ((lastTag == null) || !lastTag.Constructed)
{
if (elemLength < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidLengthException);
}
if (elemLength != 0)
{
var num8 = elemLength - 1;
var num7 = buffer.Read();
if (num7 < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, buffer.ByteCount);
}
if ((num7 < 0) || (num7 > 7))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidFormatOfBitString, num7);
}
if ((num8 == 0) && (num7 != 0))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidLengthException);
}
NumBits = (num8 * 8) - num7;
Value = new byte[num8];
buffer.Read(Value);
}
else
{
NumBits = 0;
Value = null;
}
}
else
{
var num3 = 0;
var offset = 0;
var index = -1;
var num6 = 0;
var context = new Asn1BerDecodeContext(buffer, elemLength);
while (!context.Expired())
{
var nbytes = MatchTag(buffer, Tag);
if (nbytes <= 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidFormatOfConstructedValue, buffer.ByteCount);
}
num3 += nbytes;
if (offset == 0)
{
AllocBitArray(num3 * 8);
}
else
{
ReallocBitArray(num3 * 8);
}
index = offset;
buffer.Read(Value, offset, nbytes);
offset = num3;
}
if (index >= 0)
{
num6 = Value[index];
if (((offset - index) - 1) > 0)
{
Array.Copy(Value, index + 1, Value, index, (offset - index) - 1);
}
num3--;
}
if ((num6 < 0) || (num6 > 7))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidFormatOfBitString, num6);
}
ReallocBitArray((num3 * 8) - num6);
if (elemLength == Asn1Status.IndefiniteLength)
{
MatchTag(buffer, Asn1Tag.Eoc);
}
}
buffer.TypeCode = 3;
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
var length = (NumBits + 7) / 8;
var num2 = NumBits % 8;
if (num2 != 0)
{
num2 = 8 - num2;
Value[length - 1] = (byte)(Value[length - 1] & ((byte)~((1 << num2) - 1)));
}
if (length != 0)
{
buffer.Copy(Value, 0, length);
}
buffer.Copy((byte)num2);
length++;
if (explicitTagging)
{
length += buffer.EncodeTagAndLength(Tag, length);
}
return length;
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
outs.EncodeBitString(Value, NumBits, explicitTagging, Tag);
}
public override bool Equals(object value)
{
var str = value as Asn1BitString;
if (str == null)
{
return false;
}
return Equals(str.NumBits, str.Value);
}
public virtual bool Equals(int nbits, byte[] value)
{
if (nbits != NumBits)
{
return false;
}
var num = ((nbits - 1) / 8) + 1;
for (var i = 0; i < num; ++i)
{
if (value[i] != Value[i])
{
return false;
}
}
return true;
}
public virtual bool Get(int bitno)
{
var index = bitno / 8;
var num2 = 1 << (7 - (bitno % 8));
if ((Value != null) && (Value.Length >= index))
{
int num3 = Value[index];
return ((num3 & num2) != 0);
}
return false;
}
public override int GetHashCode()
{
return (Value != null) ? Value.GetHashCode() : base.GetHashCode();
}
private void ReallocBitArray(int numbits)
{
NumBits = numbits;
var num = (NumBits + 7) / 8;
if (Value.Length != num)
{
var value = Value;
Value = new byte[num];
if (value != null)
{
Array.Copy(value, 0, Value, 0, Math.Min(value.Length, num));
}
}
}
public virtual void Set(int bitIndex)
{
Set(bitIndex, true);
}
public virtual void Set(int bitIndex, bool value)
{
var index = bitIndex / 8;
var num2 = 1 << (7 - (bitIndex % 8));
var num3 = index + 1;
if (Value == null)
{
Value = new byte[num3];
}
else if (Value.Length < num3)
{
var destinationArray = new byte[num3];
Array.Copy(Value, 0, destinationArray, 0, Value.Length);
Value = destinationArray;
}
int num4 = Value[index];
num4 = value ? (num4 | num2) : (num4 & ~num2);
Value[index] = (byte)num4;
if ((bitIndex + 1) > NumBits)
{
NumBits = bitIndex + 1;
}
}
public virtual bool[] ToBoolArray()
{
var flagArray = new bool[NumBits];
var num4 = 0;
var numbits = NumBits;
foreach (var num3 in Value)
{
var num5 = 0x80;
var num = (numbits < 8) ? numbits : 8;
for (var j = 0; j < num; ++j)
{
flagArray[num4++] = (num3 & num5) != 0;
num5 = num5 >> 1;
}
numbits -= 8;
}
return flagArray;
}
public virtual string ToHexString()
{
var str = new StringBuilder("").ToString();
foreach (var b in Value)
{
str = str + Asn1Util.ToHexString(b);
}
return str;
}
public override string ToString()
{
var str = new StringBuilder("").ToString();
if (NumBits <= 0x10)
{
if (NumBits != 0)
{
var flagArray = ToBoolArray();
foreach (bool b in flagArray)
{
str = str + (b ? "1" : "0");
}
}
return str;
}
var num2 = 4;
var capacity = (NumBits + 3) / 4;
var builder = new StringBuilder(capacity);
if (Value != null)
{
var num4 = 0;
var index = 0;
while (num4 < capacity)
{
var num6 = (Value[index] >> num2) & 15;
builder.Append((char)(num6 + ((num6 >= 10) ? 0x57 : 0x30)));
num2 -= 4;
if (num2 < 0)
{
num2 = 4;
index++;
}
num4++;
}
}
return builder.ToString();
}
public virtual bool this[int bitIndex]
{
get { return Get(bitIndex); }
set { Set(bitIndex, value); }
}
public override int Length
{
get { return NumBits; }
}
}
}

View File

@@ -0,0 +1,125 @@
using System;
using System.Text;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1BmpString : Asn1CharString
{
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, BmpStringTypeCode);
public Asn1BmpString()
: base(BmpStringTypeCode)
{
}
public Asn1BmpString(string data)
: base(data, BmpStringTypeCode)
{
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
var elemLength = explicitTagging ? MatchTag(buffer, Tag) : implicitLength;
var len = elemLength;
var sb = new StringBuilder();
var lastTag = buffer.LastTag;
if ((lastTag == null) || !lastTag.Constructed)
{
sb.EnsureCapacity(elemLength / 2);
ReadSegment(buffer, sb, len);
}
else
{
var capacity = 0;
var context = new Asn1BerDecodeContext(buffer, elemLength);
while (!context.Expired())
{
var num3 = MatchTag(buffer, Asn1OctetString.Tag);
if (num3 <= 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidFormatOfConstructedValue, buffer.ByteCount);
}
capacity += num3;
sb.EnsureCapacity(capacity);
ReadSegment(buffer, sb, num3);
}
if (elemLength == Asn1Status.IndefiniteLength)
{
MatchTag(buffer, Asn1Tag.Eoc);
}
}
Value = sb.ToString();
buffer.TypeCode = BmpStringTypeCode;
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
var length = Value.Length;
for (var i = length - 1; i >= 0; --i)
{
var num3 = Value[i];
var num = num3 % 0x100;
var num2 = num3 / 0x100;
buffer.Copy((byte)num);
buffer.Copy((byte)num2);
}
length *= 2;
if (explicitTagging)
{
length += buffer.EncodeTagAndLength(Tag, length);
}
return length;
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
outs.EncodeBmpString(Value, explicitTagging, Tag);
}
private static void ReadSegment(Asn1DecodeBuffer buffer, StringBuilder sb, int len)
{
if ((len % 2) != 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidLengthException);
}
while (len > 0)
{
var num = buffer.Read();
if (num == -1)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, buffer.ByteCount);
}
var num2 = num * 0x100;
len--;
num = buffer.Read();
if (num == -1)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, buffer.ByteCount);
}
num2 += num;
len--;
sb.Append((char)num2);
}
}
}
}

View File

@@ -0,0 +1,102 @@
using System;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1Boolean : Asn1Type
{
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, BooleanTypeCode);
public static readonly Asn1Boolean FalseValue = new Asn1Boolean(false);
public static readonly Asn1Boolean TrueValue = new Asn1Boolean(true);
[NonSerialized]
public bool Value;
public Asn1Boolean()
{
Value = false;
}
public Asn1Boolean(bool value)
{
Value = value;
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
if (explicitTagging)
{
MatchTag(buffer, Tag);
}
var num = buffer.Read();
if (num < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, buffer.ByteCount);
}
buffer.TypeCode = BooleanTypeCode;
Value = num != 0;
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
var len = 1;
buffer.Copy(Value ? byte.MaxValue : ((byte)0));
if (explicitTagging)
{
len += buffer.EncodeTagAndLength(Tag, len);
}
return len;
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
if (explicitTagging)
{
outs.EncodeTag(Tag);
}
outs.EncodeLength(1);
outs.WriteByte(Value ? -1 : 0);
}
public virtual bool Equals(bool value)
{
return (Value == value);
}
public override bool Equals(object value)
{
var flag = value as Asn1Boolean;
if (flag == null)
{
return false;
}
return (Value == flag.Value);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
public override string ToString()
{
if (!Value)
{
return "FALSE";
}
return "TRUE";
}
}
}

View File

@@ -0,0 +1,12 @@
using System.IO;
namespace GostCryptography.Asn1.Ber
{
public class Asn1CerInputStream : Asn1BerInputStream
{
public Asn1CerInputStream(Stream inputStream)
: base(inputStream)
{
}
}
}

View File

@@ -0,0 +1,236 @@
using System.IO;
namespace GostCryptography.Asn1.Ber
{
public class Asn1CerOutputStream : Asn1BerOutputStream
{
public Asn1CerOutputStream(Stream outputStream)
: base(outputStream)
{
}
public Asn1CerOutputStream(Stream outputStream, int bufSize)
: base(outputStream, bufSize)
{
}
public override void Encode(Asn1Type type, bool explicitTagging)
{
type.Encode(this, explicitTagging);
}
public override void EncodeBitString(byte[] value, int numbits, bool explicitTagging, Asn1Tag tag)
{
if ((((numbits + 7) / 8) + 1) <= 0x3e8)
{
base.EncodeBitString(value, numbits, explicitTagging, tag);
}
else
{
if (explicitTagging)
{
EncodeTagAndIndefLen(Asn1BitString.Tag.Class, 0x20, Asn1BitString.Tag.IdCode);
}
else
{
OutputStream.WriteByte(0x80);
}
var num = (numbits + 7) / 8;
var num2 = numbits % 8;
if (num2 != 0)
{
num2 = 8 - num2;
value[num - 1] = (byte)(value[num - 1] & ((byte)~((1 << num2) - 1)));
}
for (var i = 0; i < num; i += 0x3e8)
{
var len = num - i;
if (len > 0x3e8)
{
len = 0x3e8;
EncodeTagAndLength(Asn1BitString.Tag, len);
}
else
{
EncodeTagAndLength(Asn1BitString.Tag, len + 1);
OutputStream.WriteByte((byte)num2);
}
if (len > 0)
{
OutputStream.Write(value, i, len);
}
}
EncodeEoc();
}
}
public override void EncodeBmpString(string value, bool explicitTagging, Asn1Tag tag)
{
if ((value == null) || (value.Length <= 500))
{
base.EncodeBmpString(value, explicitTagging, tag);
}
else
{
if (explicitTagging)
{
EncodeTagAndIndefLen(Asn1BmpString.Tag.Class, 0x20, Asn1BmpString.Tag.IdCode);
}
else
{
OutputStream.WriteByte(0x80);
}
for (var i = 0; i < value.Length; i += 500)
{
var num2 = value.Length - i;
if (num2 > 500)
{
num2 = 500;
}
EncodeTagAndLength(Asn1OctetString.Tag, num2 * 2);
for (var j = 0; j < num2; j++)
{
var num5 = value[j + i];
var num4 = num5 / 0x100;
var num3 = num5 % 0x100;
OutputStream.WriteByte((byte)num4);
OutputStream.WriteByte((byte)num3);
}
}
EncodeEoc();
}
}
public override void EncodeCharString(string value, bool explicitTagging, Asn1Tag tag)
{
if ((value == null) || (value.Length <= 0x3e8))
{
base.EncodeCharString(value, explicitTagging, tag);
}
else
{
var data = Asn1Util.ToByteArray(value);
if (explicitTagging)
{
EncodeTag(tag.Class, 0x20, tag.IdCode);
}
EncodeOctetString(data, false, tag);
}
}
public override void EncodeOctetString(byte[] value, bool explicitTagging, Asn1Tag tag)
{
if ((value == null) || (value.Length <= 0x3e8))
{
base.EncodeOctetString(value, explicitTagging, tag);
}
else
{
if (explicitTagging)
{
EncodeTagAndIndefLen(Asn1OctetString.Tag.Class, 0x20, Asn1OctetString.Tag.IdCode);
}
else
{
OutputStream.WriteByte(0x80);
}
for (var i = 0; i < value.Length; i += 0x3e8)
{
var len = value.Length - i;
if (len > 0x3e8)
{
len = 0x3e8;
}
EncodeTagAndLength(Asn1OctetString.Tag, len);
Write(value, i, len);
}
EncodeEoc();
}
}
public virtual void EncodeStringTag(int nbytes, Asn1Tag tag)
{
if (nbytes <= 0x3e8)
{
EncodeTag(tag);
}
else
{
EncodeTag(tag.Class, 0x20, tag.IdCode);
}
}
public virtual void EncodeStringTag(int nbytes, short tagClass, short tagForm, int tagIdCode)
{
if (nbytes <= 0x3e8)
{
EncodeTag(new Asn1Tag(tagClass, tagForm, tagIdCode));
}
else
{
EncodeTag(tagClass, 0x20, tagIdCode);
}
}
public override void EncodeUnivString(int[] value, bool explicitTagging, Asn1Tag tag)
{
if ((value == null) || (value.Length <= 250))
{
base.EncodeUnivString(value, explicitTagging, tag);
}
else
{
if (explicitTagging)
{
EncodeTagAndIndefLen(Asn1UniversalString.Tag.Class, 0x20, Asn1UniversalString.Tag.IdCode);
}
else
{
OutputStream.WriteByte(0x80);
}
for (var i = 0; i < value.Length; i += 250)
{
var num2 = value.Length - i;
if (num2 > 250)
{
num2 = 250;
}
EncodeTagAndLength(Asn1OctetString.Tag, num2 * 4);
for (int j = 0; j < num2; j++)
{
var number = value[j + i];
OutputStream.WriteByte((byte)(Asn1Util.UrShift(number, 0x18) & 0xff));
OutputStream.WriteByte((byte)(Asn1Util.UrShift(number, 0x10) & 0xff));
OutputStream.WriteByte((byte)(Asn1Util.UrShift(number, 8) & 0xff));
OutputStream.WriteByte((byte)(number & 0xff));
}
}
EncodeEoc();
}
}
}
}

View File

@@ -0,0 +1,46 @@
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
public class Asn1CharRange : Asn1CharSet
{
private readonly int _lower;
private readonly int _upper;
public Asn1CharRange(int lower, int upper)
: base((upper - lower) + 1)
{
_lower = lower;
_upper = upper;
}
public override int MaxValue
{
get { return _upper; }
}
public override int GetCharAtIndex(int index)
{
index += _lower;
if (index > _upper)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1ConsVioException, "Character index", index);
}
return index;
}
public override int GetCharIndex(int charValue)
{
var num = charValue - _lower;
if (num < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1ConsVioException, "Character index", charValue);
}
return num;
}
}
}

View File

@@ -0,0 +1,35 @@
namespace GostCryptography.Asn1.Ber
{
public abstract class Asn1CharSet
{
private readonly int _aBitsPerChar;
private readonly int _uBitsPerChar;
protected internal Asn1CharSet(int nchars)
{
_uBitsPerChar = Asn1Integer.GetBitCount(nchars - 1);
_aBitsPerChar = 1;
while (_uBitsPerChar > _aBitsPerChar)
{
_aBitsPerChar = _aBitsPerChar << 1;
}
}
public abstract int MaxValue { get; }
public abstract int GetCharAtIndex(int index);
public abstract int GetCharIndex(int charValue);
public virtual int GetNumBitsPerChar(bool aligned)
{
if (!aligned)
{
return _uBitsPerChar;
}
return _aBitsPerChar;
}
}
}

View File

@@ -0,0 +1,156 @@
using System;
using System.Text;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public abstract class Asn1CharString : Asn1Type
{
[NonSerialized]
protected StringBuilder StringBuffer;
[NonSerialized]
private readonly short _typeCode;
[NonSerialized]
public string Value;
protected internal Asn1CharString(short typeCode)
{
Value = new StringBuilder().ToString();
_typeCode = typeCode;
}
protected internal Asn1CharString(string data, short typeCode)
{
Value = data;
_typeCode = typeCode;
}
public override int Length
{
get { return Value.Length; }
}
protected virtual void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength, Asn1Tag tag)
{
int num2;
var elemLength = explicitTagging ? MatchTag(buffer, tag) : implicitLength;
var num3 = elemLength;
var num4 = 0;
if (StringBuffer == null)
{
StringBuffer = new StringBuilder();
}
var lastTag = buffer.LastTag;
if ((lastTag == null) || !lastTag.Constructed)
{
if (num3 < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidLengthException);
}
StringBuffer.Length = num3;
while (num3 > 0)
{
num2 = buffer.Read();
if (num2 == -1)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, buffer.ByteCount);
}
StringBuffer[num4++] = (char)num2;
num3--;
}
}
else
{
var capacity = 0;
var context = new Asn1BerDecodeContext(buffer, elemLength);
while (!context.Expired())
{
var num5 = MatchTag(buffer, Asn1OctetString.Tag);
if (num5 <= 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidFormatOfConstructedValue, buffer.ByteCount);
}
capacity += num5;
StringBuffer.EnsureCapacity(capacity);
while (num5 > 0)
{
num2 = buffer.Read();
if (num2 == -1)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, buffer.ByteCount);
}
StringBuffer.Append((char)num2);
num5--;
}
}
if (elemLength == Asn1Status.IndefiniteLength)
{
MatchTag(buffer, Asn1Tag.Eoc);
}
}
Value = StringBuffer.ToString();
buffer.TypeCode = (short)tag.IdCode;
}
protected virtual int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging, Asn1Tag tag)
{
var length = Value.Length;
buffer.Copy(Value);
if (explicitTagging)
{
length += buffer.EncodeTagAndLength(tag, length);
}
return length;
}
public override bool Equals(object value)
{
var str = value as Asn1CharString;
if (str == null)
{
return false;
}
return Equals(str.Value);
}
public bool Equals(string value)
{
return Value.Equals(value);
}
public override int GetHashCode()
{
return (Value != null) ? Value.GetHashCode() : base.GetHashCode();
}
public override string ToString()
{
return Value;
}
}
}

View File

@@ -0,0 +1,55 @@
using System;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public abstract class Asn1Choice : Asn1Type
{
[NonSerialized]
private int _choiceId;
[NonSerialized]
protected Asn1Type Element;
public virtual int ChoiceId => _choiceId;
public abstract string ElemName { get; }
public virtual Asn1Type GetElement()
{
return Element;
}
public virtual void SetElement(int choiceId, Asn1Type element)
{
_choiceId = choiceId;
Element = element;
}
public override bool Equals(object value)
{
var choice = value as Asn1Choice;
if (choice == null)
{
return false;
}
if (_choiceId != choice._choiceId)
{
return false;
}
return Element.Equals(choice.Element);
}
public override int GetHashCode()
{
return Element?.GetHashCode() ?? base.GetHashCode();
}
}
}

View File

@@ -0,0 +1,23 @@
using System;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1ChoiceExt : Asn1OpenType
{
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
base.Decode(buffer, false, 0);
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
return base.Encode(buffer, false);
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
base.Encode(outs, false);
}
}
}

View File

@@ -0,0 +1,326 @@
using System;
using System.Collections;
using System.IO;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
public abstract class Asn1DecodeBuffer : Asn1MessageBuffer
{
private readonly ArrayList _captureBufferList;
private int _byteCount;
private Stream _inputStream;
private long _markedPosition;
private ArrayList _namedEventHandlerList;
private int _savedByteCount;
private short _typeCode;
private int[] _oidBuffer;
protected Asn1DecodeBuffer(byte[] msgdata)
{
_namedEventHandlerList = new ArrayList();
_captureBufferList = new ArrayList(5);
SetInputStream(msgdata, 0, msgdata.Length);
}
protected Asn1DecodeBuffer(Stream inputStream)
{
_namedEventHandlerList = new ArrayList();
_captureBufferList = new ArrayList(5);
_inputStream = inputStream.CanSeek ? inputStream : new BufferedStream(inputStream);
Init();
}
public virtual int ByteCount
{
get { return _byteCount; }
}
public virtual Asn1DecodeBuffer EventHandlerList
{
set { _namedEventHandlerList = value._namedEventHandlerList; }
}
public virtual short TypeCode
{
set { _typeCode = value; }
}
public virtual void AddCaptureBuffer(MemoryStream buffer)
{
_captureBufferList.Add(buffer);
}
public virtual void AddNamedEventHandler(IAsn1NamedEventHandler handler)
{
_namedEventHandlerList.Add(handler);
}
public virtual void Capture(int nbytes)
{
for (var i = 0; i < nbytes; i++)
{
var num = _inputStream.ReadByte();
if (num == -1)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, ByteCount);
}
foreach (MemoryStream s in _captureBufferList)
{
s.WriteByte((byte)num);
}
_byteCount++;
}
}
public virtual long DecodeIntValue(int length, bool signExtend)
{
return Asn1RunTime.DecodeIntValue(this, length, signExtend);
}
public virtual int[] DecodeOidContents(int llen)
{
var index = 0;
if (_oidBuffer == null)
{
_oidBuffer = new int[0x80];
}
while (llen > 0)
{
int num;
if (index >= 0x80)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidObjectIdException);
}
_oidBuffer[index] = 0;
do
{
num = ReadByte();
_oidBuffer[index] = (_oidBuffer[index] * 0x80) + (num & 0x7f);
llen--;
}
while ((num & 0x80) != 0);
if (index == 0)
{
var num3 = _oidBuffer[0];
_oidBuffer[0] = ((num3 / 40) >= 2) ? 2 : (num3 / 40);
_oidBuffer[1] = (_oidBuffer[0] == 2) ? (num3 - 80) : (num3 % 40);
index = 2;
}
else
{
index++;
}
}
if (llen != 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidLengthException);
}
var destinationArray = new int[index];
Array.Copy(_oidBuffer, 0, destinationArray, 0, index);
return destinationArray;
}
public virtual int[] DecodeRelOidContents(int llen)
{
var index = 0;
if (_oidBuffer == null)
{
_oidBuffer = new int[0x80];
}
while (llen > 0)
{
int num;
if (index >= 0x80)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidObjectIdException);
}
_oidBuffer[index] = 0;
do
{
num = ReadByte();
_oidBuffer[index] = (_oidBuffer[index] * 0x80) + (num & 0x7f);
llen--;
}
while ((num & 0x80) != 0);
index++;
}
if (llen != 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidLengthException);
}
var destinationArray = new int[index];
Array.Copy(_oidBuffer, 0, destinationArray, 0, index);
return destinationArray;
}
public override Stream GetInputStream()
{
return _inputStream;
}
public virtual void HexDump()
{
HexDump(_inputStream);
}
protected virtual void Init()
{
_byteCount = 0;
_markedPosition = 0L;
_savedByteCount = 0;
}
public virtual void InvokeCharacters(string svalue)
{
var enumerator = _namedEventHandlerList.GetEnumerator();
while (enumerator.MoveNext())
{
((IAsn1NamedEventHandler)enumerator.Current).Characters(svalue, _typeCode);
}
}
public virtual void InvokeEndElement(string name, int index)
{
var enumerator = _namedEventHandlerList.GetEnumerator();
while (enumerator.MoveNext())
{
((IAsn1NamedEventHandler)enumerator.Current).EndElement(name, index);
}
}
public virtual void InvokeStartElement(string name, int index)
{
var enumerator = _namedEventHandlerList.GetEnumerator();
while (enumerator.MoveNext())
{
((IAsn1NamedEventHandler)enumerator.Current).StartElement(name, index);
}
}
public virtual void Mark()
{
_savedByteCount = _byteCount;
_markedPosition = _inputStream.Position;
}
public virtual int Read()
{
var num = _inputStream.ReadByte();
if (num == -1)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, ByteCount);
}
foreach (MemoryStream s in _captureBufferList)
{
s.WriteByte((byte)num);
}
_byteCount++;
return num;
}
public virtual void Read(byte[] buffer)
{
Read(buffer, 0, buffer.Length);
}
public virtual void Read(byte[] buffer, int offset, int nbytes)
{
var count = nbytes;
var num3 = offset;
while (count > 0)
{
var num = _inputStream.Read(buffer, num3, count);
if (num <= 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, ByteCount);
}
num3 += num;
count -= num;
}
foreach (MemoryStream s in _captureBufferList)
{
s.Write(buffer, offset, nbytes);
}
_byteCount += nbytes;
}
public abstract int ReadByte();
public virtual void RemoveCaptureBuffer(MemoryStream buffer)
{
for (var i = 0; i < _captureBufferList.Count; i++)
{
if (buffer == _captureBufferList[i])
{
_captureBufferList.RemoveAt(i);
return;
}
}
}
public virtual void Reset()
{
try
{
_inputStream.Position = _markedPosition;
_byteCount = _savedByteCount;
}
catch (Exception)
{
}
}
public virtual void SetInputStream(byte[] msgdata, int offset, int length)
{
_inputStream = new MemoryStream(msgdata, offset, length);
Init();
}
public virtual long Skip(long nbytes)
{
var inputStream = _inputStream;
var position = inputStream.Position;
return (inputStream.Seek(nbytes, SeekOrigin.Current) - position);
}
}
}

View File

@@ -0,0 +1,17 @@
using System.IO;
namespace GostCryptography.Asn1.Ber
{
public class Asn1DerDecodeBuffer : Asn1BerDecodeBuffer
{
public Asn1DerDecodeBuffer(byte[] msgdata)
: base(msgdata)
{
}
public Asn1DerDecodeBuffer(Stream inputStream)
: base(inputStream)
{
}
}
}

View File

@@ -0,0 +1,16 @@
namespace GostCryptography.Asn1.Ber
{
public class Asn1DerEncodeBuffer : Asn1BerEncodeBuffer
{
public Asn1DerEncodeBuffer()
{
ByteIndex = SizeIncrement - 1;
}
public Asn1DerEncodeBuffer(int sizeIncrement)
: base(sizeIncrement)
{
ByteIndex = SizeIncrement - 1;
}
}
}

View File

@@ -0,0 +1,42 @@
using System.IO;
namespace GostCryptography.Asn1.Ber
{
public class Asn1DerInputStream : Asn1DerDecodeBuffer, IAsn1InputStream
{
public Asn1DerInputStream(Stream inputStream)
: base(inputStream)
{
}
public virtual int Available()
{
var inputStream = GetInputStream();
if (inputStream != null)
{
var num = inputStream.Length - inputStream.Position;
return (int)num;
}
return 0;
}
public virtual void Close()
{
var inputStream = GetInputStream();
if (inputStream != null)
{
inputStream.Close();
}
}
public virtual bool MarkSupported()
{
var inputStream = GetInputStream();
return ((inputStream != null) && inputStream.CanSeek);
}
}
}

View File

@@ -0,0 +1,58 @@
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
public class Asn1DiscreteCharSet : Asn1CharSet
{
private readonly int[] _charSet;
public Asn1DiscreteCharSet(string charSet)
: base(charSet.Length)
{
_charSet = new int[charSet.Length];
for (var i = 0; i < _charSet.Length; i++)
{
_charSet[i] = charSet[i];
}
}
public Asn1DiscreteCharSet(int[] charSet)
: base(charSet.Length)
{
_charSet = charSet;
}
public override int MaxValue
{
get { return _charSet[_charSet.Length - 1]; }
}
public override int GetCharAtIndex(int index)
{
if (index >= _charSet.Length)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1ConsVioException, "Character index", index);
}
return _charSet[index];
}
public override int GetCharIndex(int charValue)
{
var index = 0;
while ((index < _charSet.Length) && (_charSet[index] != charValue))
{
index++;
}
if (index >= _charSet.Length)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1ConsVioException, "Character index", charValue);
}
return index;
}
}
}

View File

@@ -0,0 +1,84 @@
using System;
using System.IO;
namespace GostCryptography.Asn1.Ber
{
public abstract class Asn1EncodeBuffer : Asn1MessageBuffer
{
public const int DefaultSizeIncrement = 0x400;
protected byte[] Data;
protected int ByteIndex;
protected int SizeIncrement;
protected Asn1EncodeBuffer()
{
InitBuffer(DefaultSizeIncrement);
}
protected Asn1EncodeBuffer(int sizeIncrement)
{
if (sizeIncrement == 0)
{
sizeIncrement = DefaultSizeIncrement;
}
InitBuffer(sizeIncrement);
}
public abstract byte[] MsgCopy { get; }
public abstract int MsgLength { get; }
public virtual void BinDump(string varName)
{
var outs = new StreamWriter(Console.OpenStandardOutput(), Console.Out.Encoding)
{
AutoFlush = true
};
BinDump(outs, varName);
}
public abstract void BinDump(StreamWriter outs, string varName);
protected internal virtual void CheckSize(int bytesRequired)
{
if ((ByteIndex + bytesRequired) > Data.Length)
{
var num = ((bytesRequired - 1) / SizeIncrement) + 1;
var num2 = num * SizeIncrement;
var destinationArray = new byte[Data.Length + num2];
Array.Copy(Data, 0, destinationArray, 0, ByteIndex + 1);
Data = destinationArray;
}
}
public abstract void Copy(byte value);
public abstract void Copy(byte[] value);
public virtual void HexDump()
{
HexDump(GetInputStream());
}
public virtual void HexDump(StreamWriter outs)
{
HexDump(GetInputStream(), outs);
}
protected virtual void InitBuffer(int sizeIncrement)
{
SizeIncrement = sizeIncrement;
Data = new byte[SizeIncrement];
ByteIndex = 0;
}
public abstract void Reset();
public abstract void Write(Stream outs);
}
}

View File

@@ -0,0 +1,80 @@
using System;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public abstract class Asn1Enumerated : Asn1Type
{
public const int Undefined = -999;
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, EnumeratedTypeCode);
[NonSerialized]
public int Value;
public Asn1Enumerated()
{
Value = Undefined;
}
public Asn1Enumerated(int value)
{
Value = value;
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
var length = explicitTagging ? MatchTag(buffer, Tag) : implicitLength;
Value = (int)Asn1RunTime.DecodeIntValue(buffer, length, true);
buffer.TypeCode = EnumeratedTypeCode;
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
var len = buffer.EncodeIntValue(Value);
if (explicitTagging)
{
len += buffer.EncodeTagAndLength(Tag, len);
}
return len;
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
if (explicitTagging)
{
outs.EncodeTag(Tag);
}
outs.EncodeIntValue(Value, true);
}
public virtual bool Equals(int value)
{
return (Value == value);
}
public override bool Equals(object value)
{
var enumerated = value as Asn1Enumerated;
return (enumerated != null && Value == enumerated.Value);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
public virtual int ParseValue(string value)
{
return -1;
}
public override string ToString()
{
return null;
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1GeneralString : Asn1VarWidthCharString
{
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, GeneralStringTypeCode);
public Asn1GeneralString()
: base(GeneralStringTypeCode)
{
}
public Asn1GeneralString(string data)
: base(data, GeneralStringTypeCode)
{
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
Decode(buffer, explicitTagging, implicitLength, Tag);
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
return Encode(buffer, explicitTagging, Tag);
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
outs.EncodeCharString(Value, explicitTagging, Tag);
}
}
}

View File

@@ -0,0 +1,344 @@
using System;
using System.Text;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1GeneralizedTime : Asn1Time
{
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, GeneralTimeTypeCode);
public Asn1GeneralizedTime()
: base(GeneralTimeTypeCode, false)
{
}
public Asn1GeneralizedTime(bool useDerRules)
: base(GeneralTimeTypeCode, useDerRules)
{
}
public Asn1GeneralizedTime(string data)
: base(data, GeneralTimeTypeCode, false)
{
}
public Asn1GeneralizedTime(string data, bool useDerRules)
: base(data, GeneralTimeTypeCode, useDerRules)
{
}
public virtual int Century
{
get
{
var yearValue = Year;
if (yearValue < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidYearValue, yearValue);
}
return (yearValue / 100);
}
set
{
if ((value < 0) || (value > 0x63))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidCenturyValue, value);
}
SafeParseString();
YearValue = (value * 100) + (YearValue % 100);
CompileString();
}
}
protected override bool CompileString()
{
int minuteValue;
if (((YearValue < 0) || (MonthValue <= 0)) || ((DayValue <= 0) || (HourValue < 0)))
{
return false;
}
Value = "";
if (StringBuffer == null)
{
StringBuffer = new StringBuilder();
}
else
{
StringBuffer.Length = 0;
}
if ((DerRules || UtcFlag) && ((DiffHourValue != 0) || (DiffMinValue != 0)))
{
var time = GetTime();
time.AddMinutes(-DiffMinValue);
time.AddHours(-DiffHourValue);
PutInteger(4, time.Year);
PutInteger(2, time.Month);
PutInteger(2, time.Day);
PutInteger(2, time.Hour);
minuteValue = time.Minute;
}
else
{
PutInteger(4, YearValue);
PutInteger(2, MonthValue);
PutInteger(2, DayValue);
PutInteger(2, HourValue);
minuteValue = MinuteValue;
}
if ((DerRules || (minuteValue > 0)) || ((SecondValue > 0) || (SecFraction.Length > 0)))
{
PutInteger(2, minuteValue);
if ((DerRules || (SecondValue > 0)) || (SecFraction.Length > 0))
{
PutInteger(2, SecondValue);
if (SecFraction.Length > 0)
{
StringBuffer.Append('.');
StringBuffer.Append(SecFraction);
}
}
}
if (DerRules || UtcFlag)
{
StringBuffer.Append('Z');
}
else if ((DiffHourValue != 0) || (DiffMinValue != 0))
{
StringBuffer.Append((DiffHourValue > 0) ? '+' : '-');
if (DiffMinValue != 0)
{
PutInteger(2, Math.Abs(DiffHourValue));
PutInteger(2, Math.Abs(DiffMinValue));
}
else
{
PutInteger(2, Math.Abs(DiffHourValue));
}
}
Value = StringBuffer.ToString();
return true;
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
Decode(buffer, explicitTagging, implicitLength, Tag);
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
return Encode(buffer, explicitTagging, Tag);
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
Encode(outs, explicitTagging, Tag);
}
public override void ParseString(string data)
{
if (data == null)
{
throw ExceptionUtility.ArgumentNull("data");
}
Clear();
var off = new IntHolder(0);
try
{
YearValue = ParseInt(data, off, 4);
MonthValue = ParseInt(data, off, 2);
DayValue = ParseInt(data, off, 2);
if (YearValue < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidYearValue, YearValue);
}
if ((MonthValue < 1) || (MonthValue > 12))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidMonthValue, MonthValue);
}
int num = DaysInMonth[MonthValue];
if (((MonthValue == 2) && ((YearValue % 4) == 0)) && (((YearValue % 100) != 0) || ((YearValue % 400) == 0)))
{
num++;
}
if ((DayValue < 1) || (DayValue > num))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidDayValue, DayValue);
}
var num2 = 0;
if (!char.IsDigit(CharAt(data, off.Value)))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1HoursExpected);
}
HourValue = ParseInt(data, off, 2);
num2++;
if (char.IsDigit(CharAt(data, off.Value)))
{
MinuteValue = ParseInt(data, off, 2);
num2++;
if (char.IsDigit(CharAt(data, off.Value)))
{
SecondValue = ParseInt(data, off, 2);
num2++;
}
}
if ((num2 >= 1) && ((HourValue < 0) || (HourValue > 0x17)))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidHourValue, HourValue);
}
if ((num2 >= 2) && ((MinuteValue < 0) || (MinuteValue > 0x3b)))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidMinuteValue, MinuteValue);
}
if ((num2 == 3) && ((SecondValue < 0) || (SecondValue > 0x3b)))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidSecondValue, SecondValue);
}
var ch = CharAt(data, off.Value);
if (DerRules && (ch == ','))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidDecimalMark);
}
if ((ch == '.') || (ch == ','))
{
off.Value++;
if (num2 != 3)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1UnexpectedSymbol);
}
var length = 0;
while (char.IsDigit(CharAt(data, off.Value + length)))
{
length++;
}
if (length == 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1UnexpectedSymbol);
}
SecFraction = data.Substring(off.Value, length);
off.Value += length;
}
if (CharAt(data, off.Value) == 'Z')
{
off.Value++;
UtcFlag = true;
if (off.Value != data.Length)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1UnexpectedValuesAtEndOfString);
}
}
else
{
if (DerRules)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1UnexpectedZoneOffset);
}
UtcFlag = false;
var ch2 = CharAt(data, off.Value);
switch (ch2)
{
case '-':
case '+':
off.Value++;
if (!char.IsDigit(CharAt(data, off.Value)))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidDiffHour);
}
DiffHourValue = ParseInt(data, off, 2);
if (char.IsDigit(CharAt(data, off.Value)))
{
DiffMinValue = ParseInt(data, off, 2);
}
if ((DiffHourValue < 0) || (DiffHourValue > 12))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidDiffHourValue, DiffHourValue);
}
if ((DiffMinValue < 0) || (DiffMinValue > 0x3b))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidDiffMinuteValue, DiffMinValue);
}
if (ch2 == '-')
{
DiffHourValue = -DiffHourValue;
DiffMinValue = -DiffMinValue;
}
break;
}
}
Parsed = true;
if (data != Value)
{
CompileString();
}
}
catch (IndexOutOfRangeException)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidDateFormat);
}
catch (FormatException)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidNumberFormat);
}
catch (ArgumentException)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidDateFormat);
}
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1GraphicString : Asn1VarWidthCharString
{
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, GraphicStringTypeCode);
public Asn1GraphicString()
: base(GraphicStringTypeCode)
{
}
public Asn1GraphicString(string data)
: base(data, GraphicStringTypeCode)
{
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
Decode(buffer, explicitTagging, implicitLength, Tag);
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
return Encode(buffer, explicitTagging, Tag);
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
outs.EncodeCharString(base.Value, explicitTagging, Tag);
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1Ia5String : Asn18BitCharString
{
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, Ia5StringTypeCode);
public Asn1Ia5String()
: base(Ia5StringTypeCode)
{
}
public Asn1Ia5String(string data)
: base(data, Ia5StringTypeCode)
{
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
Decode(buffer, explicitTagging, implicitLength, Tag);
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
return Encode(buffer, explicitTagging, Tag);
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
outs.EncodeCharString(Value, explicitTagging, Tag);
}
}
}

View File

@@ -0,0 +1,91 @@
using System;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1Integer : Asn1Type
{
public const int SizeOfInt = 4;
public const int SizeOfLong = 8;
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, BigIntegerTypeCode);
[NonSerialized]
public long Value;
public Asn1Integer()
{
Value = 0L;
}
public Asn1Integer(long value)
{
Value = value;
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
var length = explicitTagging ? MatchTag(buffer, Tag) : implicitLength;
Value = Asn1RunTime.DecodeIntValue(buffer, length, true);
buffer.TypeCode = BigIntegerTypeCode;
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
var len = buffer.EncodeIntValue(Value);
if (explicitTagging)
{
len += buffer.EncodeTagAndLength(Tag, len);
}
return len;
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
if (explicitTagging)
{
outs.EncodeTag(Tag);
}
outs.EncodeIntValue(Value, true);
}
public virtual bool Equals(long value)
{
return (Value == value);
}
public override bool Equals(object value)
{
var integer = value as Asn1Integer;
if (integer == null)
{
return false;
}
return (Value == integer.Value);
}
public virtual int GetBitCount()
{
return Asn1RunTime.GetLongBitCount(Value);
}
public static int GetBitCount(long ivalue)
{
return Asn1RunTime.GetLongBitCount(ivalue);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
public override string ToString()
{
return Convert.ToString(Value);
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.IO;
namespace GostCryptography.Asn1.Ber
{
public abstract class Asn1MessageBuffer
{
public abstract Stream GetInputStream();
public static void HexDump(Stream ins)
{
var outs = new StreamWriter(Console.OpenStandardOutput(), Console.Out.Encoding)
{
AutoFlush = true
};
HexDump(ins, outs);
}
public static void HexDump(Stream ins, StreamWriter outs)
{
}
}
}

View File

@@ -0,0 +1,48 @@
using System;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1Null : Asn1Type
{
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, NullTypeCode);
public static readonly Asn1Null NullValue = new Asn1Null();
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
if (explicitTagging)
{
MatchTag(buffer, Tag);
}
buffer.TypeCode = NullTypeCode;
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
var len = 0;
if (explicitTagging)
{
len += buffer.EncodeTagAndLength(Tag, len);
}
return len;
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
if (explicitTagging)
{
outs.EncodeTag(Tag);
}
outs.EncodeLength(0);
}
public override string ToString()
{
return "NULL";
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1NumericString : Asn18BitCharString
{
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, NumericStringTypeCode);
public Asn1NumericString()
: base(NumericStringTypeCode)
{
}
public Asn1NumericString(string data)
: base(data, NumericStringTypeCode)
{
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
Decode(buffer, explicitTagging, implicitLength, Tag);
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
return Encode(buffer, explicitTagging, Tag);
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
outs.EncodeCharString(Value, explicitTagging, Tag);
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1ObjectDescriptor : Asn1VarWidthCharString
{
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, ObjectDescriptorTypeCode);
public Asn1ObjectDescriptor()
: base(ObjectDescriptorTypeCode)
{
}
public Asn1ObjectDescriptor(string data)
: base(data, ObjectDescriptorTypeCode)
{
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
Decode(buffer, explicitTagging, implicitLength, Tag);
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
return Encode(buffer, explicitTagging, Tag);
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
outs.EncodeCharString(Value, explicitTagging, Tag);
}
}
}

View File

@@ -0,0 +1,137 @@
using System;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1ObjectIdentifier : Asn1Type
{
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, ObjectIdentifierTypeCode);
[NonSerialized]
protected OidValue OidValue;
public OidValue Oid => OidValue;
public Asn1ObjectIdentifier()
{
OidValue = null;
}
public Asn1ObjectIdentifier(OidValue oidValue)
{
OidValue = oidValue;
}
public static Asn1ObjectIdentifier FromString(string value)
{
return string.IsNullOrEmpty(value) ? null : new Asn1ObjectIdentifier(OidValue.FromString(value));
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
var len = explicitTagging ? MatchTag(buffer, Tag) : implicitLength;
if (len <= 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidLengthException);
}
OidValue = OidValue.FromArray(buffer.DecodeOidContents(len));
buffer.TypeCode = ObjectIdentifierTypeCode;
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
if (((OidValue.Items.Length < 2) || (OidValue.Items[0] > 2)) || ((OidValue.Items[0] != 2) && (OidValue.Items[1] > 0x27)))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidObjectIdException);
}
var len = 0;
for (var i = OidValue.Items.Length - 1; i >= 1; i--)
{
len += buffer.EncodeIdentifier((i == 1) ? ((OidValue.Items[0] * 40) + OidValue.Items[1]) : OidValue.Items[i]);
}
if (explicitTagging)
{
len += buffer.EncodeTagAndLength(Tag, len);
}
return len;
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
if (((OidValue.Items.Length < 2) || (OidValue.Items[0] > 2)) || ((OidValue.Items[0] != 2) && (OidValue.Items[1] > 0x27)))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidObjectIdException);
}
var len = 1;
for (var i = 2; i < OidValue.Items.Length; i++)
{
len += Asn1RunTime.GetIdentBytesCount(OidValue.Items[i]);
}
if (explicitTagging)
{
outs.EncodeTag(Tag);
}
outs.EncodeLength(len);
var ident = (OidValue.Items[0] * 40) + OidValue.Items[1];
outs.EncodeIdentifier(ident);
for (var i = 2; i < OidValue.Items.Length; i++)
{
outs.EncodeIdentifier(OidValue.Items[i]);
}
}
public override bool Equals(object obj)
{
if (this == obj)
{
return true;
}
if (!(obj is Asn1ObjectIdentifier))
{
return false;
}
var other = (Asn1ObjectIdentifier)obj;
if (OidValue == other.OidValue)
{
return true;
}
if (OidValue == null || other.OidValue == null)
{
return false;
}
return OidValue.Equals(other.OidValue);
}
public override int GetHashCode()
{
return OidValue?.GetHashCode() ?? base.GetHashCode();
}
public override string ToString()
{
return OidValue?.ToString() ?? base.ToString();
}
}
}

View File

@@ -0,0 +1,235 @@
using System;
using System.IO;
using System.Text;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1OctetString : Asn1Type, IComparable
{
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, OctetStringTypeCode);
[NonSerialized]
public byte[] Value;
public Asn1OctetString()
{
Value = null;
}
public Asn1OctetString(byte[] data)
{
Value = data;
}
public Asn1OctetString(string value)
{
Value = string.IsNullOrEmpty(value) ? new byte[0] : Asn1Value.ParseString(value);
}
public Asn1OctetString(byte[] data, int offset, int nbytes)
{
Value = new byte[nbytes];
if (data != null)
{
Array.Copy(data, offset, Value, 0, nbytes);
}
}
public override int Length
{
get { return Value.Length; }
}
public virtual int CompareTo(object octstr)
{
var value = ((Asn1OctetString)octstr).Value;
var num = (Value.Length < value.Length) ? Value.Length : value.Length;
for (var i = 0; i < num; i++)
{
var num2 = Value[i] & 0xff;
var num3 = value[i] & 0xff;
if (num2 < num3)
{
return -1;
}
if (num2 > num3)
{
return 1;
}
}
if (Value.Length == value.Length)
{
return 0;
}
if (Value.Length < value.Length)
{
return -1;
}
return 1;
}
private void AllocByteArray(int nbytes)
{
if (Value == null)
{
Value = new byte[nbytes];
}
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
var elemLength = explicitTagging ? MatchTag(buffer, Tag) : implicitLength;
var lastTag = buffer.LastTag;
if ((lastTag == null) || !lastTag.Constructed)
{
if (elemLength < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidLengthException);
}
Value = new byte[elemLength];
if (elemLength != 0)
{
buffer.Read(Value);
}
}
else
{
var nbytes = 0;
var offset = 0;
var context = new Asn1BerDecodeContext(buffer, elemLength);
while (!context.Expired())
{
var num2 = MatchTag(buffer, Tag);
if (num2 <= 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidFormatOfConstructedValue, buffer.ByteCount);
}
nbytes += num2;
if (offset == 0)
{
Value = new byte[nbytes];
}
else
{
ReAllocByteArray(nbytes);
}
buffer.Read(Value, offset, num2);
offset = nbytes;
}
if (elemLength == Asn1Status.IndefiniteLength)
{
MatchTag(buffer, Asn1Tag.Eoc);
}
}
buffer.TypeCode = OctetStringTypeCode;
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
if (Value == null)
{
Value = new byte[0];
}
var length = Value.Length;
if (length != 0)
{
buffer.Copy(Value);
}
if (explicitTagging)
{
length += buffer.EncodeTagAndLength(Tag, length);
}
return length;
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
outs.EncodeOctetString(Value, explicitTagging, Tag);
}
public bool Equals(byte[] value)
{
if (value.Length != Value.Length)
{
return false;
}
for (var i = 0; i < value.Length; i++)
{
if (value[i] != Value[i])
{
return false;
}
}
return true;
}
public override bool Equals(object value)
{
var str = value as Asn1OctetString;
return (str != null) && Equals(str.Value);
}
public override int GetHashCode()
{
return (Value != null) ? Value.GetHashCode() : base.GetHashCode();
}
private void ReAllocByteArray(int nbytes)
{
var value = Value;
Value = new byte[nbytes];
if (value != null)
{
Array.Copy(value, 0, Value, 0, value.Length);
}
}
public virtual Stream ToInputStream()
{
return new MemoryStream(Value, 0, Value.Length);
}
public override string ToString()
{
var str = new StringBuilder("").ToString();
if (Value != null)
{
foreach (var b in Value)
{
str = str + Asn1Util.ToHexString(b);
}
}
return str;
}
}
}

View File

@@ -0,0 +1,86 @@
using System;
using System.Collections;
using System.Text;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1OpenExt : Asn1Type
{
[NonSerialized]
public ArrayList Value = new ArrayList();
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
DecodeComponent(buffer);
}
public virtual void DecodeComponent(Asn1BerDecodeBuffer buffer)
{
var type = new Asn1OpenType();
type.Decode(buffer, false, 0);
Value.Add(type);
}
public virtual void DecodeEventComponent(Asn1BerDecodeBuffer buffer)
{
buffer.InvokeStartElement("...", -1);
var type = new Asn1OpenType();
type.Decode(buffer, false, 0);
Value.Add(type);
buffer.InvokeCharacters(type.ToString());
buffer.InvokeEndElement("...", -1);
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
var num = 0;
for (var i = Value.Count - 1; i >= 0; i--)
{
var type = (Asn1OpenType)Value[i];
num += type.Encode(buffer, false);
}
return num;
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
foreach (Asn1OpenType type in Value)
{
if (type != null)
{
type.Encode(outs, false);
}
}
}
public override string ToString()
{
if (Value == null)
{
return "<null>";
}
var builder = new StringBuilder();
for (var i = 0; i < Value.Count; i++)
{
var type = (Asn1OpenType)Value[i];
if (i != 0)
{
builder.Append(", ");
}
builder.Append(type);
}
return builder.ToString();
}
}
}

View File

@@ -0,0 +1,103 @@
using System;
using System.IO;
using System.Text;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1OpenType : Asn1OctetString
{
private const string EncodedDataMessage = "ENCODED DATA";
[NonSerialized]
private readonly Asn1EncodeBuffer _encodeBuffer;
[NonSerialized]
private readonly int _length;
[NonSerialized]
private readonly bool _textEncoding;
public Asn1OpenType()
{
_length = 0;
_textEncoding = false;
}
public Asn1OpenType(byte[] data)
: base(data)
{
_length = 0;
_textEncoding = false;
}
public Asn1OpenType(Asn1EncodeBuffer buffer)
{
if (buffer is Asn1BerEncodeBuffer)
{
_length = buffer.MsgLength;
_encodeBuffer = buffer;
}
else
{
Value = buffer.MsgCopy;
}
_textEncoding = false;
}
public Asn1OpenType(byte[] data, int offset, int nbytes)
: base(data, offset, nbytes)
{
_length = 0;
_textEncoding = false;
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
Value = buffer.DecodeOpenType();
buffer.TypeCode = OpenTypeTypeCode;
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
if (Value == null)
{
return _length;
}
return base.Encode(buffer, false);
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
if (Value != null)
{
outs.Write(Value);
}
}
public override string ToString()
{
if (Value != null)
{
try
{
return (_textEncoding ? Encoding.UTF8.GetString(Value, 0, Value.Length) : base.ToString());
}
catch (IOException)
{
return null;
}
}
if (_encodeBuffer != null)
{
return _encodeBuffer.ToString();
}
return EncodedDataMessage;
}
}
}

View File

@@ -0,0 +1,87 @@
using System.IO;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
public abstract class Asn1OutputStream : Stream
{
protected readonly Stream OutputStream;
public Asn1OutputStream(Stream outputStream)
{
OutputStream = outputStream;
}
public override bool CanRead
{
get { return false; }
}
public override bool CanSeek
{
get { return OutputStream.CanSeek; }
}
public override bool CanWrite
{
get { return OutputStream.CanWrite; }
}
public override long Length
{
get { return OutputStream.Length; }
}
public override long Position
{
get { return OutputStream.Position; }
set { OutputStream.Position = value; }
}
public override void Close()
{
OutputStream.Close();
}
public override void Flush()
{
OutputStream.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
throw ExceptionUtility.NotSupported(Resources.Asn1ReadOutputStreamNotSupported);
}
public override long Seek(long offset, SeekOrigin origin)
{
return OutputStream.Seek(offset, origin);
}
public override void SetLength(long value)
{
OutputStream.SetLength(value);
}
public virtual void Write(byte[] b)
{
OutputStream.Write(b, 0, b.Length);
}
public override void Write(byte[] b, int off, int len)
{
OutputStream.Write(b, off, len);
}
public override void WriteByte(byte b)
{
OutputStream.WriteByte(b);
}
public virtual void WriteByte(int b)
{
OutputStream.WriteByte((byte)b);
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1PrintableString : Asn18BitCharString
{
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, PrintableStringTypeCode);
public Asn1PrintableString()
: base(PrintableStringTypeCode)
{
}
public Asn1PrintableString(string data)
: base(data, PrintableStringTypeCode)
{
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
Decode(buffer, explicitTagging, implicitLength, Tag);
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
return Encode(buffer, explicitTagging, Tag);
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
outs.EncodeCharString(Value, explicitTagging, Tag);
}
}
}

View File

@@ -0,0 +1,371 @@
using System;
using System.Text;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1Real : Asn1Type
{
private const int MinusInfinity = 0x41;
private const int PlusInfinity = 0x40;
private const int RealBase2 = 0;
private const int RealBase8 = 0x10;
private const int RealBase16 = 0x20;
private const int RealBaseMask = 0x30;
private const int RealBinary = 0x80;
private const int RealExplen1 = 0;
private const int RealExplen2 = 1;
private const int RealExplen3 = 2;
private const int RealExplenLong = 3;
private const int RealExplenMask = 3;
private const int RealFactorMask = 12;
private const int RealIso6093Mask = 0x3f;
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, RealTypeCode);
[NonSerialized]
public double Value;
public Asn1Real()
{
Value = 0.0;
}
public Asn1Real(double value)
{
Value = value;
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
var length = explicitTagging ? MatchTag(buffer, Tag) : implicitLength;
if (length == 0)
{
Value = 0.0;
}
else
{
var num2 = buffer.ReadByte();
if (length == 1)
{
switch (num2)
{
case PlusInfinity:
Value = double.PositiveInfinity;
return;
case MinusInfinity:
Value = double.NegativeInfinity;
return;
}
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidFormatOfConstructedValue, buffer.ByteCount);
}
length--;
if ((num2 & RealBinary) == 0)
{
var num8 = length;
var num9 = 0;
var builder = new StringBuilder { Length = num8 };
while (num8 > 0)
{
var num7 = buffer.Read();
if (num7 == -1)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, buffer.ByteCount);
}
builder[num9++] = (char)num7;
num8--;
}
var num10 = num2 & RealIso6093Mask;
var num11 = 0;
for (var i = 0; i < builder.Length; i++)
{
var ch = builder[i];
if ((num10 >= 2) && (ch == ','))
{
builder[i] = '.';
num11++;
}
else if (((num10 >= 1) && (((ch >= '0') && (ch <= '9')) || ((ch == '+') || (ch == '-')))) || (((num10 >= 2) && (ch == '.')) || ((num10 == 3) && ((ch == 'E') || (ch == 'e')))))
{
num11++;
}
else if ((num11 != 0) || (ch != ' '))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidFormatOfConstructedValue, buffer.ByteCount);
}
}
try
{
Value = double.Parse(builder.ToString());
}
catch (FormatException)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidFormatOfConstructedValue, buffer.ByteCount);
}
}
else
{
int num6;
int num3;
switch ((num2 & RealExplenMask))
{
case RealExplen1:
num3 = 1;
break;
case RealExplen2:
num3 = 2;
break;
case RealExplen3:
num3 = 3;
break;
default:
num3 = buffer.ReadByte();
length--;
break;
}
var num4 = (int)Asn1RunTime.DecodeIntValue(buffer, num3, true);
length -= num3;
var num5 = Asn1RunTime.DecodeIntValue(buffer, length, false) * (1L << ((num2 & RealFactorMask) >> 2));
switch ((num2 & RealBaseMask))
{
case RealBase2:
num6 = 2;
break;
case RealBase8:
num6 = 8;
break;
case RealBase16:
num6 = 16;
break;
default:
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidFormatOfConstructedValue, buffer.ByteCount);
}
Value = num5 * Math.Pow(num6, num4);
if ((num2 & PlusInfinity) != 0)
{
Value = -Value;
}
}
buffer.TypeCode = RealTypeCode;
}
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
var len = 0;
if (double.IsNegativeInfinity(Value))
{
len = buffer.EncodeIntValue(MinusInfinity);
}
else if (double.IsPositiveInfinity(Value))
{
len = buffer.EncodeIntValue(PlusInfinity);
}
else if (Value != 0.0)
{
var num2 = BitConverter.DoubleToInt64Bits(Value);
var num3 = ((num2 >> RealIso6093Mask) == 0L) ? 1 : -1;
var num4 = ((int)((num2 >> 0x34) & 0x7ffL)) - 0x433;
var w = (num4 == 0) ? ((num2 & 0xfffffffffffffL) << 1) : ((num2 & 0xfffffffffffffL) | 0x10000000000000L);
if (w != 0L)
{
var bits = TrailingZerosCnt(w);
w = Asn1Util.UrShift(w, bits);
num4 += bits;
}
len += buffer.EncodeIntValue(w);
var num7 = buffer.EncodeIntValue(num4);
len += num7;
var num8 = RealBinary;
if (num3 == -1)
{
num8 |= PlusInfinity;
}
switch (num7)
{
case RealExplen2:
break;
case RealExplen3:
num8 |= 1;
break;
case RealExplenLong:
num8 |= 2;
break;
default:
num8 |= 3;
len += buffer.EncodeIntValue(num7);
break;
}
buffer.Copy((byte)num8);
len++;
}
if (explicitTagging)
{
len += buffer.EncodeTagAndLength(Tag, len);
}
return len;
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
if (explicitTagging)
{
outs.EncodeTag(Tag);
}
if (Value == 0.0)
{
outs.EncodeLength(0);
}
else if (Value == double.NegativeInfinity)
{
outs.EncodeIntValue(MinusInfinity, true);
}
else if (Value == double.PositiveInfinity)
{
outs.EncodeIntValue(PlusInfinity, true);
}
else
{
var len = 1;
var num2 = BitConverter.DoubleToInt64Bits(Value);
var num3 = ((num2 >> RealIso6093Mask) == 0L) ? 1 : -1;
var num4 = ((int)((num2 >> 0x34) & 0x7ffL)) - 0x433;
var w = (num4 == 0) ? ((num2 & 0xfffffffffffffL) << 1) : ((num2 & 0xfffffffffffffL) | 0x10000000000000L);
if (w != 0L)
{
var bits = TrailingZerosCnt(w);
w = Asn1Util.UrShift(w, bits);
num4 += bits;
len += Asn1Util.GetUlongBytesCount(w);
}
else
{
len++;
}
var num7 = RealBinary;
if (num3 == -1)
{
num7 |= PlusInfinity;
}
var bytesCount = Asn1Util.GetBytesCount(num4);
len += bytesCount;
switch (bytesCount)
{
case RealExplen2:
break;
case RealExplen3:
num7 |= 1;
break;
case RealExplenLong:
num7 |= 2;
break;
default:
num7 |= 3;
len++;
break;
}
outs.EncodeLength(len);
outs.WriteByte((byte)num7);
if ((num7 & 3) == 3)
{
outs.EncodeIntValue(bytesCount, false);
}
outs.EncodeIntValue(num4, false);
outs.EncodeIntValue(w, false);
}
}
public virtual bool Equals(double value)
{
return (Value == value);
}
public override bool Equals(object value)
{
var real = value as Asn1Real;
if (real == null)
{
return false;
}
return (Value == real.Value);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
public override string ToString()
{
return Value.ToString();
}
private static int TrailingZerosCnt(long w)
{
var num = Asn1RunTime.IntTrailingZerosCnt((int)w);
if (num >= RealBase16)
{
return (Asn1RunTime.IntTrailingZerosCnt((int)Asn1Util.UrShift(w, RealBase16)) + RealBase16);
}
return num;
}
}
}

View File

@@ -0,0 +1,74 @@
using System;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1RelativeOid : Asn1ObjectIdentifier
{
public new static readonly Asn1Tag Tag = new Asn1Tag(0, 0, RelativeOidTypeCode);
public Asn1RelativeOid()
{
}
public Asn1RelativeOid(OidValue oidValue)
: base(oidValue)
{
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
var len = explicitTagging ? MatchTag(buffer, Tag) : implicitLength;
OidValue = OidValue.FromArray(buffer.DecodeRelOidContents(len));
buffer.TypeCode = RelativeOidTypeCode;
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
if (OidValue.Items.Length < 1)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidObjectIdException);
}
var len = 0;
for (var i = OidValue.Items.Length - 1; i >= 0; i--)
{
len += buffer.EncodeIdentifier(OidValue.Items[i]);
}
if (explicitTagging)
{
len += buffer.EncodeTagAndLength(Tag, len);
}
return len;
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
var len = 0;
foreach (var i in OidValue.Items)
{
len += Asn1RunTime.GetIdentBytesCount(i);
}
if (explicitTagging)
{
outs.EncodeTag(Tag);
}
outs.EncodeLength(len);
foreach (var i in OidValue.Items)
{
outs.EncodeIdentifier(i);
}
}
}
}

View File

@@ -0,0 +1,151 @@
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
public static class Asn1RunTime
{
public const int LicBer = 1;
public const int LicPer = 2;
public const int LicXer = 4;
public const long Bit0Mask = -9223372036854775808L;
public static long DecodeIntValue(Asn1DecodeBuffer buffer, int length, bool signExtend)
{
var num = 0L;
if (length > 8)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1IntegerValueIsTooLarge);
}
for (var i = 0; i < length; i++)
{
var num2 = buffer.ReadByte();
if (num2 < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, buffer.ByteCount);
}
if ((i == 0) && signExtend)
{
num = (num2 > 0x7f) ? -1 : 0;
}
num = (num * 0x100L) + num2;
}
return num;
}
public static int GetIdentBytesCount(long ident)
{
if (ident < 0x80L)
{
return 1;
}
if (ident < 0x4000L)
{
return 2;
}
if (ident < 0x200000L)
{
return 3;
}
if (ident < 0x10000000L)
{
return 4;
}
if (ident < 0x800000000L)
{
return 5;
}
if (ident < 0x40000000000L)
{
return 6;
}
if (ident < 0x2000000000000L)
{
return 7;
}
if (ident < 0x100000000000000L)
{
return 8;
}
return 9;
}
public static int GetLongBitCount(long ivalue)
{
var num = ivalue & Bit0Mask;
var num2 = 0;
if (ivalue != 0L)
{
while ((ivalue & Bit0Mask) == num)
{
num2++;
ivalue = ivalue << 1;
}
if (num == Bit0Mask)
{
num2--;
}
return (0x40 - num2);
}
return 0;
}
public static int GetLongBytesCount(long value)
{
var num = 0x7f80000000000000L;
var num2 = 8;
if (value < 0L)
{
value ^= -1L;
}
while ((num2 > 1) && ((value & num) == 0L))
{
num = num >> 8;
num2--;
}
return num2;
}
public static int GetUlongBytesCount(long value)
{
var number = -72057594037927936L;
var num2 = 8;
while ((num2 > 1) && ((value & number) == 0L))
{
number = Asn1Util.UrShift(number, 8);
num2--;
}
return num2;
}
public static int IntTrailingZerosCnt(int w)
{
return (0x20 -
(((w & 0xffff) != 0)
? (((w & 0xff) != 0) ? ((((w & 15) != 0) ? (((w & 3) != 0) ? (((w & 1) != 0) ? 8 : 7) : (((w & 4) != 0) ? 6 : 5)) : (((w & 0x30) != 0) ? (((w & 0x10) != 0) ? 4 : 3) : (((w & 0x40) != 0) ? 2 : (((w & 0x80) != 0) ? 1 : 0)))) + 0x18) : (((((w = Asn1Util.UrShift(w, 8)) & 15) != 0) ? (((w & 3) != 0) ? (((w & 1) != 0) ? 8 : 7) : (((w & 4) != 0) ? 6 : 5)) : (((w & 0x30) != 0) ? (((w & 0x10) != 0) ? 4 : 3) : (((w & 0x40) != 0) ? 2 : (((w & 0x80) != 0) ? 1 : 0)))) + 0x10))
: ((((w = Asn1Util.UrShift(w, 0x10)) & 0xff) != 0) ? ((((w & 15) != 0) ? (((w & 3) != 0) ? (((w & 1) != 0) ? 8 : 7) : (((w & 4) != 0) ? 6 : 5)) : (((w & 0x30) != 0) ? (((w & 0x10) != 0) ? 4 : 3) : (((w & 0x40) != 0) ? 2 : (((w & 0x80) != 0) ? 1 : 0)))) + 8) : ((((w = Asn1Util.UrShift(w, 8)) & 15) != 0) ? (((w & 3) != 0) ? (((w & 1) != 0) ? 8 : 7) : (((w & 4) != 0) ? 6 : 5)) : (((w & 0x30) != 0) ? (((w & 0x10) != 0) ? 4 : 3) : (((w & 0x40) != 0) ? 2 : (((w & 0x80) != 0) ? 1 : 0)))))));
}
}
}

View File

@@ -0,0 +1,7 @@
namespace GostCryptography.Asn1.Ber
{
public static class Asn1Status
{
public const int IndefiniteLength = -9999;
}
}

View File

@@ -0,0 +1,35 @@
using System;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1T61String : Asn1VarWidthCharString
{
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, T61StringTypeCode);
public Asn1T61String()
: base(T61StringTypeCode)
{
}
public Asn1T61String(string data)
: base(data, T61StringTypeCode)
{
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
Decode(buffer, explicitTagging, implicitLength, Tag);
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
return Encode(buffer, explicitTagging, Tag);
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
outs.EncodeCharString(Value, explicitTagging, Tag);
}
}
}

View File

@@ -0,0 +1,108 @@
using System;
using System.Text;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1Tag
{
public const short Universal = 0;
public const short Private = 0xc0;
public const short Application = 0x40;
public const short Bit8Mask = 0x80;
public const short ClassMask = 0xc0;
public const short CONS = 0x20;
public const short CTXT = 0x80;
public const bool EXPL = true;
public const short EXTIDCODE = 0x1f;
public const short FormMask = 0x20;
public const short IDMask = 0x1f;
public const bool IMPL = false;
public const short L7BitsMask = 0x7f;
public const short PRIM = 0;
public static readonly Asn1Tag Eoc = new Asn1Tag(0, 0, Asn1Type.EocTypeCode);
public static readonly Asn1Tag Set = new Asn1Tag(0, 0x20, Asn1Type.SetTypeCode);
public static readonly Asn1Tag Sequence = new Asn1Tag(0, 0x20, Asn1Type.SequenceTypeCode);
public static readonly Asn1Tag Enumerated = new Asn1Tag(0, 0, Asn1Type.EnumeratedTypeCode);
[NonSerialized]
public short Class;
[NonSerialized]
public short Form;
[NonSerialized]
public int IdCode;
public Asn1Tag()
{
Class = 0;
Form = 0;
IdCode = 0;
}
public Asn1Tag(short tagclass, short form, int idCode)
{
Class = tagclass;
Form = form;
IdCode = idCode;
}
public virtual bool Constructed
{
get { return (Form == 0x20); }
}
public bool Equals(Asn1Tag tag)
{
return Equals(tag.Class, tag.Form, tag.IdCode);
}
public virtual bool Equals(short tagclass, short form, int idCode)
{
return ((Class == tagclass) && (IdCode == idCode));
}
public virtual bool IsEoc()
{
return Equals(0, 0, 0);
}
public override string ToString()
{
var builder = new StringBuilder();
builder.Append("[");
switch (Class)
{
case 0x80:
break;
case Private:
builder.Append("PRIVATE ");
break;
case Universal:
builder.Append("UNIVERSAL ");
break;
case Application:
builder.Append("APPLICATION ");
break;
default:
builder.Append("??? ");
break;
}
builder.Append(Convert.ToString(IdCode));
builder.Append("]");
return builder.ToString();
}
}
}

View File

@@ -0,0 +1,569 @@
using System;
using System.Text;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public abstract class Asn1Time : Asn18BitCharString, IComparable
{
public const int January = 1;
public const int February = 2;
public const int March = 3;
public const int April = 4;
public const int May = 5;
public const int June = 6;
public const int July = 7;
public const int August = 8;
public const int September = 9;
public const int October = 10;
public const int November = 11;
public const int December = 12;
public static readonly short[] DaysInMonth = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
public Asn1Time(short typeCode, bool useDerRules)
: base(typeCode)
{
DerRules = useDerRules;
Init();
}
public Asn1Time(string data, short typeCode, bool useDerRules)
: base(data, typeCode)
{
DerRules = useDerRules;
Init();
}
[NonSerialized]
protected bool Parsed;
[NonSerialized]
protected bool DerRules;
[NonSerialized]
protected int DiffHourValue;
public virtual int DiffHour
{
get
{
if (!Parsed)
{
ParseString(Value);
}
return DiffHourValue;
}
set
{
if ((value < -12) || (value > 12))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidDiffHourValue, value);
}
SafeParseString();
DiffHourValue = value;
CompileString();
}
}
[NonSerialized]
protected int DiffMinValue;
public virtual int DiffMinute
{
get
{
if (!Parsed)
{
ParseString(Value);
}
return DiffMinValue;
}
}
[NonSerialized]
protected string SecFraction;
public virtual string Fraction
{
get
{
if (!Parsed)
{
ParseString(Value);
}
return SecFraction;
}
set
{
SafeParseString();
SecFraction = value;
CompileString();
}
}
[NonSerialized]
protected int YearValue;
public virtual int Year
{
get
{
if (!Parsed)
{
ParseString(Value);
}
return YearValue;
}
set
{
if (value < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidYearValue, value);
}
if (!CheckDate(DayValue, MonthValue, value))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidYearValueForDayAndMonth, value, DayValue, MonthValue);
}
SafeParseString();
YearValue = value;
CompileString();
}
}
[NonSerialized]
protected int MonthValue;
public virtual int Month
{
get
{
if (!Parsed)
{
ParseString(Value);
}
return MonthValue;
}
set
{
if ((value < 1) || (value > 12))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidMonthValue, value);
}
if (!CheckDate(DayValue, value, YearValue))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidMonthValueForDayAndYear, value, DayValue, YearValue);
}
SafeParseString();
MonthValue = value;
CompileString();
}
}
[NonSerialized]
protected int DayValue;
public virtual int Day
{
get
{
if (!Parsed)
{
ParseString(Value);
}
return DayValue;
}
set
{
if (((value < 1) || (value > 31)) || !CheckDate(value, MonthValue, YearValue))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidDayValueForMonthAndYear, value, MonthValue, YearValue);
}
SafeParseString();
DayValue = value;
CompileString();
}
}
[NonSerialized]
protected int HourValue;
public virtual int Hour
{
get
{
if (!Parsed)
{
ParseString(Value);
}
return HourValue;
}
set
{
if ((value < 0) || (value > 23))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidHourValue, value);
}
SafeParseString();
HourValue = value;
CompileString();
}
}
[NonSerialized]
protected int MinuteValue;
public virtual int Minute
{
get
{
if (!Parsed)
{
ParseString(Value);
}
return MinuteValue;
}
set
{
if ((value < 0) || (value > 59))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidMinuteValue, value);
}
SafeParseString();
MinuteValue = value;
CompileString();
}
}
[NonSerialized]
protected int SecondValue;
public virtual int Second
{
get
{
if (!Parsed)
{
ParseString(Value);
}
return SecondValue;
}
set
{
if ((value < 0) || (value > 59))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidSecondValue, value);
}
SafeParseString();
SecondValue = value;
CompileString();
}
}
[NonSerialized]
protected bool UtcFlag;
public virtual bool Utc
{
get
{
if (!Parsed)
{
ParseString(Value);
}
return UtcFlag;
}
set
{
if (!DerRules)
{
SafeParseString();
UtcFlag = value;
CompileString();
}
}
}
public virtual int CompareTo(object other)
{
if (other is DateTime)
{
var time2 = (DateTime)other;
return (int)(GetTime().Ticks - time2.Ticks);
}
return (int)(GetTime().Ticks - ((Asn1Time)other).GetTime().Ticks);
}
protected static char CharAt(string s, int index)
{
if (index >= s.Length)
{
return '\0';
}
return s[index];
}
private static bool CheckDate(int day, int month, int year)
{
if ((day <= 0) || (month <= 0))
{
return true;
}
if ((year >= 0) && (month > 0))
{
int num = DaysInMonth[month];
if (((month == 2) && ((year % 4) == 0)) && (((year % 100) != 0) || ((year % 400) == 0)))
{
num++;
}
if ((day >= 1) && (day <= num))
{
return true;
}
}
else if (month > 0)
{
if (day <= DaysInMonth[month])
{
return true;
}
if ((month == 2) && (day <= (DaysInMonth[month] + 1)))
{
return true;
}
}
return false;
}
public virtual void Clear()
{
YearValue = MonthValue = DayValue = HourValue = -1;
MinuteValue = SecondValue = DiffHourValue = DiffMinValue = 0;
UtcFlag = DerRules;
Parsed = true;
SecFraction = "";
Value = "";
}
protected abstract bool CompileString();
protected override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength, Asn1Tag tag)
{
Parsed = false;
base.Decode(buffer, explicitTagging, implicitLength, tag);
DerRules = buffer is Asn1DerDecodeBuffer;
}
protected override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging, Asn1Tag tag)
{
SafeParseString();
var flag = buffer is Asn1DerEncodeBuffer;
if (DerRules != flag)
{
DerRules = flag;
if (!CompileString())
{
throw ExceptionUtility.CryptographicException(Resources.Asn1TimeStringCouldNotBeGenerated);
}
}
return base.Encode(buffer, explicitTagging, tag);
}
public virtual void Encode(Asn1BerOutputStream outs, bool explicitTagging, Asn1Tag tag)
{
SafeParseString();
outs.EncodeCharString(Value, explicitTagging, tag);
}
public override bool Equals(object value)
{
if (value is Asn1Time)
{
return GetTime().Equals(((Asn1Time)value).GetTime());
}
return ((value is DateTime) && GetTime().Equals((DateTime)value));
}
public virtual int GetDiff()
{
if (!Parsed)
{
ParseString(Value);
}
return ((DiffHourValue * 60) + DiffMinValue);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
public virtual DateTime GetTime()
{
if (!string.IsNullOrEmpty(SecFraction))
{
return new DateTime(YearValue, MonthValue, DayValue, HourValue, MinuteValue, SecondValue, int.Parse(SecFraction));
}
return new DateTime(YearValue, MonthValue, DayValue, HourValue, MinuteValue, SecondValue);
}
protected virtual void Init()
{
YearValue = MonthValue = DayValue = HourValue = -1;
MinuteValue = SecondValue = 0;
DiffHourValue = DiffMinValue = 0;
UtcFlag = DerRules;
SecFraction = "";
}
protected static int ParseInt(string str, IntHolder off, int len)
{
if ((off.Value + len) > str.Length)
{
throw ExceptionUtility.ArgumentOutOfRange("off");
}
var mValue = off.Value;
off.Value += len;
return int.Parse(str.Substring(mValue, len));
}
public abstract void ParseString(string data);
protected virtual void PutInteger(int width, int value)
{
PutInteger(StringBuffer, width, value);
}
public static void PutInteger(StringBuilder data, int width, int value)
{
var str = Convert.ToString(value);
var length = str.Length;
if (length < width)
{
for (var i = length; i < width; i++)
{
data.Append('0');
}
}
else if (length > width)
{
str = str.Substring(length - width);
}
data.Append(str);
}
protected virtual void SafeParseString()
{
try
{
if (!Parsed)
{
ParseString(Value);
}
}
catch (Exception)
{
}
}
public virtual void SetDiff(int inMinutes)
{
if (Math.Abs(inMinutes) > 720)
{
throw ExceptionUtility.CryptographicException(Resources.InvalidDiffValue, inMinutes);
}
SafeParseString();
DiffHourValue = inMinutes / 60;
DiffMinValue = inMinutes % 60;
CompileString();
}
public virtual void SetDiff(int dhour, int dminute)
{
if ((dhour < -12) || (dhour > 12))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidDiffHourValue, dhour);
}
if (Math.Abs(dminute) > 59)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidDiffMinuteValue, dminute);
}
SafeParseString();
DiffHourValue = dhour;
if (dhour < 0)
{
DiffMinValue = -Math.Abs(dminute);
}
else
{
DiffMinValue = Math.Abs(dminute);
}
CompileString();
}
public virtual void SetTime(DateTime time)
{
Clear();
YearValue = time.Year;
MonthValue = time.Month;
DayValue = time.Day;
HourValue = time.Hour;
MinuteValue = time.Minute;
SecondValue = time.Second;
SecFraction = Convert.ToString(time.Millisecond);
DiffHourValue = DiffMinValue = 0;
UtcFlag = DerRules;
CompileString();
}
}
}

View File

@@ -0,0 +1,46 @@
using System;
using System.IO;
namespace GostCryptography.Asn1.Ber
{
public class Asn1TraceHandler : IAsn1NamedEventHandler
{
internal StreamWriter mPrintStream;
public Asn1TraceHandler()
{
mPrintStream = new StreamWriter(Console.OpenStandardOutput(), Console.Out.Encoding);
mPrintStream.AutoFlush = true;
}
public Asn1TraceHandler(StreamWriter ps)
{
mPrintStream = ps;
}
public virtual void Characters(string svalue, short typeCode)
{
mPrintStream.WriteLine("data: " + svalue);
}
public virtual void EndElement(string name, int index)
{
mPrintStream.Write(name);
if (index >= 0)
{
mPrintStream.Write("[" + index + "]");
}
mPrintStream.WriteLine(": end");
}
public virtual void StartElement(string name, int index)
{
mPrintStream.Write(name);
if (index >= 0)
{
mPrintStream.Write("[" + index + "]");
}
mPrintStream.WriteLine(": start");
}
}
}

View File

@@ -0,0 +1,168 @@
using System;
using System.IO;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public abstract class Asn1Type : IAsn1Type
{
public const short EocTypeCode = 0;
public const short BooleanTypeCode = 1;
public const short BigIntegerTypeCode = 2;
public const short BitStringTypeCode = 3;
public const short OctetStringTypeCode = 4;
public const short NullTypeCode = 5;
public const short ObjectIdentifierTypeCode = 6;
public const short ObjectDescriptorTypeCode = 7;
public const short ExternalTypeCode = 8;
public const short RealTypeCode = 9;
public const short EnumeratedTypeCode = 10;
public const short Utf8StringTypeCode = 12;
public const short RelativeOidTypeCode = 13;
public const short SequenceTypeCode = 0x10;
public const short SetTypeCode = 0x11;
public const short NumericStringTypeCode = 0x12;
public const short PrintableStringTypeCode = 0x13;
public const short T61StringTypeCode = 20;
public const short VideoTexStringTypeCode = 0x15;
public const short Ia5StringTypeCode = 0x16;
public const short UtcTimeTypeCode = 0x17;
public const short GeneralTimeTypeCode = 0x18;
public const short GraphicStringTypeCode = 0x19;
public const short VisibleStringTypeCode = 0x1a;
public const short GeneralStringTypeCode = 0x1b;
public const short UniversalStringTypeCode = 0x1c;
public const short BmpStringTypeCode = 30;
public const short OpenTypeTypeCode = 0x63;
[NonSerialized]
private readonly IntHolder _parsedLen = new IntHolder();
[NonSerialized]
private readonly Asn1Tag _parsedTag = new Asn1Tag();
public virtual int Length
{
get { throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidLengthException); }
}
public virtual void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
}
public virtual int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
return 0;
}
public virtual void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
}
public virtual void Print(TextWriter outs, string varName, int level)
{
Indent(outs, level);
outs.WriteLine(varName + " = " + ToString());
}
public virtual void Decode(Asn1BerDecodeBuffer buffer)
{
Decode(buffer, true, 0);
}
public virtual int Encode(Asn1BerEncodeBuffer buffer)
{
return Encode(buffer, true);
}
public static string GetTypeName(short typeCode)
{
switch (typeCode)
{
case EocTypeCode:
return "EOC";
case BooleanTypeCode:
return "BOOLEAN";
case BigIntegerTypeCode:
return "INTEGER";
case BitStringTypeCode:
return "BIT STRING";
case OctetStringTypeCode:
return "OCTET STRING";
case NullTypeCode:
return "NULL";
case ObjectIdentifierTypeCode:
return "OBJECT IDENTIFIER";
case ObjectDescriptorTypeCode:
return "ObjectDescriptor";
case ExternalTypeCode:
return "EXTERNAL";
case RealTypeCode:
return "REAL";
case EnumeratedTypeCode:
return "ENUMERATED";
case Utf8StringTypeCode:
return "UTF8String";
case SequenceTypeCode:
return "SEQUENCE";
case SetTypeCode:
return "SET";
case NumericStringTypeCode:
return "NumericString";
case PrintableStringTypeCode:
return "PrintableString";
case T61StringTypeCode:
return "T61String";
case VideoTexStringTypeCode:
return "VideotexString";
case Ia5StringTypeCode:
return "IA5String";
case UtcTimeTypeCode:
return "UTCTime";
case GeneralTimeTypeCode:
return "GeneralTime";
case GraphicStringTypeCode:
return "GraphicString";
case VisibleStringTypeCode:
return "VisibleString";
case GeneralStringTypeCode:
return "GeneralString";
case UniversalStringTypeCode:
return "UniversalString";
case BmpStringTypeCode:
return "BMPString";
case OpenTypeTypeCode:
return "ANY";
}
return "?";
}
public virtual void Indent(TextWriter outs, int level)
{
var num2 = level * 3;
for (var i = 0; i < num2; i++)
{
outs.Write(" ");
}
}
protected virtual int MatchTag(Asn1BerDecodeBuffer buffer, Asn1Tag tag)
{
return MatchTag(buffer, tag.Class, tag.Form, tag.IdCode);
}
protected virtual int MatchTag(Asn1BerDecodeBuffer buffer, short tagClass, short tagForm, int tagIdCode)
{
if (!buffer.MatchTag(tagClass, tagForm, tagIdCode, _parsedTag, _parsedLen))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1TagMatchFailedException, new Asn1Tag(tagClass, tagForm, tagIdCode), _parsedTag, buffer.ByteCount);
}
return _parsedLen.Value;
}
}
}

View File

@@ -0,0 +1,227 @@
using System;
using System.Text;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1UniversalString : Asn1Type
{
public const int BitsPerChar = 0x20;
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, UniversalStringTypeCode);
[NonSerialized]
private StringBuilder _stringBuffer;
[NonSerialized]
private int[] _value;
public Asn1UniversalString()
{
_value = new int[0];
}
public Asn1UniversalString(int[] value)
{
_value = value;
}
public Asn1UniversalString(string value)
{
_value = new int[value.Length];
for (var i = 0; i < value.Length; i++)
{
_value[i] = value[i];
}
}
public override int Length
{
get { return _value.Length; }
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
var llen = explicitTagging ? MatchTag(buffer, Tag) : implicitLength;
var idx = new IntHolder(0);
var lastTag = buffer.LastTag;
if ((lastTag == null) || !lastTag.Constructed)
{
ReadSegment(buffer, llen, idx);
}
else
{
var context = new Asn1BerDecodeContext(buffer, llen);
while (!context.Expired())
{
var num2 = MatchTag(buffer, Asn1OctetString.Tag);
if (num2 <= 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidFormatOfConstructedValue, buffer.ByteCount);
}
ReadSegment(buffer, num2, idx);
}
if (llen == Asn1Status.IndefiniteLength)
{
MatchTag(buffer, Asn1Tag.Eoc);
}
}
buffer.TypeCode = UniversalStringTypeCode;
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
var length = _value.Length;
for (var i = length - 1; i >= 0; i--)
{
var num3 = _value[i];
for (var j = 0; j < 4; j++)
{
var num = num3 % 0x100;
num3 /= 0x100;
buffer.Copy((byte)num);
}
}
length *= 4;
if (explicitTagging)
{
length += buffer.EncodeTagAndLength(Tag, length);
}
return length;
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
outs.EncodeUnivString(_value, explicitTagging, Tag);
}
public override bool Equals(object value)
{
var str = value as Asn1UniversalString;
if (str == null)
{
return false;
}
if (_value.Length != str._value.Length)
{
return false;
}
for (var i = 0; i < _value.Length; i++)
{
if (_value[i] != str._value[i])
{
return false;
}
}
return true;
}
public override int GetHashCode()
{
if (_value.Length == 0)
{
return base.GetHashCode();
}
var num = 0;
var num2 = (_value.Length > 20) ? 20 : _value.Length;
for (var i = 0; i < num2; i++)
{
num ^= _value[i];
}
return num;
}
private void ReadSegment(Asn1BerDecodeBuffer buffer, int llen, IntHolder idx)
{
if ((llen < 0) || ((llen % 4) != 0))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidLengthException);
}
var num4 = llen / 4;
if (_value.Length == 0)
{
_value = new int[num4];
}
else if ((idx.Value + num4) >= _value.Length)
{
ReallocIntArray(idx.Value + num4);
}
var value = idx.Value;
while (value < (idx.Value + num4))
{
_value[value] = 0;
for (var i = 0; i < 4; i++)
{
var num = buffer.Read();
if (num == -1)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1EndOfBufferException, buffer.ByteCount);
}
_value[value] = (_value[value] * 0x100) + num;
}
value++;
}
idx.Value = value;
}
private void ReallocIntArray(int nint)
{
var value = _value;
_value = new int[nint];
if (value != null)
{
Array.Copy(value, 0, _value, 0, value.Length);
}
}
public override string ToString()
{
if (_stringBuffer == null)
{
_stringBuffer = new StringBuilder();
}
_stringBuffer.Length = _value.Length;
for (var i = 0; i < _value.Length; i++)
{
_stringBuffer[i] = (char)_value[i];
}
return _stringBuffer.ToString();
}
}
}

View File

@@ -0,0 +1,361 @@
using System;
using System.Text;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1UtcTime : Asn1Time
{
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, UtcTimeTypeCode);
public Asn1UtcTime()
: base(UtcTimeTypeCode, false)
{
}
public Asn1UtcTime(bool useDerRules)
: base(UtcTimeTypeCode, useDerRules)
{
}
public Asn1UtcTime(string data)
: base(data, UtcTimeTypeCode, false)
{
}
public Asn1UtcTime(string data, bool useDerRules)
: base(data, UtcTimeTypeCode, useDerRules)
{
}
public override string Fraction
{
get
{
return "";
}
set
{
SecFraction = "";
throw ExceptionUtility.CryptographicException(Resources.Asn1FractionNotSupportedForUtcTime);
}
}
public override int Year
{
get
{
if (!Parsed)
{
ParseString(Value);
}
return YearValue;
}
set
{
if (value < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidYearValue, YearValue);
}
if (value < 100)
{
if (value >= 50)
{
Year = value + 0x76c;
}
else
{
Year = value + 0x7d0;
}
}
Year = value;
}
}
public override void Clear()
{
Clear();
HourValue = MinuteValue = -1;
UtcFlag = true;
}
public override int CompareTo(object obj)
{
return base.CompareTo(obj);
}
protected override bool CompileString()
{
Value = "";
if (((YearValue < 0) || (DayValue <= 0)) || (((MonthValue <= 0) || (HourValue < 0)) || (MinuteValue < 0)))
{
return false;
}
if (StringBuffer == null)
{
StringBuffer = new StringBuilder();
}
else
{
StringBuffer.Length = 0;
}
if ((DerRules || UtcFlag) && ((DiffHourValue != 0) || (DiffMinValue != 0)))
{
var time = GetTime();
time.AddMinutes(-DiffMinValue);
time.AddHours(-DiffHourValue);
PutInteger(2, time.Year);
PutInteger(2, time.Month);
PutInteger(2, time.Day);
PutInteger(2, time.Hour);
PutInteger(2, time.Minute);
}
else
{
PutInteger(2, YearValue);
PutInteger(2, MonthValue);
PutInteger(2, DayValue);
PutInteger(2, HourValue);
PutInteger(2, MinuteValue);
}
PutInteger(2, SecondValue);
if (DerRules || UtcFlag)
{
StringBuffer.Append('Z');
}
else if ((DiffHourValue != 0) || (DiffMinValue != 0))
{
StringBuffer.Append((DiffHourValue > 0) ? '+' : '-');
PutInteger(2, Math.Abs(DiffHourValue));
PutInteger(2, Math.Abs(DiffMinValue));
}
Value = StringBuffer.ToString();
return true;
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
Decode(buffer, explicitTagging, implicitLength, Tag);
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
return Encode(buffer, explicitTagging, Tag);
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
Encode(outs, explicitTagging, Tag);
}
protected override void Init()
{
Init();
HourValue = MinuteValue = -1;
UtcFlag = true;
}
public override void ParseString(string data)
{
if (data == null)
{
throw ExceptionUtility.ArgumentNull("data");
}
Clear();
var off = new IntHolder(0);
try
{
YearValue = ParseInt(data, off, 2);
MonthValue = ParseInt(data, off, 2);
DayValue = ParseInt(data, off, 2);
if (YearValue < 0)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidYearValue, YearValue);
}
if (YearValue < 100)
{
if (YearValue > 70)
{
YearValue += 0x76c;
}
else
{
YearValue += 0x7d0;
}
}
if ((MonthValue < 1) || (MonthValue > 12))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidMonthValue, MonthValue);
}
var num = DaysInMonth[MonthValue];
if (((MonthValue == 2) && ((YearValue % 4) == 0)) && (((YearValue % 100) != 0) || ((YearValue % 400) == 0)))
{
num++;
}
if ((DayValue < 1) || (DayValue > num))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidDayValue, DayValue);
}
var num2 = 0;
if (!char.IsDigit(CharAt(data, off.Value)))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1HoursExpected);
}
HourValue = ParseInt(data, off, 2);
num2++;
if (!char.IsDigit(CharAt(data, off.Value)))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1MinutesExpected);
}
MinuteValue = ParseInt(data, off, 2);
num2++;
if (char.IsDigit(CharAt(data, off.Value)))
{
SecondValue = ParseInt(data, off, 2);
num2++;
}
if ((num2 >= 2) && ((HourValue < 0) || (HourValue > UtcTimeTypeCode)))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidHourValue, HourValue);
}
if ((num2 >= 2) && ((MinuteValue < 0) || (MinuteValue > 0x3b)))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidMinuteValue, MinuteValue);
}
if ((num2 == 3) && ((SecondValue < 0) || (SecondValue > 0x3b)))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidSecondValue, SecondValue);
}
CharAt(data, off.Value);
if (CharAt(data, off.Value) == 'Z')
{
off.Value++;
UtcFlag = true;
if (off.Value != data.Length)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1UnexpectedValuesAtEndOfString);
}
}
else
{
if (DerRules)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1UnexpectedZoneOffset);
}
UtcFlag = false;
var ch = CharAt(data, off.Value);
switch (ch)
{
case '-':
case '+':
off.Value++;
if (!char.IsDigit(CharAt(data, off.Value)))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidDiffHour);
}
DiffHourValue = ParseInt(data, off, 2);
if (!char.IsDigit(CharAt(data, off.Value)))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidDiffMinute);
}
DiffMinValue = ParseInt(data, off, 2);
if ((DiffHourValue < 0) || (DiffHourValue > 12))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidDiffHourValue, DiffHourValue);
}
if ((DiffMinValue < 0) || (DiffMinValue > 0x3b))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidDiffMinuteValue, DiffMinValue);
}
if (ch == '-')
{
DiffHourValue = -DiffHourValue;
DiffMinValue = -DiffMinValue;
}
break;
}
}
Parsed = true;
if (data != Value)
{
CompileString();
}
}
catch (IndexOutOfRangeException)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidDateFormat);
}
catch (FormatException)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidNumberFormat);
}
catch (ArgumentException)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1InvalidDateFormat);
}
}
public override void SetTime(DateTime time)
{
Clear();
YearValue = time.Year;
MonthValue = time.Month;
DayValue = time.Day;
HourValue = time.Hour;
MinuteValue = time.Minute;
SecondValue = time.Second;
SecFraction = "";
DiffHourValue = DiffMinValue = 0;
UtcFlag = true;
CompileString();
}
}
}

View File

@@ -0,0 +1,98 @@
using System;
using System.IO;
using System.Text;
namespace GostCryptography.Asn1.Ber
{
[Serializable]
public class Asn1Utf8String : Asn1CharString
{
public static readonly Asn1Tag Tag = new Asn1Tag(0, 0, Utf8StringTypeCode);
public Asn1Utf8String()
: base(Utf8StringTypeCode)
{
}
public Asn1Utf8String(string data)
: base(data, Utf8StringTypeCode)
{
}
private byte[] AllocByteArray(int nbytes)
{
return new byte[nbytes];
}
public override void Decode(Asn1BerDecodeBuffer buffer, bool explicitTagging, int implicitLength)
{
var num = explicitTagging ? MatchTag(buffer, Tag) : implicitLength;
var str = new Asn1OctetString();
str.Decode(buffer, false, num);
Value = Encoding.UTF8.GetString(str.Value, 0, str.Value.Length);
if (explicitTagging && (num == Asn1Status.IndefiniteLength))
{
MatchTag(buffer, Asn1Tag.Eoc);
}
}
public override int Encode(Asn1BerEncodeBuffer buffer, bool explicitTagging)
{
var len = 0;
try
{
var bytes = Encoding.UTF8.GetBytes(Value);
len = bytes.Length;
buffer.Copy(bytes);
}
catch (IOException exception)
{
Console.Out.WriteLine("This JVM does not support UTF-8 encoding");
Asn1Util.WriteStackTrace(exception, Console.Error);
}
if (explicitTagging)
{
len += buffer.EncodeTagAndLength(Tag, len);
}
return len;
}
public override void Encode(Asn1BerOutputStream outs, bool explicitTagging)
{
try
{
var bytes = Encoding.UTF8.GetBytes(Value);
if (explicitTagging)
{
outs.EncodeTag(Tag);
}
outs.EncodeLength(bytes.Length);
outs.Write(bytes);
}
catch (IOException exception)
{
Console.Out.WriteLine("This JVM does not support UTF-8 encoding");
Asn1Util.WriteStackTrace(exception, Console.Error);
}
}
private byte[] ReAllocByteArray(byte[] ba1, int nbytes)
{
var destinationArray = new byte[nbytes];
if (ba1 != null)
{
Array.Copy(ba1, 0, destinationArray, 0, ba1.Length);
}
return destinationArray;
}
}
}

View File

@@ -0,0 +1,336 @@
using System;
using System.Collections;
using System.IO;
using System.Text;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
public static class Asn1Util
{
private static readonly byte[] Base64DecodeTable =
{
0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
60, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 0x10, 0x11, 0x12, 0x13, 20, 0x15, 0x16,
0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 30, 0x1f, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 40, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
0x31, 50, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
};
private static readonly byte[] Base64EncodeTable =
{
0x41, 0x42, 0x43, 0x44, 0x45, 70, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 80,
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 90, 0x61, 0x62, 0x63, 100, 0x65, 0x66,
0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 110, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
0x77, 120, 0x79, 0x7a, 0x30, 0x31, 50, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f
};
public static string BcdToString(byte[] bcd)
{
var index = 0;
var builder = new StringBuilder(bcd.Length * 2);
for (var i = 0; i < (bcd.Length * 2); i++)
{
byte num3;
if ((i % 2) == 0)
{
num3 = (byte)(bcd[index] & 15);
}
else
{
num3 = (byte)UrShift(bcd[index++], 4);
}
if (num3 == 15)
{
break;
}
builder.Append((num3 < 10) ? ((char)(num3 + 0x30)) : ((char)((num3 + 0x41) - 10)));
}
return builder.ToString();
}
public static byte[] DecodeBase64Array(byte[] srcArray)
{
var num = srcArray.Length / 4;
if ((4 * num) != srcArray.Length)
{
throw ExceptionUtility.Argument("srcArray", Resources.Asn1InvalidEncodedDataLength);
}
var num2 = 0;
var num3 = num;
if (srcArray.Length != 0)
{
if (srcArray[srcArray.Length - 1] == 0x3d)
{
num2++;
num3--;
}
if (srcArray[srcArray.Length - 2] == 0x3d)
{
num2++;
}
}
var buffer = new byte[(3 * num) - num2];
var num4 = 0;
var num5 = 0;
for (var i = 0; i < num3; i++)
{
var num7 = DecodeBase64Char(srcArray[num4++]);
var num8 = DecodeBase64Char(srcArray[num4++]);
var num9 = DecodeBase64Char(srcArray[num4++]);
var num10 = DecodeBase64Char(srcArray[num4++]);
buffer[num5++] = (byte)((num7 << 2) | (num8 >> 4));
buffer[num5++] = (byte)((num8 << 4) | (num9 >> 2));
buffer[num5++] = (byte)((num9 << 6) | num10);
}
if (num2 != 0)
{
var num11 = DecodeBase64Char(srcArray[num4++]);
var num12 = DecodeBase64Char(srcArray[num4++]);
buffer[num5++] = (byte)((num11 << 2) | (num12 >> 4));
if (num2 == 1)
{
var num13 = DecodeBase64Char(srcArray[num4++]);
buffer[num5++] = (byte)((num12 << 4) | (num13 >> 2));
}
}
return buffer;
}
private static int DecodeBase64Char(byte c)
{
var num = (c < 0x80) ? Base64DecodeTable[c - 40] : -1;
if (num < 0)
{
throw ExceptionUtility.Argument("c", Resources.Asn1IllegalCharacter, c);
}
return num;
}
public static byte[] EncodeBase64Array(byte[] srcArray)
{
var num = srcArray.Length / 3;
var num2 = srcArray.Length - (3 * num);
var num3 = 4 * ((srcArray.Length + 2) / 3);
var buffer = new byte[num3];
var num4 = 0;
var num5 = 0;
for (var i = 0; i < num; i++)
{
var num7 = srcArray[num4++] & 0xff;
var num8 = srcArray[num4++] & 0xff;
var num9 = srcArray[num4++] & 0xff;
buffer[num5++] = Base64EncodeTable[num7 >> 2];
buffer[num5++] = Base64EncodeTable[((num7 << 4) & 0x3f) | (num8 >> 4)];
buffer[num5++] = Base64EncodeTable[((num8 << 2) & 0x3f) | (num9 >> 6)];
buffer[num5++] = Base64EncodeTable[num9 & 0x3f];
}
if (num2 != 0)
{
var num10 = srcArray[num4++] & 0xff;
buffer[num5++] = Base64EncodeTable[num10 >> 2];
if (num2 == 1)
{
buffer[num5++] = Base64EncodeTable[(num10 << 4) & 0x3f];
buffer[num5++] = 0x3d;
buffer[num5++] = 0x3d;
return buffer;
}
var num11 = srcArray[num4++] & 0xff;
buffer[num5++] = Base64EncodeTable[((num10 << 4) & 0x3f) | (num11 >> 4)];
buffer[num5++] = Base64EncodeTable[(num11 << 2) & 0x3f];
buffer[num5++] = 0x3d;
}
return buffer;
}
public static byte[] GetAddressBytes(string ipaddress)
{
var index = 0;
var buffer = new byte[4];
var tokenizer = new Tokenizer(ipaddress, ".");
try
{
while (tokenizer.HasMoreTokens())
{
buffer[index] = Convert.ToByte(tokenizer.NextToken());
index++;
}
}
catch (Exception)
{
}
return buffer;
}
public static int GetBytesCount(long val)
{
return Asn1RunTime.GetLongBytesCount(val);
}
public static int GetUlongBytesCount(long val)
{
return Asn1RunTime.GetUlongBytesCount(val);
}
public static byte[] StringToBcd(string str)
{
int num2;
var buffer = new byte[(str.Length + 1) / 2];
byte num = 0;
var num3 = num2 = 0;
while (num3 < str.Length)
{
var c = char.ToUpper(str[num3]);
var flag = char.IsDigit(c);
if (!flag && ((c < 'A') || (c >= 'F')))
{
throw ExceptionUtility.CryptographicException(Resources.Asn1ValueParseException, str, num3);
}
if ((num3 % 2) != 0)
{
num = (byte)(num | ((byte)(((byte)((flag != null) ? (c - 0x30) : ((c - 0x41) + 10))) << 4)));
buffer[num2++] = num;
}
else
{
num = flag ? ((byte)(c - '0')) : ((byte)((c - 'A') + 10));
}
num3++;
}
if ((num3 % 2) != 0)
{
buffer[num2++] = (byte)(num | 240);
}
return buffer;
}
public static void ToArray(ICollection c, object[] objects)
{
var num = 0;
var enumerator = c.GetEnumerator();
while (enumerator.MoveNext())
{
objects[num++] = enumerator.Current;
}
}
public static byte[] ToByteArray(string sourceString)
{
return Encoding.UTF8.GetBytes(sourceString);
}
public static char[] ToCharArray(byte[] byteArray)
{
return Encoding.UTF8.GetChars(byteArray);
}
public static string ToHexString(byte b)
{
var builder = new StringBuilder(4);
var str = Convert.ToString(b, 0x10);
var length = str.Length;
if (length < 2)
{
builder.Append('0');
builder.Append(str);
}
else if (length > 2)
{
builder.Append(str[length - 2]);
builder.Append(str[length - 1]);
}
else
{
builder.Append(str);
}
return builder.ToString();
}
public static string ToHexString(byte[] b, int offset, int nbytes)
{
var builder = new StringBuilder(nbytes * 4);
for (var i = 0; i < nbytes; i++)
{
builder.Append(ToHexString(b[offset + i]));
builder.Append(" ");
}
return builder.ToString();
}
public static int UrShift(int number, int bits)
{
if (number >= 0)
{
return (number >> bits);
}
return ((number >> bits) + (2 << ~bits));
}
public static int UrShift(int number, long bits)
{
return UrShift(number, (int)bits);
}
public static long UrShift(long number, int bits)
{
if (number >= 0L)
{
return (number >> bits);
}
return ((number >> bits) + (2L << ~bits));
}
public static long UrShift(long number, long bits)
{
return UrShift(number, (int)bits);
}
public static void WriteStackTrace(Exception throwable, TextWriter stream)
{
stream.Write(throwable.StackTrace);
stream.Flush();
}
}
}

View File

@@ -0,0 +1,170 @@
using System;
using System.Text;
using GostCryptography.Properties;
namespace GostCryptography.Asn1.Ber
{
public static class Asn1Value
{
private static byte[] AllocBitArray(int numbits)
{
var num = numbits / 8;
if ((numbits % 8) != 0)
{
num++;
}
return new byte[num];
}
public static byte[] ParseString(string data)
{
return ParseString(data, null);
}
public static byte[] ParseString(string data, IntHolder numbits)
{
char ch;
int num;
int num2;
int num3;
int num4;
int num5;
char ch2 = data[0];
byte[] buffer;
switch (ch2)
{
case '\'':
case '"':
if (!data.EndsWith("B"))
{
if (data.EndsWith("H"))
{
var builder = new StringBuilder();
num3 = (data.Length - 3) * 4;
buffer = AllocBitArray(num3);
builder.Length = 2;
num = 1;
num2 = 0;
ch = '\0';
while ((num < data.Length) && (ch != ch2))
{
ch = data[num++];
if (ch != ch2)
{
builder[0] = ch;
ch = (num >= data.Length) ? '0' : data[num];
builder[1] = (ch == ch2) ? '0' : ch;
buffer[num2++] = (byte)Convert.ToInt32(builder.ToString(), 0x10);
}
num++;
}
}
else
{
if (data[data.Length - 1] != ch2)
{
throw ExceptionUtility.CryptographicException(Resources.Asn1ValueParseException, data, data.Length - 1);
}
num3 = (data.Length - 2) * 8;
buffer = AllocBitArray(num3);
num = 1;
ch = '\0';
while ((num < data.Length) && (ch != ch2))
{
ch = data[num];
if (ch != ch2)
{
buffer[num - 1] = (byte)ch;
}
num++;
}
}
return SetNumBits(numbits, num3, buffer);
}
num3 = data.Length - 3;
buffer = AllocBitArray(num3);
num5 = 0x80;
num = 1;
num4 = 0;
num2 = 0;
while (num < data.Length)
{
ch = data[num];
if (ch == '1')
{
num4 |= num5;
}
else
{
if (ch == ch2)
{
break;
}
if (ch != '0')
{
ExceptionUtility.CryptographicException(Resources.Asn1ValueParseException, data, num);
}
}
num5 = num5 >> 1;
if (num5 == 0)
{
buffer[num2++] = (byte)num4;
num5 = 0x80;
num4 = 0;
}
num++;
}
break;
default:
num3 = data.Length * 8;
buffer = AllocBitArray(num3);
num = 0;
while (num < data.Length)
{
ch = data[num];
buffer[num] = (byte)ch;
num++;
}
return SetNumBits(numbits, num3, buffer);
}
if (num5 != 0x80)
{
buffer[num2] = (byte)num4;
}
return SetNumBits(numbits, num3, buffer);
}
private static byte[] SetNumBits(IntHolder numbits, int num3, byte[] buffer)
{
if (numbits != null)
{
numbits.Value = num3;
}
return buffer;
}
}
}

Some files were not shown because too many files have changed in this diff Show More