2nd method, extract pkey from file container
parent
5b5ba4f8c4
commit
6231a87847
|
@ -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