
10 changed files with 636 additions and 0 deletions
@ -0,0 +1,25 @@ |
|||
|
|||
Microsoft Visual Studio Solution File, Format Version 12.00 |
|||
# Visual Studio 15 |
|||
VisualStudioVersion = 15.0.28307.572 |
|||
MinimumVisualStudioVersion = 10.0.40219.1 |
|||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VipNetExtract", "VipNetExtract2\VipNetExtract.csproj", "{201ACA67-E71C-4058-96A5-F8717C484C01}" |
|||
EndProject |
|||
Global |
|||
GlobalSection(SolutionConfigurationPlatforms) = preSolution |
|||
Debug|Any CPU = Debug|Any CPU |
|||
Release|Any CPU = Release|Any CPU |
|||
EndGlobalSection |
|||
GlobalSection(ProjectConfigurationPlatforms) = postSolution |
|||
{201ACA67-E71C-4058-96A5-F8717C484C01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
|||
{201ACA67-E71C-4058-96A5-F8717C484C01}.Debug|Any CPU.Build.0 = Debug|Any CPU |
|||
{201ACA67-E71C-4058-96A5-F8717C484C01}.Release|Any CPU.ActiveCfg = Release|Any CPU |
|||
{201ACA67-E71C-4058-96A5-F8717C484C01}.Release|Any CPU.Build.0 = Release|Any CPU |
|||
EndGlobalSection |
|||
GlobalSection(SolutionProperties) = preSolution |
|||
HideSolutionNode = FALSE |
|||
EndGlobalSection |
|||
GlobalSection(ExtensibilityGlobals) = postSolution |
|||
SolutionGuid = {072DCD9B-6565-4D97-B502-D4381A85AC1A} |
|||
EndGlobalSection |
|||
EndGlobal |
@ -0,0 +1,67 @@ |
|||
using Org.BouncyCastle.Asn1; |
|||
using Org.BouncyCastle.Asn1.CryptoPro; |
|||
using Org.BouncyCastle.Crypto.Parameters; |
|||
using Org.BouncyCastle.Pkcs; |
|||
using Org.BouncyCastle.Security; |
|||
using Org.BouncyCastle.Utilities.IO.Pem; |
|||
using Org.BouncyCastle.X509; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Text; |
|||
|
|||
namespace VipNetExtract |
|||
{ |
|||
interface IExport |
|||
{ |
|||
void Export(VipNetContainer container, string pin, Stream output); |
|||
} |
|||
|
|||
class PrivateKeyExport : IExport |
|||
{ |
|||
public void Export(VipNetContainer container, string pin, Stream output) |
|||
{ |
|||
var privateKey = EncodePrivateKey(container, pin); |
|||
var pemObject = new PemObject("PRIVATE KEY", privateKey.GetDerEncoded()); |
|||
using (var sw = new StreamWriter(output)) { |
|||
var writer = new PemWriter(sw); |
|||
writer.WriteObject(pemObject); |
|||
} |
|||
} |
|||
|
|||
private static Asn1Object EncodePrivateKey(VipNetContainer container, string pin) |
|||
{ |
|||
var entry = container.Entries[0]; |
|||
var gostParams = Gost3410PublicKeyAlgParameters.GetInstance(entry.KeyInfo.Algorithm.Parameters); |
|||
|
|||
return new DerSequence( |
|||
new DerInteger(0), |
|||
new DerSequence( |
|||
entry.KeyInfo.Algorithm.Algorithm, |
|||
new DerSequence( |
|||
gostParams.PublicKeyParamSet, |
|||
gostParams.DigestParamSet |
|||
) |
|||
), |
|||
new DerOctetString(new DerInteger(entry.GetPrivateKey(pin))) |
|||
); |
|||
} |
|||
} |
|||
|
|||
class CertificateExport : IExport |
|||
{ |
|||
public void Export(VipNetContainer container, string pin, Stream output) |
|||
{ |
|||
var cert = container.Entries[0].Certificate; |
|||
if (cert == null) |
|||
throw new InvalidOperationException("Контейнер не содержит сертификата"); |
|||
|
|||
var pemObject = new PemObject("CERTIFICATE", cert.GetEncoded()); |
|||
using (var sw = new StreamWriter(output)) { |
|||
var writer = new PemWriter(sw); |
|||
writer.WriteObject(pemObject); |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,46 @@ |
|||
using System; |
|||
using Org.BouncyCastle.Asn1; |
|||
using Org.BouncyCastle.Asn1.X509; |
|||
using Org.BouncyCastle.Utilities; |
|||
|
|||
namespace VipNetExtract |
|||
{ |
|||
class KeyValidity : Asn1Encodable |
|||
{ |
|||
public KeyValidity(Asn1Sequence seq) |
|||
{ |
|||
NotBefore = Time.GetInstance(GetTime(seq[0])); |
|||
NotAfter = Time.GetInstance(GetTime(seq[1])); |
|||
} |
|||
|
|||
private static Asn1Encodable GetTime(Asn1Encodable time) |
|||
{ |
|||
if (time is Asn1TaggedObject tag) |
|||
time = tag.GetObject(); |
|||
|
|||
if (time is Asn1OctetString str) |
|||
time = new DerGeneralizedTime(Strings.FromAsciiByteArray(str.GetOctets())); |
|||
|
|||
return time; |
|||
} |
|||
|
|||
public Time NotBefore { get; } |
|||
public Time NotAfter { get; } |
|||
|
|||
public override Asn1Object ToAsn1Object() |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
public static KeyValidity GetInstance(object obj) |
|||
{ |
|||
if (obj is KeyValidity entry) |
|||
return entry; |
|||
|
|||
return new KeyValidity(Asn1Sequence.GetInstance(obj)); |
|||
} |
|||
|
|||
public static KeyValidity GetInstance(Asn1TaggedObject obj, bool explicitly) |
|||
=> GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); |
|||
} |
|||
} |
@ -0,0 +1,70 @@ |
|||
using System; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Runtime.InteropServices; |
|||
using System.Security.Cryptography; |
|||
using Mono.Options; |
|||
using Org.BouncyCastle.Utilities.Encoders; |
|||
|
|||
namespace VipNetExtract |
|||
{ |
|||
class Program |
|||
{ |
|||
enum Mode |
|||
{ |
|||
Private, Certificate |
|||
} |
|||
|
|||
private static OptionSet options; |
|||
|
|||
static void Main(string[] args) |
|||
{ |
|||
string file = null, pin = null; |
|||
Mode mode = Mode.Private; |
|||
bool showHelp = false; |
|||
|
|||
options = new OptionSet { |
|||
{ "f|file=", "Путь к контейнеру", f => file = f }, |
|||
{ "private", "Извлечь закрытый ключ (по умолчанию)", p => { if (p != null) mode = Mode.Private; } }, |
|||
{ "cert", "Извлечь сертификат", c => { if (c != null) mode = Mode.Certificate; } }, |
|||
{ "p|pin=", "ПИН-код", p => pin = p }, |
|||
{ "h|help", "Помощь", h => showHelp = h != null} |
|||
}; |
|||
|
|||
try { |
|||
options.Parse(args); |
|||
} catch (OptionException e) { |
|||
Console.Error.WriteLine(e.Message); |
|||
return; |
|||
} |
|||
|
|||
if (showHelp || String.IsNullOrEmpty(file)) { |
|||
PrintHelp(); |
|||
return; |
|||
} |
|||
|
|||
IExport export; |
|||
if (mode == Mode.Certificate) { |
|||
export = new CertificateExport(); |
|||
} else { |
|||
export = new PrivateKeyExport(); |
|||
} |
|||
|
|||
try { |
|||
var container = VipNetContainer.LoadFromFile(file); |
|||
export.Export(container, pin, Console.OpenStandardOutput()); |
|||
} catch (Exception e) { |
|||
Console.Error.WriteLine(e.Message); |
|||
} |
|||
} |
|||
|
|||
static void PrintHelp() |
|||
{ |
|||
Console.WriteLine("Использование: extractpkey {ПАРАМЕТРЫ}"); |
|||
Console.WriteLine("Извлечение данных из контейнера VipNet"); |
|||
Console.WriteLine(); |
|||
Console.WriteLine("Параметры:"); |
|||
options.WriteOptionDescriptions(Console.Out); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,36 @@ |
|||
using System.Reflection; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
// General Information about an assembly is controlled through the following
|
|||
// set of attributes. Change these attribute values to modify the information
|
|||
// associated with an assembly.
|
|||
[assembly: AssemblyTitle("VipNetExtract")] |
|||
[assembly: AssemblyDescription("")] |
|||
[assembly: AssemblyConfiguration("")] |
|||
[assembly: AssemblyCompany("")] |
|||
[assembly: AssemblyProduct("VipNetExtract")] |
|||
[assembly: AssemblyCopyright("Copyright © 2019")] |
|||
[assembly: AssemblyTrademark("")] |
|||
[assembly: AssemblyCulture("")] |
|||
|
|||
// Setting ComVisible to false makes the types in this assembly not visible
|
|||
// to COM components. If you need to access a type in this assembly from
|
|||
// COM, set the ComVisible attribute to true on that type.
|
|||
[assembly: ComVisible(false)] |
|||
|
|||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
|||
[assembly: Guid("201aca67-e71c-4058-96a5-f8717c484c01")] |
|||
|
|||
// Version information for an assembly consists of the following four values:
|
|||
//
|
|||
// Major Version
|
|||
// Minor Version
|
|||
// Build Number
|
|||
// Revision
|
|||
//
|
|||
// You can specify all the values or you can default the Build and Revision Numbers
|
|||
// by using the '*' as shown below:
|
|||
// [assembly: AssemblyVersion("1.0.*")]
|
|||
[assembly: AssemblyVersion("1.0.0.0")] |
|||
[assembly: AssemblyFileVersion("1.0.0.0")] |
@ -0,0 +1,72 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Text; |
|||
using Org.BouncyCastle.Asn1; |
|||
|
|||
namespace VipNetExtract |
|||
{ |
|||
class VipNetContainer |
|||
{ |
|||
private VipNetContainer( |
|||
string type, uint version, int headerSize, |
|||
byte[] header, IList<VipNetContainerEntry> entries) |
|||
{ |
|||
Type = type; |
|||
Version = version; |
|||
HeaderSize = headerSize; |
|||
Header = header; |
|||
Entries = entries; |
|||
} |
|||
|
|||
public string Type { get; } |
|||
public uint Version { get; } |
|||
public int HeaderSize { get; } |
|||
public byte[] Header { get; } |
|||
public IList<VipNetContainerEntry> Entries { get; } |
|||
|
|||
public static VipNetContainer LoadFromStream(Stream strm) |
|||
{ |
|||
using (var reader = new BinaryReader(strm)) { |
|||
var type = Encoding.ASCII.GetString(reader.ReadBytes(4)); |
|||
if (type != "ITCS" && type != "PKEY" && type != "_CCK" && type != "_LCK") |
|||
throw new NotSupportedException($"Неподдерживаемый тип контейнера: {type}."); |
|||
|
|||
var version = reader.ReadUInt32(); |
|||
if (LoWord(version) > 0xFF || HiWord(version) > 2) |
|||
throw new NotSupportedException($"Неподдерживаемая версия контейнера: {version}."); |
|||
|
|||
var headerSize = reader.ReadInt32(); |
|||
var header = new byte[headerSize]; |
|||
if (headerSize > 0) |
|||
header = reader.ReadBytes(headerSize); |
|||
|
|||
var entries = new List<VipNetContainerEntry>(); |
|||
while (strm.Position < strm.Length) { |
|||
var entrySize = reader.ReadInt32(); |
|||
var entryStartPos = strm.Position; |
|||
var entrySeq = (Asn1Sequence)Asn1Object.FromStream(strm); |
|||
var keySize = reader.ReadInt32(); |
|||
if (keySize < 0 || strm.Position + keySize - entryStartPos != entrySize) |
|||
throw new InvalidOperationException($"Некорректный размер блока с ключом: {keySize}."); |
|||
var key = reader.ReadBytes(keySize); |
|||
entries.Add(new VipNetContainerEntry(entrySeq, key)); |
|||
} |
|||
|
|||
if (entries.Count == 0) |
|||
throw new InvalidOperationException("Контейнер не содержит записей."); |
|||
|
|||
return new VipNetContainer(type, version, headerSize, header, entries); |
|||
} |
|||
} |
|||
|
|||
public static VipNetContainer LoadFromFile(string fileName) |
|||
{ |
|||
using (var strm = File.OpenRead(fileName)) |
|||
return LoadFromStream(strm); |
|||
} |
|||
|
|||
static uint LoWord(uint x) => x & 0x0000FFFF; |
|||
static uint HiWord(uint x) => x >> 16; |
|||
} |
|||
} |
@ -0,0 +1,142 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Security.Cryptography; |
|||
using System.Text; |
|||
using Org.BouncyCastle.Asn1; |
|||
using Org.BouncyCastle.Asn1.CryptoPro; |
|||
using Org.BouncyCastle.Asn1.X509; |
|||
using Org.BouncyCastle.Crypto; |
|||
using Org.BouncyCastle.Crypto.Digests; |
|||
using Org.BouncyCastle.Crypto.Engines; |
|||
using Org.BouncyCastle.Crypto.Macs; |
|||
using Org.BouncyCastle.Crypto.Parameters; |
|||
using Org.BouncyCastle.Math; |
|||
using Org.BouncyCastle.Security; |
|||
using Org.BouncyCastle.Utilities.Encoders; |
|||
|
|||
namespace VipNetExtract |
|||
{ |
|||
class VipNetContainerEntry |
|||
{ |
|||
public VipNetContainerEntry(Asn1Sequence seq, byte[] keyBlock) |
|||
{ |
|||
Version = (DerInteger)seq[0]; |
|||
KeyInfo = VipNetKeyInfo.GetInstance(seq[1]); |
|||
DefenceKeyInfo = VipNetKeyInfo.GetInstance(seq[2]); |
|||
KeyBlock = keyBlock; |
|||
|
|||
for (int i = 3; i < seq.Count; ++i) { |
|||
if (seq[i] is Asn1TaggedObject tag) { |
|||
switch (tag.TagNo) { |
|||
case 0: |
|||
Certificate = X509CertificateStructure.GetInstance(tag.GetObject()); |
|||
break; |
|||
case 1: |
|||
PublicKey = (DerOctetString)tag.GetObject(); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
public DerInteger Version { get; } |
|||
public VipNetKeyInfo KeyInfo { get; } |
|||
public VipNetKeyInfo DefenceKeyInfo { get; } |
|||
public X509CertificateStructure Certificate { get; } |
|||
public DerOctetString PublicKey { get; internal set; } |
|||
public byte[] KeyBlock { get; } |
|||
|
|||
public BigInteger GetPrivateKey(string pin) |
|||
{ |
|||
var cek = KeyBlock.Take(KeyBlock.Length - 12).ToArray(); |
|||
var mac = KeyBlock.Skip(cek.Length).Take(4).ToArray(); |
|||
var data = cek.Concat(KeyInfo.RawData).ToArray(); |
|||
var pinKey = GetDecryptionKey(pin); |
|||
|
|||
CheckMac(pinKey, cek, data, mac); |
|||
|
|||
var iv = KeyBlock.Skip(KeyBlock.Length - 8).ToArray(); |
|||
var pkeyMasked = DecryptKey(pinKey, cek, iv); |
|||
|
|||
byte[] privateKey; |
|||
if (KeyInfo.KeyClass.Value.And(BigInteger.Three).Equals(BigInteger.Zero)) { |
|||
data = pkeyMasked.Take(pkeyMasked.Length / 2).ToArray(); |
|||
var unwrappingKey = pkeyMasked.Skip(pkeyMasked.Length / 2).ToArray(); |
|||
privateKey = DecryptKey(unwrappingKey, data); |
|||
} else { |
|||
var wrapped = pkeyMasked.Take(pkeyMasked.Length / 2).Reverse().ToArray(); |
|||
var mask = pkeyMasked.Skip(pkeyMasked.Length / 2).Reverse().ToArray(); |
|||
|
|||
var algParams = Gost3410PublicKeyAlgParameters.GetInstance(KeyInfo.Algorithm.Parameters); |
|||
var param = new ECKeyGenerationParameters(algParams.PublicKeyParamSet, new SecureRandom()); |
|||
|
|||
var x = new BigInteger(1, wrapped); |
|||
var y = new BigInteger(1, mask); |
|||
var z = x.Multiply(y).Mod(param.DomainParameters.Curve.Order); |
|||
|
|||
CheckPrivateKey(param, z); |
|||
|
|||
privateKey = z.ToByteArrayUnsigned(); |
|||
} |
|||
|
|||
return new BigInteger(1, privateKey); |
|||
} |
|||
|
|||
private byte[] GetDecryptionKey(string pin) |
|||
{ |
|||
var digest = new Gost3411Digest(); |
|||
var passwordData = Encoding.ASCII.GetBytes(pin ?? ""); |
|||
var keyData = new byte[digest.GetDigestSize()]; |
|||
var unwrappingKey = new byte[digest.GetDigestSize()]; |
|||
|
|||
digest.BlockUpdate(passwordData, 0, passwordData.Length); |
|||
digest.DoFinal(keyData, 0); |
|||
digest.Reset(); |
|||
|
|||
var secodeData = passwordData.Concat(keyData).ToArray(); |
|||
digest.BlockUpdate(secodeData, 0, secodeData.Length); |
|||
digest.DoFinal(unwrappingKey, 0); |
|||
|
|||
var tmp = new int[keyData.Length / 4]; |
|||
for (int i = 0; i < keyData.Length; i += 4) |
|||
tmp[i / 4] = BitConverter.ToInt32(keyData, i) - BitConverter.ToInt32(unwrappingKey, i); |
|||
|
|||
return tmp.SelectMany(x => BitConverter.GetBytes(x)).ToArray(); |
|||
} |
|||
|
|||
private static void CheckMac(byte[] key, byte[] cek, byte[] data, byte[] mac) |
|||
{ |
|||
var m = new Gost28147Mac(); |
|||
var keyPrm = ParameterUtilities.CreateKeyParameter("GOST", key); |
|||
m.Init(keyPrm); |
|||
|
|||
var cekmac = new byte[4]; |
|||
m.BlockUpdate(data, 0, data.Length); |
|||
m.DoFinal(cekmac, 0); |
|||
|
|||
if (!mac.SequenceEqual(cekmac)) |
|||
throw new CryptographicException("Неверный ПИН-код"); |
|||
} |
|||
|
|||
private static byte[] DecryptKey(byte[] key, byte[] cek, byte[] iv = null) |
|||
{ |
|||
var cipher = CipherUtilities.GetCipher("GOST/CFB/NOPADDING"); |
|||
ICipherParameters prms = ParameterUtilities.CreateKeyParameter("GOST", key); |
|||
prms = new ParametersWithSBox(prms, Gost28147Engine.GetSBox("E-A")); |
|||
cipher.Init(false, iv == null ? prms : new ParametersWithIV(prms, iv)); |
|||
return cipher.ProcessBytes(cek); |
|||
} |
|||
|
|||
private void CheckPrivateKey(ECKeyGenerationParameters param, BigInteger privateKey) |
|||
{ |
|||
var point = param.DomainParameters.G.Multiply(privateKey).Normalize(); |
|||
var x = point.AffineXCoord.GetEncoded().Reverse(); |
|||
var y = point.AffineYCoord.GetEncoded().Reverse(); |
|||
var pub = PublicKey.GetOctets(); |
|||
|
|||
if (!x.SequenceEqual(pub.Take(pub.Length / 2)) || !y.SequenceEqual(pub.Skip(pub.Length / 2))) |
|||
throw new CryptographicException("Закрытый ключ не соответствует открытому ключу."); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,63 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> |
|||
<PropertyGroup> |
|||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
|||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
|||
<ProjectGuid>{201ACA67-E71C-4058-96A5-F8717C484C01}</ProjectGuid> |
|||
<OutputType>Exe</OutputType> |
|||
<RootNamespace>VipNetExtract</RootNamespace> |
|||
<AssemblyName>ExtractPKey</AssemblyName> |
|||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> |
|||
<FileAlignment>512</FileAlignment> |
|||
<Deterministic>true</Deterministic> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
|||
<PlatformTarget>AnyCPU</PlatformTarget> |
|||
<DebugSymbols>true</DebugSymbols> |
|||
<DebugType>full</DebugType> |
|||
<Optimize>false</Optimize> |
|||
<OutputPath>bin\Debug\</OutputPath> |
|||
<DefineConstants>DEBUG;TRACE</DefineConstants> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> |
|||
<PlatformTarget>AnyCPU</PlatformTarget> |
|||
<DebugType>pdbonly</DebugType> |
|||
<Optimize>true</Optimize> |
|||
<OutputPath>bin\Release\</OutputPath> |
|||
<DefineConstants>TRACE</DefineConstants> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
</PropertyGroup> |
|||
<ItemGroup> |
|||
<Reference Include="BouncyCastle.Crypto, Version=1.8.5.0, Culture=neutral, PublicKeyToken=0e99375e54769942"> |
|||
<HintPath>..\packages\BouncyCastle.1.8.5\lib\BouncyCastle.Crypto.dll</HintPath> |
|||
</Reference> |
|||
<Reference Include="Mono.Options, Version=5.0.0.0, Culture=neutral, processorArchitecture=MSIL"> |
|||
<HintPath>..\packages\Mono.Options.5.3.0.1\lib\net4-client\Mono.Options.dll</HintPath> |
|||
</Reference> |
|||
<Reference Include="System" /> |
|||
<Reference Include="System.Core" /> |
|||
<Reference Include="System.Xml.Linq" /> |
|||
<Reference Include="System.Data.DataSetExtensions" /> |
|||
<Reference Include="Microsoft.CSharp" /> |
|||
<Reference Include="System.Data" /> |
|||
<Reference Include="System.Xml" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<Compile Include="Export.cs" /> |
|||
<Compile Include="KeyValidity.cs" /> |
|||
<Compile Include="Program.cs" /> |
|||
<Compile Include="Properties\AssemblyInfo.cs" /> |
|||
<Compile Include="VipNetContainer.cs" /> |
|||
<Compile Include="VipNetContainerEntry.cs" /> |
|||
<Compile Include="VipNetKeyInfo.cs" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<None Include="packages.config" /> |
|||
</ItemGroup> |
|||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> |
|||
</Project> |
@ -0,0 +1,110 @@ |
|||
using System; |
|||
using Org.BouncyCastle.Asn1; |
|||
using Org.BouncyCastle.Asn1.Crmf; |
|||
using Org.BouncyCastle.Asn1.X509; |
|||
|
|||
namespace VipNetExtract |
|||
{ |
|||
class VipNetKeyInfo : Asn1Encodable |
|||
{ |
|||
public VipNetKeyInfo(Asn1Sequence seq) |
|||
{ |
|||
RawData = seq.GetEncoded(); |
|||
KeyClass = (DerInteger)seq[0]; |
|||
KeyType = (DerInteger)seq[1]; |
|||
|
|||
for (int i = 2; i < seq.Count; ++i) { |
|||
if (seq[i] is Asn1TaggedObject tag) { |
|||
switch (tag.TagNo) { |
|||
case 0: |
|||
Algorithm = AlgorithmIdentifier.GetInstance(tag.GetObject()); |
|||
break; |
|||
case 1: |
|||
SerialNumber = Asn1OctetString.GetInstance(tag.GetObject()); |
|||
break; |
|||
case 2: |
|||
AddSerialNumber = Asn1OctetString.GetInstance(tag.GetObject()); |
|||
break; |
|||
case 3: |
|||
CertSerialNumber = Asn1OctetString.GetInstance(tag.GetObject()); |
|||
break; |
|||
case 4: |
|||
SubjectUID = Asn1OctetString.GetInstance(tag.GetObject()); |
|||
break; |
|||
case 5: |
|||
RecipientUID = Asn1OctetString.GetInstance(tag.GetObject()); |
|||
break; |
|||
case 6: |
|||
Validity = KeyValidity.GetInstance(tag.GetObject()); |
|||
break; |
|||
case 7: |
|||
KeyUID = DerBitString.GetInstance(tag.GetObject()); |
|||
break; |
|||
case 10: |
|||
Flags = DerInteger.GetInstance(tag.GetObject()); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
internal byte[] RawData { get; } |
|||
|
|||
public DerInteger KeyClass { get; } |
|||
public DerInteger KeyType { get; } |
|||
public AlgorithmIdentifier Algorithm { get; } |
|||
public Asn1OctetString SerialNumber { get; } |
|||
public Asn1OctetString AddSerialNumber { get; } |
|||
public Asn1OctetString CertSerialNumber { get; } |
|||
public Asn1OctetString SubjectUID { get; } |
|||
public Asn1OctetString RecipientUID { get; } |
|||
public KeyValidity Validity { get; } |
|||
public DerBitString KeyUID { get; } |
|||
public DerInteger Flags { get; } |
|||
|
|||
public override Asn1Object ToAsn1Object() |
|||
{ |
|||
var vec = new Asn1EncodableVector(KeyClass, KeyType); |
|||
|
|||
if (Algorithm != null) |
|||
vec.Add(new DerTaggedObject(0, Algorithm)); |
|||
|
|||
if (SerialNumber != null) |
|||
vec.Add(new DerTaggedObject(1, SerialNumber)); |
|||
|
|||
if (AddSerialNumber != null) |
|||
vec.Add(new DerTaggedObject(2, AddSerialNumber)); |
|||
|
|||
if (CertSerialNumber != null) |
|||
vec.Add(new DerTaggedObject(3, CertSerialNumber)); |
|||
|
|||
if (SubjectUID != null) |
|||
vec.Add(new DerTaggedObject(4, SubjectUID)); |
|||
|
|||
if (RecipientUID != null) |
|||
vec.Add(new DerTaggedObject(5, RecipientUID)); |
|||
|
|||
if (Validity != null) |
|||
vec.Add(new DerTaggedObject(6, Validity)); |
|||
|
|||
if (KeyUID != null) |
|||
vec.Add(new DerTaggedObject(7, KeyUID)); |
|||
|
|||
if (Flags != null) |
|||
vec.Add(new DerTaggedObject(10, Flags)); |
|||
|
|||
return new DerSequence(vec); |
|||
} |
|||
|
|||
public static VipNetKeyInfo GetInstance(object obj) |
|||
{ |
|||
if (obj is VipNetKeyInfo keyInfo) |
|||
return keyInfo; |
|||
|
|||
return new VipNetKeyInfo(Asn1Sequence.GetInstance(obj)); |
|||
} |
|||
|
|||
public static VipNetKeyInfo GetInstance(Asn1TaggedObject obj, bool explicitly) |
|||
=> GetInstance(Asn1Sequence.GetInstance(obj, explicitly)); |
|||
} |
|||
} |
@ -0,0 +1,5 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<packages> |
|||
<package id="BouncyCastle" version="1.8.5" targetFramework="net40" /> |
|||
<package id="Mono.Options" version="5.3.0.1" targetFramework="net40" /> |
|||
</packages> |
Loading…
Reference in new issue