diff options
author | George Hazan <ghazan@miranda.im> | 2021-04-01 18:13:36 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2021-04-01 18:13:36 +0300 |
commit | 7d45798b15d73898776fc31755f550e0ff4eaf2f (patch) | |
tree | 026068b477143c2c034f029af98a80ae1c53b067 /plugins | |
parent | 5fdee0384e30820abfc334984fbc05996e7fe8cd (diff) |
fixes #2822 (dbx_sqlite: total encryption is broken)
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/Dbx_sqlite/src/dbcrypt.cpp | 165 | ||||
-rwxr-xr-x | plugins/Dbx_sqlite/src/dbevents.cpp | 89 | ||||
-rwxr-xr-x | plugins/Dbx_sqlite/src/dbintf.cpp | 5 | ||||
-rwxr-xr-x | plugins/Dbx_sqlite/src/dbintf.h | 3 | ||||
-rw-r--r-- | plugins/Dbx_sqlite/src/stdafx.h | 1 | ||||
-rw-r--r-- | plugins/Dbx_sqlite/src/version.h | 6 |
6 files changed, 208 insertions, 61 deletions
diff --git a/plugins/Dbx_sqlite/src/dbcrypt.cpp b/plugins/Dbx_sqlite/src/dbcrypt.cpp index 1acab4b150..47a8449381 100644 --- a/plugins/Dbx_sqlite/src/dbcrypt.cpp +++ b/plugins/Dbx_sqlite/src/dbcrypt.cpp @@ -1,16 +1,64 @@ #include "stdafx.h" +enum +{ + SQL_CRYPT_GET_MODE, + SQL_CRYPT_SET_MODE, + SQL_CRYPT_GET_PROVIDER, + SQL_CRYPT_SET_PROVIDER, + SQL_CRYPT_GET_KEY, + SQL_CRYPT_SET_KEY, + SQL_CRYPT_ENCRYPT, +}; + +static CQuery crypto_stmts[] = +{ + { "SELECT data FROM crypto WHERE id=1;" }, // SQL_CRYPT_GET_MODE + { "REPLACE INTO crypto VALUES (1, ?);" }, // SQL_CRYPT_SET_MODE + { "SELECT data FROM crypto WHERE id=2;" }, // SQL_CRYPT_GET_PROVIDER + { "REPLACE INTO crypto VALUES(2, ?);" }, // SQL_CRYPT_SET_PROVIDER + { "SELECT data FROM crypto WHERE id=3;" }, // SQL_CRYPT_GET_KEY + { "REPLACE INTO crypto VALUES(3, ?);" }, // SQL_CRYPT_SET_KEY + { "UPDATE events SET flags=?, data=? WHERE id=?;"}, // SQL_CRYPT_ENCRYPT +}; + +static char szCreateQuery[] = + "CREATE TABLE crypto (id INTEGER NOT NULL PRIMARY KEY, data ANY NOT NULL);\r\n" + "INSERT INTO crypto VALUES (1, 0), (2, 'AES (Rjindale)'), (3, (SELECT value FROM settings WHERE contact_id=0 AND module='CryptoEngine' AND setting='StoredKey'));\r\n" + "DELETE FROM settings WHERE contact_id=0 AND module='CryptoEngine';\r\n"; + +void CDbxSQLite::InitEncryption() +{ + int rc = sqlite3_exec(m_db, "SELECT COUNT(1) FROM crypto;", nullptr, nullptr, nullptr); + if (rc == SQLITE_ERROR) // table doesn't exist, fill it with existing data + sqlite3_exec(m_db, szCreateQuery, nullptr, nullptr, nullptr); + + for (auto &it : crypto_stmts) + sqlite3_prepare_v3(m_db, it.szQuery, -1, SQLITE_PREPARE_PERSISTENT, &it.pQuery, nullptr); +} + +void CDbxSQLite::UninintEncryption() +{ + for (auto &it : crypto_stmts) + sqlite3_finalize(it.pQuery); +} + ///////////////////////////////////////////////////////////////////////////////////////// // Saving encryption key in a database STDMETHODIMP_(BOOL) CDbxSQLite::ReadCryptoKey(MBinBuffer &buf) { - DBVARIANT dbv = {}; - dbv.type = DBVT_BLOB; - if (GetContactSetting(0, "CryptoEngine", "StoredKey", &dbv)) + mir_cslock lock(m_csDbAccess); + sqlite3_stmt *stmt = crypto_stmts[SQL_CRYPT_GET_KEY].pQuery; + int rc = sqlite3_step(stmt); + logError(rc, __FILE__, __LINE__); + if (rc != SQLITE_ROW) { + sqlite3_reset(stmt); return FALSE; + } - buf.append(dbv.pbVal, dbv.cpbVal); + buf.append((BYTE*)sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0)); + sqlite3_reset(stmt); return TRUE; } @@ -20,11 +68,12 @@ STDMETHODIMP_(BOOL) CDbxSQLite::StoreCryptoKey() BYTE *pKey = (BYTE*)_alloca(iKeyLength); m_crypto->getKey(pKey, iKeyLength); - DBCONTACTWRITESETTING dbcws = { "CryptoEngine", "StoredKey" }; - dbcws.value.type = DBVT_BLOB; - dbcws.value.cpbVal = (WORD)iKeyLength; - dbcws.value.pbVal = pKey; - WriteContactSetting(0, &dbcws); + mir_cslock lock(m_csDbAccess); + sqlite3_stmt *stmt = crypto_stmts[SQL_CRYPT_SET_KEY].pQuery; + sqlite3_bind_blob(stmt, 1, pKey, (int)iKeyLength, nullptr); + int rc = sqlite3_step(stmt); + logError(rc, __FILE__, __LINE__); + sqlite3_reset(stmt); SecureZeroMemory(pKey, iKeyLength); DBFlush(); @@ -32,40 +81,46 @@ STDMETHODIMP_(BOOL) CDbxSQLite::StoreCryptoKey() } ///////////////////////////////////////////////////////////////////////////////////////// -// Saving encryption flag +// Reads encryption flag STDMETHODIMP_(BOOL) CDbxSQLite::ReadEncryption() { - DBVARIANT dbv = {}; - dbv.type = DBVT_BYTE; - return (GetContactSetting(0, "CryptoEngine", "DatabaseEncryption", &dbv)) ? false : dbv.bVal != 0; + mir_cslock lock(m_csDbAccess); + sqlite3_stmt *stmt = crypto_stmts[SQL_CRYPT_GET_MODE].pQuery; + int rc = sqlite3_step(stmt); + logError(rc, __FILE__, __LINE__); + if (rc != SQLITE_ROW) { + sqlite3_reset(stmt); + return FALSE; + } + + int ret = sqlite3_column_int(stmt, 0); + sqlite3_reset(stmt); + return ret; } ///////////////////////////////////////////////////////////////////////////////////////// -// Saving provider in a database +// Reads crypto provider's name STDMETHODIMP_(CRYPTO_PROVIDER*) CDbxSQLite::ReadProvider() { - DBVARIANT dbv = {}; - dbv.type = DBVT_BLOB; - if (GetContactSetting(0, "CryptoEngine", "Provider", &dbv)) - return nullptr; - - if (dbv.type != DBVT_BLOB) - return nullptr; - - auto *pProvider = Crypto_GetProvider(LPCSTR(dbv.pbVal)); - FreeVariant(&dbv); - return pProvider; + mir_cslock lock(m_csDbAccess); + sqlite3_stmt *stmt = crypto_stmts[SQL_CRYPT_GET_PROVIDER].pQuery; + int rc = sqlite3_step(stmt); + logError(rc, __FILE__, __LINE__); + sqlite3_reset(stmt); + return (rc != SQLITE_ROW) ? nullptr : Crypto_GetProvider((char*)sqlite3_column_text(stmt, 0)); } STDMETHODIMP_(BOOL) CDbxSQLite::StoreProvider(CRYPTO_PROVIDER *pProvider) { - DBCONTACTWRITESETTING dbcws = { "CryptoEngine", "Provider" }; - dbcws.value.type = DBVT_BLOB; - dbcws.value.pbVal = (PBYTE)pProvider->pszName; - dbcws.value.cpbVal = (WORD)mir_strlen(pProvider->pszName) + 1; - WriteContactSetting(0, &dbcws); + mir_cslock lock(m_csDbAccess); + sqlite3_stmt *stmt = crypto_stmts[SQL_CRYPT_SET_PROVIDER].pQuery; + sqlite3_bind_text(stmt, 1, pProvider->pszName, (int)strlen(pProvider->pszName), 0); + int rc = sqlite3_step(stmt); + logError(rc, __FILE__, __LINE__); + sqlite3_reset(stmt); + DBFlush(); return TRUE; } @@ -73,7 +128,53 @@ STDMETHODIMP_(BOOL) CDbxSQLite::StoreProvider(CRYPTO_PROVIDER *pProvider) ///////////////////////////////////////////////////////////////////////////////////////// // Toggles full/partial encryption mode -STDMETHODIMP_(BOOL) CDbxSQLite::EnableEncryption(BOOL) +STDMETHODIMP_(BOOL) CDbxSQLite::EnableEncryption(BOOL bEncrypted) { - return FALSE; + if (m_bEncrypted == (bEncrypted != 0)) + return TRUE; + + mir_cslock lock(m_csDbAccess); + sqlite3_stmt *stmt = nullptr; + int rc = sqlite3_prepare_v2(m_db, "SELECT id, flags, data FROM events;", -1, &stmt, 0); + logError(rc, __FILE__, __LINE__); + while (sqlite3_step(stmt) == SQLITE_ROW) { + int dwFlags = sqlite3_column_int(stmt, 1); + if (((dwFlags & DBEF_ENCRYPTED) != 0) == bEncrypted) + continue; + + int id = sqlite3_column_int(stmt, 0); + auto *pBlob = (const BYTE *)sqlite3_column_blob(stmt, 2); + unsigned cbBlob = sqlite3_column_bytes(stmt, 2); + + mir_ptr<BYTE> pNewBlob; + size_t nNewBlob; + + if (dwFlags & DBEF_ENCRYPTED) { + pNewBlob = (BYTE*)m_crypto->decodeBuffer(pBlob, cbBlob, &nNewBlob); + dwFlags &= (~DBEF_ENCRYPTED); + } + else { + pNewBlob = m_crypto->encodeBuffer(pBlob, cbBlob, &nNewBlob); + dwFlags |= DBEF_ENCRYPTED; + } + + sqlite3_stmt *upd = crypto_stmts[SQL_CRYPT_ENCRYPT].pQuery; + sqlite3_bind_int(upd, 1, dwFlags); + sqlite3_bind_blob(upd, 2, pNewBlob, (int)nNewBlob, 0); + sqlite3_bind_int(upd, 3, id); + rc = sqlite3_step(upd); + logError(rc, __FILE__, __LINE__); + sqlite3_reset(upd); + } + sqlite3_finalize(stmt); + + // Finally update flag + stmt = crypto_stmts[SQL_CRYPT_SET_MODE].pQuery; + sqlite3_bind_int(stmt, 1, bEncrypted); + rc = sqlite3_step(stmt); + logError(rc, __FILE__, __LINE__); + sqlite3_reset(stmt); + + m_bEncrypted = bEncrypted; + return TRUE; } diff --git a/plugins/Dbx_sqlite/src/dbevents.cpp b/plugins/Dbx_sqlite/src/dbevents.cpp index 5a4471bd76..8a64af8046 100755 --- a/plugins/Dbx_sqlite/src/dbevents.cpp +++ b/plugins/Dbx_sqlite/src/dbevents.cpp @@ -134,22 +134,33 @@ MEVENT CDbxSQLite::AddEvent(MCONTACT hContact, const DBEVENTINFO *dbei) if (NotifyEventHooks(g_hevEventFiltered, hNotifyContact, (LPARAM)dbei)) return 0; + DBEVENTINFO tmp = *dbei; const char *szEventId; - DWORD dwFlags = dbei->flags; - if (dbei->szId != nullptr) { - dwFlags |= DBEF_HAS_ID; - szEventId = dbei->szId; + if (tmp.szId != nullptr) { + tmp.flags |= DBEF_HAS_ID; + szEventId = tmp.szId; } else szEventId = ""; + mir_ptr<BYTE> pCryptBlob; + if (m_bEncrypted) { + size_t len; + BYTE *pResult = m_crypto->encodeBuffer(tmp.pBlob, tmp.cbBlob, &len); + if (pResult != nullptr) { + pCryptBlob = tmp.pBlob = pResult; + tmp.cbBlob = (uint16_t)len; + tmp.flags |= DBEF_ENCRYPTED; + } + } + mir_cslockfull lock(m_csDbAccess); sqlite3_stmt *stmt = evt_stmts[SQL_EVT_STMT_ADDEVENT].pQuery; sqlite3_bind_int64(stmt, 1, hContact); - sqlite3_bind_text(stmt, 2, dbei->szModule, (int)mir_strlen(dbei->szModule), nullptr); - sqlite3_bind_int64(stmt, 3, dbei->timestamp); - sqlite3_bind_int(stmt, 4, dbei->eventType); - sqlite3_bind_int64(stmt, 5, dwFlags); - sqlite3_bind_blob(stmt, 6, dbei->pBlob, dbei->cbBlob, nullptr); + sqlite3_bind_text(stmt, 2, tmp.szModule, (int)mir_strlen(tmp.szModule), nullptr); + sqlite3_bind_int64(stmt, 3, tmp.timestamp); + sqlite3_bind_int(stmt, 4, tmp.eventType); + sqlite3_bind_int64(stmt, 5, tmp.flags); + sqlite3_bind_blob(stmt, 6, tmp.pBlob, tmp.cbBlob, nullptr); sqlite3_bind_text(stmt, 7, szEventId, (int)mir_strlen(szEventId), nullptr); int rc = sqlite3_step(stmt); logError(rc, __FILE__, __LINE__); @@ -160,32 +171,32 @@ MEVENT CDbxSQLite::AddEvent(MCONTACT hContact, const DBEVENTINFO *dbei) stmt = evt_stmts[SQL_EVT_STMT_ADDEVENT_SRT].pQuery; sqlite3_bind_int64(stmt, 1, hDbEvent); sqlite3_bind_int64(stmt, 2, cc->contactID); - sqlite3_bind_int64(stmt, 3, dbei->timestamp); + sqlite3_bind_int64(stmt, 3, tmp.timestamp); rc = sqlite3_step(stmt); logError(rc, __FILE__, __LINE__); sqlite3_reset(stmt); - cc->AddEvent(hDbEvent, dbei->timestamp, !dbei->markedRead()); + cc->AddEvent(hDbEvent, tmp.timestamp, !tmp.markedRead()); if (ccSub != nullptr) { stmt = evt_stmts[SQL_EVT_STMT_ADDEVENT_SRT].pQuery; sqlite3_bind_int64(stmt, 1, hDbEvent); sqlite3_bind_int64(stmt, 2, ccSub->contactID); - sqlite3_bind_int64(stmt, 3, dbei->timestamp); + sqlite3_bind_int64(stmt, 3, tmp.timestamp); rc = sqlite3_step(stmt); logError(rc, __FILE__, __LINE__); sqlite3_reset(stmt); //is this necessary ? - ccSub->AddEvent(hDbEvent, dbei->timestamp, !dbei->markedRead()); + ccSub->AddEvent(hDbEvent, tmp.timestamp, !tmp.markedRead()); } - char *module = m_modules.find((char *)dbei->szModule); + char *module = m_modules.find((char *)tmp.szModule); if (module == nullptr) - m_modules.insert(mir_strdup(dbei->szModule)); + m_modules.insert(mir_strdup(tmp.szModule)); lock.unlock(); DBFlush(); - if (m_safetyMode && !(dbei->flags & DBEF_TEMPORARY)) + if (m_safetyMode && !(tmp.flags & DBEF_TEMPORARY)) NotifyEventHooks(g_hevEventAdded, hNotifyContact, (LPARAM)hDbEvent); return hDbEvent; @@ -241,25 +252,37 @@ BOOL CDbxSQLite::EditEvent(MCONTACT hContact, MEVENT hDbEvent, const DBEVENTINFO if (cc == nullptr) return 1; + DBEVENTINFO tmp = *dbei; + mir_ptr<BYTE> pCryptBlob; + if (m_bEncrypted) { + size_t len; + BYTE *pResult = m_crypto->encodeBuffer(tmp.pBlob, tmp.cbBlob, &len); + if (pResult != nullptr) { + pCryptBlob = tmp.pBlob = pResult; + tmp.cbBlob = (uint16_t)len; + tmp.flags |= DBEF_ENCRYPTED; + } + } + mir_cslockfull lock(m_csDbAccess); sqlite3_stmt *stmt = evt_stmts[SQL_EVT_STMT_EDIT].pQuery; - sqlite3_bind_text(stmt, 1, dbei->szModule, (int)mir_strlen(dbei->szModule), nullptr); - sqlite3_bind_int64(stmt, 2, dbei->timestamp); - sqlite3_bind_int(stmt, 3, dbei->eventType); - sqlite3_bind_int64(stmt, 4, dbei->flags); - sqlite3_bind_blob(stmt, 5, dbei->pBlob, dbei->cbBlob, nullptr); + sqlite3_bind_text(stmt, 1, tmp.szModule, (int)mir_strlen(tmp.szModule), nullptr); + sqlite3_bind_int64(stmt, 2, tmp.timestamp); + sqlite3_bind_int(stmt, 3, tmp.eventType); + sqlite3_bind_int64(stmt, 4, tmp.flags); + sqlite3_bind_blob(stmt, 5, tmp.pBlob, tmp.cbBlob, nullptr); sqlite3_bind_int64(stmt, 6, hDbEvent); int rc = sqlite3_step(stmt); logError(rc, __FILE__, __LINE__); sqlite3_reset(stmt); - cc->EditEvent(hDbEvent, dbei->timestamp, !dbei->markedRead()); + cc->EditEvent(hDbEvent, tmp.timestamp, !tmp.markedRead()); if (cc->IsSub() && (cc = m_cache->GetCachedContact(cc->parentID))) - cc->EditEvent(hDbEvent, dbei->timestamp, !dbei->markedRead()); + cc->EditEvent(hDbEvent, tmp.timestamp, !tmp.markedRead()); - char *module = m_modules.find((char *)dbei->szModule); + char *module = m_modules.find((char *)tmp.szModule); if (module == nullptr) - m_modules.insert(mir_strdup(dbei->szModule)); + m_modules.insert(mir_strdup(tmp.szModule)); lock.unlock(); @@ -325,7 +348,21 @@ BOOL CDbxSQLite::GetEvent(MEVENT hDbEvent, DBEVENTINFO *dbei) dbei->cbBlob = cbBlob; if (bytesToCopy && dbei->pBlob) { BYTE *data = (BYTE *)sqlite3_column_blob(stmt, 5); - memcpy(dbei->pBlob, data, bytesToCopy); + + if (dbei->flags & DBEF_ENCRYPTED) { + dbei->flags &= ~DBEF_ENCRYPTED; + size_t len; + BYTE* pBlob = (BYTE*)m_crypto->decodeBuffer(data, cbBlob, &len); + if (pBlob == nullptr) + return 1; + + memcpy(dbei->pBlob, pBlob, bytesToCopy); + if (bytesToCopy > len) + memset(dbei->pBlob + len, 0, bytesToCopy - len); + + mir_free(pBlob); + } + else memcpy(dbei->pBlob, data, bytesToCopy); } sqlite3_reset(stmt); return 0; diff --git a/plugins/Dbx_sqlite/src/dbintf.cpp b/plugins/Dbx_sqlite/src/dbintf.cpp index c95af86ae8..6fd1c9b6a1 100755 --- a/plugins/Dbx_sqlite/src/dbintf.cpp +++ b/plugins/Dbx_sqlite/src/dbintf.cpp @@ -18,6 +18,7 @@ CDbxSQLite::~CDbxSQLite() UninitEvents(); UninitContacts(); UninitSettings(); + UninintEncryption(); if (m_db) { rc = sqlite3_close(m_db); @@ -42,6 +43,9 @@ int CDbxSQLite::Create() rc = sqlite3_exec(m_db, "CREATE TABLE contacts (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);", nullptr, nullptr, nullptr); logError(rc, __FILE__, __LINE__); + rc = sqlite3_exec(m_db, "CREATE TABLE crypto (id INTEGER NOT NULL PRIMARY KEY, data ANY NOT NULL);", nullptr, nullptr, nullptr); + logError(rc, __FILE__, __LINE__); + rc = sqlite3_exec(m_db, "CREATE TABLE events (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, contact_id INTEGER NOT NULL, module TEXT NOT NULL," "timestamp INTEGER NOT NULL, type INTEGER NOT NULL, flags INTEGER NOT NULL, data BLOB, server_id TEXT);", nullptr, nullptr, nullptr); logError(rc, __FILE__, __LINE__); @@ -135,6 +139,7 @@ int CDbxSQLite::Load() } InitContacts(); + InitEncryption(); InitSettings(); InitEvents(); diff --git a/plugins/Dbx_sqlite/src/dbintf.h b/plugins/Dbx_sqlite/src/dbintf.h index 490aa982bc..a2a2fbcaf5 100755 --- a/plugins/Dbx_sqlite/src/dbintf.h +++ b/plugins/Dbx_sqlite/src/dbintf.h @@ -84,6 +84,9 @@ class CDbxSQLite : public MDatabaseCommon, public MZeroedObject void InitSettings(); void UninitSettings(); + void InitEncryption(); + void UninintEncryption(); + void DBFlush(bool bForce = false); public: diff --git a/plugins/Dbx_sqlite/src/stdafx.h b/plugins/Dbx_sqlite/src/stdafx.h index ff83996237..6d8fc14a1d 100644 --- a/plugins/Dbx_sqlite/src/stdafx.h +++ b/plugins/Dbx_sqlite/src/stdafx.h @@ -5,6 +5,7 @@ #include <crtdbg.h> #include <memory> +#include <vector> #include <newpluginapi.h> #include <m_crypto.h> diff --git a/plugins/Dbx_sqlite/src/version.h b/plugins/Dbx_sqlite/src/version.h index 04c7f4a7a4..2a3e1bfa64 100644 --- a/plugins/Dbx_sqlite/src/version.h +++ b/plugins/Dbx_sqlite/src/version.h @@ -1,7 +1,7 @@ #define __MAJOR_VERSION 0 -#define __MINOR_VERSION 95 -#define __RELEASE_NUM 13 -#define __BUILD_NUM 4 +#define __MINOR_VERSION 96 +#define __RELEASE_NUM 1 +#define __BUILD_NUM 1 #include <stdver.h> |