AlexMAS / GostCryptography

.NET driver for ViPNet CSP and CryptoPro CSP
MIT License
128 stars 41 forks source link

Как просмотреть ключи в контейнере #27

Closed AshurkovAV closed 4 years ago

AshurkovAV commented 4 years ago

Здравствуйте, как просмотреть ключи в контейнере , используя GostCryptography. Криптопровайдер VipNet

AlexMAS commented 4 years ago

Здравствуйте. Такого функционала нет. Что именно вы пытаетесь сделать?

AshurkovAV commented 4 years ago

Просмотреть ключи на носителе Rutoken. Например как .net КриптоПро Gost3410CryptoServiceProvider.SelectContainer(true, false, IntPtr.Zero). Это выдаст диалоговое окно именно криптопро-шное.

AlexMAS commented 4 years ago

На счет диалогового окна не уверен, а вот функцию, которая будет возвщать список, можно будет попробовать реализовать. Это будет полезно?

AshurkovAV commented 4 years ago

Да очень нужно, это будет полезно

AlexMAS commented 4 years ago

Хорошо. Постараюсь помочь. :)

AshurkovAV commented 4 years ago

Спасибо, примерно по времени, когда можно ждать.

AlexMAS commented 4 years ago

Постараюсь в начале следующей нели предоставить тестовый образец.

AshurkovAV commented 4 years ago

Спасибо!!!

AlexMAS commented 4 years ago

@AshurkovAV Можете проверить на последнем коммите, возвращает ли следующий код то, что вам нужно:

var containers = CryptoApiHelper.GetContainers(ProviderType.VipNet_2012_1024, 
    fullContainerName: true, storeLocation: StoreLocation.LocalMachine);

Если все ОК, я выпущу новую версию пакета.

AshurkovAV commented 4 years ago

Да все сработало, вернулся список имен контейнеров. Спасибо! А как получить сертификат из контейнера! Куда благодарность направить? Хочу поддержать проект. :)

AlexMAS commented 4 years ago

Да все сработало

Отлично. :)

А как получить сертификат из контейнера

Первое, что приходит в голову - это сделать прямой перебор. Например, так:

public static X509Certificate2 FindCertificateByContainerName(
  string containerName,
  StoreName storeName = StoreName.My,
  StoreLocation storeLocation = StoreLocation.LocalMachine)
{
  var store = new X509Store(storeName, storeLocation);
  store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);

  try
  {
    foreach (var certificate in store.Certificates)
    {
      if (certificate.HasPrivateKey 
        && certificate.IsGost()
        && certificate.GetPrivateKeyInfo().KeyContainerName == containerName)
      {
        return certificate;
      }
    }
  }
  finally
  {
    store.Close();
  }

  return null;
}

Куда благодарность направить? Хочу поддержать проект. :)

Ставьте звездочку :)

AlexMAS commented 4 years ago

Опубликовал v2.0.6. Список контейнеров можно получать, как указано выше. К сожалению, пока не нашел подходящего места для этого метода. Если вопрос решен, можно закрыть задачу. ;)

AshurkovAV commented 4 years ago

Александр, еще вопрос. Необходимо найти способ получения сертификата со смарт карты (USB токена) и подписывания некоторых данных приватным ключом с этого токена. Возможно ли такое

AlexMAS commented 4 years ago

Думаю, что возможно. :) Я правильно понимаю, что реализованная выше функция перечисления позволяет найти и выбрать контейнер. (Этот контейнер в нашем случае находится на внешнем носителе - USB токен.) Далее, имея имя контейнера, вы хотите получить сертификат с закрытым ключом для подписи. И, я полагаю, его нет в X509Store и его нельзя получить/найти, как я предложил выше. Все так? :)

AshurkovAV commented 4 years ago

Прям в точку. Верно!

AshurkovAV commented 4 years ago

если их несколько буду предлагать пользователю выбрать один

AlexMAS commented 4 years ago

Полагаю, что для создания подписи вам не нужен именно X509Certificate. Можно попробовать создать подходящий ассиметричный алгоритм, используя конструктор, который принимает CspParameters. Например:

var keyContainer = new CspParameters
{
  ProviderType = (int) ProviderType.VipNet_2012_512,
  Flags = CspProviderFlags.UseMachineKeyStore,
  KeyNumber = (int) KeyNumber.Signature,
  KeyContainerName = @"path/to/key/container"
};

var signingKey = new Gost_R3410_2012_256_AsymmetricAlgorithm(keyContainer);

Обратите внимание, что ProviderType должен соответствовать ключу; Flags - зависит от того, где находится контейнер (хранилище машины или учетной записи пользователя); KeyContainerName - полный путь к ключу, полученный вышеуказанным методом.

Далее создаем экземпляр ассиметричного алгоритма с нужным типом, который также должен соответствовать ключу. Значение signingKey можно использовать для создания подписи.

Думаю, что у вас получится сделать метод получения signingKey из контейнера более универсальным, чем приведенный код. :) Есть небольшой пример, как подписывать XML документ, используя информацию о контейнере. (Правда, в целях универсальности теста экземпляр CspParameters создается не в ручную, а извлекается из сертификата.)

Если все ОК, дайте знать. :)

AshurkovAV commented 4 years ago

Доброе утро, спасибо! Подписать документ у меня получилось, но проблема еще состоит в том, что я должен передать в блоке BinarySecurityToken сведение о сертификате, с помощью которого была рассчитана ЭП. После чего я весь документ еще должен зашифровать. Шифрование до этого делал через сертификат. :)!!!!!

AlexMAS commented 4 years ago

Спасибо за детали. Постараюсь сделать это к концу текущей недели.

AshurkovAV commented 4 years ago

Спасибо! Жду!

AshurkovAV commented 4 years ago

Александр, добрый день. Извини за назойливость, подскажи получилось реализовать данный функционал?

AlexMAS commented 4 years ago

Нужный функционал реализовал в последней правке, проверьте, пожалуйста. Суть использования такова. Создаем приватный ключ на основе данных о контейнере, как описано выше. Далее на основе него получаем сертификат.

Например, так можно получить сертификат, который не включает приватный ключ:

X509Certificate2 certificate = signingKey.GetCertificate();

Так - сертификат, который использует signingKey, как приватный ключ:

X509Certificate2 certificate = signingKey.GetCertificate(true);

Жду обратной связи. :)

AshurkovAV commented 4 years ago

Да, все получилось, мне вернулся сертификат. Спасибо!!! Ваш проект очень полезный :)

AlexMAS commented 4 years ago

Спасибо за отзыв :) Выпустил версию v2.0.7.

AshurkovAV commented 4 years ago

Спасибо, поставил!

AshurkovAV commented 4 years ago

Александр, добрый день. А это же алгоритм должен сработать для криптопровайдер КриптоПро (CryptoPro_2012_256) Как это реализовать. У меня возвращается Null

AlexMAS commented 4 years ago

Да, все должно работать и для CryptoPro, к сожалению не могу сейчас проверить - нет подходящего окружения. Метод GetCertificate() возвращает null в случае, если криптопровайдер вернул ошибку ERROR_NO_SUCH_CERTIFICATE для заданной ключевой пары. Вообще это мало о чем говорит. :) Тем не менее, может быть сертификат доступен под другой учетной записью? А у текущей нет прав доступа.