From 505cb7c4f6a7e4dac3c9b7999b6d9266edbaa67a Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Mon, 25 Sep 2023 11:09:39 -0500 Subject: [PATCH 1/6] Add license file --- LICENSE | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7167add --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2008-2023, ZETETIC LLC +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the ZETETIC LLC nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From b5b6c6e3b45561757e034677028c86dc02a88d73 Mon Sep 17 00:00:00 2001 From: Eliezer Graber Date: Mon, 6 Nov 2023 13:54:50 -0500 Subject: [PATCH 2/6] Add proguard rules for consumers --- sqlcipher/build.gradle | 1 + sqlcipher/consumer-rules.pro | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 sqlcipher/consumer-rules.pro diff --git a/sqlcipher/build.gradle b/sqlcipher/build.gradle index 714392e..ba1a415 100644 --- a/sqlcipher/build.gradle +++ b/sqlcipher/build.gradle @@ -12,6 +12,7 @@ android { versionName "${rootProject.ext.libraryVersion}" project.archivesBaseName = "sqlcipher-android-${versionName}" testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + consumerProguardFile 'consumer-rules.pro' } buildTypes { diff --git a/sqlcipher/consumer-rules.pro b/sqlcipher/consumer-rules.pro new file mode 100644 index 0000000..0f8a20c --- /dev/null +++ b/sqlcipher/consumer-rules.pro @@ -0,0 +1,18 @@ +-keep class net.zetetic.** { + native ; + private native ; + public (...); + long mNativeHandle; +} + +-keepclassmembers class net.zetetic.database.sqlcipher.SQLiteCustomFunction { + public java.lang.String name; + public int numArgs; + private void dispatchCallback(java.lang.String[]); +} + +-keepclassmembers class net.zetetic.database.sqlcipher.SQLiteDebug$PagerStats { + public int largestMemAlloc; + public int memoryUsed; + public int pageCacheOverflow; +} From d3dc1ef0f8b7b1196e80ebd2c92f9619aa4751b1 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Wed, 8 Nov 2023 16:49:25 -0600 Subject: [PATCH 3/6] Source min SDK version from project extension properties --- README.md | 2 +- README.md.template | 2 +- build.gradle | 4 +++- sqlcipher/build.gradle | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b9f5580..9c17acb 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ SQLCipher for Android provides a library replacement for `android.database.sqlit ### Compatibility -SQLCipher for Android supports Android API 16 and up on `armeabi-v7a`, `x86`, `x86_64`, and `arm64_v8a` architectures. +SQLCipher for Android supports Android API 21 and up on `armeabi-v7a`, `x86`, `x86_64`, and `arm64_v8a` architectures. ### Contributions diff --git a/README.md.template b/README.md.template index 8b43a7c..9574225 100644 --- a/README.md.template +++ b/README.md.template @@ -6,7 +6,7 @@ SQLCipher for Android provides a library replacement for `android.database.sqlit ### Compatibility -SQLCipher for Android supports Android API 16 and up on `armeabi-v7a`, `x86`, `x86_64`, and `arm64_v8a` architectures. +SQLCipher for Android supports Android API <%=minSdkVersion%> and up on `armeabi-v7a`, `x86`, `x86_64`, and `arm64_v8a` architectures. ### Contributions diff --git a/build.gradle b/build.gradle index 16255ee..c27a396 100644 --- a/build.gradle +++ b/build.gradle @@ -30,6 +30,7 @@ project.ext { } else { libraryVersion = "4.5.3" } + minSdkVersion = 21 androidXSQLiteVersion = "2.2.0" roomVersion = "2.5.0" androidNdkVersion = "25.2.9519653" @@ -65,7 +66,8 @@ task generateReadMe { def binding = [ libraryVersion: project.ext.libraryVersion, androidXSQLiteVersion: project.ext.androidXSQLiteVersion, - androidNdkVersion: project.ext.androidNdkVersion + androidNdkVersion: project.ext.androidNdkVersion, + minSdkVersion: project.ext.minSdkVersion, ] def template = engine.createTemplate(reader).make(binding) readme.write(template.toString()) diff --git a/sqlcipher/build.gradle b/sqlcipher/build.gradle index 714392e..cf98593 100644 --- a/sqlcipher/build.gradle +++ b/sqlcipher/build.gradle @@ -6,7 +6,7 @@ android { compileSdkVersion 33 defaultConfig { - minSdkVersion 21 + minSdkVersion "${rootProject.ext.minSdkVersion}" targetSdkVersion 33 versionCode 1 versionName "${rootProject.ext.libraryVersion}" From 6c132c90f534e57813c5d8d2c07b3144e90ca8c3 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Mon, 27 Nov 2023 13:22:57 -0600 Subject: [PATCH 4/6] Close non-primary connections after password change on primary connection --- .../sqlcipher_cts/SupportAPIRoomTest.java | 20 ++++++++++++++++++- .../sqlcipher/SQLiteConnectionPool.java | 1 + 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SupportAPIRoomTest.java b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SupportAPIRoomTest.java index 781a6ee..9acb9f0 100644 --- a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SupportAPIRoomTest.java +++ b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SupportAPIRoomTest.java @@ -24,28 +24,34 @@ import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; +import net.zetetic.database.sqlcipher.SQLiteDatabase; import net.zetetic.database.sqlcipher.SupportOpenHelperFactory; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import java.io.File; import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.UUID; @RunWith(AndroidJUnit4.class) public class SupportAPIRoomTest { private AppDatabase db; private UserDao userDao; + private File databaseFile; @Before public void before(){ Context context = ApplicationProvider.getApplicationContext(); System.loadLibrary("sqlcipher"); + databaseFile = context.getDatabasePath("users.db"); SupportOpenHelperFactory factory = new SupportOpenHelperFactory("user".getBytes(StandardCharsets.UTF_8)); - db = Room.databaseBuilder(context, AppDatabase.class, "users.db") + db = Room.databaseBuilder(context, AppDatabase.class, databaseFile.getAbsolutePath()) .openHelperFactory(factory).build(); db.clearAllTables(); userDao = db.userDao(); @@ -92,10 +98,22 @@ public void shouldQueryDataByParametersViaDao(){ assertThat(foundUser.lastName, is(user.lastName)); } + @Test + public void shouldSupportChangingPasswordWithRoom(){ + userDao.insert(new User("foo", "bar")); + SQLiteDatabase database = (SQLiteDatabase)db.getOpenHelper().getWritableDatabase(); + database.changePassword(UUID.randomUUID().toString()); + List users = userDao.getAll(); + assertThat(users.size(), is(1)); + } + @After public void after(){ if(db != null){ db.close(); + if(databaseFile != null){ + databaseFile.delete(); + } } } diff --git a/sqlcipher/src/main/java/net/zetetic/database/sqlcipher/SQLiteConnectionPool.java b/sqlcipher/src/main/java/net/zetetic/database/sqlcipher/SQLiteConnectionPool.java index bb9d695..0750189 100644 --- a/sqlcipher/src/main/java/net/zetetic/database/sqlcipher/SQLiteConnectionPool.java +++ b/sqlcipher/src/main/java/net/zetetic/database/sqlcipher/SQLiteConnectionPool.java @@ -299,6 +299,7 @@ public void reconfigure(SQLiteDatabaseConfiguration configuration) { if(passwordChanged){ mAvailablePrimaryConnection.changePassword(configuration.password); mConfiguration.updateParametersFrom(configuration); + closeAvailableNonPrimaryConnectionsAndLogExceptionsLocked(); reconfigureAllConnectionsLocked(); } From 7d48b1f8c97b3532cfee079faf64e53c360ab1c4 Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Mon, 8 Jan 2024 12:22:27 -0600 Subject: [PATCH 5/6] Update README to include API usage and ref. library version --- README.md | 47 +++++++++++++++++++++++++++++++++++++--------- README.md.template | 47 +++++++++++++++++++++++++++++++++++++--------- build.gradle | 2 +- 3 files changed, 77 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 9c17acb..58270ea 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ SQLCipher for Android provides a library replacement for `android.database.sqlite` on the Android platform for use on [SQLCipher](https://github.com/sqlcipher/sqlcipher) databases. This library is based on the upstream [Android Bindings](https://www.sqlite.org/android/doc/trunk/www/index.wiki) project and aims to be a long-term replacement for the original [SQLCipher for Android](https://github.com/sqlcipher/android-database-sqlcipher) library. -***N.B.*** This library is currently distributed in source-only format at this time, and requires [other external dependencies](#external-dependencies) to build. Community edition AAR artifacts will be distributed eventually. - ### Compatibility SQLCipher for Android supports Android API 21 and up on `armeabi-v7a`, `x86`, `x86_64`, and `arm64_v8a` architectures. @@ -17,19 +15,19 @@ We welcome contributions, to contribute to SQLCipher for Android, a [contributor Add a local reference to the local library and dependency: -``` -implementation files('libs/sqlcipher-android-4.5.2-release.aar') +```groovy +implementation files('libs/sqlcipher-android-4.5.5-release.aar') implementation 'androidx.sqlite:sqlite:2.2.0' ``` or source a Community edition build from Maven Central: -``` -implementation 'net.zetetic:sqlcipher-android:4.5.2@aar' +```groovy +implementation 'net.zetetic:sqlcipher-android:4.5.5@aar' implementation 'androidx.sqlite:sqlite:2.2.0' ``` -``` +```java import net.zetetic.database.sqlcipher.SQLiteDatabase; System.loadLibrary("sqlcipher"); @@ -40,20 +38,51 @@ SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(databaseFile, pass To perform operations on the database instance immediately before or after the keying operation is performed, provide a `SQLiteDatabaseHook` instance when creating your database connection: -``` +```java SQLiteDatabaseHook hook = new SQLiteDatabaseHook() { public void preKey(SQLiteConnection connection) { } public void postKey(SQLiteConnection connection) { } }; ``` +### API Usage + +There are two main options for using SQLCipher for Android within an Application: + +1. [Using the SQLCipher for Android classes](#sqlcipher-for-android-classes) +2. [Using SQLCipher for Android in conjunction with the Android Room API](#sqlcipher-for-android-room-integration) + +In both cases, prior to using any portion of the SQLCipher for Android library, the native SQLCipher core library must be loaded into the running application process. The SQLCipher core library is bundled within the AAR of SQLCipher for Android, however, the developer must load this library explicitly. An example below: + +```java +System.loadLibrary("sqlcipher"); +``` + +#### SQLCipher for Android classes + +SQLCipher for Android provides two classes for opening and access database files. The `SQLiteDatabase` provides static methods for opening/creating database files and general data access. +Additionally, applications may choose to subclass the `SQLiteOpenHelper` class which provides mechanisms for performing database migrations, as well as general data access. + +#### SQLCipher for Android Room Integration + +SQLCipher for Android may also integrate with the Room API via the `SupportOpenHelperFactory`, an example is given below: + +```java +System.loadLibrary("sqlcipher"); +String password = "Password1!"; +File databaseFile = context.getDatabasePath("demo.db"); +SupportOpenHelperFactory factory = new SupportOpenHelperFactory("password.getBytes(StandardCharsets.UTF_8)); +db = Room.databaseBuilder(context, AppDatabase.class, databaseFile.getAbsolutePath()) + .openHelperFactory(factory).build(); +``` + ### Building ## Android NDK Currently, SQLCipher for Android uses NDK version "25.2.9519653". -## External dependencies: +## External dependencies This repository is not batteries-included. Specifically, you will need to build `libcrypto.a`, the static library from OpenSSL using the NDK for the [supported platforms](#compatibility), and bundle the top-level `include` folder from OpenSSL. Additionally, you will need to build a SQLCipher amalgamation. These files will need to be placed in the following locations: diff --git a/README.md.template b/README.md.template index 9574225..1139295 100644 --- a/README.md.template +++ b/README.md.template @@ -2,8 +2,6 @@ SQLCipher for Android provides a library replacement for `android.database.sqlite` on the Android platform for use on [SQLCipher](https://github.com/sqlcipher/sqlcipher) databases. This library is based on the upstream [Android Bindings](https://www.sqlite.org/android/doc/trunk/www/index.wiki) project and aims to be a long-term replacement for the original [SQLCipher for Android](https://github.com/sqlcipher/android-database-sqlcipher) library. -***N.B.*** This library is currently distributed in source-only format at this time, and requires [other external dependencies](#external-dependencies) to build. Community edition AAR artifacts will be distributed eventually. - ### Compatibility SQLCipher for Android supports Android API <%=minSdkVersion%> and up on `armeabi-v7a`, `x86`, `x86_64`, and `arm64_v8a` architectures. @@ -17,19 +15,19 @@ We welcome contributions, to contribute to SQLCipher for Android, a [contributor Add a local reference to the local library and dependency: -``` -implementation files('libs/sqlcipher-android-4.5.2-release.aar') +```groovy +implementation files('libs/sqlcipher-android-<%=libraryVersion%>-release.aar') implementation 'androidx.sqlite:sqlite:<%=androidXSQLiteVersion%>' ``` or source a Community edition build from Maven Central: -``` -implementation 'net.zetetic:sqlcipher-android:4.5.2@aar' +```groovy +implementation 'net.zetetic:sqlcipher-android:<%=libraryVersion%>@aar' implementation 'androidx.sqlite:sqlite:<%=androidXSQLiteVersion%>' ``` -``` +```java import net.zetetic.database.sqlcipher.SQLiteDatabase; System.loadLibrary("sqlcipher"); @@ -40,20 +38,51 @@ SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(databaseFile, pass To perform operations on the database instance immediately before or after the keying operation is performed, provide a `SQLiteDatabaseHook` instance when creating your database connection: -``` +```java SQLiteDatabaseHook hook = new SQLiteDatabaseHook() { public void preKey(SQLiteConnection connection) { } public void postKey(SQLiteConnection connection) { } }; ``` +### API Usage + +There are two main options for using SQLCipher for Android within an Application: + +1. [Using the SQLCipher for Android classes](#sqlcipher-for-android-classes) +2. [Using SQLCipher for Android in conjunction with the Android Room API](#sqlcipher-for-android-room-integration) + +In both cases, prior to using any portion of the SQLCipher for Android library, the native SQLCipher core library must be loaded into the running application process. The SQLCipher core library is bundled within the AAR of SQLCipher for Android, however, the developer must load this library explicitly. An example below: + +```java +System.loadLibrary("sqlcipher"); +``` + +#### SQLCipher for Android classes + +SQLCipher for Android provides two classes for opening and access database files. The `SQLiteDatabase` provides static methods for opening/creating database files and general data access. +Additionally, applications may choose to subclass the `SQLiteOpenHelper` class which provides mechanisms for performing database migrations, as well as general data access. + +#### SQLCipher for Android Room Integration + +SQLCipher for Android may also integrate with the Room API via the `SupportOpenHelperFactory`, an example is given below: + +```java +System.loadLibrary("sqlcipher"); +String password = "Password1!"; +File databaseFile = context.getDatabasePath("demo.db"); +SupportOpenHelperFactory factory = new SupportOpenHelperFactory("password.getBytes(StandardCharsets.UTF_8)); +db = Room.databaseBuilder(context, AppDatabase.class, databaseFile.getAbsolutePath()) + .openHelperFactory(factory).build(); +``` + ### Building ## Android NDK Currently, SQLCipher for Android uses NDK version "<%=androidNdkVersion%>". -## External dependencies: +## External dependencies This repository is not batteries-included. Specifically, you will need to build `libcrypto.a`, the static library from OpenSSL using the NDK for the [supported platforms](#compatibility), and bundle the top-level `include` folder from OpenSSL. Additionally, you will need to build a SQLCipher amalgamation. These files will need to be placed in the following locations: diff --git a/build.gradle b/build.gradle index c27a396..644e0dc 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ project.ext { if(project.hasProperty('sqlcipherAndroidVersion') && "${sqlcipherAndroidVersion}") { libraryVersion = "${sqlcipherAndroidVersion}" } else { - libraryVersion = "4.5.3" + libraryVersion = "4.5.5" } minSdkVersion = 21 androidXSQLiteVersion = "2.2.0" From 27c895d69989665595ef6ce48e8783537f5fec9e Mon Sep 17 00:00:00 2001 From: Nick Parker Date: Wed, 17 Jan 2024 07:54:53 -0600 Subject: [PATCH 6/6] Bump version to 4.5.6 --- README.md | 4 ++-- build.gradle | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 58270ea..0163492 100644 --- a/README.md +++ b/README.md @@ -16,14 +16,14 @@ We welcome contributions, to contribute to SQLCipher for Android, a [contributor Add a local reference to the local library and dependency: ```groovy -implementation files('libs/sqlcipher-android-4.5.5-release.aar') +implementation files('libs/sqlcipher-android-4.5.6-release.aar') implementation 'androidx.sqlite:sqlite:2.2.0' ``` or source a Community edition build from Maven Central: ```groovy -implementation 'net.zetetic:sqlcipher-android:4.5.5@aar' +implementation 'net.zetetic:sqlcipher-android:4.5.6@aar' implementation 'androidx.sqlite:sqlite:2.2.0' ``` diff --git a/build.gradle b/build.gradle index 644e0dc..a8815c9 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ project.ext { if(project.hasProperty('sqlcipherAndroidVersion') && "${sqlcipherAndroidVersion}") { libraryVersion = "${sqlcipherAndroidVersion}" } else { - libraryVersion = "4.5.5" + libraryVersion = "4.5.6" } minSdkVersion = 21 androidXSQLiteVersion = "2.2.0"