From 611ab224588e2f64db2c1b24ac8e45c55c086182 Mon Sep 17 00:00:00 2001 From: Jorrit Wronski Date: Thu, 1 Dec 2016 23:37:22 +0100 Subject: [PATCH 1/9] Added ability to open encrypted databases. --- include/SQLiteCpp/Database.h | 8 ++++-- src/Database.cpp | 50 +++++++++++++++++++++++++++++++----- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/include/SQLiteCpp/Database.h b/include/SQLiteCpp/Database.h index 70ca2e5..f3d0b0b 100644 --- a/include/SQLiteCpp/Database.h +++ b/include/SQLiteCpp/Database.h @@ -84,13 +84,15 @@ public: * @param[in] aFlags SQLite::OPEN_READONLY/SQLite::OPEN_READWRITE/SQLite::OPEN_CREATE... * @param[in] aBusyTimeoutMs Amount of milliseconds to wait before returning SQLITE_BUSY (see setBusyTimeout()) * @param[in] apVfs UTF-8 name of custom VFS to use, or nullptr for sqlite3 default + * @param[in] apPass Key to decrypt (end encrypt) the database, or nullptr for unencrypted databases * * @throw SQLite::Exception in case of error */ Database(const char* apFilename, const int aFlags = SQLite::OPEN_READONLY, const int aBusyTimeoutMs = 0, - const char* apVfs = NULL); + const char* apVfs = NULL, + const char* apPass = NULL); /** * @brief Open the provided database UTF-8 filename. @@ -106,13 +108,15 @@ public: * @param[in] aFlags SQLite::OPEN_READONLY/SQLite::OPEN_READWRITE/SQLite::OPEN_CREATE... * @param[in] aBusyTimeoutMs Amount of milliseconds to wait before returning SQLITE_BUSY (see setBusyTimeout()) * @param[in] aVfs UTF-8 name of custom VFS to use, or empty string for sqlite3 default + * @param[in] aPass Key to decrypt (end encrypt) the database, or empty string for unencrypted databases * * @throw SQLite::Exception in case of error */ Database(const std::string& aFilename, const int aFlags = SQLite::OPEN_READONLY, const int aBusyTimeoutMs = 0, - const std::string& aVfs = ""); + const std::string& aVfs = "", + const std::string& aPass = ""); /** * @brief Close the SQLite database connection. diff --git a/src/Database.cpp b/src/Database.cpp index f640218..417a83c 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -51,18 +51,37 @@ int getLibVersionNumber() noexcept // nothrow Database::Database(const char* apFilename, const int aFlags /* = SQLite::OPEN_READONLY*/, const int aBusyTimeoutMs /* = 0 */, - const char* apVfs /* = NULL*/) : + const char* apVfs /* = NULL*/, + const char* apPass /* = NULL*/) : mpSQLite(NULL), mFilename(apFilename) { - const int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, apVfs); + int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, apVfs); if (SQLITE_OK != ret) { const SQLite::Exception exception(mpSQLite, ret); // must create before closing sqlite3_close(mpSQLite); // close is required even in case of error on opening throw exception; } - +#ifdef SQLITE_HAS_CODEC + if (apPass != NULL) + { + ret = sqlite3_key(mpSQLite, apPass, strlen(apPass)); + if (SQLITE_OK != ret) + { + const SQLite::Exception exception(mpSQLite, ret); // must create before closing + sqlite3_close(mpSQLite); // close is required even in case of error on opening + throw exception; + } + } +#else + if (apPass != NULL) + { + const SQLite::Exception exception("No encryption support, recompile with SQLITE_HAS_CODEC or remove the password from the constructor."); // must create before closing + sqlite3_close(mpSQLite); // close is required even in case of error on opening + throw exception; + } +#endif if (aBusyTimeoutMs > 0) { setBusyTimeout(aBusyTimeoutMs); @@ -73,18 +92,37 @@ Database::Database(const char* apFilename, Database::Database(const std::string& aFilename, const int aFlags /* = SQLite::OPEN_READONLY*/, const int aBusyTimeoutMs /* = 0 */, - const std::string& aVfs /* = "" */) : + const std::string& aVfs /* = "" */, + const std::string& aPass /* = "" */) : mpSQLite(NULL), mFilename(aFilename) { - const int ret = sqlite3_open_v2(aFilename.c_str(), &mpSQLite, aFlags, aVfs.empty() ? NULL : aVfs.c_str()); + int ret = sqlite3_open_v2(aFilename.c_str(), &mpSQLite, aFlags, aVfs.empty() ? NULL : aVfs.c_str()); if (SQLITE_OK != ret) { const SQLite::Exception exception(mpSQLite, ret); // must create before closing sqlite3_close(mpSQLite); // close is required even in case of error on opening throw exception; } - +#ifdef SQLITE_HAS_CODEC + if (!aPass.empty()) + { + ret = sqlite3_key(mpSQLite, aPass.data(), aPass.size()); + if (SQLITE_OK != ret) + { + const SQLite::Exception exception(mpSQLite, ret); // must create before closing + sqlite3_close(mpSQLite); // close is required even in case of error on opening + throw exception; + } + } +#else + if (!aPass.empty()) + { + const SQLite::Exception exception("No encryption support, recompile with SQLITE_HAS_CODEC or remove the password from the constructor."); // must create before closing + sqlite3_close(mpSQLite); // close is required even in case of error on opening + throw exception; + } +#endif if (aBusyTimeoutMs > 0) { setBusyTimeout(aBusyTimeoutMs); From 685ff293c52f90ba441454c4175c12760c4958df Mon Sep 17 00:00:00 2001 From: Jorrit Wronski Date: Thu, 22 Dec 2016 17:52:06 +0100 Subject: [PATCH 2/9] moved the key handling to a new function, added a check for an encrypted database --- include/SQLiteCpp/Database.h | 48 +++++++++++++++--- src/Database.cpp | 97 ++++++++++++++++++++---------------- 2 files changed, 97 insertions(+), 48 deletions(-) diff --git a/include/SQLiteCpp/Database.h b/include/SQLiteCpp/Database.h index f3d0b0b..fd624d5 100644 --- a/include/SQLiteCpp/Database.h +++ b/include/SQLiteCpp/Database.h @@ -84,15 +84,13 @@ public: * @param[in] aFlags SQLite::OPEN_READONLY/SQLite::OPEN_READWRITE/SQLite::OPEN_CREATE... * @param[in] aBusyTimeoutMs Amount of milliseconds to wait before returning SQLITE_BUSY (see setBusyTimeout()) * @param[in] apVfs UTF-8 name of custom VFS to use, or nullptr for sqlite3 default - * @param[in] apPass Key to decrypt (end encrypt) the database, or nullptr for unencrypted databases * * @throw SQLite::Exception in case of error */ Database(const char* apFilename, const int aFlags = SQLite::OPEN_READONLY, const int aBusyTimeoutMs = 0, - const char* apVfs = NULL, - const char* apPass = NULL); + const char* apVfs = NULL); /** * @brief Open the provided database UTF-8 filename. @@ -108,15 +106,13 @@ public: * @param[in] aFlags SQLite::OPEN_READONLY/SQLite::OPEN_READWRITE/SQLite::OPEN_CREATE... * @param[in] aBusyTimeoutMs Amount of milliseconds to wait before returning SQLITE_BUSY (see setBusyTimeout()) * @param[in] aVfs UTF-8 name of custom VFS to use, or empty string for sqlite3 default - * @param[in] aPass Key to decrypt (end encrypt) the database, or empty string for unencrypted databases * * @throw SQLite::Exception in case of error */ Database(const std::string& aFilename, const int aFlags = SQLite::OPEN_READONLY, const int aBusyTimeoutMs = 0, - const std::string& aVfs = "", - const std::string& aPass = ""); + const std::string& aVfs = ""); /** * @brief Close the SQLite database connection. @@ -373,6 +369,46 @@ public: */ void loadExtension(const char* apExtensionName, const char* apEntryPointName); + /** + * @brief Set the key for the current sqlite database instance. + * + * This is the equivalent of the sqlite3_key call and should thus be called + * directly after opening the database. If the database is unencrypted, + * this methods encrypts it immediately. + * + * @param[in] key Key to decode/encode the database + * + * @throw SQLite::Exception in case of error + */ + void key(const std::string& aKey) const noexcept; // nothrow + + /** + * @brief Reset the key for the current sqlite database instance. + * + * This is the equivalent of the sqlite3_rekey call and should thus be called + * after the database has been opened with a valid key. To decrypt a + * database, call this method with a NULL pointer. + * + * @param[in] nkey New key to encode the database + * + * @throw SQLite::Exception in case of error + */ + void rekey(const std::string& aNewKey) const noexcept; // nothrow + + /** + * @brief Test if a file contains an unencrypted database. + * + * This is a simple test that reads the first bytes of a database file and + * compares them to the standard header for unencrypted databases. If the + * header does not match the standard string, we assume that we have an + * encrypted file. + * + * @param[in] aFilename path/uri to a file + * + * @return true if the database has the standard header. + */ + const bool isUnencrypted(const std::string& aFilename) const noexcept; // nothrow + private: /// @{ Database must be non-copyable Database(const Database&); diff --git a/src/Database.cpp b/src/Database.cpp index 417a83c..30cf177 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -15,6 +15,7 @@ #include #include +#include #ifndef SQLITE_DETERMINISTIC #define SQLITE_DETERMINISTIC 0x800 @@ -51,8 +52,7 @@ int getLibVersionNumber() noexcept // nothrow Database::Database(const char* apFilename, const int aFlags /* = SQLite::OPEN_READONLY*/, const int aBusyTimeoutMs /* = 0 */, - const char* apVfs /* = NULL*/, - const char* apPass /* = NULL*/) : + const char* apVfs /* = NULL*/) : mpSQLite(NULL), mFilename(apFilename) { @@ -63,25 +63,6 @@ Database::Database(const char* apFilename, sqlite3_close(mpSQLite); // close is required even in case of error on opening throw exception; } -#ifdef SQLITE_HAS_CODEC - if (apPass != NULL) - { - ret = sqlite3_key(mpSQLite, apPass, strlen(apPass)); - if (SQLITE_OK != ret) - { - const SQLite::Exception exception(mpSQLite, ret); // must create before closing - sqlite3_close(mpSQLite); // close is required even in case of error on opening - throw exception; - } - } -#else - if (apPass != NULL) - { - const SQLite::Exception exception("No encryption support, recompile with SQLITE_HAS_CODEC or remove the password from the constructor."); // must create before closing - sqlite3_close(mpSQLite); // close is required even in case of error on opening - throw exception; - } -#endif if (aBusyTimeoutMs > 0) { setBusyTimeout(aBusyTimeoutMs); @@ -92,8 +73,7 @@ Database::Database(const char* apFilename, Database::Database(const std::string& aFilename, const int aFlags /* = SQLite::OPEN_READONLY*/, const int aBusyTimeoutMs /* = 0 */, - const std::string& aVfs /* = "" */, - const std::string& aPass /* = "" */) : + const std::string& aVfs /* = "" */) : mpSQLite(NULL), mFilename(aFilename) { @@ -104,25 +84,6 @@ Database::Database(const std::string& aFilename, sqlite3_close(mpSQLite); // close is required even in case of error on opening throw exception; } -#ifdef SQLITE_HAS_CODEC - if (!aPass.empty()) - { - ret = sqlite3_key(mpSQLite, aPass.data(), aPass.size()); - if (SQLITE_OK != ret) - { - const SQLite::Exception exception(mpSQLite, ret); // must create before closing - sqlite3_close(mpSQLite); // close is required even in case of error on opening - throw exception; - } - } -#else - if (!aPass.empty()) - { - const SQLite::Exception exception("No encryption support, recompile with SQLITE_HAS_CODEC or remove the password from the constructor."); // must create before closing - sqlite3_close(mpSQLite); // close is required even in case of error on opening - throw exception; - } -#endif if (aBusyTimeoutMs > 0) { setBusyTimeout(aBusyTimeoutMs); @@ -267,4 +228,56 @@ void Database::loadExtension(const char* apExtensionName, const char *apEntryPoi #endif } +//Set the key for the current sqlite database instance. +void Database::key(const std::string& aKey) const noexcept // nothrow +{ + int pass_len = aKey.length(); +#ifdef SQLITE_HAS_CODEC + if (pass_len > 0) { + int ret = sqlite3_key(mpSQLite, aKey.c_str(), pass_len); + check(ret); + } +#else + if (pass_len > 0) { + const SQLite::Exception exception("No encryption support, recompile with SQLITE_HAS_CODEC to use this function."); + throw exception; + } +#endif // SQLITE_HAS_CODEC +} + +// Reset the key for the current sqlite database instance. +void Database::rekey(const std::string& aNewKey) const noexcept // nothrow +{ +#ifdef SQLITE_HAS_CODEC + int pass_len = aNewKey.length(); + if (pass_len > 0) { + int ret = sqlite3_rekey(mpSQLite, aNewKey.c_str(), pass_len); + check(ret); + } else { + int ret = sqlite3_rekey(mpSQLite, nullptr, 0); + check(ret); + } +#else + const SQLite::Exception exception("No encryption support, recompile with SQLITE_HAS_CODEC to use this function."); + throw exception; +#endif // SQLITE_HAS_CODEC +} + +//Test if a file contains an unencrypted database. +const bool Database::isUnencrypted(const std::string& aFilename) const noexcept // nothrow +{ + bool encrypted_db = false; + if (aFilename.length() > 0) { + std::ifstream fileBuffer(aFilename, std::ios::in | std::ios::binary); + char header[16]; + if (fileBuffer.is_open()) { + fileBuffer.seekg(0, std::ios::beg); + fileBuffer.getline(header, 16); + fileBuffer.close(); + } + encrypted_db = strncmp(header, "SQLite format 3\000", 16) != 0; + } + return encrypted_db; +} + } // namespace SQLite From 02f8fe19c0fa18adc3f50e496bbe887154cfc799 Mon Sep 17 00:00:00 2001 From: Jorrit Wronski Date: Fri, 23 Dec 2016 07:53:55 +0100 Subject: [PATCH 3/9] Fixed some documentation and corrected the encryption detection. --- include/SQLiteCpp/Database.h | 18 ++++++++++++------ src/Database.cpp | 29 ++++++++++++++++------------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/include/SQLiteCpp/Database.h b/include/SQLiteCpp/Database.h index fd624d5..293c330 100644 --- a/include/SQLiteCpp/Database.h +++ b/include/SQLiteCpp/Database.h @@ -375,25 +375,29 @@ public: * This is the equivalent of the sqlite3_key call and should thus be called * directly after opening the database. If the database is unencrypted, * this methods encrypts it immediately. + * Normal database -> call db.key("secret") -> encrypted database, database ready + * Encrypted database -> call db.key("secret") -> database ready * - * @param[in] key Key to decode/encode the database + * @param[in] aKey Key to decode/encode the database * * @throw SQLite::Exception in case of error */ - void key(const std::string& aKey) const noexcept; // nothrow + void key(const std::string& aKey) const; /** * @brief Reset the key for the current sqlite database instance. * * This is the equivalent of the sqlite3_rekey call and should thus be called * after the database has been opened with a valid key. To decrypt a - * database, call this method with a NULL pointer. + * database, call this method with an empty string. + * Encrypted database -> call db.key("secret") -> call db.rekey("newsecret") -> change key, database ready + * Encrypted database -> call db.key("secret") -> call db.rekey("") -> decrypted database, database ready * - * @param[in] nkey New key to encode the database + * @param[in] aNewKey New key to encode the database * * @throw SQLite::Exception in case of error */ - void rekey(const std::string& aNewKey) const noexcept; // nothrow + void rekey(const std::string& aNewKey) const; /** * @brief Test if a file contains an unencrypted database. @@ -406,8 +410,10 @@ public: * @param[in] aFilename path/uri to a file * * @return true if the database has the standard header. + * + * @throw SQLite::Exception in case of error */ - const bool isUnencrypted(const std::string& aFilename) const noexcept; // nothrow + const bool isUnencrypted(const std::string& aFilename) const; private: /// @{ Database must be non-copyable diff --git a/src/Database.cpp b/src/Database.cpp index 30cf177..f24a7fd 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -56,7 +56,7 @@ Database::Database(const char* apFilename, mpSQLite(NULL), mFilename(apFilename) { - int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, apVfs); + const int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, apVfs); if (SQLITE_OK != ret) { const SQLite::Exception exception(mpSQLite, ret); // must create before closing @@ -77,7 +77,7 @@ Database::Database(const std::string& aFilename, mpSQLite(NULL), mFilename(aFilename) { - int ret = sqlite3_open_v2(aFilename.c_str(), &mpSQLite, aFlags, aVfs.empty() ? NULL : aVfs.c_str()); + const int ret = sqlite3_open_v2(aFilename.c_str(), &mpSQLite, aFlags, aVfs.empty() ? NULL : aVfs.c_str()); if (SQLITE_OK != ret) { const SQLite::Exception exception(mpSQLite, ret); // must create before closing @@ -107,8 +107,8 @@ Database::~Database() noexcept // nothrow * @brief Set a busy handler that sleeps for a specified amount of time when a table is locked. * * This is useful in multithreaded program to handle case where a table is locked for writting by a thread. - * Any other thread cannot access the table and will receive a SQLITE_BUSY error: - * setting a timeout will wait and retry up to the time specified before returning this SQLITE_BUSY error. + * Any other thread cannot access the table and will receive a SQLITE_BUSY error: + * setting a timeout will wait and retry up to the time specified before returning this SQLITE_BUSY error. * Reading the value of timeout for current connection can be done with SQL query "PRAGMA busy_timeout;". * Default busy timeout is 0ms. * @@ -229,12 +229,12 @@ void Database::loadExtension(const char* apExtensionName, const char *apEntryPoi } //Set the key for the current sqlite database instance. -void Database::key(const std::string& aKey) const noexcept // nothrow +void Database::key(const std::string& aKey) const { int pass_len = aKey.length(); #ifdef SQLITE_HAS_CODEC if (pass_len > 0) { - int ret = sqlite3_key(mpSQLite, aKey.c_str(), pass_len); + const int ret = sqlite3_key(mpSQLite, aKey.c_str(), pass_len); check(ret); } #else @@ -246,15 +246,15 @@ void Database::key(const std::string& aKey) const noexcept // nothrow } // Reset the key for the current sqlite database instance. -void Database::rekey(const std::string& aNewKey) const noexcept // nothrow +void Database::rekey(const std::string& aNewKey) const { #ifdef SQLITE_HAS_CODEC int pass_len = aNewKey.length(); if (pass_len > 0) { - int ret = sqlite3_rekey(mpSQLite, aNewKey.c_str(), pass_len); + const int ret = sqlite3_rekey(mpSQLite, aNewKey.c_str(), pass_len); check(ret); } else { - int ret = sqlite3_rekey(mpSQLite, nullptr, 0); + const int ret = sqlite3_rekey(mpSQLite, nullptr, 0); check(ret); } #else @@ -264,9 +264,8 @@ void Database::rekey(const std::string& aNewKey) const noexcept // nothrow } //Test if a file contains an unencrypted database. -const bool Database::isUnencrypted(const std::string& aFilename) const noexcept // nothrow +const bool Database::isUnencrypted(const std::string& aFilename) const { - bool encrypted_db = false; if (aFilename.length() > 0) { std::ifstream fileBuffer(aFilename, std::ios::in | std::ios::binary); char header[16]; @@ -274,10 +273,14 @@ const bool Database::isUnencrypted(const std::string& aFilename) const noexcept fileBuffer.seekg(0, std::ios::beg); fileBuffer.getline(header, 16); fileBuffer.close(); + } else { + const SQLite::Exception exception("Error opening file: " + aFilename); + throw exception; } - encrypted_db = strncmp(header, "SQLite format 3\000", 16) != 0; + return strncmp(header, "SQLite format 3\000", 16) == 0; } - return encrypted_db; + const SQLite::Exception exception("Could not open database, the aFilename parameter was empty."); + throw exception; } } // namespace SQLite From 823828fc9e1f511d1ad1cad80f42e29526288c88 Mon Sep 17 00:00:00 2001 From: Jorrit Wronski Date: Fri, 23 Dec 2016 13:52:59 +0100 Subject: [PATCH 4/9] Made encryption test static and fixed the encryption docs --- include/SQLiteCpp/Database.h | 13 ++++++------- src/Database.cpp | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/include/SQLiteCpp/Database.h b/include/SQLiteCpp/Database.h index 293c330..4044a61 100644 --- a/include/SQLiteCpp/Database.h +++ b/include/SQLiteCpp/Database.h @@ -373,10 +373,8 @@ public: * @brief Set the key for the current sqlite database instance. * * This is the equivalent of the sqlite3_key call and should thus be called - * directly after opening the database. If the database is unencrypted, - * this methods encrypts it immediately. - * Normal database -> call db.key("secret") -> encrypted database, database ready - * Encrypted database -> call db.key("secret") -> database ready + * directly after opening the database. + * Open encrypted database -> call db.key("secret") -> database ready * * @param[in] aKey Key to decode/encode the database * @@ -390,8 +388,9 @@ public: * This is the equivalent of the sqlite3_rekey call and should thus be called * after the database has been opened with a valid key. To decrypt a * database, call this method with an empty string. - * Encrypted database -> call db.key("secret") -> call db.rekey("newsecret") -> change key, database ready - * Encrypted database -> call db.key("secret") -> call db.rekey("") -> decrypted database, database ready + * Open normal database -> call db.rekey("secret") -> encrypted database, database ready + * Open encrypted database -> call db.key("secret") -> call db.rekey("newsecret") -> change key, database ready + * Open encrypted database -> call db.key("secret") -> call db.rekey("") -> decrypted database, database ready * * @param[in] aNewKey New key to encode the database * @@ -413,7 +412,7 @@ public: * * @throw SQLite::Exception in case of error */ - const bool isUnencrypted(const std::string& aFilename) const; + static const bool isUnencrypted(const std::string& aFilename); private: /// @{ Database must be non-copyable diff --git a/src/Database.cpp b/src/Database.cpp index f24a7fd..7102444 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -264,7 +264,7 @@ void Database::rekey(const std::string& aNewKey) const } //Test if a file contains an unencrypted database. -const bool Database::isUnencrypted(const std::string& aFilename) const +const bool Database::isUnencrypted(const std::string& aFilename) { if (aFilename.length() > 0) { std::ifstream fileBuffer(aFilename, std::ios::in | std::ios::binary); From a7d5ea4c2b93a4b08428b972d49f8de43eca6e00 Mon Sep 17 00:00:00 2001 From: Jorrit Wronski Date: Fri, 23 Dec 2016 14:06:36 +0100 Subject: [PATCH 5/9] Trying to gcc happy --- src/Database.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Database.cpp b/src/Database.cpp index 7102444..1606be5 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -16,6 +16,7 @@ #include #include +#include #ifndef SQLITE_DETERMINISTIC #define SQLITE_DETERMINISTIC 0x800 @@ -267,7 +268,7 @@ void Database::rekey(const std::string& aNewKey) const const bool Database::isUnencrypted(const std::string& aFilename) { if (aFilename.length() > 0) { - std::ifstream fileBuffer(aFilename, std::ios::in | std::ios::binary); + std::ifstream fileBuffer(aFilename.c_str(), std::ios::in | std::ios::binary); char header[16]; if (fileBuffer.is_open()) { fileBuffer.seekg(0, std::ios::beg); From f5a25167a474debd51e24e04cc0eb8d6f7df1f17 Mon Sep 17 00:00:00 2001 From: Jorrit Wronski Date: Fri, 23 Dec 2016 14:16:37 +0100 Subject: [PATCH 6/9] Debugging GCC build errors remotely is not fun... --- include/SQLiteCpp/Database.h | 2 +- src/Database.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/SQLiteCpp/Database.h b/include/SQLiteCpp/Database.h index 4044a61..0129809 100644 --- a/include/SQLiteCpp/Database.h +++ b/include/SQLiteCpp/Database.h @@ -12,7 +12,7 @@ #include -#include +#include // Forward declarations to avoid inclusion of in a header struct sqlite3; diff --git a/src/Database.cpp b/src/Database.cpp index 1606be5..482bf05 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -16,7 +16,7 @@ #include #include -#include +#include #ifndef SQLITE_DETERMINISTIC #define SQLITE_DETERMINISTIC 0x800 From 498525bb2653ad8d7824b56029304f9d44bc7287 Mon Sep 17 00:00:00 2001 From: Jorrit Wronski Date: Fri, 23 Dec 2016 14:20:54 +0100 Subject: [PATCH 7/9] Final modifications for cpplint and gcc --- src/Database.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Database.cpp b/src/Database.cpp index 482bf05..b97b070 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -229,7 +229,7 @@ void Database::loadExtension(const char* apExtensionName, const char *apEntryPoi #endif } -//Set the key for the current sqlite database instance. +// Set the key for the current sqlite database instance. void Database::key(const std::string& aKey) const { int pass_len = aKey.length(); @@ -240,7 +240,7 @@ void Database::key(const std::string& aKey) const } #else if (pass_len > 0) { - const SQLite::Exception exception("No encryption support, recompile with SQLITE_HAS_CODEC to use this function."); + const SQLite::Exception exception("No encryption support, recompile with SQLITE_HAS_CODEC to enable."); throw exception; } #endif // SQLITE_HAS_CODEC @@ -264,7 +264,7 @@ void Database::rekey(const std::string& aNewKey) const #endif // SQLITE_HAS_CODEC } -//Test if a file contains an unencrypted database. +// Test if a file contains an unencrypted database. const bool Database::isUnencrypted(const std::string& aFilename) { if (aFilename.length() > 0) { From d26bd2cb8aeba00908d4b0445c07f2783b58f096 Mon Sep 17 00:00:00 2001 From: Jorrit Wronski Date: Fri, 23 Dec 2016 14:49:28 +0100 Subject: [PATCH 8/9] Added tests for the encrypted database --- src/Database.cpp | 2 +- tests/Database_test.cpp | 69 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/Database.cpp b/src/Database.cpp index b97b070..45e2463 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -259,7 +259,7 @@ void Database::rekey(const std::string& aNewKey) const check(ret); } #else - const SQLite::Exception exception("No encryption support, recompile with SQLITE_HAS_CODEC to use this function."); + const SQLite::Exception exception("No encryption support, recompile with SQLITE_HAS_CODEC to enable."); throw exception; #endif // SQLITE_HAS_CODEC } diff --git a/tests/Database_test.cpp b/tests/Database_test.cpp index e38c101..0e49bef 100644 --- a/tests/Database_test.cpp +++ b/tests/Database_test.cpp @@ -258,3 +258,72 @@ TEST(Database, execException) { // TODO: test Database::createFunction() // TODO: test Database::loadExtension() + +#ifdef SQLITE_HAS_CODEC +TEST(Database, encryptAndDecrypt) { + remove("test.db3"); + { + // Try to open the non-existing database + EXPECT_THROW(SQLite::Database not_found("test.db3"), SQLite::Exception); + + // Create a new database + SQLite::Database db("test.db3", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE); + EXPECT_FALSE(db.tableExists("test")); + db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)"); + EXPECT_TRUE(db.tableExists("test")); + } // Close DB test.db3 + { + // Reopen the database file and encrypt it + EXPECT_TRUE(SQLite::Database::isUnencrypted("test.db3")); + SQLite::Database db("test.db3", SQLite::OPEN_READWRITE); + // Encrypt the database + db.rekey("123secret"); + } // Close DB test.db3 + { + // Reopen the database file and try to use it + EXPECT_FALSE(SQLite::Database::isUnencrypted("test.db3")); + SQLite::Database db("test.db3", SQLite::OPEN_READONLY); + EXPECT_THROW(db.tableExists("test"), SQLite::Exception); + db.key("123secret"); + EXPECT_TRUE(db.tableExists("test")); + } // Close DB test.db3 + { + // Reopen the database file and decrypt it + EXPECT_FALSE(SQLite::Database::isUnencrypted("test.db3")); + SQLite::Database db("test.db3", SQLite::OPEN_READWRITE); + // Decrypt the database + db.key("123secret"); + db.rekey(""); + } // Close DB test.db3 + { + // Reopen the database file and use it + EXPECT_TRUE(SQLite::Database::isUnencrypted("test.db3")); + SQLite::Database db("test.db3", SQLite::OPEN_READWRITE); + EXPECT_TRUE(db.tableExists("test")); + } // Close DB test.db3 + remove("test.db3"); +} +#else SQLITE_HAS_CODEC +TEST(Database, encryptAndDecrypt) { + remove("test.db3"); + { + // Try to open the non-existing database + EXPECT_THROW(SQLite::Database not_found("test.db3"), SQLite::Exception); + + // Create a new database + SQLite::Database db("test.db3", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE); + EXPECT_FALSE(db.tableExists("test")); + db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)"); + EXPECT_TRUE(db.tableExists("test")); + } // Close DB test.db3 + { + // Reopen the database file and encrypt it + EXPECT_TRUE(SQLite::Database::isUnencrypted("test.db3")); + SQLite::Database db("test.db3", SQLite::OPEN_READWRITE); + // Encrypt the database + EXPECT_THROW(db.key("123secret"), SQLite::Exception); + EXPECT_THROW(db.rekey("123secret"), SQLite::Exception); + } // Close DB test.db3 + remove("test.db3"); +} +#endif SQLITE_HAS_CODEC \ No newline at end of file From dbd31fb56b7a4b94244c03a1156b192700262afd Mon Sep 17 00:00:00 2001 From: Jorrit Wronski Date: Fri, 23 Dec 2016 14:56:44 +0100 Subject: [PATCH 9/9] Fixed some compiler warnings --- src/Database.cpp | 4 ++-- tests/Database_test.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Database.cpp b/src/Database.cpp index 45e2463..cfa5447 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -238,7 +238,7 @@ void Database::key(const std::string& aKey) const const int ret = sqlite3_key(mpSQLite, aKey.c_str(), pass_len); check(ret); } -#else +#else // SQLITE_HAS_CODEC if (pass_len > 0) { const SQLite::Exception exception("No encryption support, recompile with SQLITE_HAS_CODEC to enable."); throw exception; @@ -258,7 +258,7 @@ void Database::rekey(const std::string& aNewKey) const const int ret = sqlite3_rekey(mpSQLite, nullptr, 0); check(ret); } -#else +#else // SQLITE_HAS_CODEC const SQLite::Exception exception("No encryption support, recompile with SQLITE_HAS_CODEC to enable."); throw exception; #endif // SQLITE_HAS_CODEC diff --git a/tests/Database_test.cpp b/tests/Database_test.cpp index 0e49bef..b42e89c 100644 --- a/tests/Database_test.cpp +++ b/tests/Database_test.cpp @@ -303,7 +303,7 @@ TEST(Database, encryptAndDecrypt) { } // Close DB test.db3 remove("test.db3"); } -#else SQLITE_HAS_CODEC +#else // SQLITE_HAS_CODEC TEST(Database, encryptAndDecrypt) { remove("test.db3"); { @@ -326,4 +326,4 @@ TEST(Database, encryptAndDecrypt) { } // Close DB test.db3 remove("test.db3"); } -#endif SQLITE_HAS_CODEC \ No newline at end of file +#endif // SQLITE_HAS_CODEC \ No newline at end of file