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,211 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Bb]in/
[Oo]bj/
[Aa]ssemblies/
[Dd]esigner[Bb]in/
[Ll]ogs/
project.lock.json
compiled/
*/[Cc]ontent/
# Visual Studio 2015 cache/options directory
.vs/
# Visual Studio Code cache/options directory
.vscode/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding addin-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
# !**/packages/repositories.config
# Windows Azure Build Output
csx/
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
*.[Cc]ache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.publishsettings
**/node_modules/
**/bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# .NET Portability Analyzer
*/PortabilityAnalysis*.html
# JetBrains Rider
.idea/**
*.iml
BlobStorage/

View File

@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29512.175
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GostCryptography", "Source\GostCryptography\GostCryptography.csproj", "{EE8D8C45-326A-4D71-84D0-DC71B18B22A7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GostCryptography.Tests", "Source\GostCryptography.Tests\GostCryptography.Tests.csproj", "{95439866-6A37-4343-BBD5-8C1625E11A6F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EE8D8C45-326A-4D71-84D0-DC71B18B22A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EE8D8C45-326A-4D71-84D0-DC71B18B22A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EE8D8C45-326A-4D71-84D0-DC71B18B22A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EE8D8C45-326A-4D71-84D0-DC71B18B22A7}.Release|Any CPU.Build.0 = Release|Any CPU
{95439866-6A37-4343-BBD5-8C1625E11A6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{95439866-6A37-4343-BBD5-8C1625E11A6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{95439866-6A37-4343-BBD5-8C1625E11A6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{95439866-6A37-4343-BBD5-8C1625E11A6F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {931A6A65-5EA6-4213-9740-14B08A622AEF}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,236 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeEditing/Intellisense/CodeCompletion/IntelliSenseCompletingCharacters/CSharpCompletingCharacters/UpgradedFromVSSettings/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Emin_002Ejs/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=EmptyGeneralCatchClause/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=LoopCanBeConvertedToQuery/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantLambdaParameterType/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOR/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOREACH/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_FIRST_ARG_BY_PAREN/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_LINQ_QUERY/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_ARGUMENT/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_ARRAY_AND_OBJECT_INITIALIZER/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_FOR_STMT/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTILINE_PARAMETER/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTIPLE_DECLARATION/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTLINE_TYPE_PARAMETER_CONSTRAINS/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ALIGN_MULTLINE_TYPE_PARAMETER_LIST/@EntryValue">True</s:Boolean>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_SINGLE_LINE_AUTO_PROPERTY/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_SINGLE_LINE_INVOCABLE/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_AROUND_TYPE/@EntryValue">2</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/BLANK_LINES_BETWEEN_USING_GROUPS/@EntryValue">1</s:Int64>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_FIXED_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_FOR_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_FOREACH_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_IFELSE_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_USING_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_WHILE_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_ANONYMOUS_METHOD_BLOCK/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_STYLE/@EntryValue">Tab</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_EXISTING_INITIALIZER_ARRANGEMENT/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_EMBEDDED_STATEMENT_ON_SAME_LINE/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_WHILE_ON_NEW_LINE/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_EMBEDDED_STATEMENT_STYLE/@EntryValue">LINE_BREAK</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AROUND_MULTIPLICATIVE_OP/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_SIZEOF_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_BEFORE_TYPEOF_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_SINGLE_LINE_ARRAY_INITIALIZER_BRACES/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/STICK_COMMENT/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/USE_INDENT_FROM_VS/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_BEFORE_BINARY_OPSIGN/@EntryValue">True</s:Boolean>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LIMIT/@EntryValue">240</s:Int64>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_LINES/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/XmlDocFormatter/IndentTagContent/@EntryValue">ZeroIndent</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&#xD;
&lt;Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"&gt;&#xD;
&lt;TypePattern DisplayName="COM interfaces or structs"&gt;&#xD;
&lt;TypePattern.Match&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Interface" /&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" /&gt;&#xD;
&lt;HasAttribute Name="System.Runtime.InteropServices.ComImport" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;Kind Is="Struct" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/TypePattern.Match&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&lt;TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All"&gt;&#xD;
&lt;TypePattern.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Class" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="True" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/TypePattern.Match&gt;&#xD;
&lt;Entry DisplayName="Setup/Teardown Methods"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="True" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="True" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.FixtureSetUpAttribute" Inherited="True" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.FixtureTearDownAttribute" Inherited="True" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="All other members" /&gt;&#xD;
&lt;Entry Priority="100" DisplayName="Test Methods"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Method" /&gt;&#xD;
&lt;HasAttribute Name="NUnit.Framework.TestAttribute" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&lt;TypePattern DisplayName="Default Pattern"&gt;&#xD;
&lt;Entry Priority="100" DisplayName="Public Delegates"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Access Is="Public" /&gt;&#xD;
&lt;Kind Is="Delegate" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Static Fields and Constants"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;Kind Is="Constant" /&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Field" /&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Kind Order="Constant Field" /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Constructors"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Constructor" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Fields"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Field" /&gt;&#xD;
&lt;Not&gt;&#xD;
&lt;Static /&gt;&#xD;
&lt;/Not&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Readonly /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="Properties, Indexers"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Or&gt;&#xD;
&lt;Kind Is="Property" /&gt;&#xD;
&lt;Kind Is="Indexer" /&gt;&#xD;
&lt;/Or&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry Priority="100" DisplayName="Interface Implementations"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Kind Is="Member" /&gt;&#xD;
&lt;ImplementsInterface /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;ImplementsInterface Immediate="True" /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry DisplayName="All other members" /&gt;&#xD;
&lt;Entry DisplayName="Nested Types"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;Kind Is="Type" /&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;Entry Priority="100" DisplayName="Public Enums"&gt;&#xD;
&lt;Entry.Match&gt;&#xD;
&lt;And&gt;&#xD;
&lt;Access Is="Public" /&gt;&#xD;
&lt;Kind Is="Enum" /&gt;&#xD;
&lt;/And&gt;&#xD;
&lt;/Entry.Match&gt;&#xD;
&lt;Entry.SortBy&gt;&#xD;
&lt;Name /&gt;&#xD;
&lt;/Entry.SortBy&gt;&#xD;
&lt;/Entry&gt;&#xD;
&lt;/TypePattern&gt;&#xD;
&lt;/Patterns&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HMAC/@EntryIndexedValue">HMAC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IV/@EntryIndexedValue">IV</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OI/@EntryIndexedValue">OI</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OID/@EntryIndexedValue">OID</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PRF/@EntryIndexedValue">PRF</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=EnumMember/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Locals/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb_AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=MethodPropertyEvent/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb_AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PublicFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypeParameters/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb_AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb_AaBb" /&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/ExternalSources/Decompiler/DecompilerLegalNoticeAccepted/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/ExternalSources/FirstTimeFormShown/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/GenerateMru/GroupByType/=Implementations/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/Environment/GenerateMru/SortByName/=Implementations/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAlwaysTreatStructAsNotReorderableMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002EXml_002ECodeStyle_002EFormatSettingsUpgrade_002EXmlMoveToCommonFormatterSettingsUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/Environment/UpdatesManger/LastUpdateCheck/@EntryValue">09/10/2015 10:20:14</s:String>
<s:Int64 x:Key="/Default/Environment/UserInterface/QuickDoc/Width/@EntryValue">1094</s:Int64>
<s:String x:Key="/Default/Environment/UserInterface/ShortcutSchemeName/@EntryValue">VS</s:String>
<s:Boolean x:Key="/Default/Housekeeping/GlobalSettingsUpgraded/IsUpgraded/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Housekeeping/IntellisenseHousekeeping/HintUsed/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/Housekeeping/Layout/DialogWindows/OptionsDialog/Position/@EntryValue">[130,3](1024,768)</s:String>
<s:String x:Key="/Default/Housekeeping/Layout/DialogWindows/OptionsDialog/SelectedPageId/@EntryValue">CSharpOtherPage</s:String>
<s:String x:Key="/Default/Housekeeping/Layout/DialogWindows/RefactoringWizardWindow/Location/@EntryValue">-504,-12</s:String>
<s:Boolean x:Key="/Default/Housekeeping/LiveTemplatesHousekeeping/HotspotSessionHintIsShown/@EntryValue">True</s:Boolean>
<s:Int64 x:Key="/Default/Housekeeping/TreeModelBrowserPanelPersistance/PreviewSplitterVerticalPosition/=UnitTestSessionView/@EntryIndexedValue">959</s:Int64>
<s:Boolean x:Key="/Default/Housekeeping/UpgradeFromExceptionReport/UpgradePerformed/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Alexander Mezhov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,51 @@
# GostCryptography
.NET driver for [ViPNet CSP](http://www.infotecs.ru/) and [CryptoPro CSP](http://www.cryptopro.ru/).
Implements crypto algorithms based on Russian national cryptographic standards `GOST 28147-89`, `GOST R 34.12`,
`GOST R 34.10` and `GOST R 34.11`. Also provides abstractions to sign and verify `CMS/PKCS #7` messages, sign,
verify and encrypt XML documents.
- [NuGet Package](https://www.nuget.org/packages/GostCryptography)
- [Examples](Source/GostCryptography.Tests)
- [License](LICENSE)
## Implemented Algorithms
- [Symmetric algorithm based on GOST 28147-89](Source/GostCryptography/Gost_28147_89/Gost_28147_89_SymmetricAlgorithm.cs)
- [Hash-based Message Authentication Code (HMAC) based on GOST 28147-89](Source/GostCryptography/Gost_28147_89/Gost_28147_89_ImitHashAlgorithm.cs)
- [Symmetric algorithm based on GOST R 34.12 Magma](Source/GostCryptography/Gost_28147_89/Gost_3412_M_SymmetricAlgorithm.cs)
- [Hash-based Message Authentication Code (HMAC) based on GOST R 34.12 Magma](Source/GostCryptography/Gost_28147_89/Gost_3412_M_ImitHashAlgorithm.cs)
- [Symmetric algorithm based on GOST R 34.12 Kuznyechik](Source/GostCryptography/Gost_28147_89/Gost_3412_K_SymmetricAlgorithm.cs)
- [Hash-based Message Authentication Code (HMAC) based on GOST R 34.12 Kuznyechik](Source/GostCryptography/Gost_28147_89/Gost_3412_K_ImitHashAlgorithm.cs)
- [Hash algorithm based on GOST R 34.11-94](Source/GostCryptography/Gost_R3411/Gost_R3411_94_HashAlgorithm.cs), [2012/256](Source/GostCryptography/Gost_R3411/Gost_R3411_2012_256_HashAlgorithm.cs), [2012/512](Source/GostCryptography/Gost_R3411/Gost_R3411_2012_512_HashAlgorithm.cs)
- [Hash-based Message Authentication Code (HMAC) based on GOST R 34.11-94](Source/GostCryptography/Gost_R3411/Gost_R3411_94_HMAC.cs), [2012/256](Source/GostCryptography/Gost_R3411/Gost_R3411_2012_256_HMAC.cs), [2012/512](Source/GostCryptography/Gost_R3411/Gost_R3411_2012_512_HMAC.cs)
- [Pseudorandom Function (PRF) based on GOST R 34.11-94](Source/GostCryptography/Gost_R3411/Gost_R3411_94_PRF.cs), [2012/256](Source/GostCryptography/Gost_R3411/Gost_R3411_2012_256_PRF.cs), [2012/512](Source/GostCryptography/Gost_R3411/Gost_R3411_2012_512_PRF.cs)
- [Asymmetric algorithm based on GOST R 34.10-2001](Source/GostCryptography/Gost_R3410/Gost_R3410_2001_AsymmetricAlgorithm.cs), [2012/256](Source/GostCryptography/Gost_R3410/Gost_R3410_2012_256_AsymmetricAlgorithm.cs), [2012/512](Source/GostCryptography/Gost_R3410/Gost_R3410_2012_512_AsymmetricAlgorithm.cs)
- [Asymmetric algorithm with an ephemeral key based on GOST R 34.10-2001](Source/GostCryptography/Gost_R3410/Gost_R3410_2001_EphemeralAsymmetricAlgorithm.cs), [2012/256](Source/GostCryptography/Gost_R3410/Gost_R3410_2012_256_EphemeralAsymmetricAlgorithm.cs), [2012/512](Source/GostCryptography/Gost_R3410/Gost_R3410_2012_512_EphemeralAsymmetricAlgorithm.cs)
- [Asymmetric key exchange formatter based on GOST R 34.10-2001](Source/GostCryptography/Gost_R3410/Gost_R3410_2001_KeyExchangeFormatter.cs), [2012/256](Source/GostCryptography/Gost_R3410/Gost_R3410_2012_256_KeyExchangeFormatter.cs), [2012/512](Source/GostCryptography/Gost_R3410/Gost_R3410_2012_512_KeyExchangeFormatter.cs)
- [Asymmetric key exchange deformatter based on GOST R 34.10-2001](Source/GostCryptography/Gost_R3410/Gost_R3410_2001_KeyExchangeDeformatter.cs), [2012/256](Source/GostCryptography/Gost_R3410/Gost_R3410_2012_256_KeyExchangeDeformatter.cs), [2012/512](Source/GostCryptography/Gost_R3410/Gost_R3410_2012_512_KeyExchangeDeformatter.cs)
- [Asymmetric signature formatter based on GOST R 34.10-2001, 2012/256, 2012/512](Source/GostCryptography/Base/GostSignatureFormatter.cs)
- [Asymmetric signature deformatter based on GOST R 34.10-2001, 2012/256, 2012/512](Source/GostCryptography/Base/GostSignatureDeformatter.cs)
- [XML encryption based on GOST R 34.10-2001, 2012/256, 2012/512](Source/GostCryptography/Xml/GostEncryptedXml.cs)
- [XML signing based on XML-DSig and GOST R 34.10-2001, 2012/256, 2012/512](Source/GostCryptography/Xml/GostSignedXml.cs)
- [Signing and verifying of CMS/PKCS #7 messages based on GOST R 34.10-2001, 2012/256, 2012/512](Source/GostCryptography/Pkcs/GostSignedCms.cs)
## Tested On
- Windows 10 x64, CryptoPro CSP 5.0.13000 KC1
- Windows 10 x64, ViPNet CSP 4.2.8.51670
## Build instructions
To build package run in repository root:
```
dotnet build --configuration Release
```

View File

@@ -0,0 +1,15 @@
# Fork Notes — AlexMAS/GostCryptography
- Source repo: https://github.com/AlexMAS/GostCryptography (commit 31413f6621d1e77e4fe5d7bb2f95a9746d64e9e0)
- Reason for fork: Need a maintained source base for the CryptoPro plug-in that covers the full CSP surface (CMS, XML DSig, Magma/Kuznyechik, etc.) while we replace the vulnerable IT.GostCryptography dependency.
- Alternatives considered:
- pairbit/IT.Hashing — modern .NET 8 hashing helpers, but it only ships digest algorithms and lacks CSP bindings, CMS, or signing primitives, so it cannot back our plug-in on its own.
- NuGet GostCryptography binary — already packaged but not patchable; we need source control plus the ability to vendor patches.
- Local customizations: None yet; this directory is a vanilla mirror of upstream. All StellaOps-specific changes must be committed on top so that we can periodically rebase from upstream.
- Sync process:
1. git clone https://github.com/AlexMAS/GostCryptography.git /tmp/gost
2. Checkout the desired commit/tag and run: rsync -a --delete --exclude .git /tmp/gost/ third_party/forks/AlexMAS.GostCryptography/
3. Update this file with the new commit hash and summarize notable upstream diffs.
- License: MIT (upstream LICENSE kept verbatim in this folder).
This fork lives under third_party/forks to keep upstream sources separate from StellaOps code while we integrate the replacement CryptoPro provider.

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

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