diff options
Diffstat (limited to 'plugins/Dbx_sqlite/src/dbcrypt.cpp')
-rw-r--r-- | plugins/Dbx_sqlite/src/dbcrypt.cpp | 165 |
1 files changed, 133 insertions, 32 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; } |