Написал примитивный плагин для шифрования - шифрует AES всегда одним паралём зашитым в код.
Не требует KeyHolder-а.
Если после начала процесса шифрования попробовать сделать коннект к этой базе, или gstat -e, то сервер падает.
И после этого любой коннект к базе падает с сообщением:
Гоняю на виртуалке Win7
Сервер: Firebird-3.0.3.32900_0_Win32.exe
Установлен как сервис
В конфиге добавлена только 1 значение
В databases.conf добавил только 1 строку:
Базу для тестов копирую с хоста.
gstat:
Коннекчись isql и запускаю шифрование:
Лог в это время пуст.
Коннектимся ещё одним isql:
В первом isql потерянно соединение:
Сам плагин:
Код AES взят отсюда: plusaes
Не требует KeyHolder-а.
Если после начала процесса шифрования попробовать сделать коннект к этой базе, или gstat -e, то сервер падает.
И после этого любой коннект к базе падает с сообщением:
internal Firebird consistency check (decompression overran buffer (179), file: sqz.cpp line: 293)
Гоняю на виртуалке Win7
Сервер: Firebird-3.0.3.32900_0_Win32.exe
Установлен как сервис
В конфиге добавлена только 1 значение
ServerMode = SuperКонфиг полностью:
+ |
######################################### |
В databases.conf добавил только 1 строку:
raduga6 = C:\Lang\Firebird\DB\RADUGA6.FDBdatabases.conf полностью:
+ |
# ------------------------------ |
Базу для тестов копирую с хоста.
gstat:
+ |
>gstat.exe -h ../db/RADUGA6.FDB |
Коннекчись isql и запускаю шифрование:
>isql.exe xnet://raduga6 -user SYSDBA -pass masterkeyПосле этого можно наблюдать в таск менеджере что Firebird занимает почти всё ядро.
Database: xnet://raduga6, User: SYSDBA
SQL> alter database encrypt with dbcryptraduga;
SQL>
Лог в это время пуст.
Коннектимся ещё одним isql:
>isql.exe xnet://raduga6 -user SYSDBA -pass masterkeyПри этом в логе полно ошибок:
Statement failed, SQLSTATE = XX000
internal Firebird consistency check (decompression overran buffer (179), file: sqz.cpp line: 293)
Use CONNECT or CREATE DATABASE to specify a database
SQL>
+ |
|
В первом isql потерянно соединение:
SQL> use raduga6;Сервер перезапустился системой.
Statement failed, SQLSTATE = XX000
internal Firebird consistency check (can't continue after bugcheck)
>gfix -v ../DB/RADUGA6.FDB
internal Firebird consistency check (decompression overran buffer (179), file: sqz.cpp line: 282)
Сам плагин:
+ |
// dbcryptw.cpp : Defines the exported functions for the DLL application. // #include "stdafx.h" #include "ifaceExamples.h" #include <cstring> #include <cstddef> #include "plusaes.hpp" using namespace Firebird; #pragma warning(disable : 4996) namespace { class PluginModule : public IPluginModuleImpl<PluginModule, CheckStatusWrapper> { public: PluginModule() : pluginManager(NULL) { } ~PluginModule() { if (pluginManager) { pluginManager->unregisterModule(this); doClean(); } } void registerMe(IPluginManager* m) { pluginManager = m; pluginManager->registerModule(this); } void doClean() { pluginManager = NULL; } private: IPluginManager* pluginManager; }; class DbCryptRaduga : public IDbCryptPluginImpl<DbCryptRaduga, CheckStatusWrapper> { public: explicit DbCryptRaduga(IPluginConfig* cnf) throw() : config(cnf), key(), iv(), refCounter(0), owner(NULL) { config->addRef(); } ~DbCryptRaduga() { config->release(); } // ICryptPlugin implementation void encrypt(CheckStatusWrapper* status, unsigned int length, const void* from, void* to); void decrypt(CheckStatusWrapper* status, unsigned int length, const void* from, void* to); void setKey(CheckStatusWrapper* status, unsigned int length, IKeyHolderPlugin** sources, const char* keyName); // One if free to ignore passed info when not needed void setInfo(CheckStatusWrapper* status, IDbCryptInfo* info) { #ifdef NEVERDEF fprintf(stderr, "DbInfo: name is %s\n", info->getDatabaseFullPath(status)); #endif } int release() { if (--refCounter == 0) { delete this; return 0; } return 1; } void addRef() { ++refCounter; } void setOwner(IReferenceCounted* o) { owner = o; } IReferenceCounted* getOwner() { return owner; } private: IPluginConfig* config; char savedKeyName[32]; struct key_type { ISC_UCHAR val[32]; }; key_type key; struct iv_type { ISC_UCHAR val[16]; }; iv_type iv; FbSampleAtomic refCounter; IReferenceCounted* owner; void setError(CheckStatusWrapper* status, const char* msg); void noKeyError(CheckStatusWrapper* status); void encDecError(CheckStatusWrapper* status, plusaes::Error e, bool encrypt); }; void DbCryptRaduga::setError(CheckStatusWrapper* status, const char* msg) { ISC_STATUS_ARRAY vector; vector[0] = isc_arg_gds; vector[1] = isc_random; vector[2] = isc_arg_string; vector[3] = (ISC_STATUS)msg; vector[4] = isc_arg_end; status->setErrors(vector); } void DbCryptRaduga::noKeyError(CheckStatusWrapper* status) { char msg[100]; sprintf(msg, "Crypt key %s not set", savedKeyName); setError(status, msg); } void DbCryptRaduga::encDecError( CheckStatusWrapper* status, plusaes::Error e, bool encrypt ) { using namespace plusaes; if (e == kErrorOk) return; char buf[100] = { 0 }; const char* alg = encrypt ? "Encrypt" : "Decrypt"; const char* msg = nullptr; switch (e) { case kErrorInvalidDataSize: msg = "invalid data size"; break; case kErrorInvalidKeySize: msg = "invalid key size"; break; case kErrorInvalidBufferSize: msg = "invalid buffer size"; break; case kErrorInvalidKey: msg = "invalid key"; break; default: msg = "unknown"; } sprintf(buf, "%s error: %s", alg, msg); setError(status, buf); } void DbCryptRaduga::encrypt(CheckStatusWrapper* status, unsigned int length, const void* from, void* to) { status->init(); if (!*key.val) return noKeyError(status); const ISC_UCHAR* f = static_cast<const ISC_UCHAR*>(from); ISC_UCHAR* t = static_cast<ISC_UCHAR*>(to); using namespace plusaes; if (length == 16) { const Error e = encrypt_ecb( f, length, key.val, sizeof(key), t, length, false); if (e != kErrorOk) encDecError(status, e, true); return; } if (length > 16) { const Error e = encrypt_cbc( f, length, key.val, sizeof(key), &iv.val, t, length, false); if (e != kErrorOk) encDecError(status, e, true); return; } char msg[100] = { 0 }; sprintf(msg, "Encrypt buffer to small. Need 16 but %d bytes", length); setError(status, msg); } void DbCryptRaduga::decrypt(CheckStatusWrapper* status, unsigned int length, const void* from, void* to) { status->init(); if (!*key.val) return noKeyError(status); const ISC_UCHAR* f = static_cast<const ISC_UCHAR*>(from); ISC_UCHAR* t = static_cast<ISC_UCHAR*>(to); /*while (length--) { *t++ = (*f++) ^ key; }*/ using namespace plusaes; if (length == 16) { const Error e = decrypt_ecb( f, length, key.val, sizeof(key), t, length, false); if (e != kErrorOk) encDecError(status, e, false); return; } if (length > 16) { const Error e = decrypt_cbc( f, length, key.val, sizeof(key), &iv.val, t, length, false); if (e != kErrorOk) encDecError(status, e, false); return; } char msg[100] = { 0 }; sprintf(msg, "Decrypt buffer to small. Need 16 but %d bytes", length); setError(status, msg); } void DbCryptRaduga::setKey( CheckStatusWrapper* status, unsigned int length, IKeyHolderPlugin** sources, const char* keyName ) { status->init(); if (*key.val != 0) return; strncpy(savedKeyName, (keyName ? keyName : ""), sizeof(savedKeyName)); savedKeyName[sizeof(savedKeyName) - 1] = 0; key = key_type{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2 }; status->clearException(); /* IConfig* def = config->getDefaultConfig(status); if (status->getState() & Firebird::IStatus::STATE_ERRORS) return; IConfigEntry* confEntry = def->find(status, "Auto"); if (status->getState() & Firebird::IStatus::STATE_ERRORS) { def->release(); return; } if (confEntry) { char v = *(confEntry->getValue()); confEntry->release(); if (v == '1' || v == 'y' || v == 'Y' || v == 't' || v == 'T') { confEntry = def->find(status, "Value"); def->release(); if (confEntry) { const char* val = confEntry->getValue(); confEntry->release(); if (v) { auto ikey = key_from_string(val); memcpy(&key, &ikey[0], sizeof(key)); return; } } key = key_type { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2}; return; } def->release(); } for (unsigned n = 0; n < length; ++n) { ICryptKeyCallback* callback = sources[n]->keyHandle(status, savedKeyName); if (status->getState() & Firebird::IStatus::STATE_ERRORS) return; if (callback && callback->callback(0, NULL, 1, &key) == 1) return; } key.val[0] = 0; noKeyError(status); */ } class Factory : public IPluginFactoryImpl<Factory, CheckStatusWrapper> { public: IPluginBase* createPlugin(CheckStatusWrapper* status, IPluginConfig* factoryParameter) { /* // *** Uncomment this 2 lines to see how plugin creation errors are handled const ISC_STATUS_ARRAY vector = {isc_arg_gds, isc_virmemexh, isc_arg_end}; throw FbException(status, vector); */ DbCryptRaduga* p = new DbCryptRaduga(factoryParameter); p->addRef(); return p; } }; PluginModule module; Factory factory; } // anonymous namespace extern "C" void FB_DLL_EXPORT FB_PLUGIN_ENTRY_POINT(IMaster* master) { IPluginManager* pluginManager = master->getPluginManager(); module.registerMe(pluginManager); pluginManager->registerPluginFactory(IPluginManager::TYPE_DB_CRYPT, "DbCryptRaduga", &factory); } |
Код AES взят отсюда: plusaes