Использование PGP SDK
Часть 2. Расшифрование и ввод пароля
Опубликовано: 28.11.2002
Исправлено: 13.03.2005
Версия текста: 1.2
Класс CSimplePGP – исходные тексты (Win API, STL)
Демонстрационный проект (VC7, WTL7)
Исполняемый файл демонстрационной программы – PGPtest2.exe (для запуска необходимы PGP_SDK.dll, PGPsdkUI.dll и PGPsdkNL.dll)
PGP_SDK.dll
PGPsdkUI.dll
PGPsdkNL.dll
Функции PGP SDK, используемые при расшифровании
Собственно расшифрование данных, зашифрованных открытым ключом, осуществляется при помощи функции
PGPDecode
PGPError PGPDecode(
PGPContextRef pgpContext,
PGPOptionListRef firstOption,
...,
PGPOLastOption() );
|
pgpContext | Используемый PGP-контекст. |
firstOption | Первая опция расшифрования |
... | Список других необходимых опций |
PGPOLastOption() | Последняя опция в списке, показывает, что список опций закончен |
При передаче в PGPDecode неправильного пароля данная функция не возвращает никакой ошибки, просто не создается выходной файл (при выводе результатов в файл) либо не выделяется память под выходной буфер (при выводе результатов в буфер в памяти).
Проверить соответствие пароля ключу расшифрования можно предварительно вызовом функции
PGPPassphraseIsValid
PGPBoolean PGPPassphraseIsValid(
PGPKeySetRef key,
const char *passphrase );
|
key | Секретный ключ, на соответствие которому проверяется пароль |
passphrase | Указатель на строку – пароль к секретному ключу |
В дополнение к рассмотренным в первой части опциям PGPOInputFile, PGPOOutputFile, PGPOInputBuffer, PGPOOutputBuffer функция PGPDecode использует также следующие опции:
PGPOPassphrase
PGPOptionListRef PGPOPassphrase(
PGPContextRef pgpContext,
const char *passphraseBuf );
|
pgpContext | Используемый PGP-контекст. |
passphraseBuf | Указатель на строку – пароль к секретному ключу |
PGPOPassphraseBuffer
PGPOptionListRef PGPOPassphraseBuffer(
PGPContextRef pgpContext,
const void *passphraseBuf,
PGPSize passphraseLength );
|
pgpContext | Используемый PGP-контекст. |
passphraseBuf | Указатель на буфер с паролем к секретному ключу |
passphraseLength | Размер буфера с парольной фразой |
PGPOPassphraseBuffer отличается от PGPOPassphrase тем, что буфер с паролем может иметь размер и содержание, не ограниченные синтаксисом строк языка C.
|
PGPOKeySetRef
PGPOptionListRef PGPOKeySetRef(
PGPContextRef pgpContext,
PGPKeySetRef keySet );
|
pgpContext | Используемый PGP-контекст. |
keySet | Набор ключей расшифрования. |
Для запроса пароля расшифрования можно использовать диалоговое окно, выводимое функцией
PGPPassphraseDialog
PGPError PGPPassphraseDialog(
PGPContextRef pgpContext,
PGPOptionListRef firstOption,
...,
PGPOLastOption() );
|
pgpContext | Используемый PGP-контекст. |
firstOption | Первая опция в списке |
... | Список других необходимых опций |
PGPOLastOption() | Последняя опция в списке, показывает, что список опций закончен |
В функцию, выводящую диалог, могут быть переданы следующие опции:
PGPOUIOutputPassphrase
PGPOptionListRef PGPOUIOutputPassphrase(
PGPContextRef pgpContext,
char **passphrase );
|
pgpContext | Используемый PGP-контекст. |
passphrase | Указатель на строку, в которой будет размещена полученная парольная фраза. |
Если пользователь закроет диалог запроса пароля нажатием на кнопку Cancel или Close passphrase будет установлено в NULL. PGPOUIOutputPassphrase - единственная обязательная опция при вызове диалога ввода пароля. Освобождать память, выделенную при записи парольной фразы в passphrase необходимо вызовом функции
PGPFreeData
PGPError PGPFreeData( void *allocation );
|
allocation | Указатель на освобождаемую область памяти. |
PGPOUIWindowTitle
PGPOptionListRef PGPOUIWindowTitle(
PGPContextRef pgpContext,
const char *title );
|
pgpContext | Используемый PGP-контекст. |
title | Указатель на строку, которую надо установить в качестве заголовком для окна запроса пароля. |
Если данная опция не применяется при вызове диалога запроса пароля, в заголовке окна устанавливается фраза по умолчанию: "PGP Enter Passphrase".
PGPOUIDialogPrompt
PGPOptionListRef PGPOUIDialogPrompt(
PGPContextRef pgpContext,
const char *prompt );
|
pgpContext | Используемый PGP-контекст. |
prompt | Указатель на строку, которую надо установить в качестве запроса перед полем для ввода пароля. |
Если данная опция не применяется при вызове диалога запроса пароля, в качестве запроса устанавливается фраза по умолчанию: "Passphrase of private key".
PGPOUIParentWindowHandle
PGPOptionListRef PGPOUIParentWindowHandle(
PGPContextRef pgpContext,
HWND hwndParent );
|
pgpContext | Используемый PGP-контекст. |
hwndParent | HWND окна, которое надо установить в качестве родительского для окна запроса пароля. |
Если данная опция не применяется при вызове диалога запроса пароля, в качестве родительского окна устанавливается десктоп.
Кроме указанных, в PGPPassphraseDialog могут быть также переданы опции PGPOUIDialogOptions, PGPOUIMinimumPassphraseLength, PGPOUIMinimumPassphraseQuality.
Начинать работу с библиотекой пользовательских интерфейсов, PGPsdkUI.dll, нужно с инициализации:
PGPsdkUILibInit
PGPError PGPsdkUILibInit( void );
|
По завершении работы с библиотекой пользовательских интерфейсов необходимо вызвать функцию очистки -
PGPsdkUILibCleanup
PGPError PGPsdkUILibCleanup( void );
|
Поддержка операции расшифрования в классе CSimplePGP
Для поддержки операций расшифрования в класс CSimplePGP добавлены следующие члены:
protected:
PGPOptionListRef m_optsDecode;
public:
BOOL SetPassphrase ( LPCTSTR sPassphrase );
#ifdef _WITH_PGPUI_
BOOL AskPassphrase( HWND hwndParent );
#endif
BOOL DecodeFile2File( LPCTSTR inFileName,
LPCTSTR outFileName,
LPCTSTR keyFileName );
BOOL DecodeFile2File( LPCTSTR inFileName,
LPCTSTR outFileName,
LPCTSTR resourceName,
LPCTSTR resourceType );
BOOL DecodeBuff2File( const VOID* inData,
DWORD dwDataSize,
LPCTSTR outFileName,
LPCTSTR keyFileName );
BOOL DecodeBuff2File( const VOID* inData,
DWORD dwDataSize,
LPCTSTR outFileName,
LPCTSTR resourceName,
LPCTSTR resourceType );
BOOL DecodeFile2Buff( LPCTSTR inFileName,
LPBYTE& OutData,
DWORD& BuffSize,
LPCTSTR keyFileName );
BOOL DecodeFile2Buff( LPCTSTR inFileName,
LPBYTE& OutData,
DWORD& BuffSize,
LPCTSTR resourceName,
LPCTSTR resourceType );
BOOL DecodeBuff2Buff( const VOID* inData,
DWORD dwDataSize,
LPBYTE& OutData,
DWORD& BuffSize,
LPCTSTR keyFileName );
BOOL DecodeBuff2Buff( const VOID* inData,
DWORD dwDataSize,
LPBYTE& OutData,
DWORD& BuffSize,
LPCTSTR resourceName,
LPCTSTR resourceType );
|
Реализация и применение функций DecodeXXXXXXX аналогичны описанным в первой части функциям шифрования – EncodeXXXXXX. Подробности можно посмотреть в исходных текстах CSimplePGP.
Функция SetPassphrase() осуществляет непосредственное внесение парольной фразы в список опций используемых при расшифровании:
BOOL CSimplePGP::SetPassphrase ( LPCTSTR sPassphrase )
{
if ( !m_bIsInit )
Init();
PGPError err = kPGPError_NoErr;
if ( m_optsDecode != NULL )
{
PGPFreeOptionList( m_optsDecode );
m_optsDecode = NULL;
}
err = PGPBuildOptionList( m_context,
&m_optsDecode,
PGPOPassphrase( m_context, sPassphrase ),
PGPOLastOption( m_context ) );
if ( IsPGPError( err ) )
{
m_sWhere = "SetPassphrase()";
return FALSE;
}
return TRUE;
}
|
В функцию Init() добавлена инициализация библиотеки пользовательских интерфейсов PGPSDK:
#ifdef _WITH_PGPUI_
#include "pgpUserInterface.h"
#pragma comment(lib,"pgpsdkui.lib")
#endif
BOOL CSimplePGP::Init()
{
...
...
#ifdef _WITH_PGPUI_
err = PGPsdkUILibInit();
if ( IsPGPError( err ) )
{
m_sWhere = "PGPsdkUILibInit()";
goto Exit;
}
#endif
...
...
}
|
А в деструктор – вызов функции очистки
CSimplePGP::~CSimplePGP( void )
{
if ( m_bIsInit )
{
if ( m_optsEncode != NULL )
{
PGPFreeOptionList( m_optsEncode );
m_optsEncode = NULL;
}
if ( m_optsDecode != NULL )
{
PGPFreeOptionList( m_optsDecode );
m_optsEncode = NULL;
}
if ( PGPContextRefIsValid( m_context ) )
PGPFreeContext( m_context );
#ifdef _WITH_PGPUI_
PGPsdkUILibCleanup();
#endif
PGPsdkCleanup();
}
}
|
Следует, пожалуй, отдельно остановится на операции запроса пароля расшифрования у пользователя. Функция AskPassphrase() использует для вывода диалога запроса пароля соответствующую функцию PGPSDK:
#ifdef _WITH_PGPUI_
BOOL CSimplePGP::AskPassphrase( HWND hwndParent )
{
char * passphrase;
BOOL ret = TRUE;
PGPError err = kPGPError_NoErr;
err = PGPPassphraseDialog( m_context,
PGPOUIOutputPassphrase( m_context, &passphrase ),
PGPOUIWindowTitle( m_context, "Введите пароль" ),
PGPOUIDialogPrompt( m_context, "Пароль секретного ключа:" ),
PGPOUIParentWindowHandle( m_context, hwndParent ),
PGPOLastOption( m_context ) );
if ( IsPGPError( err ) )
{
m_sWhere = "PGPPassphraseDialog()";
ret = FALSE;
PGPGetErrorString( err, sizeof( m_sWhat ), m_sWhat );
}
if ( passphrase )
{
SetPassphrase( passphrase );
PGPFreeData ( ( void* ) passphrase );
passphrase = NULL;
}
else
{
ret = FALSE;
}
return ret;
}
#endif
|
Т.к. данные возможности нужны далеко не всегда, а требуют дополнительно наличия PGPsdkUI.dll и PGPsdkNL.dll, они внесены в класс CSimplePGP опционально и зависят от определения в проекте макроса _WITH_PGPUI_. Если вам интересно, зачем вообще нужно использовать для ввода пароля специальный диалог из PGPSDK, запустите демонстрационную программу вместе с каким-либо логгером, ведущим протокол всех нажатых клавиш (см., например HookDump), введите пароль в стандартном диалоге Windows и в диалоге из PGPSDK и посмотрите записанный протокол.
Экспорт секретного ключа из менеджера ключей PGP
Менеджер ключей PGP и, забегая вперед, функции PGP SDK не позволяют экспортировать только секретный ключ, но можно экспортировать в текстовый файл пару ключей – секретный и открытый, а затем удалить из него блок текста, соответствующий открытому ключу.
Демонстрационная программа PGPTest2
Программа позволяет протестировать возможности PGP SDK по расшифрованию данных, реализованные в классе CSimplePGP.
Пароль расшифрования для тестовых зашифрованных сообщений – test. После нажатия кнопки "Расшифровать" в зависимости от настроек программы для ввода пароля будет выведен стандартный диалог Windows:
либо "фирменный" диалог PGP SDK:
Если пароль введен правильно, откроется окно с расшифрованным текстом:
При вводе неправильного пароля выводится соответствующее сообщение.
И еще кое-что о секретных и открытых ключах PGP
Программа PGP хранит ключи в связке из двух файлов – pubring.pkr и secring.skr. Функции PGP SDK, и, соответственно, класс CSimplePGP могут работать с ключами непосредственно из этих файлов. Однако, имейте ввиду,
ПРЕДУПРЕЖДЕНИЕ
Не смотря на название файл secring.skr содержит не только секретные ключи.
|
В этом легко убедиться – тестовая программа из первой части, PGPtest1, позволяет зашифровать что-либо, используя только secring.skr. Тоже касается и собственно программы PGP – если заменить pubring.pkr на файл с таким же названием, но нулевого размера, в списке менеджера ключей останутся только имеющиеся у вас секретные ключи, но возможность зашифровать что-либо используя только эти ключи все равно остается.
Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы
то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских
прав.