Skip to content

Commit

Permalink
Added encryption support, and local copy of SQLCipher
Browse files Browse the repository at this point in the history
  • Loading branch information
snej committed Jul 9, 2024
1 parent 500beeb commit 14fb017
Show file tree
Hide file tree
Showing 7 changed files with 275,706 additions and 11 deletions.
39 changes: 35 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)


option(USE_LOCAL_SQLITE "Use copy of sqlite in the vendor subdirectory" OFF)
option(USE_LOCAL_SQLITE "Use copy of sqlite in the vendor subdirectory" OFF)
option(USE_LOCAL_SQLCIPHER "Use copy of SQLCipher in the vendor subdirectory" OFF)


#### CONFIG
Expand All @@ -30,7 +31,6 @@ else()
-Wall
-Wpedantic
-Wno-unknown-pragmas
-Wno-unknown-warning-option
)
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
# GCC-specific:
Expand All @@ -51,7 +51,11 @@ else()
endif()


if (USE_LOCAL_SQLITE)
if (USE_LOCAL_SQLCIPHER)
include_directories( BEFORE SYSTEM
vendor/sqlcipher/
)
elseif (USE_LOCAL_SQLITE)
include_directories( BEFORE SYSTEM
vendor/sqlite/
)
Expand All @@ -71,7 +75,34 @@ target_include_directories( sqnice PUBLIC
include/
)

if (USE_LOCAL_SQLITE)
if (USE_LOCAL_SQLCIPHER)
target_sources( sqnice PRIVATE
vendor/sqlcipher/sqlite3.c
)
set_source_files_properties(
vendor/sqlcipher/sqlite3.c PROPERTIES COMPILE_OPTIONS "-Wno-error"
)
target_compile_definitions(sqnice PRIVATE
SQLITE_HAS_CODEC
SQLITE_TEMP_STORE=3
)
if(APPLE)
target_compile_definitions(sqnice PRIVATE
SQLCIPHER_CRYPTO_CC # Use Apple's CommonCrypto lib for encryption
)
target_link_libraries( sqnice INTERFACE
"-framework CoreFoundation"
"-framework Security"
)
else()
target_compile_definitions(sqnice PRIVATE
SQLCIPHER_CRYPTO_OPENSSL
)
target_link_libraries( sqnice INTERFACE
crypto
)
endif()
elseif (USE_LOCAL_SQLITE)
target_sources( sqnice PRIVATE
vendor/sqlite/sqlite3.c
)
Expand Down
10 changes: 5 additions & 5 deletions include/sqnice/base.hh
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,16 @@ namespace sqnice {

/** A SQLite error code. Values are the same as `SQLITE_OK`, `SQLITE_ERROR`, ... */
enum class status : int {
ok = 0, cantopen = 14,
ok = 0, cantopen = 14, done = 101,
error = 1, constraint = 19,
perm = 3, mismatch = 20,
abort = 4, misuse = 21,
busy = 5, auth = 23,
locked = 6, range = 25,
readonly = 8, notice = 27,
interrupt = 9, warning = 28,
ioerr = 10, row = 100,
corrupt = 11, done = 101,
readonly = 8, not_a_db = 26,
interrupt = 9, notice = 27,
ioerr = 10, warning = 28,
corrupt = 11, row = 100,
};

/// Masks out other bits set in extended status codes
Expand Down
25 changes: 23 additions & 2 deletions include/sqnice/database.hh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "sqnice/base.hh"
#include <functional>
#include <optional>
#include <span>
#include <tuple>

ASSUME_NONNULL_BEGIN
Expand Down Expand Up @@ -114,7 +115,7 @@ namespace sqnice {
const char* _Nullable vfs = nullptr);

/// Constructs an instance that isn't connected to any database.
/// You must call `connect` before doing anything else with it.
/// You must call `open` before doing anything else with it.
database() noexcept;

/// Constructs an instance that uses an already-open SQLite database handle.
Expand Down Expand Up @@ -406,7 +407,6 @@ namespace sqnice {
nullptr, stepx_impl<T, Ps...>, finishN_impl<T>, nullptr);
}


#pragma mark - MAINTENANCE

/// Runs `PRAGMA incremental_vacuum(N)`. This causes up to N free pages to be removed from
Expand Down Expand Up @@ -436,6 +436,27 @@ namespace sqnice {
const backup_handler& h,
int step_page = 5);

#pragma mark - ENCRYPTED DATABASES:

/// True if sqnice was built with encryption support (SQLCipher or SEE)
static const bool encryption_available;

/// Unlocks an encrypted database, or makes a newly-created database encrypted,
/// by providing the key to use to encrypt/decrypt data.
///
/// This should be called immediately after opening the database, since no data can be
/// read from an encrypted database without the key, and encryption can't be enabled in
/// a new database once data has been written to it.
/// @note This function requires SQLCipher or the SQLite Encryption Extension.
/// Otherwise it returns/throws status::error.
status use_encryption_key(std::span<const std::byte> key);

/// Changes the encryption key of an already-encrypted database.
/// Will not encrypt an existing unencrypted database!
/// @note This function requires SQLCipher or the SQLite Encryption Extension.
/// Otherwise it returns/throws status::error.
status rekey(std::span<const std::byte> newKey);

#pragma mark - LOGGING

using log_handler = std::function<void (status, const char* message)>;
Expand Down
26 changes: 26 additions & 0 deletions src/database.cc
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,32 @@ namespace sqnice {
}


#pragma mark - ENCRYPTION:


#ifdef SQLITE_HAS_CODEC
// See <https://www.zetetic.net/sqlcipher/sqlcipher-api/>

const bool database::encryption_available = true;

status database::use_encryption_key(std::span<const std::byte> key) {
return check(sqlite3_key(check_handle(), key.data(), int(key.size())));
}

status database::rekey(std::span<const std::byte> newKey) {
return check(sqlite3_rekey(check_handle(), newKey.data(), int(newKey.size())));
}

#else
const bool database::encryption_available = false;
status database::use_encryption_key(std::span<const std::byte> key) {
return check(status::error);
}
status database::rekey(std::span<const std::byte> newKey) {
return check(status::error);
}
#endif


#pragma mark - HOOKS:

Expand Down
Loading

0 comments on commit 14fb017

Please sign in to comment.