вторник, 16 февраля 2010 г.

Криптография под Qt выпуск 3

Криптография с симметричным ключом вполне заработала. Ширфемся по алгоритму AES.

Чтобы расшифроваться нужно у чипера  поменять QCA::Encode на QCA::Decode.
 
QString encrypt(const QString & strToEnrypt)
{
  //инициализация
  QCA::Initializer init;
  //переводим строку в засекречивамый массив
  QCA::SecureArray arg = QVariant(strToEnrypt).toByteArray();
 
  QString res;
  // проверка что поддерживаем алгоритм AES128 testing
  if (QCA::isSupported("aes128-cbc-pkcs7"))
  {
   QString sKey = "aes128-cbc-pkcs7-sn93-sh21-jks-12";
   //некоторые преобразования над ключом
   //по идее должны затруднять реверсинг
   QStringList lst = sKey.split("-");
   lst = lst.replaceInStrings("c", "s");
   lst.removeAt(0);
   lst.removeAt(5);
   QString sKeyCh = lst.join(".");
   //создаем ключ
   QCA::SymmetricKey key(QVariant(lst.join(".")).toByteArray());
  
   //Создать случайный инициализирующий вектор
   //вам нужно это значение чтобы расшифровать результат шифра
   //но это нужно хранить в секрете в отличие от ключа
   QCA::InitializationVector iv(QVariant(lst.join(">")).toByteArray());

   //содать 128 битный AES шифр объект используя CBC режим
   QCA::Cipher cipher(QString("aes128"), QCA::Cipher::CBC,
      //использовать отступ по умолчанию который эквивалентен PKCS7 для CBC
              QCA::Cipher::DefaultPadding,
              // этот объект будет зашифрован
              QCA::Encode,
              key, iv);

   QCA::SecureArray u = cipher.update(arg);
   if (!cipher.ok())
   {
     return res;
   }

   QCA::SecureArray f = cipher.final();
   if (!cipher.ok())
   {
     return res;
   }
   res = QString(f.data());
  }
 
  return res;
}

* This source code was highlighted with Source Code Highlighter.

В следующем выпуске рассмотрим какие библиотеки нужны для переноса OpenSSL на чистую машину.

понедельник, 15 февраля 2010 г.

Криптография под Qt выпуск 2

Как оказалось, чтобы собрать нормальную дебаг версию надо было указать ключ --debug-and-release для configure.exe.
Но это еще не все.
По умолчанию QCA поддерживает только алгоритмы SHA1 и MD5. Чтобы получить остальное нужно ставить дополнительный плагин qca-ossl-2.0.0-beta3.tar.bz2.
Установка его дает нам такой комбайн поддерживаемых алгоритмов: TLS, CMS, X.509, RSA, DSA, Diffie-Hellman, PKCS#7, PKCS#12, SHA0, SHA1, SHA224, SHA256, SHA384, SHA512, MD2, MD4, MD5, RIPEMD160, Blowfish, DES, 3DES, AES128, AES192, AES256, CAST5, HMAC(SHA1, MD5, RIPEMD160), PBKDF1(MD2, SHA1), PBKDF2(SHA1).
Этот плагин в свою очередь зависит от OpenSSL версии не ниже 0.9.6
Взять его можно здесь openssl-0.9.8l
OpenSSL — криптографический пакет с открытым исходным кодом для работы с SSL/TLS. Позволяет создавать ключи RSA, DH, DSA и сертификаты X.509, подписывать их, формировать CSR и CRT. Также имеется возможность шифрования данных и тестирования SSL/TLS соединений.
OpenSSL поддерживает разные алгоритмы шифрования и хеширования:
Симметричные
Blowfish, Camellia, DES, RC2, RC4, RC5, IDEA, AES, ГОСТ 28147-89
Хеш-функции
MD5, MD2, SHA, MDC-2, ГОСТ Р 34.11-94
Асимметричные
RSA, DSA, Diffie-Hellman key exchange, ГОСТ Р 34.10-2001, ГОСТ Р 34.10-94
Поддержка алгоритмов ГОСТ появилась в версии 1.0.0, в данный момент находящейся в стадии бета-тестирования.
Чтобы собрать OpenSSL нужен Perl. Пришлось поставить Strawberry Perl.

После чего конфигуряется командой
> perl Configure VC-WIN32 --prefix=c:/some/openssl/dir
Затем
> ms\do_ms
И
 > nmake -f ms\ntdll.mak
> nmake -f ms\ntdll.mak install
После установки OpenSSL нужно сплясать еще один танец с бубном. Это касатся уже установки плагина qca-ossl.
В Папке %QTDIR% \mkspecs\features нужно создать файл winlocal.prf со строчкой WINLOCAL_PREFIX = D:/OpenSSL
То есть, указать путь до собранной OpenSSL.

В ходе сборки плагина у меня выскакивала ошибка, что де не найден OBJ_whirlpool. Эта переменная определена в OpenSSL, и управляет включением алгоритма Whirlpool — криптографическая хеш-функция.
Однако плагин в упор не видит исходного кода алгоритма и вылетает. Пришлось в коде плагина убрать упоминания о Whirlpool.
В итоге плагин qca-ossl2.dll все таки собрался.
Копируем его в %QTDIR%\plugins\crypto.
Завтра будем пробовать. По крайней мере if(QCA::isSupported("aes128-cbc-pkcs7")) стало возвращать true.

Конвертация QString в LPTSTR

LPTSTR это 32-битный указатель на Unicode строку.
Возвращать указатель из функции не совсем корректно и, например, у нас на фирме запрещено писать функции, возвращающие указатели. Т.к. программист в такой функции выделяет память и возвращает указатель на нее. А об удалении должен заботиться прикладной программист, а он может легко это забыть и получим утечку ресурсов.
Поэтому я приведу кусок кода, конвертирующий QString в LPTSTR без этих тонкостей. Кому надо напишут нужную функцию.
  QString str = "String";

  WCHAR * wStr = new WCHAR[str.length() + 1];
  MultiByteToWideChar( 0, 0, str.toAscii().data(), str.length(), wStr, str.length());
  wStr[str.length()] = '\0';
  LPTSTR lpszStr = wStr;
  delete [] wStr;
  wStr = 0;

* This source code was highlighted with Source Code Highlighter.

пятница, 12 февраля 2010 г.

Криптография под Qt выпуск 1

В стандартной поставке Qt совсем немного средств для криптографии. По сути все ограничивается одним классом QCryptographicHash.

Этот класс может получать хэш от некоторых данных, представленных в QByteArray, используя алгоритмы Md4, Md5, Sha.
Ну а что такое хэш? Хэш это необратимая последовательность символов, зная которую исходные данные никак не получить. Это удобно для хранения паролей. Хранишь хэш пароля и сравниваешь хэши паролей вместо них самих.
Однако в ряде случаев этого бывает недостаточно. И хочется иметь нормальное обратимое шифрование с ключами.

Порыскал в инете на эту тему, нашел пакет Qt Cryptographic Architecture (QCA).
Обитает он на:
http://delta.affinix.com/qca/
Скачиваем, разворачиваем в %QTDIR%/src/3rdparty/
Далее, configure.exe & nmake & installwin.exe
В результате оно установит Qt feature, т.е. фишку Qt.
Теперь в файле проекта можно написать CONFIG += crypto
И использовать в коде #include <QtCrypto>

На этом пока мое знакомство с QCA закончилось. В дебаге оно почему то не может найти либу qcad.lib, в релизе собирается нормально. Будем разбираться дальше.

Upd:
Для дебага пришлось поправить строку в %QTDIR%/mkspecs/features/crypto.prf
Вместо        windows:LINKAGE = -lqcad
написал         windows:LINKAGE = -lqca2

Поднимаем привилегии до админа под Windows XP

Понадобилось мне как-то сделать так, чтобы моя программа, будучи запущенной под ограниченным пользователем,  могла сама себе поднимать привилегии до администраторских.

Исходные условия: Windows XP, известные логин и пароль админа.
Цель: Научить программу поднимать себе привилегии.

Все оказалось достаточно просто:
#include "windows.h"

//Поднять права до админских
bool logonAsAdmin()
{
  LPTSTR lpszUsername = L"Admin"; // логин админа
  LPTSTR lpszDomain = NULL;  // домен
  LPTSTR lpszPassword = L"passw"; // пароль админа
  HANDLE hToken;  //маркер доступа (токен)

  //Получаем токен админа
  if (!LogonUser(lpszUsername, lpszDomain, lpszPassword, LOGON32_LOGON_INTERACTIVE,
         LOGON32_PROVIDER_DEFAULT, &hToken))
   return false;

  //Прикидываемся админом
  if (!ImpersonateLoggedOnUser(hToken))
   return false;

  return true;
}

* This source code was highlighted with Source Code Highlighter.
Но тут надо помнить о дыре, которую дает данный код. Дело в том, что в программе может быть код, дающий пользователю доступ к файловой системе с правами админа. Например, если в вашей программе есть диалог открытия файла и вы дали своей программе админский доступ, то такой доступ получит и пользователь программы.
Поэтому, перед тем как вызвать диалог открытия/сохранения файла - верните программе юзерский уровень и поднимите его обратно после работы с диалогом.
Или давайте админский уровень своей программе только на очень короткий срок и немедленно возвращайте его обратно, как только надобность в нем отпадет.

среда, 27 января 2010 г.

Продолжаем удалять файлы и каталоги

Функция рекурсивного удаления папок не работает если в папке есть файлы только для чтения.
Функция QFile::remove() при попытке удалить такой файл возвращает false. Чтобы этого избежать нужно выставлять права для таких файлов. В Qt для этого есть функция
bool QFile::setPermissions ( const QString & fileNamePermissions permissions )   [static]
Таким образом окончательный вид функции удаления каталога имеет вид:

четверг, 21 января 2010 г.

Очистка каталога

void cleanFolder(const QString & folder)
{
  QDir dir(folder);
  //Получаем список файлов 
  QStringList lstFiles = dir.entryList(QDir::Files);

  //Удаляем файлы
  foreach (QString entry, lstFiles)
  {
   QString entryAbsPath = dir.absolutePath() + "/" + entry;
   QFile::remove(entryAbsPath);
  }
}


* This source code was highlighted with Source Code Highlighter.

вторник, 19 января 2010 г.

Подсветка кода для блога

Изначально я планировал в этом блоге писать о программировании на Qt. Однако сейчас на блоге больше всего постов о покере, Москве, пиве и прочем непотребстве.
Объясняю в чем секрет - отсутствие толковой подсветки кода. Те куски кода, что я помещал в блог имели столь ужасное форматирование и подсветку, что без содрогания читать программу просто невозможно. Я перепробовал множество подсветчиков, однако у всех были недостатки - кто-то по  глупому делает подсветку, кто-то мутит с CSS, что вызывает трудности со вставкой кода.

Наконец я нашел приличный подсветчик: http://source.virtser.net
Он не использует CSS и делает подсветку аналогично Visual Studio.

Вот пример сгенеренного им кода.

ApPhotoRobot::ApPhotoRobot(QWidget * parent )
: DirSelecter(tr("Applications - PhotoRobot"), parent)
{
  lstlblPath.at(0)->setText(tr("Folder of Bars PhotoRobot"));
  lstlblName.at(0)->setText(tr("Executable name of Bars PhotoRobot"));
 
  leOut = new QLineEdit(this);

  QLabel * lblOut = new QLabel(tr("Output folder for Bars Photorobot"), this);

  QToolButton * btnBars = new QToolButton(this);
  btnBars->setFixedSize(20, 20);
  btnBars->setText("...");
  connect(btnBars, SIGNAL(clicked()), this, SLOT(browseDir()));

  mapBtnEdt[btnBars] = leOut;
  grid->addItem(new QSpacerItem(1, 10, QSizePolicy::Fixed, QSizePolicy::Fixed), 5, 0); 
  grid->addWidget(lblOut, 6, 0, 1, 2);
  grid->addWidget(leOut, 7, 0);
  grid->addWidget(btnBars, 7, 1);
 
  grid->setRowStretch(8, 1);

}

* This source code was highlighted with Source Code Highlighter.

На мой взгляд - лучшее решение для вставки кода в блог.

понедельник, 7 декабря 2009 г.

Настоящий программист

Понравилась цитата:
Настоящий программист не использует буфер обмена. (с)

От себя добавлю - Настоящий программист использует наследование.