Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход. Новые регистрации запрещены.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline Сашка  
#1 Оставлено : 2 апреля 2009 г. 13:19:34(UTC)
Сашка

Статус: Новичок

Группы: Участники
Зарегистрирован: 20.03.2009(UTC)
Сообщений: 9

Есть немудреный код:

Код:

HCRYPTPROV	getProviderContext(LPCSTR provider,LPCSTR container,ULONG type)
{
	printf("\n Provider: '%s'",provider  ? provider  : "NULL");
	printf("\nContainer: '%s'",container ? container : "NULL");
	printf("\n     Type: %u",type);
	for(ULONG i = 0,f = CRYPT_SILENT;;++i)
	{
		HCRYPTPROV hProv;
		if(::CryptAcquireContext(&hProv,container,provider,type,f))
		{
			printf("\ndone i=%u f=%8.8x\n",i,f);
			return hProv;
		}
		ULONG nerr = ::GetLastError();
		printf("\nerr=%8.8x i=%u f=%8.8x",nerr,i,f);
		switch(nerr)
		{
			case NTE_BAD_KEYSET	:
				if(i == 0)
				{
					f |= CRYPT_NEWKEYSET;
					f &= ~CRYPT_SILENT;
					continue;
				}
				break;
			case NTE_EXISTS	   :
				if(f & CRYPT_NEWKEYSET)
				{
					f &= ~CRYPT_NEWKEYSET;
					continue;
				}
		}
		printf("\nfail\n");
		return 0;
	}
}

INT	main(INT, LPCSTR argv[])
{
	HCRYPTPROV hProv1 = getProviderContext(argv[1],argv[2],atoi(argv[3]));
	HCRYPTPROV hProv2 = getProviderContext(argv[1],argv[2],atoi(argv[3]));
	if(hProv1) ::CryptReleaseContext(hProv1,0);
	if(hProv2) ::CryptReleaseContext(hProv2,0);
	return 0;
}


Вот результаты его выполнения:

Код:

C:\Source\java\crypto\src\cpp\plugins\debug>test.exe "Microsoft Base Cryptographic Provider v1.0" "my_new_test_container" 1

 Provider: 'Microsoft Base Cryptographic Provider v1.0'
Container: 'my_new_test_container'
     Type: 1
err=80090016 i=0 f=00000040
done i=1 f=00000008

 Provider: 'Microsoft Base Cryptographic Provider v1.0'
Container: 'my_new_test_container'
     Type: 1
done i=0 f=00000040

C:\Source\java\crypto\src\cpp\plugins\debug>test.exe "Crypto-Pro GOST R 34.10-94 Cryptographic Service Provider" "my_new_test_container" 71

 Provider: 'Crypto-Pro GOST R 34.10-94 Cryptographic Service Provider'
Container: 'my_new_test_container'
     Type: 71
err=80090016 i=0 f=00000040
done i=1 f=00000008

 Provider: 'Crypto-Pro GOST R 34.10-94 Cryptographic Service Provider'
Container: 'my_new_test_container'
     Type: 71
err=000000aa i=0 f=00000040
fail

C:\Source\java\crypto\src\cpp\plugins\debug>test.exe "Microsoft Base Cryptographic Provider v1.0" "my_new_test_container" 1

 Provider: 'Microsoft Base Cryptographic Provider v1.0'
Container: 'my_new_test_container'
     Type: 1
done i=0 f=00000040

 Provider: 'Microsoft Base Cryptographic Provider v1.0'
Container: 'my_new_test_container'
     Type: 1
done i=0 f=00000040

C:\Source\java\crypto\src\cpp\plugins\debug>test.exe "Crypto-Pro GOST R 34.10-94 Cryptographic Service Provider" "my_new_test_container" 71

 Provider: 'Crypto-Pro GOST R 34.10-94 Cryptographic Service Provider'
Container: 'my_new_test_container'
     Type: 71
err=80090016 i=0 f=00000040
done i=1 f=00000008

 Provider: 'Crypto-Pro GOST R 34.10-94 Cryptographic Service Provider'
Container: 'my_new_test_container'
     Type: 71
err=000000aa i=0 f=00000040
fail


Получается, что в случае с CryptoPro (версия 3.0, в качестве хранилища используется реестр) я не могу получить несколько контекстов на пустой контейнер? Это так задумано специально? Я понимаю, что если после создания контейнера сгенерировать там ключевую пару, то все будет нормально, но это уже будет не пустой контейнер...
Offline Челпанов А.  
#2 Оставлено : 2 апреля 2009 г. 18:45:58(UTC)
Челпанов А.

Статус: Активный участник

Группы: Участники
Зарегистрирован: 24.12.2007(UTC)
Сообщений: 390
Мужчина
Откуда: КриптоПро

Поблагодарили: 2 раз в 2 постах
Если коротко, то так и было задумано в CSP 3.0.

Чуть более подробнее.
1. При CryptAcquireContext( CRYPT_NEWKEYSET ) контейнер не записывается на носитель, да же пустой, и, если не предпринимать никаких действий, то и его следов не останется, а после закрытия его можно попробовать создать заново. Такая функиональность необходима для тех носителей, которые требуют пароль для любой записи.
2. Самый простой способ создать пустой контейнер (именно сохранить пустой на носителе) в КриптоПро CSP, выполнить:
Код:
::CryptGetProvParam( hProv, PP_HCRYPTPROV, (BYTE*)&dwData, &dwDataLen, 0 )

после CryptAcquireContext, но перед этим потребуется задать пароль на вновь создаваемый контейнер. Если это не сделать, то сохранение контейнера, потребует его ввести в окне. В режиме без окон (CRYPT_SILENT), его можно задать, например, пустой так:
Код:
CRYPT_PIN_PARAM param;
param.type = CRYPT_PIN_PASSWD;
param.dest.passwd = "";
CryptSetProvParam( hProv, PP_SET_PIN, (BYTE*)&param, 0 )

3. Если внести это в Вашу программу получится, примерно так
Код:

    ...
    for(ULONG i = 0,f = CRYPT_SILENT;;++i)
    {
        HCRYPTPROV hProv;
        if(::CryptAcquireContext(&hProv,container,provider,type,f))
        {
            printf("\ndone i=%u f=%8.8x\n",i,f);
            if( ( f & CRYPT_NEWKEYSET ) && ( type == 75 || type == 71 )  )
            {
                DWORD dwData;
                DWORD dwDataLen = sizeof( dwData );
                CRYPT_PIN_PARAM param;
                param.type = CRYPT_PIN_PASSWD;
                param.dest.passwd = "";
                if( !::CryptSetProvParam( hProv, PP_SET_PIN, (BYTE*)&param, 0 ) )
                {
                    printf( "\nset passwd fail\n");
                    return 0;
                }
                if( !::CryptGetProvParam( hProv, PP_HCRYPTPROV, (BYTE*)&dwData, &dwDataLen, 0 ) )
                {
                    printf( "\nsave fail\n");
                    return 0;
                }
            }
            ....

4. В последних версиях CSP 3.6 открыть созданный контейнер, но без следов на носителе можно, но, если его не записывать (генерировать ключи или не сохранять как в примере Выше), то сохранен на диске он все равно не будет.
С уважением, Александр.
Offline Сашка  
#3 Оставлено : 2 апреля 2009 г. 19:15:00(UTC)
Сашка

Статус: Новичок

Группы: Участники
Зарегистрирован: 20.03.2009(UTC)
Сообщений: 9

Огромное спасибо. Я догадывался, что это не просто так сделано, но теперь совсем понятно. А параметры PP_HCRYPTPROV и PP_SET_PIN, как я понимаю, специфические для CryptoPro? Нельзя добиться того же эффекта с пином через PP_KEYEXCHANGE_PIN/PP_SIGNATURE_PIN?

И раз уж речь зашла про параметры, не сочтите за труд, разъясните по поводу параметра ключа KP_CERTIFICATE, у меня создалось впечатление, что криптопровайдеры с ним не церемонятся - хотят поддерживают, не хотят - нет. Я не ошибся? Я почему спрашиваю: с CryptoPro он к примеру отлично работает, а со стандартными от MS (Base,Strong) - нет, дает ошибку NTE_BAD_TYPE. Это реальность или все-таки есть нюансы использования, которых я не знаю? Я понимаю, что это не совсем вопрос по CryptoPro, но может Вы знаете...
Offline Челпанов А.  
#4 Оставлено : 2 апреля 2009 г. 22:55:56(UTC)
Челпанов А.

Статус: Активный участник

Группы: Участники
Зарегистрирован: 24.12.2007(UTC)
Сообщений: 390
Мужчина
Откуда: КриптоПро

Поблагодарили: 2 раз в 2 постах
PP_HCRYPTPROV параметр специфический для КриптоПро. Он имеет двойное назначение: первое, это синхронизация контейнера в памяти с контейнером на диске (для этого он и стоит в примере); второе, получение хендла провайдера уровня CP (в данном случае надо просто выделить под нее память и забыть).

PP_SET_PIN то же специфика КриптоПро. Есть масса вариантов защиты контейнера, которые не удается прокинуть через PP_KEYEXCHANGE_PIN, например, шифрование одного контейнера на другом, поэтому он и поддерживается. У нас функциональность PP_KEYEXCHANGE_PIN реализована через PP_SET_PIN.

В документации Microsoft сказано, что
1) передача пустого пароля (NULL) и передача пароля нулевой длины эквивалентны,
2) передача NULL пароля приводит к сбросу текущего установленного пароля,
и эту функциональность мы поддерживаем, поэтому установить пустой пароль на контейнер КриптоПро через PP_KEYEXCHANGE_PIN не получится.

У microsoft по умолчанию контейнер не содержит пароля, поэтому, при создании контейнера пароль задан не будет. В CSP по умолчанию выдается окно. Если оно Вам не мешает, то все хорошо. Если мешает (а CRYPT_SILENT я так понял вы не зря привели в программе) и требуется обычный строковый пароль можно воспользоваться PP_KEYEXCHANGE_PIN, а можно PP_SET_PIN. Если же нужен пустой пароль, то придется делать через PP_SET_PIN. Если укажите CRYPT_SILENT при создании контейнера, то придется использовать физический ДСЧ, биологический к сожалению оконный Angel.

Отредактировано пользователем 2 апреля 2009 г. 22:59:25(UTC)  | Причина: Не указана

С уважением, Александр.
Offline Челпанов А.  
#5 Оставлено : 2 апреля 2009 г. 23:00:31(UTC)
Челпанов А.

Статус: Активный участник

Группы: Участники
Зарегистрирован: 24.12.2007(UTC)
Сообщений: 390
Мужчина
Откуда: КриптоПро

Поблагодарили: 2 раз в 2 постах
KP_CERTIFICATE MS (Base,Strong) не поддерживают.
С уважением, Александр.
Offline Сашка  
#6 Оставлено : 2 апреля 2009 г. 23:02:09(UTC)
Сашка

Статус: Новичок

Группы: Участники
Зарегистрирован: 20.03.2009(UTC)
Сообщений: 9

Огромное спасибо за разъяснения.

RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Guest
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.