Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[RFC] Minimal SQLCipher support #77

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Feb 16, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ addons:
- gcc-5
- g++-5
- libsqlite3-dev
- libsqlcipher-dev
- libboost-all-dev

before_install:
- export CXX="g++-5" CC="gcc-5"

script: ./configure && make test && make clean && make LDFLAGS="-lsqlcipher -DENABLE_SQLCIPHER_TESTS" test
2 changes: 1 addition & 1 deletion Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ tests/%.result_: tests/%.test
a=$$? ;\
if [ $$a != 0 ]; \
then \
if [ $$a -ge 128 and ] ; \
if [ $$a -ge 128 ] ; \
then \
echo Crash!! > $@ ; \
elif [ $$a -eq 42 ] ;\
Expand Down
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,47 @@ NDK support
Just Make sure you are using the full path of your database file :
`sqlite::database db("/data/data/com.your.package/dbfile.db")`.

SQLCipher
----

The library has native support for [SQLCipher](https://www.zetetic.net/sqlcipher/). If you want to use encrypted databases, you have to include the `sqlite_moder_cpp/sqlcipher.h` header.
Then you can create a `sqlcipher_database`.

```c++
#include<iostream>
#include <sqlite_modern_cpp/sqlcipher.h>
using namespace sqlite;
using namespace std;

int main() {

try {
// creates a database file 'dbfile.db' if it does not exists with password 'secret'
sqlcipher_config config;
config.key = secret;
sqlcipher_database db("dbfile.db", config);

// executes the query and creates a 'user' table
db <<
"create table if not exists user ("
" _id integer primary key autoincrement not null,"
" age int,"
" name text,"
" weight real"
");";

// More queries

db.rekey("new_secret"); // Change the password of the already encrypted database.

// Even more queries
}
catch (exception& e) {
cout << e.what() << endl;
}
}
```

Building and Installing
----

Expand Down
16 changes: 13 additions & 3 deletions hdr/sqlite_modern_cpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ namespace sqlite {
std::is_floating_point<Type>::value
|| std::is_integral<Type>::value
|| std::is_same<sqlite_int64, Type>::value
> { };
> { };


template<typename T> friend database_binder& operator <<(database_binder& db, const T& val);
Expand Down Expand Up @@ -318,8 +318,11 @@ namespace sqlite {
}
};

struct sqlite_config {
};

class database {
private:
protected:
std::shared_ptr<sqlite3> _db;

public:
Expand All @@ -342,6 +345,14 @@ namespace sqlite {
database(std::shared_ptr<sqlite3> db):
_db(db) {}

database(const std::string &db_name, const sqlite_config &config): database(db_name) {
(void)config; // Suppress unused warning
}

database(const std::u16string &db_name, const sqlite_config &config): database(db_name) {
(void)config; // Suppress unused warning
}

database_binder operator<<(const std::string& sql) {
return database_binder(_db, sql);
}
Expand All @@ -363,7 +374,6 @@ namespace sqlite {
sqlite3_int64 last_insert_rowid() const {
return sqlite3_last_insert_rowid(_db.get());
}

};

template<std::size_t Count>
Expand Down
44 changes: 44 additions & 0 deletions hdr/sqlite_modern_cpp/sqlcipher.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once

#ifndef SQLITE_HAS_CODEC
#define SQLITE_HAS_CODEC
#endif

#include "../sqlite_modern_cpp.h"

namespace sqlite {
struct sqlcipher_config : public sqlite_config {
std::string key;
};

class sqlcipher_database : public database {
public:
sqlcipher_database(std::string db, const sqlcipher_config &config): database(db, config) {
set_key(config.key);
}

sqlcipher_database(std::u16string db, const sqlcipher_config &config): database(db, config) {
set_key(config.key);
}

void set_key(const std::string &key) {
if(auto ret = sqlite3_key(_db.get(), key.data(), key.size()))
exceptions::throw_sqlite_error(ret);
}

void set_key(const std::string &key, const std::string &db_name) {
if(auto ret = sqlite3_key_v2(_db.get(), db_name.c_str(), key.data(), key.size()))
exceptions::throw_sqlite_error(ret);
}

void rekey(const std::string &new_key) {
if(auto ret = sqlite3_rekey(_db.get(), new_key.data(), new_key.size()))
exceptions::throw_sqlite_error(ret);
}

void rekey(const std::string &new_key, const std::string &db_name) {
if(auto ret = sqlite3_rekey_v2(_db.get(), db_name.c_str(), new_key.data(), new_key.size()))
exceptions::throw_sqlite_error(ret);
}
};
}
90 changes: 90 additions & 0 deletions tests/sqlcipher.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#ifdef ENABLE_SQLCIPHER_TESTS
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <sqlite_modern_cpp/sqlcipher.h>
using namespace sqlite;
using namespace std;

struct TmpFile
{
string fname;

TmpFile()
{
char f[]="/tmp/sqlite_modern_cpp_test_XXXXXX";
int fid = mkstemp(f);
close(fid);

fname = f;
}

~TmpFile()
{
unlink(fname.c_str());
}
};

int main()
{
try
{
TmpFile file;
sqlcipher_config config;
{
config.key = "DebugKey";
sqlcipher_database db(file.fname, config);

db << "CREATE TABLE foo (a integer, b string);";
db << "INSERT INTO foo VALUES (?, ?)" << 1 << "hello";
db << "INSERT INTO foo VALUES (?, ?)" << 2 << "world";

string str;
db << "SELECT b from FOO where a=?;" << 2 >> str;

if(str != "world")
{
cout << "Bad result on line " << __LINE__ << endl;
exit(EXIT_FAILURE);
}
}
try {
config.key = "DebugKey2";
sqlcipher_database db(file.fname, config);
db << "INSERT INTO foo VALUES (?, ?)" << 3 << "fail";

cout << "Can open with wrong key";
exit(EXIT_FAILURE);
} catch(exceptions::notadb) {
// Expected, wrong key
}
{
config.key = "DebugKey";
sqlcipher_database db(file.fname, config);
db.rekey("DebugKey2");
}
{
config.key = "DebugKey2";
sqlcipher_database db(file.fname, config);
db << "INSERT INTO foo VALUES (?, ?)" << 3 << "fail";
}
}
catch(sqlite_exception e)
{
cout << "Unexpected error " << e.what() << endl;
exit(EXIT_FAILURE);
}
catch(...)
{
cout << "Unknown error\n";
exit(EXIT_FAILURE);
}

cout << "OK\n";
exit(EXIT_SUCCESS);
}
#else
int main() {
return 42; //Skip test
}
#endif