summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2021-04-01 18:13:36 +0300
committerGeorge Hazan <ghazan@miranda.im>2021-04-01 18:13:36 +0300
commit7d45798b15d73898776fc31755f550e0ff4eaf2f (patch)
tree026068b477143c2c034f029af98a80ae1c53b067 /plugins
parent5fdee0384e30820abfc334984fbc05996e7fe8cd (diff)
fixes #2822 (dbx_sqlite: total encryption is broken)
Diffstat (limited to 'plugins')
-rw-r--r--plugins/Dbx_sqlite/src/dbcrypt.cpp165
-rwxr-xr-xplugins/Dbx_sqlite/src/dbevents.cpp89
-rwxr-xr-xplugins/Dbx_sqlite/src/dbintf.cpp5
-rwxr-xr-xplugins/Dbx_sqlite/src/dbintf.h3
-rw-r--r--plugins/Dbx_sqlite/src/stdafx.h1
-rw-r--r--plugins/Dbx_sqlite/src/version.h6
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>