Support keys encrypted with secret keys stored in a separate container instead of just a key derived from the password
parent
890b30fa0d
commit
dc06412197
|
@ -15,14 +15,14 @@ namespace VipNetExtract
|
|||
{
|
||||
interface IExport
|
||||
{
|
||||
void Export(VipNetContainer container, string pin, Stream output);
|
||||
void Export(VipNetContainer container, VipNetContainer defence, string pin, Stream output);
|
||||
}
|
||||
|
||||
class PrivateKeyExport : IExport
|
||||
{
|
||||
public void Export(VipNetContainer container, string pin, Stream output)
|
||||
public void Export(VipNetContainer container, VipNetContainer defence, string pin, Stream output)
|
||||
{
|
||||
var privateKey = EncodePrivateKey(container, pin);
|
||||
var privateKey = EncodePrivateKey(container, defence, pin);
|
||||
var pemObject = new PemObject("PRIVATE KEY", privateKey.GetDerEncoded());
|
||||
using (var sw = new StreamWriter(output)) {
|
||||
var writer = new PemWriter(sw);
|
||||
|
@ -30,7 +30,7 @@ namespace VipNetExtract
|
|||
}
|
||||
}
|
||||
|
||||
private static Asn1Object EncodePrivateKey(VipNetContainer container, string pin)
|
||||
private static Asn1Object EncodePrivateKey(VipNetContainer container, VipNetContainer defence, string pin)
|
||||
{
|
||||
var entry = container.Entries[0];
|
||||
var gostParams = Gost3410PublicKeyAlgParameters.GetInstance(entry.KeyInfo.Algorithm.Parameters);
|
||||
|
@ -44,14 +44,14 @@ namespace VipNetExtract
|
|||
gostParams.DigestParamSet
|
||||
)
|
||||
),
|
||||
new DerOctetString(new DerInteger(entry.GetPrivateKey(pin)))
|
||||
new DerOctetString(new DerInteger(entry.GetPrivateKey(pin, defence)))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CertificateExport : IExport
|
||||
{
|
||||
public void Export(VipNetContainer container, string pin, Stream output)
|
||||
public void Export(VipNetContainer container, VipNetContainer defence, string pin, Stream output)
|
||||
{
|
||||
var cert = container.Entries[0].Certificate;
|
||||
if (cert == null)
|
||||
|
|
|
@ -19,12 +19,13 @@ namespace VipNetExtract
|
|||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
string file = null, pin = null;
|
||||
string file = null, pin = null, defenceFile = null;
|
||||
Mode mode = Mode.Private;
|
||||
bool showHelp = false;
|
||||
|
||||
options = new OptionSet {
|
||||
{ "f|file=", "Путь к контейнеру", f => file = f },
|
||||
{ "d|defence=", "Путь к вспомогательному контейнеру секретного ключа", f => defenceFile = f },
|
||||
{ "private", "Извлечь закрытый ключ (по умолчанию)", p => { if (p != null) mode = Mode.Private; } },
|
||||
{ "cert", "Извлечь сертификат", c => { if (c != null) mode = Mode.Certificate; } },
|
||||
{ "p|pin=", "ПИН-код", p => pin = p },
|
||||
|
@ -52,7 +53,8 @@ namespace VipNetExtract
|
|||
|
||||
try {
|
||||
var container = VipNetContainer.LoadFromFile(file);
|
||||
export.Export(container, pin, Console.OpenStandardOutput());
|
||||
var defence = defenceFile != null ? VipNetContainer.LoadFromFile(defenceFile) : null;
|
||||
export.Export(container, defence, pin, Console.OpenStandardOutput());
|
||||
} catch (Exception e) {
|
||||
Console.Error.WriteLine(e.Message);
|
||||
}
|
||||
|
|
|
@ -48,12 +48,27 @@ namespace VipNetExtract
|
|||
public DerOctetString PublicKey { get; internal set; }
|
||||
public byte[] KeyBlock { get; }
|
||||
|
||||
public BigInteger GetPrivateKey(string pin)
|
||||
public byte[] GetProtectionKey(string pin)
|
||||
{
|
||||
if (KeyInfo.KeyClass.Value.IntValue != 64 && KeyInfo.KeyType.Value.IntValue != 24622)
|
||||
throw new CryptographicException("Вспомогательный контейнер не содержит ключа защиты");
|
||||
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, null);
|
||||
|
||||
CheckMac(pinKey, cek, data, mac);
|
||||
|
||||
var iv = KeyBlock.Skip(KeyBlock.Length - 8).ToArray();
|
||||
return DecryptKey(pinKey, cek, iv);
|
||||
}
|
||||
|
||||
public BigInteger GetPrivateKey(string pin, VipNetContainer defence)
|
||||
{
|
||||
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);
|
||||
var pinKey = GetDecryptionKey(pin, defence);
|
||||
|
||||
CheckMac(pinKey, cek, data, mac);
|
||||
|
||||
|
@ -127,10 +142,18 @@ namespace VipNetExtract
|
|||
return output;
|
||||
}
|
||||
|
||||
private byte[] GetDecryptionKey(string pin)
|
||||
private byte[] GetDecryptionKey(string pin, VipNetContainer defence)
|
||||
{
|
||||
var passwordData = Encoding.ASCII.GetBytes(pin ?? "");
|
||||
if (DefenceKeyInfo.Algorithm.Algorithm.Equals(PkcsObjectIdentifiers.IdPbkdf2))
|
||||
if (DefenceKeyInfo.KeyClass.Value.IntValue == 64 && DefenceKeyInfo.KeyType.Value.IntValue == 24622)
|
||||
{
|
||||
// Контейнер зашифрован ключом, лежащим в ещё одном контейнере
|
||||
if (defence == null)
|
||||
throw new CryptographicException("Закрытый ключ зашифрован секретным ключом, расположенным в отдельном вспомогательном контейнере. Используйте опцию --defence");
|
||||
return defence.Entries[0].GetProtectionKey(pin);
|
||||
}
|
||||
if (DefenceKeyInfo.Algorithm != null &&
|
||||
DefenceKeyInfo.Algorithm.Algorithm.Equals(PkcsObjectIdentifiers.IdPbkdf2))
|
||||
{
|
||||
// PBKDF2 используется в контейнерах ViPNet Jcrypto SDK
|
||||
// Самое смешное, что сам десктопный ViPNet CSP не понимает такие контейнеры
|
||||
|
|
Loading…
Reference in New Issue