Closed DPonomarchuk closed 7 years ago
Здравствуйте.
Если я правильно помню, то сделать это можно примерно так:
// Получение параметров криптопровайдера по сертификату
var cspParameters = X509CertificateHelper.GetPrivateKeyInfo(Certificate);
// Запрет вывода окна ввода пароля, при неправильном пароле получить ошибку
cspParameters.Flags = CspProviderFlags.NoPrompt;
// Создание строки с паролем (пример: Qwerty123)
var password = new SecureString();
password.AppendChar('Q');
password.AppendChar('w');
password.AppendChar('e');
password.AppendChar('r');
password.AppendChar('t');
password.AppendChar('y');
password.AppendChar('1');
password.AppendChar('2');
password.AppendChar('3');
var alg = new Gost3410AsymmetricAlgorithm(cspParameters);
alg.SetContainerPassword(password);
Далее, например, в случае с подписью XML:
xml.SigningKey = alg;
xml.ComputeSignature();
Да. При подписи xml все прекрасно работает и окно ввода пароля не появляется. А вот при дешифрации каждый раз запрашивается пароль. Ума не приложу, как его задать программно.
А можете кусочек кода с примером, который воспроизводит ситуацию? ;)
Забял сказать, что у класса CspParameters
также есть свойство для установки пароля. Можно попробовать использовать его.
cspParameters.KeyPassword = password;
Это нужно сделать соответственно до создания алгоритма.
Пример кода (вчера не получилось ответить - немного приболел...). Указание пароля в cspParamets также не помогло.
XmlDocument doc = new XmlDocument();
var fileName = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location),
@"XmlFile1.xml");
doc.Load(fileName);
var exml = new GostEncryptedXml(doc);
X509Certificate2 Certificate = GetCertByNum("01 d1 fe a4 65 b3 f8 40 00 00 00 0d 00 05 00 01");
var cspParam = X509CertificateHelper.GetPrivateKeyInfo(Certificate);
System.Security.SecureString ss = new System.Security.SecureString();
for (int i = 0; i < "1234567890".Length; i++)
{
ss.AppendChar("1234567890".ToCharArray(i, 1)[0]);
}
cspParam.KeyPassword = ss;
Gost3410AsymmetricAlgorithm alg = new Gost3410AsymmetricAlgorithm(cspParam);
alg.SetContainerPassword(ss); //При вычислении ЭЦП установка пароля прекрасно работает
exml.AddKeyNameMapping("KeyName1", alg); // Возможно тут я делаю, что-то неправильно
exml.DecryptDocument(); // появляется окно ввода пароля.
Зашифрованная xml и сертификат (если нужно) [https://1drv.ms/u/s!AopaN--FViu5a-002UWBgxSkVkI]
Я создал self-signed сертификат (реального у меня, к сожалению, нет). Установил его во вновь созданный контейнер VipNet. В настройках контейнера указал, что пароль доступа нужно сохранить на компьютере и не запрашивать при доступе к контейнеру (см. ниже). После этого выполнил тест https://github.com/AlexMAS/GostCryptography/blob/master/Source/GostCryptography.Tests/Xml/Encrypt/EncryptedXmlCertificateTest.cs#L22 Все прошло успешно, без запроса пароля.
Я не знаю, безопасно ли хранить пароль к контейнеру таким образом. Даже если не хранить, его придется как-то получать в коде вашей программы, например, из конфигурационного файла приложения.
Сейчас попробую удалить пароль и воспроизвести вашу ситуацию.
Да, после того, как я указал, что пароль доступа не нужно хранить, я смог воспроизвести вашу ситуацию. Я попробовал разные способы, но у меня так и не получилось заставить GostEncryptedXml
работать без окна ввода пароля (в отличие от ЭЦП). Возможно, есть способ сделать это через CryptoAPI и указать пароль программно, как в случае с методом SetContainerPassword()
класса Gost3410AsymmetricAlgorithm
, но я не знаю, как, слишком мало информации по этому поводу.
По всей видимости, единственный возможный способ отключить диалог - это сохранить пароль доступа, как указанно в предыдущем ответе. Подойдет ли такой вариант решения вопроса? Также буду благодарен, если вы скажите, как в итоге решили проблему. :)
Меня бы устроил такой вариант хранения пароля, но проблема в том, что доступ к контейнеру будет осуществляться через сервис, развернутый в IIS. А при обращении сервиса к контейнеру пароль, заданный для пользователя не подходит, и запрашивается заново + также окно для ввода пароля не появляется на экране, а выводится где-то там, внутри IIS-ки. Если, хотя бы окно появлялось, можно было бы поставить галку "Сохранить пароль" и при следующих операциях дешифровка проходила бы без проблем...
Поправьте меня, если я не прав. У вас есть некоторое Web-приложение, которое размещается на IIS. Для каждого пользователя этого приложения есть сертификат, который хранится в своем контейнере, со своим паролем доступа. При дешифрации пользователь (видимо, через Web-интерфейс) вводит пароль, который должен использоваться на стороне Web-приложения. То есть получается, что пароль в общем случае знает только конечный пользователь вашего Web-приложения. Все верно?
P.s. Я постараюсь в свободное время попробовать найти решение проблемы, просто хочется представлять понять суть проблемы.
Всё практически так, как вы себе и представляете. Имеется веб-приложение развернутое на сервере IIS. Пользователь отправляет ему xml, которая подписывается ЭЦП и оборачивается в сообщение, которое в зашифрованном виде передаётся на сторонний сервис, далее веб приложение дешифрует ответ от стороннего сервиса и возвращает ответ пользователю. (пароль от сертификата хранится в файле конфигурации веб-приложения) Подпись и дешифрация проходят на одном сертификате. Буду крайне благодарен, если поможете разобраться )
Может я что-то не до конца понимаю, но смотрите. Web-приложение, работающее на базе IIS, и CSP со всеми сертификатами физически находятся на одной машине (виртуальной или нет, не имеет значения). Хранить пароль контейнера в конфигурационном файле Web-приложения или на диске, используя средства CSP, в общем случае одно и тоже (суть одна - пароль будет сохранен на этой же машине, на постоянном носителе). Только в первом случае мы имеем проблему с диалоговым окном, а во втором - нет. Я полагаю, что проблема в том процесс вашего Web-приложения, будучи запущенным под управлением IIS, запускается от имени какой-то конкретной учетной записи. И, возможно, для нее пароль не сохранен (в понимании CSP). Попробуйте поэкспериментировать с "Параметрами доступа" (см. настройку на картинке выше ), например, добавив туда учетную запись, от имени которой работает процесс IIS. В общем, постарайтесь как-то через настройки CSP сохранить пароль для пользователя, от имени которого запускается ваше Web-приложение. Должно получиться.
P.s. Теорию можно проверить следующим образом. На своей машине установите CSP, сертификат и сохраните пароль. Запустите приложение из под IDE (или как-то из под своей учетной записи) и проверьте, что все работает нормально. После этого создайте новую учетную запись, зайдите под ней, запустите приложение из под IDE. (или как-то из под своей новой учетной записи). Должен появиться диалог. После этого сохраните пароль для новой учетной записи и повторите действия. Диалог должен пропасть.
@DPonomarchuk, у вас получилось добиться успеха?
Добрый день, да, похоже такой вариант жизнеспособен. Но пришлось покопаться в IIS. Проблема состояла в том, что учетные записи IIS AppPool \
Спасибо за информацию. Хорошо, что нашелся рабочий способ решить проблему, пускай даже таким образом. К сожалению, механизмы работы с криптографией в .NET Framework не назовешь удобными, особенно, когда речь заходит о криптографии по ГОСТ. Надеюсь в .NET Standard 2+ появятся более гибкие механизмы расширения. С программной реализацией указания пароля постараюсь разобраться в ближайшее время, правда, не уверен, что смогу это сделать, судя по тому, что мне удалось вспомнить.
Здравствуйте, Александр. Пробую использовать вашу библиотеку в сервисе на IIS. При дешифрации использовал пример из https://github.com/AlexMAS/GostCryptography/tree/master/Source/GostCryptography.Tests
var encryptedXml= new GostEncryptedXml(doc); encryptedXml.AddKeyNameMapping("KeyName1", privateKey); / Добавляю ссылку на приватный ассиметричный ключ с установленным privateKey.SetContainerPassword(secureString); / encryptedXml.DecryptDocument(); / Но на этапе дешифровки криптопровайдер всё равно запрашивает выводит окно для указания пароля для сертификата /
Возможно ли установить пароль для контейнера сертификата программно без вывода на экран окна криптопровайдера при дешифрации (сертификаты находятся в локальном хранилище компьютера)?