UserStat - 1. Qt + QCA

Jul 01, 2008 15:17

Коли давно omega сказав мені, що класно було б мати невеличку апплікуху, на кшталт InetAccess для Stargazer, що не авторизувала б користувача, а лише повідомляла про стан його рахунку (незалежно від того, можливий для нього доступ в інет чи ні). Я тоді трошки посперечався, бо фактично - це дублювання функціоналу InetAccess.
Через деякий час та сама ідея промайнуа десь на форумі Локальних мереж України (у розділі Stargazer, звичайно). Потім ми з Борисом трошки обговорили ідею і дійшли до висновку що вона варта реалізації. Поговорили й забули.
Пройшло досить багато часу, і якось мені, після оновлення Qt захотілось спробувати цей тулкіт у роботі. Ну і вирішив я для забави написати юзерський інформатор. Перше що я зробив - витягнув інсталляцію Qt + Mingw для Windows. Все таки 90% користувачів сидять під віндами. Встановив під віртуалкою, запустив - працює! Ніяких шаманств, одразу завелось. А раз така справа - треба продумати протокол обміну даними. Стандартний простокол авторизатора, що реалізований бібліотекою ia_auth_c.lib не підходив, бо він був орієнтований на авторизацію користувача, а не на отримання інформації.
Порозкинувши мізками, я вирішив що було б неправильно обмежувати протокол на передачу лише певних параметрів юзера. А ну як хто захоче побачити свою статистику за минулий місяць? Звичайно, такий функціонал у версії 0.0.1 не передбачується, але я завжди намагаюсь "зазирнути у майбутнє". Тож для протоколу я вирішив використовувати XML - стандартний та досить гнучкий. Звичайно, як користувач, я б не хотів щоб моя "кухня" була кимось перехоплена по дорозі від сервера до клієнта. Тому цей XML треба шифрувати. А щоб довго не думати - шифрувати Blowfish'ем, який є у складі Stargazer і активно ним використовується.
Ну, Qt я знаю поганенько - то ж декілька днів боровся з ним. Днів - бо працювати міг лише вранці, за чашкою чаю перед роботою. І вечорами, за чашкою чаю після роботи. І по вихідним у той час я теж частенько працював. Trolltech порадував своїм тулкітом. Досить простий, логічний та зручний. І документація класна. Спочатку накидав примітивний інтерфейс головного вікна. Потім задумався про налаштування.
Думка перша: std::map та файл формату
= .
Друга думка: DOTCONFpp - рідковживана бібліотека для розбору конфігів а-ля Apache, що використовується у Stargazer'і для розбору головного конфігураційного файлу системи.
Третя думка: "Це ж Qt! Тут має бути підтримка конфіг-файлів!" - пішла на реалізацію.
Qt не просто надає інструментаррій для написання конфіг-файлів. Він ще й відповідає за те, де вони будуть розташовані у системі. О як!
Потім трошки розібрався як робити діалогові віконця і запустив всю цю штуку. Подивився на неї, помилувався, погрався "кнопочками" - і перейшов до наступної стадії. А саме - клієнтська частина. Як прихильник "Кобзаря" Т. Г. Шевченка паттерну MVC (Model-View-Controller) я гостро відточеним лезом думки відділив логіку протоколу від інтерфейсної частини. Далі, як уже звик, швиденько накидав стандартний інтерфейс для більшості клієнтів Stg і зайнявся питанням формування пакету даних. Зазвичай, при створенні XML-документу я використовую std::stringstream і заповнюю його руками. До того-ж, ще й розставляю переноси рядків і ідентацію. Бо, слідуючи філософії Unix, ці дані у першу чергу створені для людини. А вже потім - для машини. Я навіть накидав пару рядків коду, аж тут мені сяйнула думка: "Це ж Qt! Він має підтримувати XML!". І дійсно! Qt має класну модель роботи з даними. Спеціальний клас форматування XML пацює як з текстовим буфером, так і зі стандартними потоками. В тому числі - з сокетами.
Погравшись трошки з XML на предмет створення та розбирання документів я зайнявся криптографією. У декілька натисканнь клавіш у vim я переніс 3 функції, що відповідають у Stargazer'і за ініціалізацію контексту, шифрування та дешифрування за алгоритмом Blowfish. Уже написав пару рядків обв'язки для роботи з QString як мені знову сяйнула думка: "Це ж Qt! У ньому мають бути вбудовані криптографічні алгоритми!". А от тут усе вже не так просто.
Сам Qt не має засобів для роботи з криптоалгоритмами. Але розробники мого улюбленого IM-клієнту Psi (Jabber) подумали те-ж саме раніше мене. І поступили як справжні програмісти - взяли і створили інструментарій. І назвали його QCA - Qt Cryptographic Architecture. І успішно використовують його у своєму клієнті. А оскільки цей клієнт у мене встановлено - я навіть не став робити eix qca. Я одразу пішов шукати бінарники для Windows. І знайшов! І документацію знайшов. Все знайшов - у них на сайті. QCA - це не просто набір криптоалгоритмів. Це потужний комбайн, що надає цілу купу додаткових корисних інструментів. Наприклад, клас SecureArray: "The SecureArray provides an array of memory from a pool that is, at least partly, secure. In this sense, secure means that the contents of the memory should not be made available to other applications. By comparison, a QByteArray or QString may be held in pages that might be swapped to disk or free'd without being cleared first.". Круто, еге ж? За декілька хвилин я прикрутив QXmlStreamWriter до QString, цей QString - до QCA::SecureArray, його - до QCA::Cipher і до QTcpSocket. Запустив і... Пшик! QCA не знайшов відповідного криптопровайдера! Як я вже писав, QCA - дуже гнучка бібліотека. Всі криптоалгоритми у ній - суть плагіни. Так звані, криптопровайдери. І моя система сказала, що мої провадери не підтримують Blowfish. Більш того - вони майже нічого не підтримують! Я навіть розгубився. Ненадовго, правда. Я таки зробив eix qca і серед qcad та gqcam знайшов app-crypt/qca-ossl. Чесно кажучи, я не знав у якому з пакетів буде підтримка Blowfish, тож поставив і app-crypt/qca-tls і app-crypt/qca-gnupg. Виявилось що, таки, qca-ossl. Та й справді, як це OpenSSL - і без Blowfish? Додатково знайшов пакетики під вінду. Зібрав, запустив - працює!

$ ./userstats
Searching QCA::Provider for Blowfish support...
Found 'qca-ossl' QCA::Provider to use
Encrypt XML stream with password: '123456'
Encrypted: 2e4f0a0418362388e8189a00563511cc9425713a831b07ae2e3deaf01ef8adc9c4bf5be7442dc8a55852e4f9651677db92f180adb2b510db94b64bd2ae53890f5c0d99eef5b7c40f

На цьому я зупинився. Зупинився - бо подумав. Подумав про дуже нехороші речі. А саме - про сумісність qca-ossl Blowfish з тим Blowfish, що використовуэться у Stargazer'і. Звичайно, я використовував самий примітивний метод шифрування - ECB - Electronic Codebook (здрастуйте дядько Сівцов, що викладав у нас криптографію!). Бо я знав, що саме так працюють криптоалгоритми Stargazer'а. перевірити можливо лише 1 шляхом - написати, хоч частково, серверну частину. І я взявся за сервер. Вже на роботі, бо саме в цей час у мене з'явилось трошки вільного часу. Та як з'явилось - так і зникло. Напівготовий для теста серверний плагін навіть ні разу не компілювався.
Настала велика перерва у моїх пошуках, що закінчилась позавчора. Я як раз сидів в офісі, чека доки Боря накидає у Wiki всі відомі йому дані про новому проекту. Робити було особливо нічого, в неділю я не збирався займатись роботою, тож підняв цей проект. Стряхнув пилюку і трошки дописав і віддав компілятору. За пару годин повиловлював всі помилки і запустив сервер. Потім зібрав клієнтську частину (встановив на роботі qca-ossl) і запустив. Послав запит на сервер і замість красивого XML отримав беліберду. Не сумісний!
Ні, руки в мене не опустились. Спершу я перевірив що співпадають ключі для шифрування. Вони співпадали. Потім я перевірив що приймається саме той масив даних, що й надсилається. Тут теж все було в порядку. Корячити та ламати такий гарний клієнт не хотілось, тож я розпакував вихідні коди qca-ossl. Подивився уважненько і... нічого не побачив! Плагін не займався шифруванням. Від делеґував ці функції OpenSSL. Що, до речі, логічно випливає з його назви. Тоді я поряд розпакував вихідні коди OpenSSL і заліз у них по самі вуха. У директорії crypto я наштовхнувся на bf. Схоже на Blowfish, еге ж? Так і є, Blowfish. В першу чергу мене зацікавив файл bf_ecb.c, бо я використовував саме ECB і файл bf_skey.c, у якому реалізована функція ініціалізації контексту. Крім того я подивився опис алгоритму на Вікіпедії, почитав що написано на офсайті та у головному документі. Аналіз файлу bf_skey.c показав, що вихідні дані для ключа ідентичні тім, що використовуються у Stargazer'і та описані у алгоритмі на офсайті. Ініціалізація контексту (формування S-блоків та Pi-блоків) теж не відрізняється (хоча, написана, звичайно, дещо інакше). Аналіз bf_ecb.c привів мене до файлу bf_enc.c, де була реалізація одного блоку шифрування. Інтерпретація файла "у голові" не показала різниці з тим, що родить crypto.lib у Stargazer'і. Потім я написав маленьку тестову аплікуху, що шифрувала і дешифрувала число 0x0001020304050607 за допомогою функцій BF_encrypt та BF_decrypt зі складу OpenSSL (лінкував з ключем -lcrypto). Потым таку саму апплікуху я написав для crypto.lib Stargazer'а. І порівняв їх вихлоп. Він був ідентичний. Але сервер все одно не розумів того, що йому каже клієнт! Тоді я звернув свою увагу на те, як працює функція BF_ecb_encrypt. Вона використовує 2 макроса: n2l та l2n що перетворюють char * на uint32_t і навпаки. Справа в тому, що BF_encrypt та BF_decrypt працюють з двома половинками 64-бітного блоку даних:

void BF_ecb_encrypt(const unsigned char *in, unsigned char *out,
const BF_KEY *key, int encrypt)
{
BF_LONG l,d[2];

n2l(in,l); d[0]=l;
n2l(in,l); d[1]=l;
if (encrypt)
BF_encrypt(d,key);
else
BF_decrypt(d,key);
l=d[0]; l2n(l,out);
l=d[1]; l2n(l,out);
l=d[0]=d[1]=0;
}

Тоді я переписав свої тестові аплікухи. OpenSSl'ну - на використання функції BF_ecb_encryp, а ту що працює з crypto.lib - на аналогічний "ручний" варіант. Завдали вони мені клопоту! Відняли декілька годин життя! Я задовбав калькулятор (kcalc, до речі) на ноуті та списав пару форматних листків (папір та олівець для програміста важливіший за комп'ютер!) але все таки розколов алгоритм! Вихлоп програм (вони тепер шифрують рядок "abcdabcdabcdabcd"):

$ ./test_ossl
Source value: abcdabcdabcdabcd
Resulting value: æì-gÆúabcdabcd
Recovered value: abcdabcdabcdabcd

$ ./test_blowfish
Source value: abcdabcdabcdabcd
Resulting value: æì-gÆúabcdabcd
Recovered value: abcdabcdabcdabcd

Ух! День прожитий не марно! Підправив сервену частину і...

userstat.cpp > 16:04:11 > USERSTAT::Operate() size = 72
userstat.cpp > 16:04:11 > Received data: .O
6#è
userstat.cpp > 16:04:11 > USERSTAT::Operate() Requested user: 'faust'
userstat.cpp > 16:04:11 > USERSTAT::Operate() Encription init using password: '123456'
userstat.cpp > 16:04:11 > Received XML:

Отаке...
To be continued...

qca, userstat, криптографія, робота, stargazer, qt, cpp, blowfish, програмування

Previous post Next post
Up