Skip to content
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

Hidden early PRAGMAs prevent using SQLCipher #621

Closed
kashikoibumi opened this issue Aug 8, 2020 · 5 comments
Closed

Hidden early PRAGMAs prevent using SQLCipher #621

kashikoibumi opened this issue Aug 8, 2020 · 5 comments

Comments

@kashikoibumi
Copy link

In order to use encryption with SQLCipher,
it is required to issue "PRAGMA key = 'passphrase'" as the first command
just after connected.

But, current implementation of SQLx always issues
"PRAGMA journal_mode = {}; PRAGMA foreign_keys = {};"
just after connected before any user's command issued.
That prevents using SQLx with SQLCipher.

@kashikoibumi
Copy link
Author

Specifying journal_mode Delete on SqliteConnectOptions resolved the issue.
Sorry for disturbing.

@kashikoibumi
Copy link
Author

Creating a database can be resolved by specifying journal_mode Delete on SqliteConnectOptions,
but when reopened the created database cannot be read.
The reason is same, hidden PRAGMAs.

@kashikoibumi kashikoibumi reopened this Aug 9, 2020
@kashikoibumi
Copy link
Author

SQLx's SQLite support depends on libsqlite3-sys which also supports SQLCipher in addition to SQLite.
If you specify

libsqlite3-sys = { version = "0.18.0", features = ["sqlcipher"] }

in your application's Cargo.toml, SQLx will use SQLCipher via libsqlite3-sys.

SQLCipher source code is not bundled with libsqlite3-sys.
On Debian buster or derived distro, if libsqlcipher-dev package is installed its library file will be used.
The Debian package version of SQLCipher is sufficient for rusqlite, but not for SQLx.
When building SQLx, it complains that symbol sqlite3_prepare_v3 is undefined.

In replacement, a SQLCipher built from its source code retrieved from GitHub can be used with SQLx.
v3.4.2 tag version works.
I built it as follows:

./configure --prefix=$HOME/local --enable-load-extension=yes --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC -DSQLITE_ENABLE_COLUMN_METADATA"
make
make install

Note, if you omit SQLITE_ENABLE_COLUMN_METADATA, SQLx complains again that symbol sqlite3_column_origin_name is undefined.
And note, before running cargo build, set the environment variables as follows:

export LD_LIBRARY_PATH=$HOME/local/lib
export PKG_CONFIG_PATH=$HOME/local/lib/pkgconfig

To test disabling SQLx's hidden early PRAGMAs, modify connect function in sqlx-core/src/sqlite/options/connect.rs commenting out not to execute PRAGMAs.

    fn connect(&self) -> BoxFuture<'_, Result<Self::Connection, Error>>
    where
        Self::Connection: Sized,
    {
        Box::pin(async move {
            let mut conn = establish(self).await?;

/*
            // send an initial sql statement comprised of options
            let init = format!(
                "PRAGMA journal_mode = {}; PRAGMA foreign_keys = {};",
                self.journal_mode.as_str(),
                if self.foreign_keys { "ON" } else { "OFF" }
            );

            conn.execute(&*init).await?;
*/

            Ok(conn)
        })

In your application issue "PRAGMA key = 'passphrase'" as the first command after connection, and encryption works.

@igalic
Copy link

igalic commented Aug 10, 2020

BTW, Diesel allows you to implement the CustomizeConnection, and then hook that into the Builder.something like that would be very useful for SQLx as well

@abonander
Copy link
Collaborator

Closed by #1295

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants