Giter Site home page Giter Site logo

cwac-saferoom's Introduction

CWAC-SafeRoom: A Room<->SQLCipher for Android Bridge

This project implements the Support... series of classes and interfaces that Room can use for working with a particular edition of SQLite. Specficially, this project's classes connect Room with SQLCipher for Android, a version of SQLite that offers transparent encryption of its contents.

Notable Forks

Installation

There are two versions of this library, for AndroidX and for the older Android Support Library.

If you cannot use SSL, use http://repo.commonsware.com for the repository URL.

AndroidX

repositories {
    maven {
        url "https://s3.amazonaws.com/repo.commonsware.com"
    }
}

dependencies {
    implementation "com.commonsware.cwac:saferoom.x:1.1.1"
}

Android Support Library

repositories {
    maven {
        url "https://s3.amazonaws.com/repo.commonsware.com"
    }
}

dependencies {
    implementation "com.commonsware.cwac:saferoom:1.1.1"
}

Usage

When you use Room, you use Room.databaseBuilder() or Room.inMemoryDatabaseBuilder() to get a RoomDatabase.Builder. After configuring that object, you call build() to get an instance of your custom subclass of RoomDatabase, whichever one that you supplied as a Java class object to the Room.databaseBuilder() or Room.inMemoryDatabaseBuilder() method.

To use SafeRoom, on the RoomDatabase.Builder, before calling build():

  • Create an instance of com.commonsware.cwac.saferoom.SafeHelperFactory, passing in the passphrase to use

  • Pass that SafeHelperFactory to the RoomDatabase.Builder via the openHelperFactory() method

// EditText passphraseField;
SafeHelperFactory factory=SafeHelperFactory.fromUser(passphraseField.getText());

StuffDatabase db=Room.databaseBuilder(ctxt, StuffDatabase.class, DB_NAME)
  .openHelperFactory(factory)
  .build();

Supplying a Passphrase

A cardinal rule of passphrases in Java is: do not hold them in String objects. You have no means of clearing those from memory, as a String is an immutable value.

The SafeHelperFactory constructor takes a either a byte[] or a char[] for the passphrase. If you are getting the passphrase from the user via an EditText widget, use the fromUser() factory method instead, supplying the Editable that you get from getText() on the EditText.

SafeRoom will zero out the byte[] or char[] once the database is opened. If you use fromUser(), SafeRoom will also clear the contents of the Editable.

Encrypting Existing Databases

If you have an existing SQLite database — created with Room or otherwise — the SQLCipherUtils class has getDatabaseState() and encrypt() methods for you.

getDatabaseState() returns a State object indicating whether a database is ENCRYPTED, UNENCRYPTED, or DOES_NOT_EXIST. The determination of whether the database is unencrypted is based on whether we can open it without a passphrase. There are two versions of getDatabaseState():

  • getDatabaseState(Context, String) for a Context and database name

  • getDatabaseState(File), where the File points to the database

encrypt() will take an unencrypted database as input and encrypt it using the supplied passphrase. Technically, it will encrypt a copy of the database, then delete the unencrypted one and rename the copy to the original name. There are five versions of encrypt():

  • encrypt(Context, String, Editable) where the String is the database name and the Editable is the passphrase (e.g., from getText() on an EditText)

  • encrypt(Context, String, char[]) where the String is the database name and the char[] is the passphrase

  • encrypt(Context, File, char[]) where the File points to the database and the char[] is the passphrase

  • encrypt(Context, String, byte[]) where the String is the database name and the byte[] is the passphrase

  • encrypt(Context, File, byte[]) where the File points to the database and the byte[] is the passphrase

The passphrase is left untouched by encrypt(), so you can turn around and use it with SafeHelperFactory. If you are not planning on opening the database, please clear out the passphrase after encrypt() returns.

Only call encrypt() when the database is closed. Ideally, call encrypt() before opening the database in Room. At minimum, call close() on your RoomDatabase before calling encrypt().

Changing the Passphrase

If you want to change the passphrase for an existing database:

  • Open it in writeable mode

  • Call SafeHelperFactory.rekey(), supplying that database plus either a char[] or an Editable reflecting the new passphrase to use

Note that this does not encrypt an unencrypted database. Use the encrypt() option listed above for that.

The Editable will be cleared as part of this work, but the char[] will not be zero'd out. Please clear that array as soon as you are done with it.

Decrypting Existing Databases

You can call decrypt() on SQLCipherUtils to decrypt an existing SQLCipher-encrypted database. Supply the Context, the File pointing to the database, and a char[] or byte[] with the passphrase. decrypt() will replace the encrypted database with a decrypted one, so that database can be opened using ordinary SQLite.

Upgrading to 1.0.0 and Higher

SafeRoom 1.x uses SQLCipher for Android 4.x. SafeRoom 0.x used SQLCipher for Android 3.x.

The problem is that Zetetic changed the SQLCipher for Android file format between 3.x and 4.x.

If you have existing SQLCipher for Android 3.x files, you will need to do a bit of extra work for existing databases in the older format.

Keeping the Old Format

Perhaps you have a strong need to keep the database in the older format, for whatever reason. In that case, pass SafeHelperFactory.POST_KEY_SQL_V3 as the second parameter to either the SafeHelperFactory constructor or fromUser() static method:

SafeHelperFactory factory=
  SafeHelperFactory.fromUser(new SpannableStringBuilder(passphraseField.getText()),
    SafeHelperFactory.POST_KEY_SQL_V3);

This will open the database using PRAGMA cipher_compatibility = 3;, which was introduced in SQLCipher for Android 4.0.1.

Migrating to the New Format

If you wish to convert to the newer, more secure settings, the first time that you open the existing database, pass SafeHelperFactory.POST_KEY_SQL_MIGRATE as the second parameter to the SafeHelperFactory constructor or fromUser() static method:

SafeHelperFactory factory=
  SafeHelperFactory.fromUser(new SpannableStringBuilder(passphraseField.getText()),
    SafeHelperFactory.POST_KEY_SQL_MIGRATE);

This will convert the existing database in place. The second and subsequent times that you work with the database, you can (and should) skip this parameter, as the database will have already been migrated.

Support for Pre-Key and Post-Key SQL

SQLCipher for Android supports a number of custom PRAGMAs for configuring the encryption, such as the number of PBKDF2 iterations to use for key stretching. Some of that SQL needs to be performed at specific times with respect to opening the database.

For SQL that needs to be executed after the database key is set but before you get to start using the database, you can pass the SQL in as a parameter to the SafeHelperFactory constructor or fromUser() methods — that is what the upgrade options in the preceding sections are doing.

More formally, you can pass a SafeHelperFactory.Options object as the second parameter, supplying both pre-key and post-key SQL statements to be executed. You can create an Options object by calling the builder() static method on Options, calling setters for the SQL, then build() to get the options:

SafeHelperFactory.Options options = SafeHelperFactory.Options.builder().setPreKeySql(PREKEY_SQL).build();

Dependencies

As one might expect, this project depends on SQLCipher for Android.

This project also depends upon android.arch.persistence:db (Android Support Library edition) or androidx.sqlite:sqlite-framework (AndroidX edition), which is the support database API that Room uses.

The Android Support Library edition of CWAC-SafeRoom is frozen at supporting 1.1.1 of android.arch.persistence:db.

The AndroidX edition of CWAC-SafeRoom supports 2.0.1 of androidx.sqlite:sqlite-framework and should be updated to support newer versions of AndroidX over time.

Tests

This project has two sources of tests. Some are local to the project. The rest come from the support-db-tests project. That project contains tests that exercise any support database API implementation.

TL;DR: to run the full set of CWAC-SafeRoom tests, use SafeRoomSuite. Either run that directly from your IDE, or set up a run configuration pointing to it, etc.

Version

This is version v1.1.1 of this library.

Additional Documentation

JavaDocs are available, though most of the library is not public, as it does not need to be.

Android's Architecture Components contains a chapter dedicated to SafeRoom.

License

The code in this project is licensed under the Apache Software License 2.0, per the terms of the included LICENSE file. The copyrights are owned by CommonsWare for things unique to this library and a combination of CommonsWare and the Android Open Source Project for code modified from the Architecture Components' Framework* set of classes.

Questions

If you have questions regarding the use of this code, please post a question on Stack Overflow tagged with commonsware-cwac and android after searching to see if there already is an answer. Be sure to indicate what CWAC module you are having issues with, and be sure to include source code and stack traces if you are encountering crashes.

If you have encountered what is clearly a bug, or if you have a feature request, please post an issue. Be certain to include complete steps for reproducing the issue. The contribution guidelines provide some suggestions for how to create a bug report that will get the problem fixed the fastest.

You are also welcome to join the CommonsWare Community and post questions and ideas to the CWAC category.

Do not ask for help via social media.

Also, if you plan on hacking on the code with an eye for contributing something back, please open an issue that we can use for discussing implementation details. Just lobbing a pull request over the fence may work, but it may not. Again, the contribution guidelines provide a bit of guidance here.

Release Notes

Android X

  • v1.1.1: fixed a bug in BindingsRecorder
  • v1.1.0: added SafeHelperFactory.Options and support for pre-key SQL
  • v1.0.5: upgraded to SQLCipher for Android 4.2.0
  • v1.0.4: added support for byte[] passphrases to SQLCipherUtils
  • v1.0.3: added support for byte[] passphrases
  • v1.0.2: upgraded to SQLCipher for Android 4.1.3
  • v1.0.1: changed SQLCipherUtils per issue #45
  • v1.0.0:
    • Upgraded to SQLCipher for Android 4.0.1
    • SQLCipherUtils.encrypt() and SQLCipherUtils.decrypt() will throw FileNotFoundException if the database to encrypt/decrypt is not found
  • v0.5.1: added more synchronization
  • v0.5.0: released AndroidX edition

Android Support Library

  • v1.1.1: fixed a bug in BindingsRecorder
  • v1.1.0: added SafeHelperFactory.Options and support for pre-key SQL
  • v1.0.5: upgraded to SQLCipher for Android 4.2.0
  • v1.0.4: added support for byte[] passphrases to SQLCipherUtils
  • v1.0.3: added support for byte[] passphrases
  • v1.0.2: upgraded to SQLCipher for Android 4.1.3
  • v1.0.1: changed SQLCipherUtils per issue #45
  • v1.0.0:
    • Upgraded to SQLCipher for Android 4.0.1
    • SQLCipherUtils.encrypt() and SQLCipherUtils.decrypt() will throw FileNotFoundException if the database to encrypt/decrypt is not found
  • v0.4.5: added more synchronization
  • v0.4.4: addressed thread-safety issue
  • v0.4.3: bumped android.arch.persistence:db dependency to 1.1.1
  • v0.4.2: fixed edge case WAL issue
  • v0.4.1: added Room-specific tests, fixed WAL issue
  • v0.4.0: updated to 1.1.0 of the support database API
  • v0.3.4: changed non-WAL journal mode to TRUNCATE
  • v0.3.3: added WAL support, with an assist from plackemacher
  • v0.3.2: added decrypt() utility method
  • v0.3.1: changed rekey() to use the existing changePassword()
  • v0.3.0: added rekey(), upgraded to SQLCipher for Android 3.5.9, replaced tests
  • v0.2.1: added temporary implementation of getDatabaseName() to Helper
  • v0.2.0: added SQLCipherUtils to help encrypt existing databases
  • v0.1.3: upgraded to Android Gradle Plugin 3.0.0, set transitive dependencies to api
  • v0.1.2: fixed issue #3, related to closing statements
  • v0.1.1: updated support database dependency to 1.0.0
  • v0.1.0: eliminated Room dependency
  • v0.0.4: raised Room dependencies to 1.0.0-beta1 and SQLCipher for Android to 3.5.7
  • v0.0.3: raised Room dependencies to 1.0.0-alpha8
  • v0.0.2: raised Room dependencies to 1.0.0-alpha5
  • v0.0.1: initial release

Who Made This?

CommonsWare

cwac-saferoom's People

Contributors

commonsguy avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.