+7(960) 250-82-68 spam@mirossa.ru


 mirossa        1С           C         PHP       JAVA       MCU  


Статьи
 
 

08 янв 2020

Encrypt Decrypt 365 based on GPG

title.exe

Видео. Создание ключа, шифрование сообщения

Ссылки на это видео : 01GenKey.mp4 или 01GenKey.webm

Приложение, использующее пакет GPG ( https://ru.wikipedia.org/wiki/GnuPG ) и имеющее следующие функции:
Генерация ключей. Экспорт, импорт, подпись ключей, удаление ключей.
Шифрование. Расшифровка.
Для передачи сообщений использовать любой доступный канал связи.
Использование синонимов вместо идентификаторов ключей.

История
Изначально приложение задумывалось для переписки во vkontakte через vk Api(программный интерфейс для доступа к VK используя своё собственное приложение, а не браузер или официальное мобильное приложение) из под учетной записи пользователя. Но эти товарищи заблокировали возможность чтения своих сообщений(по умолчанию). Получить доступ можно, но для этого нужно пройти через разные унижения и этот вариант отпал.
А для отправки сообщений через vk Api запретов по умолчанию нет, но тогда выглядело бы это однобоко(отправляем автоматически, а читаем вручную) : пишем сообщение, шифруем, отправляем, получаем сообщение от другого пользователя в vk, вручную копируем в приложение, расшифровываем.
В vk есть ещё один нюанс. Там любят, когда ваша переписка ведётся в незашифрованном виде, чтобы, если будет нужно, прочитать её (просто так до вас, конечно, дела нет(до критического количества подписчиков, кажется, 100 тысяч ), но при каких-либо технических работах(внедрение нового фильтра) случайный выбор падёт на вас).

Шифровать можно не всё подряд, а только самое ценное(без фанатизма).
- - - - - - - - - - - - -

Установка

- - 1 вариант - -
Установка не требуется. Нужно распаковать архив(полностью) CMD.exedownload GnuPGunpacked.zip , а не просто запустить приложение из архива.
Имена каталогов(куда вы распакуете архив) могут содержать любые символы, но если что-то не работает, то удалите русские символы и пробелы.
Там в каталоге \GnuPG\bin есть приложение encrypt-decrypt_365.exe. Запускаете. Всё.
В архиве есть и 64-х и 32-х разрядная версии: bothVersion.png

- - 2 вариант - -
Нужно запустить CMD.exedownload gpg4win3110.zip (или скачать в другом месте)
Но запустить нужно с ключом /S (описание есть в .pdf, вложенном в архив) :
пример: gpg4win.exe /S /D=D:\Programme\Gpg4win
И тогда вы придёте к варианту № 1. Скорируйте приложение encrypt-decrypt_365.exe из архива в пункте 1 в каталог \GnuPG\bin.

Особенности запуска

Запуск приложения encrypt-decrypt_365.exe должен быть под тем же пользователем, под которым создавались ключи.
Ключи создаются и хранятся в каталоге пользователя типа этого C:\Users\User\AppData\Roaming\gnupg\ (вместо User - ваш пользователь) .
И при удалении приложения не забудьте что-нибудь сделать с этим каталогом.
То есть если вы запустите приложение вначале под Администратором, создадите ключи, а затем запустите под другим(своим) пользователем, то тех ключей вы не увидите.
Т.о. можно создавать разные группы ключей для разных пользователей.

Короткая инструкция:

1. сгенерировать ключи
2. передать свой открытый ключ другому пользователю (экспорт)
3. получить(импорт) от другого пользователя его открытый ключ. (+ Сверить отпечатки ключей. Подписать ключ)
4. Шифруем/расшифровываем сообщения.
- - - - - - - - - - - - -

Инструкция :

Создание новой пары ключей(приватного и публичного)
Кнопка 'generate key'. Нужно пройти диалог. Пример того, что нужно ввести, есть на картинке. Обведено оранжевым цветом.
Также появится окно с заголовком Pinentry, где нужно ввести(два раза) парольную фразу для защиты создаваемого приватного ключа.
(есть небольшие глюки с отображением шрифтов, поэтому вместо нормального текста - знаки вопроса)

genKey.png

После завершения диалога в списке появится созданный ключ (его идентификатор). Знак '+' слева от id ключа означает, что есть приватный + публичный ключи. (знак '-' будет означать, что есть только публичный ключ)
Публичным ключом сообщения шифруются. Приватным ключом - расшифровываются.

afterGenKey_m.png

Удаление приватного ключа.
Если нужно удалить ключи, но вначале удаляется приватный, затем - публичный. Нужно выбрать ключ в списке. Нажать 'delete secret key'. В появившемся диалоге подтвердить удаление.
После удаления приватного ключа знак '+' слева от id этого ключа (в списке) изменится на '-'(остался только публичный ключ).

delSecKey_m.png

Удаление публичного ключа.
Выбрать ключ в списке. Нажать 'delete public key'. В появившемся диалоге подтвердить удаление.

delPubKey_m.png

Использование синонимов вместо идентификаторов ключей.
Так проще распознавать, с кем вы ведёте переписку. В списке ваших ключей вы видите идентификаторы ( Ivan7 (no) <ivan777@mail.ru> ) , которые могут ничего не значить и трудно запоминаться.
Тогда вы можете назначить этому id осмысленное для вас имя.
Нажимаете кнопку 'Syn1'. Верхнее текстовое поле заполняется информацией о ваших ключах(включая синонимы, если вы ранее уже их указывали). Вначале - идентификатор, затем отпечаток ключа и после отпечатка через пробел укаываете синоним. Если вы указываете синонимы только для некоторых ключей, то остальные строки можно не удалять.
Для сохранения настройки нажмите кнопку 'Syn2'. ( В каталоге \GnuPG\bin будет создан файл synonyms.txt, который можно удалить для прекращения использования этой функции.)

synonym_m.png

Списки ключей двух пользователей. У Пользователя 1 есть 1 ключ, у Пользователя 2 есть 3 ключа.

user1user2_m.png

Экспорт открытого ключа.
Пользователь 1 экспортирует открытый ключ. нужно выбрать ключ в списке и нажать 'Export public key'. Ключ выведется в верхнее текстовое поле. Его можно передать другому лицу любым способом.

user1export_m.png

Импорт открытого ключа.
Пользователь 2 загружает к себе открытый ключ, полученный от Пользователя 1. Нужно скопировать ключ в верхнее текстовое поле и нажать 'Import public key'. Список ключей обновится и там будет новый ключ. Слева от него будет знак '-' - это означает, что у вас есть только открытый ключ. (открытые ключи можно передавать кому угодно, закрытые ключи хранятся только у вас)

user2import_m.png

(Перед импортом) При получении открытого ключа проконтролируйте, что отсутствуют искажения в начале и окончании текстового представления ключа.
Например, при передаче ключа через VK бывает, что пара дефисов "сливается" в один символ(уже не дефис) и ключ не импортируется. Везде по 5 дефисов.
user2import_m.png

Шифрование сообщения.
Вы получили и импортировали ключ, полученный от другого пользователя. Выберите его в списке, напишите сообщение в верхнем текстовом поле и нажмите кнопку 'enctypt'. В нижнем текстовом поле появится зашифрованное сообщение. Его отправляете владельцу этого ключа. У него есть приватный ключ, которым он расшифрует это сообщение.
На картинке вы видите чёрное окно с дополнительным вопросом. Ответьте положительно. Этот дополнительный вопрос появился потому, что вы ещё не подписали импортированный ключ своим приватным ключом. Чужой ключ не обязательно подписывать, но тогда этот дополнительный вопрос будет каждый раз появляться. Полписывание ключа - в следующем пункте.
(также на картинке есть отпечатки этого ключа)

encrypt_m.png

Подпись импортированного ключа.
Для подписи ключа нажмите кнопку 'Sign public key', но
Прежде, чем подписать импортированный ключ, нужно сверить отпечаток загруженного ключа с оригинальным отпечатком. Нужно это для того, чтобы убедится, что полученный вами ключ никто не подменил в процессе передачи. Сверить отпечатки можно по другому каналу связи (телефонный звонок владельцу ключа). Для вывода отпечатков ваших ключей - нажмите кнопку 'Syn1'. Или вернитесь к предыдущему пункту - там тоже выводится нужный отпечаток. Или можете запустить подпись ключа( 'Sign public key' ) - там тоже выводится отпечаток первичного ключа. После сверки ответьте на все вопросы положительно.
Если отпечатки не совпадают - удалите этот ключ ( 'delete public key' ).

signPubKey_m.png

Расшифровка сообщения.
Вставьте зашифрованное сообщение в нижнее текстовое поле. Выберите нужный(свой) ключ в списке. Нажмите 'decrypt'. В верхнем текстовом поле появится расшифрованное сообщение.
В процессе переписки может быть неудобно каждый раз менять ключи при шифровании(выбирать открытый ключ собеседника) и расшифровке(выбирать свой ключ). Поэтому вы может выбрать в списке открытый ключ собеседника, а при расшифровке приложение переберёт последовательно ключи, найдёт нужный и расшифрует сообщение(то есть в итоге будет использовать не выбранный в списке ключ, подходящий для расшифровки. Цена - чуть медленнее.).

decrypt_m.png

Что это такое?
Это функция, которой лучше не пользоваться
- Хранение пароля от приватного ключа в файле.
Сейчас так: когда вы начинаете сеанс работы с этим приложением, то при первом обращении к функции, задействующей приватный ключ (Шифрование, подпись ключа) появится окно для ввода парольной фразы, которую вы задали при создании ключа. После ввода пароля он сохраняется и не запрашивается до конца сеанса(завершение работы операционной системы или можете, открыв Диспетчер задач, найти в фоновых процессах и завершить приложение GnuPG's private key daemon)
Будет так: если вы создадите в каталоге \GnuPG\bin файл passphrase.txt со строкой-парольной фразой, то окно для ввода парольной фразы не появится - будет использоваться первая строка из этого файла. Если пароль ошибочен, то вы не получите сообщения об этом. И ещё, парольные фразы у вас могут быть разные для разных ключей, а в файле указывается только одна фраза.
Если вы создадите этот файл и перезапустите приложение, то символы дефисов '- - - -' изменятся на '********'.

passwfile_m.png

исходный код приложения:

// протестировано с gpg 2.2.17

//компиляция:
//cd "C:\Program Files\mingw-w64\x86_64-8.1.0-win32-seh-rt_v6-rev0\mingw64\bin"
//
//x86_64-w64-mingw32-gcc.exe encrypt-decrypt_365.c  -l:libgdi32.a  -o encrypt-decrypt_365.exe -mwindows
//
//x86_64-w64-mingw32-gcc.exe encrypt-decrypt_365.c  -l:libgdi32.a  -o encrypt-decrypt_365.exe -mwindows -mconsole
//
//cd "C:\Program Files (x86)\C-Free 5\mingw\bin"
//mingw32-gcc.exe encrypt-decrypt_365.c  -l:libgdi32.a  -o encrypt-decrypt_365_32bit.exe -mwindows

#include <windows.h> // заголовочный файл, содержащий WINAPI
#include <stdio.h>
#include <commctrl.h>
#include <string.h> 
 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT APIENTRY EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT APIENTRY Edit2SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int encodeToBase64(char * inF, char * outB64F);
int copyTextToFile( HWND id, char * fname);
int decodeBase64(char * inF, char * outT);
int copyTextToControl(  HWND id, char * fname );
int deleteFiles( char * f1, char * f2, char * f3);
void getField(int nfield, const char * source, char * target , int maxLen);

//TCHAR mainMessage[] = "Kakoi-to text!"; // строка с сообщением
HWND editctl, editctl2, hWnd_button2, hWnd_buttonDecrypt, hWnd_expPubKey, hWnd_signPubKey, hWnd_impPubKey,
	 hWnd_ComboBox_pub, hWnd_Text1, hWnd_synonym1, hWnd_synonym2, hWnd_genKey, hWnd_delPrivateKey, hWnd_delPublicKey;
HWND hMainWnd; // дескриптор будущего окна

char sizeCL[60];
WORD sx, sy;
WNDPROC wpOrigEditProc, wpOrigEdit2Proc;
int slen;
char * passw = NULL;
char * synR, * synRc;

#define fprML 40
#define uidML 150
char str[400];    // [fprML + uidML + 40];

struct infoKey {
	char fpr[fprML+1];
	char uid[uidML+1];
	char synonym[100];
	int withoutPrivate;
};
int numPubKeys = 0, currSel = -1;
struct infoKey * arrInfoKey = NULL;
int fillKeyList(int * numPubKeys, size_t sz, struct infoKey ** arrInfoKey);
void updKeyList(int * numPubKeys, size_t sz, struct infoKey ** arrInfoKey, char * str);
void loadPassPhrase(char ** passw);

/* 64-bit */ 
long long id_button2 = 10001;
long long id_buttonDecrypt = 10003;
long long IDC_EDIT   = 10002;
long long id_expPubKey = 10004;
long long id_impPubKey = 10005;
long long id_signPubKey = 10006;
long long id_ComboBox_pub = 10007;
long long id_synonym1 = 10008;
long long id_synonym2 = 10009;
long long id_genKey = 10010;
long long id_delPrivateKey = 10011;
long long id_delPublicKey = 10012;

/* // 32-bit
int id_button2 = 10001;
int id_buttonDecrypt = 10003;
int IDC_EDIT   = 10002;
int id_expPubKey = 10004;
int id_impPubKey = 10005;
int id_signPubKey = 10006;
int id_ComboBox_pub = 10007;
int id_synonym1 = 10008;
int id_synonym2 = 10009;
int id_genKey = 10010;
int id_delPrivateKey = 10011;
int id_delPublicKey = 10012;
*/


// Управляющая функция:
int WINAPI WinMain(HINSTANCE hInst, // дескриптор экземпляра приложения
                   HINSTANCE hPrevInst, // не используем
                   LPSTR lpCmdLine, // не используем
                   int nCmdShow) // режим отображения окна
{
    TCHAR szClassName[] = "Mein Kampf"; // строка с именем класса
    MSG msg; // создаём экземпляр структуры MSG для обработки сообщений
    WNDCLASSEX wc; // создааём экземпляр, для обращения к членам класса WNDCLASSEX
    wc.cbSize        = sizeof(wc); // размер структуры (в байтах)
    wc.style         = CS_HREDRAW | CS_VREDRAW; // стиль класса окна
    wc.lpfnWndProc   = WndProc; // указатель на пользовательскую функцию
    wc.lpszMenuName  = NULL; // указатель на имя меню (у нас его нет)
    wc.lpszClassName = szClassName; // указатель на имя класса
    wc.cbWndExtra    = 0; // число освобождаемых байтов в конце структуры
    wc.cbClsExtra    = 0; // число освобождаемых байтов при создании экземпляра приложения
    wc.hIcon         = LoadIcon(NULL, IDI_WINLOGO); // декриптор пиктограммы
    wc.hIconSm       = LoadIcon(NULL, IDI_WINLOGO); // дескриптор маленькой пиктограммы (в трэе)
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW); // дескриптор курсора
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // дескриптор кисти для закраски фона окна
    wc.hInstance     = hInst; // указатель на строку, содержащую имя меню, применяемого для класса
    if(!RegisterClassEx(&wc)){
        // в случае отсутствия регистрации класса:
        MessageBox(NULL, "Ne poluchilos zaregistrirovat class!", "Err_Err", MB_OK);
        return 1; // возвращаем, следовательно, выходим из WinMain
    }
    
    // Функция, создающая окно:
    hMainWnd = CreateWindow(
        szClassName, // имя класса
        "encrypt-decrypt", // имя окна (то что сверху)
        WS_OVERLAPPEDWINDOW,              // | WS_VSCROLL, // режимы отображения окна
        CW_USEDEFAULT, // позиция окна по оси х
        0, // позиция окна по оси у (раз дефолт в х, то писать не нужно)
        CW_USEDEFAULT, // ширина окна
        0, // высота окна (раз дефолт в ширине, то писать не нужно)
        NULL, // дескриптор родительского окна
        NULL, // дескриптор меню
        hInst, // дескриптор экземпляра приложения
        NULL); // ничего не передааём из WndProc
    if(!hMainWnd){
        // в случае некорректного создания окна (неверные параметры и тп):
        MessageBox(NULL, "Window is not created!", "Err_Err2", MB_OK);
        return 0;
    }
	
	//////////////button2//////////////////////////////////
	
	//Создаем кнопку2

	hWnd_button2 = CreateWindow(TEXT("button"), TEXT("encrypt"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	10, 30, 130, 30, hMainWnd, (HMENU)id_button2, hInst, NULL);
	
	//////////////Decrypt button//////////////////////////////////
	
	//Создаем кнопку Decrypt

	hWnd_buttonDecrypt = CreateWindow(TEXT("button"), TEXT("decrypt"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	400, 30, 130, 30, hMainWnd, (HMENU)id_buttonDecrypt, hInst, NULL);
	
	//Создаем кнопку для экспорта открытого ключа

	hWnd_expPubKey = CreateWindow(TEXT("button"), TEXT("Export public key"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	370, 10, 130, 20, hMainWnd, (HMENU)id_expPubKey, hInst, NULL);
	
	//Создаем кнопку для инпорта открытого ключа

	hWnd_impPubKey = CreateWindow(TEXT("button"), TEXT("Import public key"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	370, 35, 130, 20, hMainWnd, (HMENU)id_impPubKey, hInst, NULL);
	
	//Создаем кнопку для подписания открытого ключа

	hWnd_signPubKey = CreateWindow(TEXT("button"), TEXT("Sign public key"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	510, 30, 110, 30, hMainWnd, (HMENU)id_signPubKey, hInst, NULL);
	
	// кнопка отображения текущего списка id + отпечаток + синоним (для редактирования)

	hWnd_synonym1 = CreateWindow(TEXT("button"), TEXT("Syn1"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	300, 10, 50, 20, hMainWnd, (HMENU)id_synonym1, hInst, NULL);
	
	// кнопка для записи отредактированного списка

	hWnd_synonym2 = CreateWindow(TEXT("button"), TEXT("Syn2"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	300, 36, 50, 20, hMainWnd, (HMENU)id_synonym2, hInst, NULL);
	
	// кнопка для запуска генерации ключей

	hWnd_genKey = CreateWindow(TEXT("button"), TEXT("generate key"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	150, 3, 130, 19, hMainWnd, (HMENU)id_genKey, hInst, NULL);
	
	// кнопка для запуска удаления приватного ключа

	hWnd_delPrivateKey = CreateWindow(TEXT("button"), TEXT("delete secret key"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	150, 25, 130, 19, hMainWnd, (HMENU)id_delPrivateKey, hInst, NULL);
	
	// кнопка для запуска публичного ключа

	hWnd_delPublicKey = CreateWindow(TEXT("button"), TEXT("delete public key"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
	150, 47, 130, 19, hMainWnd, (HMENU)id_delPublicKey, hInst, NULL);
	
	////////////// EDIT 1/////////////////////////////////////////

editctl = CreateWindow("EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_HSCROLL |
		ES_LEFT | ES_AUTOHSCROLL | ES_WANTRETURN | ES_MULTILINE | ES_AUTOVSCROLL | ES_NOHIDESEL,
	10, 70, 100, 100, hMainWnd, (HMENU)IDC_EDIT, hInst, 0);
	
	//////////////// установка своей оконной процедуры для Edit
	
	// Retrieve the handle to the edit control.    
	//hwndEdit = GetDlgItem(hWnd, IDC_EDIT);  // возвращает то же значение, которое уже есть в editctl  (в WndProc)

		// Subclass the edit control. 
		//wpOrigEditProc = (WNDPROC)
		SetLastError(0);
		// GWL_WNDPROC = -4  //(long long), not (long)
		wpOrigEditProc = (WNDPROC)SetWindowLongPtr(editctl, (int)-4 , (LONG_PTR)EditSubclassProc); 
		if (0 == wpOrigEditProc){
			//dw = GetLastError(); 
			//sprintf(sizeCL, "errorCode = %d", dw);
			//MessageBox(hWnd, sizeCL, TEXT(""), 0);   //  Code: 1400. Недопустимый дескриптор окна
			MessageBox(hMainWnd, "Error of a reset WNDPROC for Edit1.", TEXT(""), 0);
		}
	
	////////////// EDIT 2/////////////////////////////////////////

editctl2 = CreateWindow("EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_HSCROLL |
		ES_LEFT | ES_AUTOHSCROLL | ES_WANTRETURN | ES_MULTILINE | ES_AUTOVSCROLL | ES_NOHIDESEL,
	10, 200, 100, 50, hMainWnd, (HMENU)IDC_EDIT, hInst, 0);
	
	//////////////// установка своей оконной процедуры для Edit
	
		SetLastError(0);
		// GWL_WNDPROC = -4  //(long long), not (long)
		wpOrigEdit2Proc = (WNDPROC)SetWindowLongPtr(editctl2, (int)-4 , (LONG_PTR)Edit2SubclassProc); 
		if (0 == wpOrigEdit2Proc)
			MessageBox(hMainWnd, "Error of a reset WNDPROC for Edit2.", TEXT(""), 0);
		
	///////////////// COMBOBOX  //////////////////////////////////////
	
hWnd_ComboBox_pub = CreateWindow ("combobox",NULL,
		 WS_CHILD | WS_VISIBLE | WS_VSCROLL | CBS_AUTOHSCROLL | CBS_DROPDOWNLIST | CBS_DISABLENOSCROLL,
         640, 30, 400, 210, hMainWnd,(HMENU) id_ComboBox_pub, hInst, NULL);
	
		
   
		updKeyList(&numPubKeys, sizeof(struct infoKey), &arrInfoKey, str);
		
		
		
	//////////////////  STATIC /////////////////////////////
	hWnd_Text1 = CreateWindow("STATIC", "- - - -", WS_VISIBLE | WS_CHILD | SS_CENTER,
								150, 30, 60,30,
								hMainWnd, NULL, hInst, NULL);

		loadPassPhrase(&passw);
	
	
	
	
	ShowWindow(hMainWnd, nCmdShow); // отображаем окно
    UpdateWindow(hMainWnd); // обновляем окно
    while(GetMessage(&msg, NULL, 0, 0)){ // извлекаем сообщения из очереди, посылаемые фу-циями, ОС
        TranslateMessage(&msg); // интерпретируем сообщения
        DispatchMessage(&msg); // передааём сообщения обратно ОС
    }
    return msg.wParam; // возвращаем код выхода из приложения
}
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
    //HDC hDC; // создааём дескриптор ориентации текста на экране
    //PAINTSTRUCT ps; // структура, сод-щая информацию о клиентской области (размеры, цвет и тп)
    //RECT rect; // стр-ра, определяющая размер клиентской области
    //COLORREF colorText = RGB(255, 0, 0); // задааём цвет текста
	
	int resB64;
	static int i;
	
	switch(uMsg){
		
	case WM_CREATE:
			 // при этом событии(WM_CREATE) остальных элементов ещё не сущестует и следовательно все их дескрипторы = 0
			 		
		
	break;
	///////////////////////////////////////////
	case WM_INITDIALOG: ; //This is an empty statement.
			
		
	break;
		
	case WM_COMMAND:
    if (LOWORD(wParam) == id_button2)   //  encrypt
	{	
	
		//+++1. Копирование текста из editctl в файл
		//+++2. запуск gpg. Шифрование сообщения
		//+++3. кодирование полученного шифрованого текста в Base64
		//+++4. копирование текста base64 в editctl2
		//+++5. удаляем созданные файлы
		//6. добавить кнопку для удаления текста в editctl.
			
			if ( currSel == -1 ){
					MessageBox(hMainWnd, "Select one public key.", TEXT(""), 0);
					break;
			}
			
			if ( copyTextToFile( editctl, "out.txt") == 1)
				break;
			
			
		/*  2. запуск gpg. Шифрование сообщения
			system() ожидает завершения
			(по умолчанию) запуск основного приложения должен быть под тем же пользователем , под которым создавались ключи
			так как они лежат в каталоге пользователя типа этого C:\Users\User\AppData\Roaming\gnupg\     */
			
//  можно добавить --throw-keyids  - Do not put the recipient key IDs into encrypted messages
			sprintf(str, "gpg.exe --yes --output outEnc.txt --recipient %s --encrypt out.txt", arrInfoKey[currSel].fpr);


			system(str);
				
			// 3.кодирование полученного шифрованого текста в Base64 
			resB64 = encodeToBase64("outEnc.txt", "outB64.txt");
			if (resB64 == 1 ){
				MessageBox(hWnd, "Cannot open incoming file.", TEXT(""), 0);
				break;
			}else if (resB64 == 2 ){
				MessageBox(hWnd, "Cannot open outcoming file.", TEXT(""), 0);
				break;
			}
			
			// 4. копирование текста base64 из файла в editctl2
			if ( copyTextToControl( editctl2, "outB64.txt") != 0)
				break;
			
			//5. удаляем созданные файлы
			if ( deleteFiles( "out.txt", "outEnc.txt", "outB64.txt") == 1)
				MessageBox(hWnd, "Error removing of one or some files.", TEXT(""), 0);
		
		
	} //  encrypt-button click END
	  //  decrypt-button click
	else if (LOWORD(wParam) == id_buttonDecrypt){    
		//+++1. Копирование зашифрованного текста из editctl2 в файл
		//+++2. декодирование текста. Снимаю Base64
		//+++3. запуск gpg. Расшифровка сообщения
		//+++4. копирование расшифрованного текста из файла в editctl
		//+++5. удаляем созданные файлы
		//6. добавить кнопку для удаления текста в editctl2.
	
		if ( copyTextToFile( editctl2, "in.txt" ) == 1)
			break;
			
		// 2.декодирование текста. Снимаю Base64
			resB64 = decodeBase64("in.txt", "inEnc.txt");
			if (resB64 == 1 ){
				MessageBox(hWnd, "Cannot open incoming file.", TEXT(""), 0);
				break;
			}else if (resB64 == 2 ){
				MessageBox(hWnd, "Cannot open outcoming file.", TEXT(""), 0);
				break;
			}
			
		//3. запуск gpg. Расшифровка сообщения
		
		//Парольная фраза для разблокировки приватного ключа вводится один раз и
		//хранится до конца сеанса.
		// при выполнении команды --decrypt запускается GnuPG's private key daemon
		// --recipient и --default-key здесь не актуальны
		
		// если "gpg.exe --pinentry-mode loopback --passphrase pw" пароль неправильный, то
		// команда не выполняется и ничего не выведется.
		
		// Если при шифровании используется --throw-keyids, то при расшифровке перебираются приватные ключи,
		// находится нужный, запрашивается пароль.
		
		// заметил. У меня было два ключа (две пары) с полностью одинаковы id и паролем.
		// Зашифровал сообщение одним ключом, указав Отпечаток (отпечатки то разные).
		// При расшифровке ввел пароль.
		// Зашифровал сообщение вторым ключом. А при расшифровке пароль не потребовался.
		// Но ключ-то другой (id такой же). (?)
		
	if ( passw != NULL ){
		sprintf(str, "gpg.exe --pinentry-mode loopback --passphrase \"%s\" --yes --output inDec.txt --decrypt inEnc.txt", passw);
		system(str);
	}	
		else
			system("gpg.exe --yes --output inDec.txt --decrypt inEnc.txt");
			
		
		//4. копирование расшифрованного текста из файла в editctl
		if ( copyTextToControl( editctl, "inDec.txt") != 0)
				break;
		
		//5. удаляем созданные файлы
		if ( deleteFiles( "in.txt", "inEnc.txt", "inDec.txt" ) == 1)
				MessageBox(hWnd, "Error removing of one or some files.", TEXT(""), 0);
			
	} //  decrypt-button click END
	  //  export-button click START
	else if (LOWORD(wParam) == id_expPubKey){   //  export public key
		
		//1. вывод ключа в файл
		//2. копирование ключа из файла в editctl
		//3. удаление файла
		
		//1. вывод ключа
		//   ключ выводится в файл в ASCII формате.
		
		if ( currSel == -1 ){
					MessageBox(hMainWnd, "Select one public key.", TEXT(""), 0);
					break;
		}
			
		sprintf(str, "gpg.exe --armor --output pubKey.txt --yes --export %s", arrInfoKey[currSel].fpr);
		system(str);
		
		//2. копирование ключа из файла в editctl
		int r1;
		if ( (r1 = copyTextToControl( editctl, "pubKey.txt") ) != 0){
			if( r1 == 1)
				MessageBox(hWnd, "Is you using correct email(id)?", TEXT(""), 0);
			break;
		}
				
		//3. удаление файла
		if ( deleteFiles( "pubKey.txt", NULL, NULL ) == 1)
				MessageBox(hWnd, "Error removing of one or some files.", TEXT(""), 0);
		
		
	}
	else if (LOWORD(wParam) == id_impPubKey){ // Import public key
		
		// при импорте ключа добавляется также суб ключ
		
		// +++1. Копирую ключ из верхнего текстового поля в файл
		// +++2. запуск коменды импорта
		// +++3. удалить файл
		if ( copyTextToFile( editctl, "pubKeyI.txt" ) == 1)
			break;
		
		system("gpg.exe --import pubKeyI.txt");
		
		if ( deleteFiles( "pubKeyI.txt", NULL, NULL ) == 1)
				MessageBox(hWnd, "Error removing the file.", TEXT(""), 0);

		updKeyList(&numPubKeys, sizeof(struct infoKey), &arrInfoKey, str);
		
	}
	else if (LOWORD(wParam) == id_signPubKey){ // Sign public key
		
		// не подписанным ключом можно шифровать сообщения,
		// но каждый раз gpg будет задавать дополнительный вопрос.
		
		//+++1. Запуск последовательности операций "sign trust save"" для подписи ключа,
		// установки значения доверия владельца, и сохранение.

		// будет диалог со вводом парольной фразы (выбор приватного ключа по умолчанию)
		//system("gpg.exe --yes --edit-key id sign");
		
		if ( currSel == -1 ){
				MessageBox(hMainWnd, "Select one public key.", TEXT(""), 0);
				break;
		}
		
		// без показа окна pinentry. Но парольная фраза для конкретного ключа и будет
		// использоваться для того ключа, который выбран по умолчанию.
		//system("gpg.exe --pinentry-mode loopback --passphrase \"rE6ds18R\" --yes --edit-key keyId sign trust save");
		
		//для этой команды можно использовать --default-key . 
		//Тогда подписываться импортированный ключ будет указанным приватным ключом.
		
		//gpg использует ключ по умолчанию, откроется окно Pinentry для ввода парольной фразы или
		//если пароль прочитан из файла, то он будет
		//использован без открытия Pinentry.
		
		if ( passw != NULL ){
			sprintf(str, "gpg.exe --pinentry-mode loopback --passphrase \"%s\" --yes --edit-key %s sign trust save",
					passw, arrInfoKey[currSel].fpr);
			
		}	
		else
			sprintf(str, "gpg.exe --yes --edit-key %s sign trust save", arrInfoKey[currSel].fpr);
		
		system(str);
		
		// при этом текстовый диалог останется.
		//y
		//5
		//y
		
	}
	//редактирование списка синонимов
	else if ( LOWORD(wParam) == id_synonym1 ) {
		
		if ( arrInfoKey == NULL )
			break;
		
		slen = 0;
		for (i = 0; i < numPubKeys; i++){
			slen += strlen(arrInfoKey[i].fpr);
			slen += strlen(arrInfoKey[i].uid);
			slen += strlen(arrInfoKey[i].synonym);
		}
		slen += numPubKeys * 6; // 2 - <>; 2 - 1310; 2 - ' '
		
		synR = (char *) malloc( slen + 1 );
		if ( synR == NULL){
			MessageBox(hMainWnd, "err of malloc()", TEXT(""), 0);
			break;
		}
		synR[slen] = '\0';
		
		synRc = synR;
		
		for (i = 0; i < numPubKeys; i++){
			sprintf(str, "<%s> %s %s\xD\xA", arrInfoKey[i].uid, arrInfoKey[i].fpr, arrInfoKey[i].synonym);
			slen = strlen(str);
			strncpy(synRc, str, slen);
			synRc += slen;
		}
		
		SetWindowText(editctl, synR);
		
		free(synR);
		synR = NULL;
		synRc = NULL;
	}
	// сохранение списка синонимов
	else if ( LOWORD(wParam) == id_synonym2 ) {
		
		if ( copyTextToFile( editctl, "synonyms.txt" ) == 1)
			break;
		
		SetWindowText(editctl, "");
		
		updKeyList(&numPubKeys, sizeof(struct infoKey), &arrInfoKey, str);
	}
	// запуск генерирования ключей
	else if ( LOWORD(wParam) == id_genKey ) {
		
		system("gpg.exe --full-generate-key");
		
		updKeyList(&numPubKeys, sizeof(struct infoKey), &arrInfoKey, str);
	}
	// запуск удаления приватного ключа
	else if ( LOWORD(wParam) == id_delPrivateKey ) {
		
		if ( currSel == -1 ){
				MessageBox(hMainWnd, "Select one public key.", TEXT(""), 0);
				break;
		}
		
		sprintf(str, "gpg.exe --delete-secret-key %s", arrInfoKey[currSel].fpr);
		system(str);
		
		updKeyList(&numPubKeys, sizeof(struct infoKey), &arrInfoKey, str);
		
	}
	// запуск удаления публичного ключа
	else if ( LOWORD(wParam) == id_delPublicKey ) {
		
		if ( currSel == -1 ){
				MessageBox(hMainWnd, "Select one public key.", TEXT(""), 0);
				break;
		}
		
		sprintf(str, "gpg.exe --delete-key %s", arrInfoKey[currSel].fpr);
		system(str);
		
		updKeyList(&numPubKeys, sizeof(struct infoKey), &arrInfoKey, str);
	}
	// изменение выбранного элемента в combobox
	else if ( LOWORD(wParam) == id_ComboBox_pub ) {
		
			if ( HIWORD(wParam) == CBN_SELCHANGE ){
				if ( ( currSel = SendMessage(hWnd_ComboBox_pub, CB_GETCURSEL, 0, 0 ) ) == CB_ERR )
					currSel = -1;
			}
		
		
	}
	
	
	break;
	
	
	case WM_SIZE:     // Sent to a window after its size has changed
          
        sx = LOWORD(lParam); //ширина клиентской области
        sy = HIWORD(lParam); //высота
				
		//sprintf(sizeCL, "size. w = %d, h = %d", sx, sy);
		//MessageBox(hWnd, sizeCL, TEXT(""), 0);
		SetWindowPos(editctl, (HWND)NULL, 10, 70, sx- 20, sy/2 - 80, 0);
		SetWindowPos(editctl2, (HWND)NULL, 10, sy/2 + 40, sx- 20, sy/2-50, 0);
		SetWindowPos(hWnd_buttonDecrypt, (HWND)NULL, 10, sy/2, 130, 30, 0);
		SetWindowPos(hWnd_Text1, (HWND)NULL, 150, sy/2, 60, 30, 0);
		
    break;
	
    /*case WM_PAINT: // если нужно нарисовать, то:
        hDC = BeginPaint(hWnd, &ps); // инициализируем контекст устройства
        GetClientRect(hWnd, &rect); // получаем ширину и высоту области для рисования
        SetTextColor(hDC, colorText); // устанавливаем цвет контекстного устройства
        DrawText(hDC, mainMessage, -1, &rect, DT_SINGLELINE|DT_CENTER|DT_VCENTER); // рисуем текст
        EndPaint(hWnd, &ps); // заканчиваем рисовать
        break;
	*/
    case WM_DESTROY: // если окно закрылось, то:
		SetWindowLongPtr(editctl, (int)-4, (LONG_PTR)wpOrigEditProc);  // GWL_WNDPROC = -4
		SetWindowLongPtr(editctl2, (int)-4, (LONG_PTR)wpOrigEdit2Proc);  // GWL_WNDPROC = -4
		
		if ( arrInfoKey != NULL )
			free(arrInfoKey);
		if ( passw == NULL )
			free(passw);
		
        PostQuitMessage(0); // отправляем WinMain() сообщение WM_QUIT
        break;
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam); // если закрыли окно
    }
    return 0; // возвращаем значение
}


// Edit's WinProc
LRESULT APIENTRY EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    switch(uMsg){
		
	case WM_CREATE:
			 
			 
	break;
	///////////////////////////////////////////
	case WM_KEYDOWN:
			
		
		if (GetKeyState(VK_CONTROL) & 0x8000 && wParam == 'A') {
            SendMessage(hwnd, EM_SETSEL, 0, -1);
			//MessageBox(hwnd, "test 11111.", TEXT(""), 0);
        }
		
	break;
		
	case WM_COMMAND:
		
	break;
	}
	
 
    return CallWindowProc(wpOrigEditProc, hwnd, uMsg, wParam, lParam); 
} 

// Edit2's WinProc
LRESULT APIENTRY Edit2SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    switch(uMsg){
		
	case WM_CREATE:
			 
			 
	
	break;
	///////////////////////////////////////////
	case WM_KEYDOWN:
			
		
		if (GetKeyState(VK_CONTROL) & 0x8000 && wParam == 'A')
            SendMessage(hwnd, EM_SETSEL, 0, -1);
			//MessageBox(hwnd, "test 11111.", TEXT(""), 0);
		
	break;
		
	case WM_COMMAND:
		
	break;
	}
	
 
    return CallWindowProc(wpOrigEdit2Proc, hwnd, uMsg, wParam, lParam); 
} 

int encodeToBase64(char * inF, char * outB64F){
	
	static char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	 int i;
	 char line[100];
	 char lineRes[133];
	 char * p;
	 
	 FILE * in = fopen(inF, "rb");
	 int numread;
	 
	 if (in == NULL)
		 return 1;
	 
	 FILE * out = fopen(outB64F, "wb");
	 if (out == NULL) 
		 return 2;
		
	while ((numread = fread(line, sizeof(char), 99, in)) != 0) {
		p = lineRes;
		
		for (i = 0; numread > i; i = i + 3) {
			if ( (numread - i) > 2){
				*p++ = b64[(line[i] >> 2) & 0x3F];  // & 0x3F
				*p++ = b64[((line[i] & 0x3) << 4) | ((int) (line[i + 1] & 0xF0) >> 4)];
				*p++ = b64[((line[i + 1] & 0xF) << 2) | ((int) (line[i + 2] & 0xC0) >> 6)];  // & 0xC0
				*p++ = b64[line[i + 2] & 0x3F];
				
			}else if ( (numread - i) == 2){
				*p++ = b64[(line[i] >> 2) & 0x3F];  // & 0x3F
				*p++ = b64[((line[i] & 0x3) << 4) | ((int) (line[i + 1] & 0xF0) >> 4)];
				*p++ = b64[(line[i + 1] & 0xF) << 2]; // на 2 тоже сдвигаем(там всегда 00)
				*p++ = '=';
				
			}else { // = 1
				*p++ = b64[(line[i] >> 2) & 0x3F];
				*p++ = b64[ ((line[i] & 0x3) << 4) ];
				*p++ = '=';
				*p++ = '=';
			}
		}
		
		fwrite(lineRes, sizeof(char), p - lineRes, out);
		
	 }
	 
	 fclose(out);
	 fclose(in);
	 
	return 0;
}

int decodeBase64(char * inF, char * outT){
	
	char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	char errS[] = " conversion error!";
	
	 int i, err = 0, end = 0;
	 char line[100];
	 char lineRes[75];
	 char * p, * fch;
	 
	 FILE * in = fopen(inF, "rb");
	 if (in == NULL) 
		 return 1;
	 
	 FILE * out = fopen(outT, "wb");
	 int numread;
	 
	 if (out == NULL) 
		 return 2;
		
	while ((numread = fread(line, sizeof(char), 100, in)) != 0) {
		p = lineRes;
		
		for (i = 0; numread > i; i = i + 4) {
			
			fch = strchr(b64, (int)line[i]);
			if (fch != NULL){

				*p = (char)(fch - b64) << 2;
			}else{
				err = 1; 
				break;
			}
			
			fch = strchr(b64, (int)line[i + 1]);
			if (fch != NULL){
				
				*p = *p | (((char)(fch - b64) & 0x30) >> 4);
				*(p+1) = ((char)(fch - b64) << 4);
			}else{
				err = 1; 
				break;
			}
			
			fch = strchr(b64, (int)line[i + 2]);
			if (fch != NULL){
				*(p + 1) = *(p + 1) | ((char)(fch - b64) >> 2);
				*(p + 2) = (char)(fch - b64) << 6;
			}else{
				
				if ((char)line[i + 2] == '='){
					p = p + 1;
					end = 1;
					break;
				}else{
					err = 1; 
					break;
				}
			}
			
			fch = strchr(b64, (int)line[i + 3]);
			if (fch != NULL){
				*(p + 2) = *(p + 2) | (char)(fch - b64);
			}else{
				if ((char)line[i + 3] == '='){
					p = p + 2;
					end = 1;
					break;
				}else{
					err = 1; 
					break;
				}
			}
			
			p = p + 3;
			
		}
		
		if (err == 0){
			fwrite(lineRes, sizeof(char), p - lineRes, out);
			
			if(end == 1)
				break;
			
		}else {
			 if ( (int)(p - lineRes) > 0 )
				fwrite(lineRes, sizeof(char), p - lineRes, out);
			
			fwrite(errS, sizeof(char), 18, out);
			break;
		}
	 }
	 
	 fclose(in); 
	 fclose(out);
	
	return 0;
}	
	
int copyTextToFile( HWND id, char * fname){
	
	int lenFact, len1;
	FILE * out;
	char * txt;
	
	len1 = GetWindowTextLength(id);   //символов без \0
	if (len1 == 0){
		MessageBox(hMainWnd, "Edit control is empty.", TEXT(""), 0);
		return 1;
	}	
	
	txt = malloc( (len1 + 1) * sizeof(char) );  
	GetWindowText(id, txt, len1+1); //sizeof(txt));    // +1   - для \0
	
	//MessageBox(hMainWnd, txt, TEXT(""), 0);  //показывает сообщение, копируемое в файл
	
	// GetWindowText даёт текст с \13\10 . если открыть файл в текстовом режиме ("w"), то 
	// при записи символ '\10' заменяется функциями Си на \13\10 и превращается в \13\13\10
	out = fopen(fname, "wb");  
	
	if (out == NULL) {
		MessageBox(hMainWnd, "Error opening file.", TEXT(""), 0);
		return 1;
	} 
	
	lenFact = fwrite(txt, len1, 1, out);  // вывод исходного сообщения в файл
	fclose(out); 
	free(txt);
	txt = NULL;
	
	if (lenFact == 0){
		MessageBox(hMainWnd, "Data were not wrote to file.", TEXT(""), 0);
		//break;
		return 1;
	}
	
	return 0;
}

int copyTextToControl(  HWND id, char * fname ){
	FILE * out;
	long sz;
	char * txt;
	int lenFact;
	
		// размер получившегося файла
		out = fopen(fname, "rb"); 
		if (out == NULL) {
			MessageBox(hMainWnd, "Error opening file.", TEXT(""), 0);
			return 1;
		} 	
		fseek(out, 0L, SEEK_END);
		sz = ftell(out);
		rewind(out);
		if (-1L == sz ){
			MessageBox(hMainWnd, "Error getting size of file.", TEXT(""), 0);
			fclose(out);
			return 2;
		}
			//чтение данных
		
		txt = malloc( (sz + 1) * sizeof(char) );
		if ( (lenFact = fread(txt, sz, 1, out)) == 0 ){
			MessageBox(hMainWnd, "Error reading file.", TEXT(""), 0);
			fclose(out);
			free(txt);
			return 3;
		}
		txt[sz] = '\0';
		
		fclose(out);
		
		SetWindowText(id, txt);   // typedef const char* LPCSTR;
		
		free(txt);
		txt = NULL;
	return 0;
}

int deleteFiles( char * f1, char * f2, char * f3){
	
	int fdel = 0;
	
	if ( f1 != NULL )
		if ( remove(f1) != 0 ){
			fdel = 1;
		}
	if ( f2 != NULL )
		if ( remove(f2) != 0 ){
			fdel = 1;
		}
	if ( f3 != NULL )	
		if ( remove(f3) != 0 ){
			fdel = 1;
		}
	
	return fdel;
}

		// --keyid-format long  не обязательно
		// --list-public-keys  - выводит информацию в удобном для человека виде
		// --with-colons --list-public-keys  - выводит ту же инфу для парсинга. 
		//   но есть отличие здесь выводится отпечаток ещё и для субключа
		
		// ФОРМАТ вывода --with-colons ТУТ https://github.com/gpg/gnupg/blob/master/doc/DETAILS
		// https://wiki.debian.org/Subkeys
	//заполнение массива информацией о ключах по списку публичных ключей. Дополнение по списку приватных. Синоним
int fillKeyList(int * numPubKeys, size_t sz, struct infoKey ** arrInfoKey){
	
	FILE * fKeys;
	char line[250];
	int pubSec = 0, currN = -1, x = 0;
	
	//освобождение памяти и очистка списка перед заполнением
	if ( *arrInfoKey != NULL ){
		free(*arrInfoKey);
		*arrInfoKey = NULL;
		SendMessage(hWnd_ComboBox_pub, CB_RESETCONTENT, 0, 0 );
	}
		
	
	system("gpg.exe --with-colons --list-public-keys > listPub.txt");
	
	//заполнение массива информацией о ключах по списку публичных ключей.
	fKeys = fopen("listPub.txt", "r"); 
	if (fKeys == NULL) {
		MessageBox(hMainWnd, "Error opening file listPub.txt.", TEXT(""), 0);
		return 1;
	}
	
	*numPubKeys = 0;
	while ( fgets(line, 250, fKeys) != NULL ){
		if ( strncmp(line, "pub", 3) != 0 )
			continue;
		
		(*numPubKeys)++; 
	}
	
	if ( *numPubKeys == 0 ){
		fclose(fKeys);
		return 0;
	}
		
	rewind(fKeys);

	
	*arrInfoKey = (struct infoKey *) malloc( *numPubKeys * sz );
	if ( arrInfoKey == NULL){
		fclose(fKeys);
		MessageBox(hMainWnd, "err of malloc()", TEXT(""), 0);
		return 1;
	}
	while ( fgets(line, 250, fKeys) != NULL ){
		if (pubSec == 0){
			if ( strncmp(line, "pub", 3) == 0 ){
				pubSec = 1;
				currN++;
			}
		}else if ( pubSec == 1){
			if ( strncmp(line, "fpr", 3) == 0 ){
				pubSec = 2;
				getField(10, line, (*arrInfoKey)[currN].fpr , fprML);
				(*arrInfoKey)[currN].withoutPrivate = 1;
				(*arrInfoKey)[currN].synonym[0] = '\0';
			}
		}else{ // pubSec == 2
			if ( strncmp(line, "uid", 3) == 0 ){
				pubSec = 0;
				getField(10, line, (*arrInfoKey)[currN].uid , uidML);						
			}
		}	
	}
	
	fclose(fKeys);
	
	system("gpg.exe --with-colons --list-secret-keys > listPriv.txt");
	
	//Дополнение по списку приватных. Если в списке приватных ключей нет отпечатка публичного ключа, то
	//считаю, что этот ключ был импортирован. Помечаю его символом +.
	fKeys = fopen("listPriv.txt", "r"); 
	if (fKeys == NULL) {
		MessageBox(hMainWnd, "Error opening file listPriv.txt.", TEXT(""), 0);
		return 1;
	} 
	pubSec = 0;
	
	while ( fgets(line, 250, fKeys) != NULL ){
		if (pubSec == 0){
			if ( strncmp(line, "sec", 3) == 0 )
				pubSec = 1;
				
			
		}else {  // if ( pubSec == 1)
			if ( strncmp(line, "fpr", 3) == 0 ){
				pubSec = 0;
				
				for ( currN = 0; currN < *numPubKeys; currN++){
					if ( (*arrInfoKey)[currN].withoutPrivate == 0)
						continue;
					if ( strstr(line, (*arrInfoKey)[currN].fpr) != NULL){
						(*arrInfoKey)[currN].withoutPrivate = 0;
						x++;
						break;
					}
				}
				
				if ( x == *numPubKeys )  //когда все отпечатки найдены, а приватных ключей ещё много
					break;
			}
		}	
	}
	
	
	fclose(fKeys);
	
	if ( deleteFiles( "listPub.txt", "listPriv.txt", NULL ) == 1)
				MessageBox(hMainWnd, "Error removing of one or some files.", TEXT(""), 0);
			
	//добавляем синонимы
	fKeys = fopen("synonyms.txt", "r"); 
	if (fKeys == NULL)
		return 0; 
	
	while ( fgets(line, 250, fKeys) != NULL ){
		currN = 0;
		for (x = 0; x < 250; x++){
			if ( line[x] == '\n' ){
				line[x] = '\0';
				break;
			}
		
			if ( currN <= 2 && line[x] == '>' ){ //ищу конец id
				currN++;
				pubSec = x;
			}
		}
		
		if (currN < 2 )
			continue;
		
		pubSec += 2; // начало fingerprint
		
		for ( currN = 0; currN < *numPubKeys; currN++){
			
			if ( strncmp(line + pubSec, (*arrInfoKey)[currN].fpr, fprML) == 0){
				
				strcpy( (*arrInfoKey)[currN].synonym, line + pubSec + fprML + 1);
				
				break;
			}
		}
		
	}
		
	fclose(fKeys);
			
	return 0;
}

void getField(int nfield, const char * source, char * target , int maxLen){
	
	int i, cn = 0, start = -1, end = 0, lfact;
	
	for( i = 0; i < strlen(source); i++){
		if( source[i] == ':')
			cn++;
		if ( start == -1 && cn == nfield-1 )   //fix me
			start = i+1;
		if ( cn == nfield ){
			end = i;
			break;
		}
	}
	
	if (start == -1) // nfield == 1
		start = 0;
	
	lfact = end - start;
	
	if ( lfact > maxLen ){
		MessageBox(hMainWnd, "The actual length of the key field is greater than maxLen.", TEXT("The string was cut off."), 0);
		lfact = maxLen;
	}

	strncpy(target, source + start, lfact);
	target[lfact] = '\0';
}

void updKeyList(int * numPubKeys, size_t sz, struct infoKey ** arrInfoKey, char * str){
	
	int i;
		
	fillKeyList(numPubKeys, sz, arrInfoKey);  // заполнение массива
	
	currSel = -1;
	
	if ( *arrInfoKey != NULL ){
		for (i = 0; i < *numPubKeys; i++){   //заполнение combobox из этого массива
		
			//sprintf(str, "%c %s - %s", ( (*arrInfoKey)[i].withoutPrivate ) ? '-' : '+',
			//				(*arrInfoKey)[i].uid, (*arrInfoKey)[i].fpr );
			
			sprintf(str, "%c %s", ( (*arrInfoKey)[i].withoutPrivate ) ? '-' : '+',
			( (*arrInfoKey)[i].synonym[0] == '\0' ) ? (*arrInfoKey)[i].uid : (*arrInfoKey)[i].synonym );
							
			//if ( SendMessage(hWnd_ComboBox_pub, CB_ADDSTRING, 0, (int ) str ) == CB_ERR )    // 32-bit
			if ( SendMessage(hWnd_ComboBox_pub, CB_ADDSTRING, 0, (long long ) str ) == CB_ERR ) //64-bit
				MessageBox(hMainWnd, "err CB_ERR CB_ADDSTRING", TEXT(""), 0);
		}
		
		if ( *numPubKeys == 1 )
			currSel = SendMessage(hWnd_ComboBox_pub, CB_SETCURSEL, 0, 0);
			
	}else{
		MessageBox(hMainWnd, "There is not available keys.", TEXT(""), 0);
	}
}

void loadPassPhrase(char ** passw){
	
	FILE * fp;
	char line[151];
	int i = 0;
	
	fp = fopen("passphrase.txt", "r"); 
	if (fp == NULL) {
		return;
	}
	
	if ( fgets(line, 151, fp) == NULL ){
		fclose(fp);
		return;
	}
	//delete \n if it is in the line.
	while ( line[i] != '\0' ){
		if( line[i] == '\n' ){
			line[i] =  '\0';  // optionally
			break;
		}
		i++;
	}
	
	*passw = (char *) malloc( i + 1 );
	strncpy(*passw, line, i);
	(*passw)[i] = '\0';
	
	fclose(fp);
	
	SetWindowText(hWnd_Text1, "********"); 
	
}

// материалы
// https://docs.microsoft.com/en-us/windows/win32/controls/edit-control-styles
// Window Class Styles  https://docs.microsoft.com/en-us/windows/win32/winmsg/window-class-styles
// Window Styles        https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles
// EM_SETSEL message  https://docs.microsoft.com/en-us/windows/win32/controls/em-setsel        
// вариант https://stackoverflow.com/questions/10127054/select-all-text-in-edit-contol-by-clicking-ctrla
// https://docs.microsoft.com/ru-ru/windows/win32/winmsg/using-window-procedures
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowlonga
// https://unix.stackexchange.com/questions/60213/gpg-asks-for-password-even-with-passphrase
// https://www.gnupg.org/gph/en/manual/x56.html
// http://www.cyberforum.ru/win-api/thread630959.html  - создание меню
// http://www.cyberforum.ru/win-api/thread1844562.html  - подключение меню из ресурсов
// https://habr.com/ru/post/358182/

> 70

Комментарии




information