
#ifndef CryptH
#define CryptH

//-----------------------------------------------------------------------------
#include <windows.h>
#include <wincrypt.h>

#include "Strings.h"


//*********************************************************
//  GetUIDPassword
//  Функция возвращает пароль сгенерированныйна основе UID
//  Пароль будет одинаков для всех процессов и запусков
//  на данной машине, но уникальный для каждой машины
//*********************************************************
PCHAR GetUIDPassword();




//****************************************************************************
//  BASE64 - Методы кодирования/декодирования BASE64
//****************************************************************************

namespace BASE64
{
	// Зашифровать данные в строку формата BASE64
	PCHAR Encode(LPBYTE Buf, DWORD BufSize);

	// Раcшифровать данные из формата BASE64
	// Размер итогового буфера можно узнать функцией STR::Length,
	// Либо передать указатель на переменную, куда его записатиь
	// Результат уничтожить функцией STR::Free()
	PCHAR Decode(PCHAR Buf, DWORD *ResultSize = NULL);
}



// Метод криптования
typedef bool (*TCryptMethod)(LPVOID Key, LPBYTE Buffer, DWORD BufferSize, PDWORD ResultBufferSize);


//****************************************************************************
//  Методы для шифрования XOR алгоритмом
//  Шифрование и расшифровка выполняются одними и теме-же методами
//****************************************************************************
namespace XORCrypt
{
	// Шифрование XOR алгоритмом
	DWORD Crypt(PCHAR Password, LPBYTE Buffer, DWORD Size);

	// Для соответствия TCryptMethod
	bool Crypt(LPVOID Password, LPBYTE Buffer, DWORD Size, PDWORD OutSize);


	//----------------------------------------------------------------
	//   DecodeBuffer - Функция декодирует буфер содержащий в себе
	//                   пароль
	//   Формат буфера
	//   [Сигнатура](DWORD Размер пароля)(Пароль)(Данные)
	//
	//
	//  Signature - Сигнатура буфера. NULL если отсутствует
	//
	//  Buffer - Буфер зашифрованных данных
	//
	//   Size - Размер буфера. После работы функции будет содержать
	//			размер расшифрованных данных
	//
	//  Результат - Функция возвращает указатель на первый символ
	//              декодированного буфера.
	//  Память под результат НЕ выделяется!
	//----------------------------------------------------------------
	LPBYTE DecodeBuffer(PCHAR Signature, LPVOID Buffer, DWORD &Size);

	//---------------------------------------------------------
	//  EncodeString  Функция кодирует строку. Максимальный
	//                размер строки 255 байт
	//  Фактически длина строки должна равняться длине исходной
	//  строки. т.к вместо закрывающего нуля мы смещаем строку
	//  на один байт и первым байтом записываем размер
	//  исходной строки. Но для удобства размер результирующей
	//  строки удет на один байт больше!!!!
	//---------------------------------------------------------
	string EncodeString(const char* Password, const char* Str);

	//---------------------------------------------------------
	//  DecodeString Функция дешифрует строку , что была
	// зашифрована функцией EncodeString
	//---------------------------------------------------------
	string DecodeString(const char* Password, const char* Str);
}


//****************************************************************************
//  Методы для шифрования методами WIN Crypt
//  буфер собран по следующему алгоритму (Б - байт):
//
//  (4Б перваля половина IV)(BASE64 данные)(4Б вторая половина IV)(окончание BASE64 ==)
//
//****************************************************************************


//  Рекомендуемый размер пароля для алгоритма RC2
#define RC2_DEFAULT_PASSWORD_SIZE 16


namespace RC2Crypt
{
	// Функция извлекает вектор инициализации ключа из буфера
	PCHAR ExtractIV(PCHAR Buf, DWORD StrLen);

	// Генерировать случайный вектор
	PCHAR GenerateIV();

	// кодировать буфер
    PCHAR Encode(LPBYTE Buf, DWORD BufSize,  PCHAR Password);

	// Декодировать буфер
	// на входе строка BASE64 символов с вшитым в них ыектором IV
	// BufSize - Размер передаваемого буфера.
	// Если содержит нулевое значение, то размер буфера
	// будет просчитан до нулевого символа.
	// После отработки метода BufSize будет указывать на размер
	// расшифрованного буфера
	bool Decode(PCHAR Password, PCHAR Buf, DWORD &BufSize);

	// Функция декодирует строку и возвращает её размер
    bool DecodeStr(PCHAR Password, PCHAR Str, DWORD &Size);

	// Шифровать буфер используя Win Crypto API
    // Функция выделяет необходимый объём памяти методом MemAlloc()
	LPBYTE WinEncode(LPBYTE Buf, DWORD &BufSize, PCHAR Password, PCHAR IV);

	// Декодировать буфер используя Win Crypto API
	PCHAR WinDecode(PCHAR Buf, DWORD &BufSize, PCHAR Password, PCHAR IV);

	// Генерировать ключ криптования на основе пароля и вектора инициализации IV
	bool GenerateKey(PCHAR Password, PCHAR IV, HCRYPTPROV &Provider, HCRYPTKEY &Key);


    PCHAR CryptByUID(LPVOID Buffer );
}


//****************************************************************************
//  Методы для шифрования данных файлов
//****************************************************************************
namespace CryptFile
{
	//----------------------------------------------------------
	//  WriteFromBuffer
	//  Функция зашифровывает содержимое
	//  буфера и записывает его в буфер
	//----------------------------------------------------------
	bool WriteFromBuffer(PCHAR FileName, LPVOID Buffer, DWORD BufferSize);

	//----------------------------------------------------------
	//  ReadToBuffer
	//  Функция читает содержимое файла,
	//	расшифровывает его и возвращает указатель
	//----------------------------------------------------------
    LPVOID ReadToBuffer(PCHAR FileName, LPDWORD BufferSize);
}


//****************************************************************************
//  Методы для шифрования данных идентификатором бота (UID) вместо пароля
//  Шифрование производится методами  RC2Crypt
//
//  Специфика данного шифрования в том, что данные всегда одинаковы на
//  одном компьютере, но отличаться от данных на других компьютерах
//****************************************************************************
namespace UIDCrypt
{
	//------------------------------------------------------------------
	//  Функция шифруем данные ключём бота
	//
	//  Data - Данные необходимые зашифровать
	//
	//  DataSize - Размер данных
	//
	//  Vector - Дополнительный вектор шифрования. Если не указать то
	//			 будет использован стандартный вектор
	//------------------------------------------------------------------
	PCHAR Crypt(LPVOID Data, DWORD DataSize, PCHAR Vector);

	//------------------------------------------------------------------
	//  CryptFileName - Функция криптует имя файла делая его уникальным
	//				    для данного компьютера. Путь к файлу не
	//					шифруется
	//
	//  FileName - Исходное имя файла
	//
	//  CryptExt - Признак необходимости шифровать расширение файла
	//------------------------------------------------------------------
	PCHAR CryptFileName(const char* FileName, bool CryptExt);

	//------------------------------------------------------------------
	// ConvertFileNameChars - Функция преобразует недопустимые символы
	//                        имени файла полученного путём шифрования
	//------------------------------------------------------------------
    void ConvertFileNameChars(PCHAR Name);
}



//*********************************************************************
//  Базовый класс для шифрования используя CryptoApi
//*********************************************************************
class TWinCrypt : public TBotObject
{
protected:
	HCRYPTPROV FProvider;
	bool       FProviderAssigned;
	HCRYPTKEY  FKey;
	void InitializeProvider(HCRYPTPROV Provider, const char* Container, DWORD Flags);
	void DestroyKey();
protected:
//	LPBYTE DoExportKey(HCRYPTKEY ExpKey, DWORD BlobType, DWORD *BufSize);
//	bool   DoImportKey(HCRYPTKEY ExpKey, DWORD BlobType, LPBYTE Buf, DWORD BufSize);
public:

	TWinCrypt();
	TWinCrypt(const char *Container, DWORD Flags);
	TWinCrypt(HCRYPTPROV Provider);
	~TWinCrypt();

    bool GenerateKey(DWORD AlgId, DWORD Flags);
	bool CreateRC4Key(const char *Password);

	//---------------------------------------------------
	//  Encrypt
	//  Функция шифрует блок данных
	//
	//  Data
	//    Буфер содержаший данные. Должен быть размером
	//    достаточным для вмешения зашифрованных данных.
	//
	//  DataLen
	//    Размер данных. После выполнения в этот параметр
	//    будет записан результирующий размер данных
	//
	//  BufLen
	//    Размер буфера. Должен быть достаточным для
	//    вмещения зашифрованных данных
	//    Узнать необходимы размер можно вызвав функйию
	//    с нулевым буфером. Значение будет возвращено
	//    в параметре DataLen
	//
	//  FinalBlock
	//    Признак того, что это последний блок данных.
	//    Необхдим для корректного завершения шифрования
	//
	//---------------------------------------------------
	bool Encrypt(const void* Data, DWORD &DataLen, DWORD BufLen,  bool FinalBlock);


	//---------------------------------------------------
	//  Decrypt
	//  Функция расшифровывает блок данных
	//
	//  Buf
	//    Буфер содержаший данные. Должен быть размером
	//    достаточным для вмешения зашифрованных данных.
	//
	//  DataLen
	//    Размер данных. После выполнения в этот параметр
	//    будет записан результирующий размер данных
	//
	//
	//  FinalBlock
	//    Признак того, что это последний блок данных.
	//    Необхдим для корректного завершения шифрования
	//
	//---------------------------------------------------
    bool Decrypt(const void* Data, DWORD &DataLen, bool FinalBlock);


   HCRYPTHASH HashData(DWORD Algoritm, const void* Data, DWORD DataLen);

//	LPBYTE ExportPrivateKey(const char *ExpPassword, DWORD *BufSize);
//	LPBYTE ExportPublicKey(DWORD *BufSize);
//	bool   ImportPrivateKey(const char *ExpPassword, LPBYTE Buf, DWORD BufSize);
//	bool   ImportPublicKey(LPBYTE Buf, DWORD BufSize);


	//--------------------------------------------------------
	// Encode - Функция шифрует данные
	// Data - Данные для шифрования
	// DataSize - Размер данных.
	// В случае успеха функция выделит память под шифрованный
	// буфер и вернёт на него указатель. Размер буфера
	// запишется в переменную DataSize
	//--------------------------------------------------------
//	LPBYTE Encode(LPBYTE Data, DWORD &DataSize);

	//--------------------------------------------------------
	//  Decode - функция расшифровывает данные.
	//  Data - Указатель на блок шифрованных данных
	//  DataSize - Размер буфера.
	//  В случае успеха функция вернёт новый размер данных в
	//  переменную DataSize
	//--------------------------------------------------------
//	bool Decode(LPBYTE Data, DWORD &DataSize);

	HCRYPTPROV inline Provider()  { return FProvider; }
	HCRYPTKEY  inline Key()       { return FKey; }
};


//-----------------------------------------------------------------------------
#endif