diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a967ba3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "sqlcipher/src/main/jni/libtomcrypt/src"] + path = sqlcipher/src/main/jni/libtomcrypt/src + url = https://github.com/sqlcipher/libtomcrypt +[submodule "sqlcipher/src/main/jni/sqlcipher/src"] + path = sqlcipher/src/main/jni/sqlcipher/src + url = https://github.com/sqlcipher/sqlcipher diff --git a/Makefile b/Makefile index 9ca7336..fa0fe44 100644 --- a/Makefile +++ b/Makefile @@ -15,18 +15,7 @@ build-debug: $(GRADLE) assembleDebug build-release: - $(GRADLE) \ - -PsqlcipherAndroidVersion="$(SQLCIPHER_ANDROID_VERSION)" \ - assembleRelease - -publish-snapshot-to-local-maven: - @ $(collect-signing-info) \ - $(GRADLE) \ - -PpublishSnapshot=true \ - -Psigning.keyId="$$gpgKeyId" \ - -Psigning.secretKeyRingFile="$$gpgKeyRingFile" \ - -Psigning.password="$$gpgPassword" \ - publishReleasePublicationToMavenLocal + $(GRADLE) assembleRelease publish-remote-release: @ $(collect-signing-info) \ @@ -40,7 +29,6 @@ publish-remote-release: -PsigningKeyPassword="$$gpgPassword" \ -PnexusUsername="$$nexusUsername" \ -PnexusPassword="$$nexusPassword" \ - -PsqlcipherAndroidVersion="$(SQLCIPHER_ANDROID_VERSION)" \ sqlcipher:publish collect-signing-info := \ diff --git a/README.md b/README.md index 184f9e9..e3870ec 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ SQLCipher for Android provides a library replacement for `android.database.sqlit ### Compatibility -SQLCipher for Android supports Android API 21 and up on `armeabi-v7a`, `x86`, `x86_64`, and `arm64-v8a` architectures. +SQLCipher for Android supports Android API 23 and up on `armeabi-v7a`, `x86`, `x86_64`, and `arm64-v8a` architectures. ### Contributions @@ -16,15 +16,15 @@ 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-undefined-release.aar') -implementation 'androidx.sqlite:sqlite:2.2.0' +implementation files('libs/sqlcipher-android-4.15.0-release.aar') +implementation 'androidx.sqlite:sqlite:2.6.2' ``` or source a Community edition build from Maven Central: ```groovy -implementation 'net.zetetic:sqlcipher-android:undefined@aar' -implementation 'androidx.sqlite:sqlite:2.2.0' +implementation 'net.zetetic:sqlcipher-android:4.15.0@aar' +implementation 'androidx.sqlite:sqlite:2.6.2' ``` ```java @@ -71,7 +71,7 @@ SQLCipher for Android may also integrate with the Room API via the `SupportOpenH System.loadLibrary("sqlcipher"); String password = "Password1!"; File databaseFile = context.getDatabasePath("demo.db"); -SupportOpenHelperFactory factory = new SupportOpenHelperFactory("password.getBytes(StandardCharsets.UTF_8)); +SupportOpenHelperFactory factory = new SupportOpenHelperFactory(password.getBytes(StandardCharsets.UTF_8)); db = Room.databaseBuilder(context, AppDatabase.class, databaseFile.getAbsolutePath()) .openHelperFactory(factory).build(); ``` @@ -106,22 +106,10 @@ To manage the logging produced from SQLCipher core, please review the runtime co ### Building -## Android NDK - -Currently, SQLCipher for Android uses NDK version "25.2.9519653". - -## 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: +This project and it's dependencies can be built directly within Android Studio. Currently, SQLCipher for Android uses NDK version "25.2.9519653". The repository includes a submodule for SQLCipher core, and LibTomCrypt as external dependencies. When cloning the repository, please execute the following command at the root of the project (the build phase will check for this on your behalf): ``` -/sqlcipher/src/main/jni/sqlcipher/android-libs/armeabi-v7a/libcrypto.a -/sqlcipher/src/main/jni/sqlcipher/android-libs/x86/libcrypto.a -/sqlcipher/src/main/jni/sqlcipher/android-libs/x86_64/libcrypto.a -/sqlcipher/src/main/jni/sqlcipher/android-libs/arm64-v8a/libcrypto.a -/sqlcipher/src/main/jni/sqlcipher/android-libs/include/ -/sqlcipher/src/main/jni/sqlcipher/sqlite3.c -/sqlcipher/src/main/jni/sqlcipher/sqlite3.h +git submodule update --init ``` To build the AAR package, either build directly within Android Studio, or from the command line: @@ -130,3 +118,9 @@ To build the AAR package, either build directly within Android Studio, or from t ./gradlew assembleRelease ``` +#### Using OpenSSL + +By default, SQLCipher for Android uses LibTomCrypt as the default crypto provider. Alternatively, you may build SQLCipher for Android linked with OpenSSL. Instructions for building OpenSSL to target Android-specific ABI's are outside the scope of this project. Below are the integration steps necessary for the project to utilize the OpenSSL libraries during the build phase. + +1. Place your ABI-specific `libcrypto.a` files and `include` directory in `sqlcipher/src/main/jni/sqlcipher/android-libs` +2. Specify all required SQLCipher Core `CFLAGS` within the environment variable `SQLCIPHER_CFLAGS` including `-DSQLCIPHER_CRYPTO_OPENSSL` and `-DSQLITE_HAS_CODEC` diff --git a/README.md.template b/README.md.template index 1a215f0..65b3a34 100644 --- a/README.md.template +++ b/README.md.template @@ -71,7 +71,7 @@ SQLCipher for Android may also integrate with the Room API via the `SupportOpenH System.loadLibrary("sqlcipher"); String password = "Password1!"; File databaseFile = context.getDatabasePath("demo.db"); -SupportOpenHelperFactory factory = new SupportOpenHelperFactory("password.getBytes(StandardCharsets.UTF_8)); +SupportOpenHelperFactory factory = new SupportOpenHelperFactory(password.getBytes(StandardCharsets.UTF_8)); db = Room.databaseBuilder(context, AppDatabase.class, databaseFile.getAbsolutePath()) .openHelperFactory(factory).build(); ``` @@ -106,22 +106,10 @@ To manage the logging produced from SQLCipher core, please review the runtime co ### Building -## Android NDK - -Currently, SQLCipher for Android uses NDK version "<%=androidNdkVersion%>". - -## 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: +This project and it's dependencies can be built directly within Android Studio. Currently, SQLCipher for Android uses NDK version "<%=androidNdkVersion%>". The repository includes a submodule for SQLCipher core, and LibTomCrypt as external dependencies. When cloning the repository, please execute the following command at the root of the project (the build phase will check for this on your behalf): ``` -/sqlcipher/src/main/jni/sqlcipher/android-libs/armeabi-v7a/libcrypto.a -/sqlcipher/src/main/jni/sqlcipher/android-libs/x86/libcrypto.a -/sqlcipher/src/main/jni/sqlcipher/android-libs/x86_64/libcrypto.a -/sqlcipher/src/main/jni/sqlcipher/android-libs/arm64-v8a/libcrypto.a -/sqlcipher/src/main/jni/sqlcipher/android-libs/include/ -/sqlcipher/src/main/jni/sqlcipher/sqlite3.c -/sqlcipher/src/main/jni/sqlcipher/sqlite3.h +git submodule update --init ``` To build the AAR package, either build directly within Android Studio, or from the command line: @@ -130,3 +118,9 @@ To build the AAR package, either build directly within Android Studio, or from t ./gradlew assembleRelease ``` +#### Using OpenSSL + +By default, SQLCipher for Android uses LibTomCrypt as the default crypto provider. Alternatively, you may build SQLCipher for Android linked with OpenSSL. Instructions for building OpenSSL to target Android-specific ABI's are outside the scope of this project. Below are the integration steps necessary for the project to utilize the OpenSSL libraries during the build phase. + +1. Place your ABI-specific `libcrypto.a` files and `include` directory in `sqlcipher/src/main/jni/sqlcipher/android-libs` +2. Specify all required SQLCipher Core `CFLAGS` within the environment variable `SQLCIPHER_CFLAGS` including `-DSQLCIPHER_CRYPTO_OPENSSL` and `-DSQLITE_HAS_CODEC` diff --git a/build.gradle b/build.gradle index 882915d..1a94a03 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { google() } dependencies { - def gradleToolsVersion = "8.7.2" + def gradleToolsVersion = "8.9.0" classpath "com.android.tools.build:gradle:${gradleToolsVersion}" } } @@ -33,11 +33,11 @@ project.ext { if(project.hasProperty('sqlcipherAndroidVersion') && "${sqlcipherAndroidVersion}") { libraryVersion = "${sqlcipherAndroidVersion}" } else { - libraryVersion = "undefined" + libraryVersion = "4.15.0" } - minSdkVersion = 21 - androidXSQLiteVersion = "2.2.0" - roomVersion = "2.5.0" + minSdkVersion = 23 + androidXSQLiteVersion = "2.6.2" + roomVersion = "2.8.4" androidNdkVersion = "25.2.9519653" mavenLocalRepositoryPrefix = "file://" if(project.hasProperty('publishLocal') && publishLocal.toBoolean()){ @@ -64,20 +64,20 @@ project.ext { nexusStagingProfileId = project.hasProperty('nexusStagingProfileId') ? "${nexusStagingProfileId}" : "" } -task generateReadMe { +def generateReadMe = tasks.register('generateReadMe') { def readme = new File("README.md") def engine = new SimpleTemplateEngine() def reader = new FileReader("README.md.template") def binding = [ - libraryVersion: project.ext.libraryVersion, - androidXSQLiteVersion: project.ext.androidXSQLiteVersion, - androidNdkVersion: project.ext.androidNdkVersion, - minSdkVersion: project.ext.minSdkVersion, - ] + libraryVersion : project.ext.libraryVersion, + androidXSQLiteVersion: project.ext.androidXSQLiteVersion, + androidNdkVersion : project.ext.androidNdkVersion, + minSdkVersion : project.ext.minSdkVersion, + ] def template = engine.createTemplate(reader).make(binding) readme.write(template.toString()) } project.afterEvaluate { - build.dependsOn generateReadMe + build.dependsOn(generateReadMe) } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d76bd07..ff702a8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ -#Thu Jun 16 15:29:23 CDT 2022 +#Thu Feb 19 08:45:35 CST 2026 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip distributionPath=wrapper/dists -zipStorePath=wrapper/dists +distributionSha256Sum=f397b287023acdba1e9f6fc5ea72d22dd63669d59ed4a289a29b1a76eee151c6 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/sqlcipher/build.gradle b/sqlcipher/build.gradle index 9732cc5..872bcb6 100644 --- a/sqlcipher/build.gradle +++ b/sqlcipher/build.gradle @@ -2,6 +2,14 @@ apply plugin: 'com.android.library' apply plugin: "maven-publish" apply plugin: "signing" +import org.gradle.internal.logging.text.StyledTextOutputFactory +import static org.gradle.internal.logging.text.StyledTextOutput.Style +import java.nio.file.Files +import java.nio.file.Paths +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING + +def log = services.get(StyledTextOutputFactory).create("sqlcipher") + android { compileSdkVersion 34 namespace "net.zetetic.database" @@ -16,7 +24,7 @@ android { // "pm clear" command after each test invocation. This command ensures // that the app's state is completely cleared between tests. testInstrumentationRunnerArguments clearPackageData: 'true' - consumerProguardFile 'consumer-rules.pro' + consumerProguardFiles 'consumer-rules.pro' } buildTypes { @@ -69,6 +77,76 @@ android { } +static def shellCmd(String workingDirectory, + String... arguments) { + if (!arguments || arguments.length == 0) { + throw new IllegalArgumentException("At least one argument is required") + } + def command = ["sh", "-c", 'exec "$@"', "sh", *arguments] + def processBuilder = new ProcessBuilder(command) + processBuilder.directory(new File(workingDirectory)) + def process = processBuilder.start() + process.inputStream.eachLine { println it } + process.errorStream.eachLine { System.err.println(it) } + process.waitFor() +} + +def generateAmalgamation = tasks.register("generateAmalgamation") { + description = "Generate SQLCipher amalgamation source files" + group = "SQLCipher" + def sqlcipherDir = new File("${project.rootDir}/sqlcipher/src/main/jni/sqlcipher/") + def sqlcipherSourceDir = new File(sqlcipherDir.absolutePath, "src/") + def sqlcipherReadMe = new File(sqlcipherSourceDir.absolutePath, "README.md") + def amalgamationSource = new File(sqlcipherDir.absolutePath, "sqlite3.c") + def amalgamationHeader = new File(sqlcipherDir.absolutePath, "sqlite3.h") + doLast { + if(!sqlcipherReadMe.exists()) { + log.withStyle(Style.Info).println('SQLCipher README missing, initializing submodule') + shellCmd(project.rootDir.absolutePath, "git", "submodule", "update", "--init") + } + log.withStyle(Style.Info).println('SQLCipher amalgamation not found, generating.') + shellCmd(sqlcipherSourceDir.absolutePath, "./configure", "--with-tempstore=yes", "--disable-tcl") + shellCmd(sqlcipherSourceDir.absolutePath, "make", "clean") + shellCmd(sqlcipherSourceDir.absolutePath, "make", "sqlite3.c") + def filesToMove = ["sqlite3.c", "sqlite3.h"] + filesToMove.each { + def sourcePath = Paths.get(sqlcipherSourceDir.absolutePath, it) + def targetPath = Paths.get(sqlcipherDir.absolutePath, it) + def moveResult = Files.move(sourcePath, targetPath, REPLACE_EXISTING) + if(moveResult == null){ + throw new GradleException("Faile to move ${sourcePath} to ${targetPath}") + } + } + } + onlyIf { + return !(amalgamationSource.exists() + && amalgamationHeader.exists()) + } +} + +tasks.matching { it.name == "preBuild" }.configureEach { + dependsOn generateAmalgamation +} + +def cleanAmalgamation = tasks.register("cleanAmalgamation") { + description = "Cleans SQLCipher amalgamation source files" + group = "SQLCipher" + def amalgamationSource = file("${project.rootDir}/sqlcipher/src/main/jni/sqlcipher/sqlite3.c") + def amalgamationHeader = file("${project.rootDir}/sqlcipher/src/main/jni/sqlcipher/sqlite3.h") + doLast { + println "Clean SQLCipher amalgamation" + delete(amalgamationSource, amalgamationHeader) + } + onlyIf { + return amalgamationSource.exists() + || amalgamationHeader.exists() + } +} + +tasks.named("clean") { + dependsOn(cleanAmalgamation) +} + dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') @@ -81,10 +159,10 @@ dependencies { androidTestAnnotationProcessor "androidx.room:room-compiler:${rootProject.ext.roomVersion}" // Needed for supporting tests - androidTestImplementation 'androidx.test.ext:junit:1.1.3' - androidTestImplementation 'androidx.test:rules:1.4.0' - androidTestImplementation 'androidx.test:core:1.4.0' - androidTestImplementation 'org.hamcrest:hamcrest-library:1.3' + androidTestImplementation 'androidx.test.ext:junit:1.3.0' + androidTestImplementation 'androidx.test:rules:1.7.0' + androidTestImplementation 'androidx.test:core:1.7.0' + androidTestImplementation 'org.hamcrest:hamcrest-library:3.0' testImplementation 'junit:junit:4.13.2' } @@ -95,22 +173,8 @@ allprojects { } } -def isReleaseBuild() { - return mavenVersionName.contains("SNAPSHOT") == false -} - -def getReleaseRepositoryUrl() { - return hasProperty('mavenReleaseRepositoryUrl') ? mavenReleaseRepositoryUrl - : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" -} - -def getSnapshotRepositoryUrl() { - if(hasProperty('mavenLocalRepositoryPrefix')) { - return "${mavenLocalRepositoryPrefix}${buildDir}/${mavenSnapshotRepositoryUrl}" - } else { - return hasProperty('mavenSnapshotRepositoryUrl') ? mavenSnapshotRepositoryUrl - : "https://oss.sonatype.org/content/repositories/snapshots/" - } +static def getReleaseRepositoryUrl() { + return "https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/" } def getRepositoryUsername() { @@ -166,9 +230,7 @@ afterEvaluate { repositories { maven { - def repoUrl = isReleaseBuild() - ? getReleaseRepositoryUrl() - : getSnapshotRepositoryUrl() + def repoUrl = getReleaseRepositoryUrl() url = repoUrl credentials { username = getRepositoryUsername() @@ -180,7 +242,7 @@ afterEvaluate { } signing { - required { isReleaseBuild() && gradle.taskGraph.hasTask("publish") } + required { gradle.taskGraph.hasTask("publish") } sign publishing.publications.mavenJava } } diff --git a/sqlcipher/consumer-rules.pro b/sqlcipher/consumer-rules.pro index 0f8a20c..dd0e964 100644 --- a/sqlcipher/consumer-rules.pro +++ b/sqlcipher/consumer-rules.pro @@ -1,18 +1,14 @@ --keep class net.zetetic.** { - native ; - private native ; - public (...); - long mNativeHandle; -} +# Keep SQLCipher classes and JNI descriptors +-keep,includedescriptorclasses class net.zetetic.database.** { *; } +-keep,includedescriptorclasses interface net.zetetic.database.** { *; } --keepclassmembers class net.zetetic.database.sqlcipher.SQLiteCustomFunction { - public java.lang.String name; - public int numArgs; - private void dispatchCallback(java.lang.String[]); +# Keep native methods +-keepclasseswithmembernames class net.zetetic.database.** { + native ; } --keepclassmembers class net.zetetic.database.sqlcipher.SQLiteDebug$PagerStats { - public int largestMemAlloc; - public int memoryUsed; - public int pageCacheOverflow; -} +# Prevent warnings for optional Android APIs +-dontwarn net.zetetic.database.** + +# Support Room with annontation-based reflection support +-keepattributes *Annotation* \ No newline at end of file diff --git a/sqlcipher/src/androidTest/java/net/zetetic/database/database_cts/AbstractCursorTest.java b/sqlcipher/src/androidTest/java/net/zetetic/database/database_cts/AbstractCursorTest.java index 230af5a..2db7b1e 100644 --- a/sqlcipher/src/androidTest/java/net/zetetic/database/database_cts/AbstractCursorTest.java +++ b/sqlcipher/src/androidTest/java/net/zetetic/database/database_cts/AbstractCursorTest.java @@ -23,6 +23,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.annotation.SuppressLint; import android.content.Context; import android.database.CharArrayBuffer; import android.database.ContentObserver; @@ -38,10 +39,10 @@ import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.Suppress; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -192,7 +193,8 @@ public void testOnChange() throws InterruptedException { assertTrue(mock.hadCalledOnChange()); } - @Suppress + @SuppressLint("IgnoreWithoutReason") + @Ignore @Test public void testOnMove() { assertFalse(mTestAbstractCursor.getOnMoveRet()); @@ -207,7 +209,8 @@ public void testOnMove() { assertEquals(5, mTestAbstractCursor.getNewPos()); } - @Suppress + @SuppressLint("IgnoreWithoutReason") + @Ignore @Test public void testOnMove_samePosition() { mTestAbstractCursor.moveToFirst(); @@ -364,7 +367,8 @@ public void testDeactivate() { assertTrue(mock.hadCalledOnInvalid()); } - @Suppress + @SuppressLint("IgnoreWithoutReason") + @Ignore @Test public void testCopyStringToBuffer() { CharArrayBuffer ca = new CharArrayBuffer(1000); @@ -380,7 +384,8 @@ public void testCopyStringToBuffer() { assertEquals(sb.toString(), new String(ca.data, 0, ca.sizeCopied)); } - @Suppress + @SuppressLint("IgnoreWithoutReason") + @Ignore @Test public void testCheckPosition() { // Test with position = -1. diff --git a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_android/DatabaseGeneralTest.java b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_android/DatabaseGeneralTest.java index 12cd90e..636aefa 100644 --- a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_android/DatabaseGeneralTest.java +++ b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_android/DatabaseGeneralTest.java @@ -27,6 +27,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.annotation.SuppressLint; import android.content.ContentValues; import android.content.Context; import android.database.CharArrayBuffer; @@ -37,7 +38,6 @@ import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.LargeTest; -import androidx.test.filters.Suppress; import android.util.Log; import android.util.Pair; @@ -51,6 +51,7 @@ import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -140,7 +141,7 @@ public void testUpdate() throws Exception { assertEquals("this is an updated test", value); } - @Suppress // PHONE_NUMBERS_EQUAL not supported + @Ignore // PHONE_NUMBERS_EQUAL not supported @Test public void testPhoneNumbersEqual() throws Exception { mDatabase.execSQL("CREATE TABLE phones (num TEXT);"); @@ -290,7 +291,7 @@ private void assertPhoneNumberNotEqual(String phone1, String phone2, boolean use * * @throws Exception */ - @Suppress // PHONE_NUMBERS_EQUAL not supported + @Ignore // PHONE_NUMBERS_EQUAL not supported @Test public void testPhoneNumbersEqualInternationl() throws Exception { assertPhoneNumberEqual("1", "1"); @@ -458,7 +459,7 @@ public void testSelectionArgs() throws Exception { c.close(); } - @Suppress // unicode collator not supported yet + @Ignore // unicode collator not supported yet @Test public void testTokenize() throws Exception { Cursor c; @@ -859,7 +860,7 @@ public void testUnionsWithBindArgs() { * This test is available only when the platform has a locale with the language "ja". * It finishes without failure when it is not available. */ - @Suppress + @Ignore @Test public void testCollateLocalizedForJapanese() throws Exception { final String testName = "DatabaseGeneralTest#testCollateLocalizedForJapanese()"; diff --git a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/CipherCompatibilityTest.java b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/CipherCompatibilityTest.java index 9d4c63c..7f0c2d6 100644 --- a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/CipherCompatibilityTest.java +++ b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/CipherCompatibilityTest.java @@ -1,10 +1,9 @@ package net.zetetic.database.sqlcipher_cts; import static org.hamcrest.Matchers.greaterThan; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import android.database.Cursor; -import android.util.Log; import net.zetetic.database.sqlcipher.SQLiteConnection; import net.zetetic.database.sqlcipher.SQLiteDatabase; diff --git a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/ImportUnencryptedDatabaseTest.java b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/ImportUnencryptedDatabaseTest.java index 8c8b728..6d56676 100644 --- a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/ImportUnencryptedDatabaseTest.java +++ b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/ImportUnencryptedDatabaseTest.java @@ -1,7 +1,7 @@ package net.zetetic.database.sqlcipher_cts; import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import android.database.Cursor; diff --git a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/JsonCastTest.java b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/JsonCastTest.java index 4293ab2..d9fc707 100644 --- a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/JsonCastTest.java +++ b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/JsonCastTest.java @@ -1,7 +1,7 @@ package net.zetetic.database.sqlcipher_cts; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; import android.database.Cursor; diff --git a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/MigrateDatabaseFrom1xFormatToCurrentFormatTest.java b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/MigrateDatabaseFrom1xFormatToCurrentFormatTest.java index d59fbac..a203de5 100644 --- a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/MigrateDatabaseFrom1xFormatToCurrentFormatTest.java +++ b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/MigrateDatabaseFrom1xFormatToCurrentFormatTest.java @@ -1,7 +1,7 @@ package net.zetetic.database.sqlcipher_cts; import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import android.database.Cursor; diff --git a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SQLCipherOpenHelperTest.java b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SQLCipherOpenHelperTest.java index 9f47658..6cd997d 100644 --- a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SQLCipherOpenHelperTest.java +++ b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SQLCipherOpenHelperTest.java @@ -2,7 +2,7 @@ import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import android.content.Context; import android.util.Log; @@ -20,7 +20,18 @@ public class SQLCipherOpenHelperTest extends AndroidSQLCipherTestCase { @Test - public void shouldAccessReadOnlyDatabaseFromOpenHelper(){ + public void shouldAccessCipherProviderFromReadOnlyDatabaseUsingOpenHelper(){ + database.close(); + SqlCipherOpenHelper helper = new SqlCipherOpenHelper(context); + SQLiteDatabase db = helper.getReadableDatabase(); + SQLiteStatement statement = db.compileStatement("PRAGMA cipher_provider;"); + String version = statement.simpleQueryForString(); + Log.i(TAG, String.format("SQLCipher provider:%s", version)); + assertThat(db, is(notNullValue())); + } + + @Test + public void shouldAccessCipherProviderVersionFromReadOnlyDatabaseUsingOpenHelper(){ database.close(); SqlCipherOpenHelper helper = new SqlCipherOpenHelper(context); SQLiteDatabase db = helper.getReadableDatabase(); diff --git a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SQLCipherVersionTest.java b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SQLCipherVersionTest.java index 1ed9111..a5ea345 100644 --- a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SQLCipherVersionTest.java +++ b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SQLCipherVersionTest.java @@ -17,6 +17,6 @@ public void shouldExtractLibraryCipherVersion() { cipherVersion = cursor.getString(0); cursor.close(); } - assertThat(cipherVersion, containsString("4.6.1")); + assertThat(cipherVersion, containsString("4.14.0")); } } diff --git a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SQLiteStatementTest.java b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SQLiteStatementTest.java index c9f62a9..1ae8d8f 100644 --- a/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SQLiteStatementTest.java +++ b/sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SQLiteStatementTest.java @@ -23,6 +23,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; +import android.annotation.SuppressLint; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; @@ -36,10 +37,10 @@ import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.Suppress; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -234,19 +235,22 @@ public void testSimpleQueryForString() { statement.close(); } - @Suppress + @SuppressLint("IgnoreWithoutReason") + @Ignore @Test public void testSimpleQueryForBlobFileDescriptorSuccessNormal() throws IOException { doTestSimpleQueryForBlobFileDescriptorSuccess(0); } - @Suppress + @SuppressLint("IgnoreWithoutReason") + @Ignore @Test public void testSimpleQueryForBlobFileDescriptorSuccessEmpty() throws IOException { doTestSimpleQueryForBlobFileDescriptorSuccess(1); } - @Suppress + @SuppressLint("IgnoreWithoutReason") + @Ignore @Test public void testSimpleQueryForBlobFileDescriptorSuccessNull() { populateBlobTable(); @@ -256,25 +260,29 @@ public void testSimpleQueryForBlobFileDescriptorSuccessNull() { assertNull(stm.simpleQueryForBlobFileDescriptor()); } - @Suppress + @SuppressLint("IgnoreWithoutReason") + @Ignore @Test public void testSimpleQueryForBlobFileDescriptorSuccess00() throws IOException { doTestSimpleQueryForBlobFileDescriptorSuccess(3); } - @Suppress + @SuppressLint("IgnoreWithoutReason") + @Ignore @Test public void testSimpleQueryForBlobFileDescriptorSuccessFF() throws IOException { doTestSimpleQueryForBlobFileDescriptorSuccess(4); } - @Suppress + @SuppressLint("IgnoreWithoutReason") + @Ignore @Test public void testSimpleQueryForBlobFileDescriptorSuccessEmbeddedNul() throws IOException { doTestSimpleQueryForBlobFileDescriptorSuccess(5); } - @Suppress + @SuppressLint("IgnoreWithoutReason") + @Ignore public void doTestSimpleQueryForBlobFileDescriptorSuccess(int i) throws IOException { populateBlobTable(); @@ -284,7 +292,8 @@ public void doTestSimpleQueryForBlobFileDescriptorSuccess(int i) throws IOExcept assertFileDescriptorContent(BLOBS[i], fd); } - @Suppress + @SuppressLint("IgnoreWithoutReason") + @Ignore @Test public void testSimpleQueryForBlobFileDescriptorSuccessParam() throws IOException { populateBlobTable(); 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 0e7895c..1162ed9 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 @@ -2,7 +2,7 @@ import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import android.content.Context; import android.database.Cursor; diff --git a/sqlcipher/src/main/java/net/zetetic/database/sqlcipher/SQLiteDatabase.java b/sqlcipher/src/main/java/net/zetetic/database/sqlcipher/SQLiteDatabase.java index 1a26f71..2fba349 100644 --- a/sqlcipher/src/main/java/net/zetetic/database/sqlcipher/SQLiteDatabase.java +++ b/sqlcipher/src/main/java/net/zetetic/database/sqlcipher/SQLiteDatabase.java @@ -401,6 +401,10 @@ private static boolean isMainThread() { return looper != null && looper == Looper.getMainLooper(); } + public void beginTransactionReadOnly() { + beginTransaction(); + } + /** * Begins a transaction in EXCLUSIVE mode. *

diff --git a/sqlcipher/src/main/jni/libtomcrypt/Android.mk b/sqlcipher/src/main/jni/libtomcrypt/Android.mk new file mode 100644 index 0000000..52c9a88 --- /dev/null +++ b/sqlcipher/src/main/jni/libtomcrypt/Android.mk @@ -0,0 +1,435 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := static-libtomcrypt + +# All LibTomCrypt source files, excluding tests and demos +# find src/ -name *.c | grep -v demos | grep -v tests | sort +LOCAL_SRC_FILES := \ +src/notes/etc/saferp_optimizer.c \ +src/notes/etc/whirlgen.c \ +src/notes/etc/whirltest.c \ +src/notes/rsa-testvectors/oaep-vect.c \ +src/notes/rsa-testvectors/pkcs1v15crypt-vectors.c \ +src/notes/rsa-testvectors/pkcs1v15sign-vectors.c \ +src/notes/rsa-testvectors/pss-vect.c \ +src/src/ciphers/aes/aes.c \ +src/src/ciphers/aes/aes_tab.c \ +src/src/ciphers/anubis.c \ +src/src/ciphers/blowfish.c \ +src/src/ciphers/camellia.c \ +src/src/ciphers/cast5.c \ +src/src/ciphers/des.c \ +src/src/ciphers/kasumi.c \ +src/src/ciphers/khazad.c \ +src/src/ciphers/kseed.c \ +src/src/ciphers/multi2.c \ +src/src/ciphers/noekeon.c \ +src/src/ciphers/rc2.c \ +src/src/ciphers/rc5.c \ +src/src/ciphers/rc6.c \ +src/src/ciphers/safer/safer.c \ +src/src/ciphers/safer/saferp.c \ +src/src/ciphers/safer/safer_tab.c \ +src/src/ciphers/skipjack.c \ +src/src/ciphers/twofish/twofish.c \ +src/src/ciphers/twofish/twofish_tab.c \ +src/src/ciphers/xtea.c \ +src/src/encauth/ccm/ccm_add_aad.c \ +src/src/encauth/ccm/ccm_add_nonce.c \ +src/src/encauth/ccm/ccm_done.c \ +src/src/encauth/ccm/ccm_init.c \ +src/src/encauth/ccm/ccm_memory.c \ +src/src/encauth/ccm/ccm_process.c \ +src/src/encauth/ccm/ccm_reset.c \ +src/src/encauth/ccm/ccm_test.c \ +src/src/encauth/chachapoly/chacha20poly1305_add_aad.c \ +src/src/encauth/chachapoly/chacha20poly1305_decrypt.c \ +src/src/encauth/chachapoly/chacha20poly1305_done.c \ +src/src/encauth/chachapoly/chacha20poly1305_encrypt.c \ +src/src/encauth/chachapoly/chacha20poly1305_init.c \ +src/src/encauth/chachapoly/chacha20poly1305_memory.c \ +src/src/encauth/chachapoly/chacha20poly1305_setiv.c \ +src/src/encauth/chachapoly/chacha20poly1305_setiv_rfc7905.c \ +src/src/encauth/chachapoly/chacha20poly1305_test.c \ +src/src/encauth/eax/eax_addheader.c \ +src/src/encauth/eax/eax_decrypt.c \ +src/src/encauth/eax/eax_decrypt_verify_memory.c \ +src/src/encauth/eax/eax_done.c \ +src/src/encauth/eax/eax_encrypt_authenticate_memory.c \ +src/src/encauth/eax/eax_encrypt.c \ +src/src/encauth/eax/eax_init.c \ +src/src/encauth/eax/eax_test.c \ +src/src/encauth/gcm/gcm_add_aad.c \ +src/src/encauth/gcm/gcm_add_iv.c \ +src/src/encauth/gcm/gcm_done.c \ +src/src/encauth/gcm/gcm_gf_mult.c \ +src/src/encauth/gcm/gcm_init.c \ +src/src/encauth/gcm/gcm_memory.c \ +src/src/encauth/gcm/gcm_mult_h.c \ +src/src/encauth/gcm/gcm_process.c \ +src/src/encauth/gcm/gcm_reset.c \ +src/src/encauth/gcm/gcm_test.c \ +src/src/encauth/ocb3/ocb3_add_aad.c \ +src/src/encauth/ocb3/ocb3_decrypt.c \ +src/src/encauth/ocb3/ocb3_decrypt_last.c \ +src/src/encauth/ocb3/ocb3_decrypt_verify_memory.c \ +src/src/encauth/ocb3/ocb3_done.c \ +src/src/encauth/ocb3/ocb3_encrypt_authenticate_memory.c \ +src/src/encauth/ocb3/ocb3_encrypt.c \ +src/src/encauth/ocb3/ocb3_encrypt_last.c \ +src/src/encauth/ocb3/ocb3_init.c \ +src/src/encauth/ocb3/ocb3_int_ntz.c \ +src/src/encauth/ocb3/ocb3_int_xor_blocks.c \ +src/src/encauth/ocb3/ocb3_test.c \ +src/src/encauth/ocb/ocb_decrypt.c \ +src/src/encauth/ocb/ocb_decrypt_verify_memory.c \ +src/src/encauth/ocb/ocb_done_decrypt.c \ +src/src/encauth/ocb/ocb_done_encrypt.c \ +src/src/encauth/ocb/ocb_encrypt_authenticate_memory.c \ +src/src/encauth/ocb/ocb_encrypt.c \ +src/src/encauth/ocb/ocb_init.c \ +src/src/encauth/ocb/ocb_ntz.c \ +src/src/encauth/ocb/ocb_shift_xor.c \ +src/src/encauth/ocb/ocb_test.c \ +src/src/encauth/ocb/s_ocb_done.c \ +src/src/hashes/blake2b.c \ +src/src/hashes/blake2s.c \ +src/src/hashes/chc/chc.c \ +src/src/hashes/helper/hash_file.c \ +src/src/hashes/helper/hash_filehandle.c \ +src/src/hashes/helper/hash_memory.c \ +src/src/hashes/helper/hash_memory_multi.c \ +src/src/hashes/md2.c \ +src/src/hashes/md4.c \ +src/src/hashes/md5.c \ +src/src/hashes/rmd128.c \ +src/src/hashes/rmd160.c \ +src/src/hashes/rmd256.c \ +src/src/hashes/rmd320.c \ +src/src/hashes/sha1.c \ +src/src/hashes/sha2/sha224.c \ +src/src/hashes/sha2/sha256.c \ +src/src/hashes/sha2/sha384.c \ +src/src/hashes/sha2/sha512_224.c \ +src/src/hashes/sha2/sha512_256.c \ +src/src/hashes/sha2/sha512.c \ +src/src/hashes/sha3.c \ +src/src/hashes/sha3_test.c \ +src/src/hashes/tiger.c \ +src/src/hashes/whirl/whirl.c \ +src/src/hashes/whirl/whirltab.c \ +src/src/mac/blake2/blake2bmac.c \ +src/src/mac/blake2/blake2bmac_file.c \ +src/src/mac/blake2/blake2bmac_memory.c \ +src/src/mac/blake2/blake2bmac_memory_multi.c \ +src/src/mac/blake2/blake2bmac_test.c \ +src/src/mac/blake2/blake2smac.c \ +src/src/mac/blake2/blake2smac_file.c \ +src/src/mac/blake2/blake2smac_memory.c \ +src/src/mac/blake2/blake2smac_memory_multi.c \ +src/src/mac/blake2/blake2smac_test.c \ +src/src/mac/f9/f9_done.c \ +src/src/mac/f9/f9_file.c \ +src/src/mac/f9/f9_init.c \ +src/src/mac/f9/f9_memory.c \ +src/src/mac/f9/f9_memory_multi.c \ +src/src/mac/f9/f9_process.c \ +src/src/mac/f9/f9_test.c \ +src/src/mac/hmac/hmac_done.c \ +src/src/mac/hmac/hmac_file.c \ +src/src/mac/hmac/hmac_init.c \ +src/src/mac/hmac/hmac_memory.c \ +src/src/mac/hmac/hmac_memory_multi.c \ +src/src/mac/hmac/hmac_process.c \ +src/src/mac/hmac/hmac_test.c \ +src/src/mac/omac/omac_done.c \ +src/src/mac/omac/omac_file.c \ +src/src/mac/omac/omac_init.c \ +src/src/mac/omac/omac_memory.c \ +src/src/mac/omac/omac_memory_multi.c \ +src/src/mac/omac/omac_process.c \ +src/src/mac/omac/omac_test.c \ +src/src/mac/pelican/pelican.c \ +src/src/mac/pelican/pelican_memory.c \ +src/src/mac/pelican/pelican_test.c \ +src/src/mac/pmac/pmac_done.c \ +src/src/mac/pmac/pmac_file.c \ +src/src/mac/pmac/pmac_init.c \ +src/src/mac/pmac/pmac_memory.c \ +src/src/mac/pmac/pmac_memory_multi.c \ +src/src/mac/pmac/pmac_ntz.c \ +src/src/mac/pmac/pmac_process.c \ +src/src/mac/pmac/pmac_shift_xor.c \ +src/src/mac/pmac/pmac_test.c \ +src/src/mac/poly1305/poly1305.c \ +src/src/mac/poly1305/poly1305_file.c \ +src/src/mac/poly1305/poly1305_memory.c \ +src/src/mac/poly1305/poly1305_memory_multi.c \ +src/src/mac/poly1305/poly1305_test.c \ +src/src/mac/xcbc/xcbc_done.c \ +src/src/mac/xcbc/xcbc_file.c \ +src/src/mac/xcbc/xcbc_init.c \ +src/src/mac/xcbc/xcbc_memory.c \ +src/src/mac/xcbc/xcbc_memory_multi.c \ +src/src/mac/xcbc/xcbc_process.c \ +src/src/mac/xcbc/xcbc_test.c \ +src/src/math/fp/ltc_ecc_fp_mulmod.c \ +src/src/math/gmp_desc.c \ +src/src/math/ltm_desc.c \ +src/src/math/multi.c \ +src/src/math/radix_to_bin.c \ +src/src/math/rand_bn.c \ +src/src/math/rand_prime.c \ +src/src/math/tfm_desc.c \ +src/src/misc/adler32.c \ +src/src/misc/base64/base64_decode.c \ +src/src/misc/base64/base64_encode.c \ +src/src/misc/burn_stack.c \ +src/src/misc/compare_testvector.c \ +src/src/misc/crc32.c \ +src/src/misc/crypt/crypt_argchk.c \ +src/src/misc/crypt/crypt.c \ +src/src/misc/crypt/crypt_cipher_descriptor.c \ +src/src/misc/crypt/crypt_cipher_is_valid.c \ +src/src/misc/crypt/crypt_constants.c \ +src/src/misc/crypt/crypt_find_cipher_any.c \ +src/src/misc/crypt/crypt_find_cipher.c \ +src/src/misc/crypt/crypt_find_cipher_id.c \ +src/src/misc/crypt/crypt_find_hash_any.c \ +src/src/misc/crypt/crypt_find_hash.c \ +src/src/misc/crypt/crypt_find_hash_id.c \ +src/src/misc/crypt/crypt_find_hash_oid.c \ +src/src/misc/crypt/crypt_find_prng.c \ +src/src/misc/crypt/crypt_fsa.c \ +src/src/misc/crypt/crypt_hash_descriptor.c \ +src/src/misc/crypt/crypt_hash_is_valid.c \ +src/src/misc/crypt/crypt_inits.c \ +src/src/misc/crypt/crypt_ltc_mp_descriptor.c \ +src/src/misc/crypt/crypt_prng_descriptor.c \ +src/src/misc/crypt/crypt_prng_is_valid.c \ +src/src/misc/crypt/crypt_prng_rng_descriptor.c \ +src/src/misc/crypt/crypt_register_all_ciphers.c \ +src/src/misc/crypt/crypt_register_all_hashes.c \ +src/src/misc/crypt/crypt_register_all_prngs.c \ +src/src/misc/crypt/crypt_register_cipher.c \ +src/src/misc/crypt/crypt_register_hash.c \ +src/src/misc/crypt/crypt_register_prng.c \ +src/src/misc/crypt/crypt_sizes.c \ +src/src/misc/crypt/crypt_unregister_cipher.c \ +src/src/misc/crypt/crypt_unregister_hash.c \ +src/src/misc/crypt/crypt_unregister_prng.c \ +src/src/misc/error_to_string.c \ +src/src/misc/hkdf/hkdf.c \ +src/src/misc/hkdf/hkdf_test.c \ +src/src/misc/mem_neq.c \ +src/src/misc/pkcs5/pkcs_5_1.c \ +src/src/misc/pkcs5/pkcs_5_2.c \ +src/src/misc/pkcs5/pkcs_5_test.c \ +src/src/misc/pk_get_oid.c \ +src/src/misc/zeromem.c \ +src/src/modes/cbc/cbc_decrypt.c \ +src/src/modes/cbc/cbc_done.c \ +src/src/modes/cbc/cbc_encrypt.c \ +src/src/modes/cbc/cbc_getiv.c \ +src/src/modes/cbc/cbc_setiv.c \ +src/src/modes/cbc/cbc_start.c \ +src/src/modes/cfb/cfb_decrypt.c \ +src/src/modes/cfb/cfb_done.c \ +src/src/modes/cfb/cfb_encrypt.c \ +src/src/modes/cfb/cfb_getiv.c \ +src/src/modes/cfb/cfb_setiv.c \ +src/src/modes/cfb/cfb_start.c \ +src/src/modes/ctr/ctr_decrypt.c \ +src/src/modes/ctr/ctr_done.c \ +src/src/modes/ctr/ctr_encrypt.c \ +src/src/modes/ctr/ctr_getiv.c \ +src/src/modes/ctr/ctr_setiv.c \ +src/src/modes/ctr/ctr_start.c \ +src/src/modes/ctr/ctr_test.c \ +src/src/modes/ecb/ecb_decrypt.c \ +src/src/modes/ecb/ecb_done.c \ +src/src/modes/ecb/ecb_encrypt.c \ +src/src/modes/ecb/ecb_start.c \ +src/src/modes/f8/f8_decrypt.c \ +src/src/modes/f8/f8_done.c \ +src/src/modes/f8/f8_encrypt.c \ +src/src/modes/f8/f8_getiv.c \ +src/src/modes/f8/f8_setiv.c \ +src/src/modes/f8/f8_start.c \ +src/src/modes/f8/f8_test_mode.c \ +src/src/modes/lrw/lrw_decrypt.c \ +src/src/modes/lrw/lrw_done.c \ +src/src/modes/lrw/lrw_encrypt.c \ +src/src/modes/lrw/lrw_getiv.c \ +src/src/modes/lrw/lrw_process.c \ +src/src/modes/lrw/lrw_setiv.c \ +src/src/modes/lrw/lrw_start.c \ +src/src/modes/lrw/lrw_test.c \ +src/src/modes/ofb/ofb_decrypt.c \ +src/src/modes/ofb/ofb_done.c \ +src/src/modes/ofb/ofb_encrypt.c \ +src/src/modes/ofb/ofb_getiv.c \ +src/src/modes/ofb/ofb_setiv.c \ +src/src/modes/ofb/ofb_start.c \ +src/src/modes/xts/xts_decrypt.c \ +src/src/modes/xts/xts_done.c \ +src/src/modes/xts/xts_encrypt.c \ +src/src/modes/xts/xts_init.c \ +src/src/modes/xts/xts_mult_x.c \ +src/src/modes/xts/xts_test.c \ +src/src/pk/asn1/der/bit/der_decode_bit_string.c \ +src/src/pk/asn1/der/bit/der_decode_raw_bit_string.c \ +src/src/pk/asn1/der/bit/der_encode_bit_string.c \ +src/src/pk/asn1/der/bit/der_encode_raw_bit_string.c \ +src/src/pk/asn1/der/bit/der_length_bit_string.c \ +src/src/pk/asn1/der/boolean/der_decode_boolean.c \ +src/src/pk/asn1/der/boolean/der_encode_boolean.c \ +src/src/pk/asn1/der/boolean/der_length_boolean.c \ +src/src/pk/asn1/der/choice/der_decode_choice.c \ +src/src/pk/asn1/der/generalizedtime/der_decode_generalizedtime.c \ +src/src/pk/asn1/der/generalizedtime/der_encode_generalizedtime.c \ +src/src/pk/asn1/der/generalizedtime/der_length_generalizedtime.c \ +src/src/pk/asn1/der/ia5/der_decode_ia5_string.c \ +src/src/pk/asn1/der/ia5/der_encode_ia5_string.c \ +src/src/pk/asn1/der/ia5/der_length_ia5_string.c \ +src/src/pk/asn1/der/integer/der_decode_integer.c \ +src/src/pk/asn1/der/integer/der_encode_integer.c \ +src/src/pk/asn1/der/integer/der_length_integer.c \ +src/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c \ +src/src/pk/asn1/der/object_identifier/der_encode_object_identifier.c \ +src/src/pk/asn1/der/object_identifier/der_length_object_identifier.c \ +src/src/pk/asn1/der/octet/der_decode_octet_string.c \ +src/src/pk/asn1/der/octet/der_encode_octet_string.c \ +src/src/pk/asn1/der/octet/der_length_octet_string.c \ +src/src/pk/asn1/der/printable_string/der_decode_printable_string.c \ +src/src/pk/asn1/der/printable_string/der_encode_printable_string.c \ +src/src/pk/asn1/der/printable_string/der_length_printable_string.c \ +src/src/pk/asn1/der/sequence/der_decode_sequence_ex.c \ +src/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c \ +src/src/pk/asn1/der/sequence/der_decode_sequence_multi.c \ +src/src/pk/asn1/der/sequence/der_decode_subject_public_key_info.c \ +src/src/pk/asn1/der/sequence/der_encode_sequence_ex.c \ +src/src/pk/asn1/der/sequence/der_encode_sequence_multi.c \ +src/src/pk/asn1/der/sequence/der_encode_subject_public_key_info.c \ +src/src/pk/asn1/der/sequence/der_length_sequence.c \ +src/src/pk/asn1/der/sequence/der_sequence_free.c \ +src/src/pk/asn1/der/sequence/der_sequence_shrink.c \ +src/src/pk/asn1/der/set/der_encode_set.c \ +src/src/pk/asn1/der/set/der_encode_setof.c \ +src/src/pk/asn1/der/short_integer/der_decode_short_integer.c \ +src/src/pk/asn1/der/short_integer/der_encode_short_integer.c \ +src/src/pk/asn1/der/short_integer/der_length_short_integer.c \ +src/src/pk/asn1/der/teletex_string/der_decode_teletex_string.c \ +src/src/pk/asn1/der/teletex_string/der_length_teletex_string.c \ +src/src/pk/asn1/der/utctime/der_decode_utctime.c \ +src/src/pk/asn1/der/utctime/der_encode_utctime.c \ +src/src/pk/asn1/der/utctime/der_length_utctime.c \ +src/src/pk/asn1/der/utf8/der_decode_utf8_string.c \ +src/src/pk/asn1/der/utf8/der_encode_utf8_string.c \ +src/src/pk/asn1/der/utf8/der_length_utf8_string.c \ +src/src/pk/dh/dh.c \ +src/src/pk/dh/dh_check_pubkey.c \ +src/src/pk/dh/dh_export.c \ +src/src/pk/dh/dh_export_key.c \ +src/src/pk/dh/dh_free.c \ +src/src/pk/dh/dh_generate_key.c \ +src/src/pk/dh/dh_import.c \ +src/src/pk/dh/dh_set.c \ +src/src/pk/dh/dh_set_pg_dhparam.c \ +src/src/pk/dh/dh_shared_secret.c \ +src/src/pk/dsa/dsa_decrypt_key.c \ +src/src/pk/dsa/dsa_encrypt_key.c \ +src/src/pk/dsa/dsa_export.c \ +src/src/pk/dsa/dsa_free.c \ +src/src/pk/dsa/dsa_generate_key.c \ +src/src/pk/dsa/dsa_generate_pqg.c \ +src/src/pk/dsa/dsa_import.c \ +src/src/pk/dsa/dsa_make_key.c \ +src/src/pk/dsa/dsa_set.c \ +src/src/pk/dsa/dsa_set_pqg_dsaparam.c \ +src/src/pk/dsa/dsa_shared_secret.c \ +src/src/pk/dsa/dsa_sign_hash.c \ +src/src/pk/dsa/dsa_verify_hash.c \ +src/src/pk/dsa/dsa_verify_key.c \ +src/src/pk/ecc/ecc_ansi_x963_export.c \ +src/src/pk/ecc/ecc_ansi_x963_import.c \ +src/src/pk/ecc/ecc.c \ +src/src/pk/ecc/ecc_decrypt_key.c \ +src/src/pk/ecc/ecc_encrypt_key.c \ +src/src/pk/ecc/ecc_export.c \ +src/src/pk/ecc/ecc_free.c \ +src/src/pk/ecc/ecc_get_size.c \ +src/src/pk/ecc/ecc_import.c \ +src/src/pk/ecc/ecc_make_key.c \ +src/src/pk/ecc/ecc_shared_secret.c \ +src/src/pk/ecc/ecc_sign_hash.c \ +src/src/pk/ecc/ecc_sizes.c \ +src/src/pk/ecc/ecc_test.c \ +src/src/pk/ecc/ecc_verify_hash.c \ +src/src/pk/ecc/ltc_ecc_is_valid_idx.c \ +src/src/pk/ecc/ltc_ecc_map.c \ +src/src/pk/ecc/ltc_ecc_mul2add.c \ +src/src/pk/ecc/ltc_ecc_mulmod.c \ +src/src/pk/ecc/ltc_ecc_mulmod_timing.c \ +src/src/pk/ecc/ltc_ecc_points.c \ +src/src/pk/ecc/ltc_ecc_projective_add_point.c \ +src/src/pk/ecc/ltc_ecc_projective_dbl_point.c \ +src/src/pk/katja/katja_decrypt_key.c \ +src/src/pk/katja/katja_encrypt_key.c \ +src/src/pk/katja/katja_export.c \ +src/src/pk/katja/katja_exptmod.c \ +src/src/pk/katja/katja_free.c \ +src/src/pk/katja/katja_import.c \ +src/src/pk/katja/katja_make_key.c \ +src/src/pk/pkcs1/pkcs_1_i2osp.c \ +src/src/pk/pkcs1/pkcs_1_mgf1.c \ +src/src/pk/pkcs1/pkcs_1_oaep_decode.c \ +src/src/pk/pkcs1/pkcs_1_oaep_encode.c \ +src/src/pk/pkcs1/pkcs_1_os2ip.c \ +src/src/pk/pkcs1/pkcs_1_pss_decode.c \ +src/src/pk/pkcs1/pkcs_1_pss_encode.c \ +src/src/pk/pkcs1/pkcs_1_v1_5_decode.c \ +src/src/pk/pkcs1/pkcs_1_v1_5_encode.c \ +src/src/pk/rsa/rsa_decrypt_key.c \ +src/src/pk/rsa/rsa_encrypt_key.c \ +src/src/pk/rsa/rsa_export.c \ +src/src/pk/rsa/rsa_exptmod.c \ +src/src/pk/rsa/rsa_free.c \ +src/src/pk/rsa/rsa_get_size.c \ +src/src/pk/rsa/rsa_import.c \ +src/src/pk/rsa/rsa_import_pkcs8.c \ +src/src/pk/rsa/rsa_import_x509.c \ +src/src/pk/rsa/rsa_make_key.c \ +src/src/pk/rsa/rsa_set.c \ +src/src/pk/rsa/rsa_sign_hash.c \ +src/src/pk/rsa/rsa_sign_saltlen_get.c \ +src/src/pk/rsa/rsa_verify_hash.c \ +src/src/prngs/chacha20.c \ +src/src/prngs/fortuna.c \ +src/src/prngs/rc4.c \ +src/src/prngs/rng_get_bytes.c \ +src/src/prngs/rng_make_prng.c \ +src/src/prngs/sober128.c \ +src/src/prngs/sprng.c \ +src/src/prngs/yarrow.c \ +src/src/stream/chacha/chacha_crypt.c \ +src/src/stream/chacha/chacha_done.c \ +src/src/stream/chacha/chacha_ivctr32.c \ +src/src/stream/chacha/chacha_ivctr64.c \ +src/src/stream/chacha/chacha_keystream.c \ +src/src/stream/chacha/chacha_setup.c \ +src/src/stream/chacha/chacha_test.c \ +src/src/stream/rc4/rc4_stream.c \ +src/src/stream/rc4/rc4_test.c \ +src/src/stream/sober128/sober128_stream.c \ +src/src/stream/sober128/sober128tab.c \ +src/src/stream/sober128/sober128_test.c + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/src/src/headers +LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/src/src/headers + +LOCAL_CFLAGS := -DLTC_SOURCE -O3 -funroll-loops + +include $(BUILD_STATIC_LIBRARY) diff --git a/sqlcipher/src/main/jni/libtomcrypt/src b/sqlcipher/src/main/jni/libtomcrypt/src new file mode 160000 index 0000000..476a957 --- /dev/null +++ b/sqlcipher/src/main/jni/libtomcrypt/src @@ -0,0 +1 @@ +Subproject commit 476a9579ae94f32b9ea9e2747bfb04b302370259 diff --git a/sqlcipher/src/main/jni/sqlcipher/Android.mk b/sqlcipher/src/main/jni/sqlcipher/Android.mk index 6ed942b..ced979f 100644 --- a/sqlcipher/src/main/jni/sqlcipher/Android.mk +++ b/sqlcipher/src/main/jni/sqlcipher/Android.mk @@ -1,25 +1,52 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -ifdef $SSQLCIPHER_CFLAGS +ifdef SQLCIPHER_CFLAGS +$(info "Using external CFLAGS") LOCAL_CFLAGS += ${SQLCIPHER_CFLAGS} else -LOCAL_CFLAGS += -DSQLITE_HAS_CODEC -DSQLCIPHER_CRYPTO_OPENSSL -DSQLITE_TEMP_STORE=2 \ - -DSQLITE_THREADSAFE=1 -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_FTS3_PARENTHESIS \ - -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS4_UNICODE61 -DSQLITE_ENABLE_FTS5 \ - -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_UNLOCK_NOTIFY -DSQLITE_ENABLE_RTREE \ - -DSQLITE_SOUNDEX -DHAVE_USLEEP -DSQLITE_ENABLE_LOAD_EXTENSION -DSQLITE_ENABLE_STAT3 \ - -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ - -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_MAX_VARIABLE_NUMBER=99999 \ - -DSQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576 -DSQLITE_ENABLE_SESSION \ - -DSQLITE_ENABLE_PREUPDATE_HOOK -DSQLITE_ENABLE_DBSTAT_VTAB +$(info "Using default internal CFLAGS") +LOCAL_CFLAGS += \ + -DSQLITE_HAS_CODEC \ + -DSQLCIPHER_CRYPTO_LIBTOMCRYPT \ + -DSQLITE_TEMP_STORE=2 \ + -DSQLITE_THREADSAFE=1 \ + -DSQLITE_ENABLE_COLUMN_METADATA \ + -DSQLITE_ENABLE_FTS3_PARENTHESIS \ + -DSQLITE_ENABLE_FTS4 \ + -DSQLITE_ENABLE_FTS4_UNICODE61 \ + -DSQLITE_ENABLE_FTS5 \ + -DSQLITE_ENABLE_MEMORY_MANAGEMENT \ + -DSQLITE_ENABLE_UNLOCK_NOTIFY \ + -DSQLITE_ENABLE_RTREE \ + -DSQLITE_SOUNDEX \ + -DHAVE_USLEEP \ + -DSQLITE_ENABLE_LOAD_EXTENSION \ + -DSQLITE_ENABLE_STAT3 \ + -DSQLITE_ENABLE_STAT4 \ + -DSQLITE_ENABLE_JSON1 \ + -DSQLITE_ENABLE_EXPLAIN_COMMENTS \ + -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \ + -DSQLITE_MAX_VARIABLE_NUMBER=99999 \ + -DSQLITE_DEFAULT_JOURNAL_SIZE_LIMIT=1048576 \ + -DSQLITE_ENABLE_SESSION \ + -DSQLITE_ENABLE_PREUPDATE_HOOK \ + -DSQLITE_ENABLE_DBSTAT_VTAB \ + -DSQLITE_ENABLE_SNAPSHOT \ + -DSQLITE_USE_URI \ + -DSQLITE_EXTRA_INIT=sqlcipher_extra_init \ + -DSQLITE_EXTRA_SHUTDOWN=sqlcipher_extra_shutdown +endif + +ifeq ($(APP_OPTIM),release) +LOCAL_CFLAGS += -DNDEBUG endif LOCAL_CPPFLAGS += -Wno-conversion-null $(info SQLCipher LOCAL_CFLAGS:${LOCAL_CFLAGS}) -LOCAL_SRC_FILES:= \ +LOCAL_SRC_FILES := \ android_database_SQLiteCommon.cpp \ android_database_SQLiteConnection.cpp \ android_database_CursorWindow.cpp \ @@ -28,20 +55,31 @@ LOCAL_SRC_FILES:= \ JNIHelp.cpp \ JniConstants.cpp \ JNIString.cpp \ - CursorWindow.cpp - -LOCAL_SRC_FILES += sqlite3.c + CursorWindow.cpp \ + sqlite3.c -LOCAL_C_INCLUDES += $(LOCAL_PATH) $(LOCAL_PATH)/nativehelper/ $(LOCAL_PATH)/android-libs/include/ +LOCAL_C_INCLUDES += $(LOCAL_PATH) \ + $(LOCAL_PATH)/nativehelper/ \ + $(LOCAL_PATH)/android-libs/include/ \ + $(LOCAL_PATH)/android-libs/include/$(TARGET_ARCH_ABI) \ LOCAL_MODULE:= libsqlcipher LOCAL_LDLIBS += -ldl -llog LOCAL_LDFLAGS += -Wl,-z,max-page-size=16384 +ifeq ($(findstring SSL,$(LOCAL_CFLAGS)),SSL) LOCAL_STATIC_LIBRARIES += static-libcrypto - +else +LOCAL_STATIC_LIBRARIES += static-libtomcrypt +endif include $(BUILD_SHARED_LIBRARY) +ifeq ($(findstring SSL,$(LOCAL_CFLAGS)),SSL) include $(CLEAR_VARS) LOCAL_MODULE := static-libcrypto LOCAL_SRC_FILES := $(LOCAL_PATH)/android-libs/$(TARGET_ARCH_ABI)/libcrypto.a include $(PREBUILT_STATIC_LIBRARY) +else +include $(CLEAR_VARS) +include $(LOCAL_PATH)/../libtomcrypt/Android.mk +include $(CLEAR_VARS) +endif \ No newline at end of file diff --git a/sqlcipher/src/main/jni/sqlcipher/JNIHelp.cpp b/sqlcipher/src/main/jni/sqlcipher/JNIHelp.cpp index fd5884a..1e7088f 100644 --- a/sqlcipher/src/main/jni/sqlcipher/JNIHelp.cpp +++ b/sqlcipher/src/main/jni/sqlcipher/JNIHelp.cpp @@ -294,13 +294,11 @@ const char* jniStrError(int errnum, char* buf, size_t buflen) { // char *strerror_r(int errnum, char *buf, size_t n); return strerror_r(errnum, buf, buflen); #else - int rc = strerror_r(errnum, buf, buflen); - if (rc != 0) { - // (POSIX only guarantees a value other than 0. The safest - // way to implement this function is to use C++ and overload on the - // type of strerror_r to accurately distinguish GNU from POSIX.) - snprintf(buf, buflen, "errno %d", errnum); + char* msg = strerror_r(errnum, buf, buflen); + if (msg != nullptr){ + return msg; } + snprintf(buf, buflen, "errno %d", errnum); return buf; #endif } diff --git a/sqlcipher/src/main/jni/sqlcipher/android_database_CursorWindow.cpp b/sqlcipher/src/main/jni/sqlcipher/android_database_CursorWindow.cpp index a835f6d..8ddce4e 100644 --- a/sqlcipher/src/main/jni/sqlcipher/android_database_CursorWindow.cpp +++ b/sqlcipher/src/main/jni/sqlcipher/android_database_CursorWindow.cpp @@ -275,9 +275,9 @@ namespace android { jbyteArray valueObj, jint row, jint column) { auto* window = reinterpret_cast(windowPtr); jsize len = env->GetArrayLength(valueObj); - void* value = env->GetPrimitiveArrayCritical(valueObj, NULL); + jbyte* value = static_cast(env->GetByteArrayElements(valueObj, NULL)); status_t status = window->putBlob(row, column, value, len); - env->ReleasePrimitiveArrayCritical(valueObj, value, JNI_ABORT); + env->ReleaseByteArrayElements(valueObj, value, JNI_ABORT); if (status) { ALOGD("Failed to put blob. error=%d", status); return false; diff --git a/sqlcipher/src/main/jni/sqlcipher/android_database_SQLiteConnection.cpp b/sqlcipher/src/main/jni/sqlcipher/android_database_SQLiteConnection.cpp index fe82135..dcb6a7a 100644 --- a/sqlcipher/src/main/jni/sqlcipher/android_database_SQLiteConnection.cpp +++ b/sqlcipher/src/main/jni/sqlcipher/android_database_SQLiteConnection.cpp @@ -157,7 +157,7 @@ static jint nativeKey(JNIEnv* env, jclass clazz, jlong connectionPtr, jbyteArray } if (rc != SQLITE_OK) { ALOGE("sqlite3_key(%p) failed: %d", connection->db, rc); - throw_sqlite3_exception(env, connection->db, "Could not key db."); + throw_sqlite3_exception_errcode(env, rc, "Could not key db."); } return rc; } @@ -178,7 +178,7 @@ static jint nativeKey(JNIEnv* env, jclass clazz, jlong connectionPtr, jbyteArray } if (rc != SQLITE_OK) { ALOGE("sqlite3_rekey(%p) failed: %d", connection->db, rc); - throw_sqlite3_exception(env, connection->db, "Could not rekey db."); + throw_sqlite3_exception_errcode(env, rc, "Could not rekey db."); } return rc; } @@ -211,14 +211,14 @@ static jlong nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFla err = sqlite3_create_collation(db, "localized", SQLITE_UTF8, 0, coll_localized); if (err != SQLITE_OK) { throw_sqlite3_exception_errcode(env, err, "Could not register collation"); - sqlite3_close(db); + sqlite3_close_v2(db); return 0; } // Check that the database is really read/write when that is what we asked for. if ((sqliteFlags & SQLITE_OPEN_READWRITE) && sqlite3_db_readonly(db, NULL)) { throw_sqlite3_exception(env, db, "Could not open the database in read/write mode."); - sqlite3_close(db); + sqlite3_close_v2(db); return 0; } @@ -226,10 +226,13 @@ static jlong nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFla err = sqlite3_busy_timeout(db, BUSY_TIMEOUT_MS); if (err != SQLITE_OK) { throw_sqlite3_exception(env, db, "Could not set busy timeout"); - sqlite3_close(db); + sqlite3_close_v2(db); return 0; } + // Enable extension loading + sqlite3_enable_load_extension(db, 1); + // Create wrapper object. auto* connection = new SQLiteConnection(db, openFlags, path, label); @@ -250,10 +253,10 @@ static void nativeClose(JNIEnv* env, jclass clazz, jlong connectionPtr) { if (connection) { ALOGV("Closing connection %p", connection->db); - int err = sqlite3_close(connection->db); + int err = sqlite3_close_v2(connection->db); if (err != SQLITE_OK) { // This can happen if sub-objects aren't closed first. Make sure the caller knows. - ALOGE("sqlite3_close(%p) failed: %d", connection->db, err); + ALOGE("sqlite3_close_v2(%p) failed: %d", connection->db, err); throw_sqlite3_exception(env, connection->db, "Count not close db."); return; } @@ -351,11 +354,11 @@ static jlong nativePrepareStatement(JNIEnv* env, jclass clazz, jlong connectionP auto* connection = reinterpret_cast(connectionPtr); jsize sqlLength = env->GetStringLength(sqlString); - const jchar* sql = env->GetStringCritical(sqlString, NULL); + const jchar* sql = env->GetStringChars(sqlString, NULL); sqlite3_stmt* statement; int err = sqlite3_prepare16_v2(connection->db, sql, sqlLength * sizeof(jchar), &statement, NULL); - env->ReleaseStringCritical(sqlString, sql); + env->ReleaseStringChars(sqlString, sql); if (err != SQLITE_OK) { // Error messages like 'near ")": syntax error' are not @@ -456,10 +459,10 @@ static void nativeBindString(JNIEnv* env, jclass clazz, jlong connectionPtr, auto* connection = reinterpret_cast(connectionPtr); auto* statement = reinterpret_cast(statementPtr); jsize valueLength = env->GetStringLength(valueString); - const jchar* value = env->GetStringCritical(valueString, NULL); + const jchar* value = env->GetStringChars(valueString, NULL); int err = sqlite3_bind_text16(statement, index, value, valueLength * sizeof(jchar), SQLITE_TRANSIENT); - env->ReleaseStringCritical(valueString, value); + env->ReleaseStringChars(valueString, value); if (err != SQLITE_OK) { throw_sqlite3_exception(env, connection->db, NULL); } @@ -470,9 +473,9 @@ static void nativeBindBlob(JNIEnv* env, jclass clazz, jlong connectionPtr, auto* connection = reinterpret_cast(connectionPtr); auto* statement = reinterpret_cast(statementPtr); jsize valueLength = env->GetArrayLength(valueArray); - auto* value = static_cast(env->GetPrimitiveArrayCritical(valueArray, NULL)); + jbyte* value = static_cast(env->GetByteArrayElements(valueArray, NULL)); int err = sqlite3_bind_blob(statement, index, value, valueLength, SQLITE_TRANSIENT); - env->ReleasePrimitiveArrayCritical(valueArray, value, JNI_ABORT); + env->ReleaseByteArrayElements(valueArray, value, JNI_ABORT); if (err != SQLITE_OK) { throw_sqlite3_exception(env, connection->db, NULL); } @@ -918,17 +921,59 @@ extern int register_android_database_CursorWindow(JNIEnv *env); } // namespace android +void setEnvarToCacheDirectory(JNIEnv* env, const char *envar) { + jclass activity = NULL, context = NULL, file = NULL; + jmethodID getCurrentApp = NULL, getCacheDir = NULL, getAbsolutePath = NULL; + jobject app = NULL, cache = NULL; + jstring path = NULL; + const char *pathUtf8 = NULL, *tmpdir = getenv(envar); + + /* check if SQLCIPHER_TMP is already set externally by the application (i.e. an override), and return immediately if it is */ + if(tmpdir && strlen(tmpdir) > 0) { + return; + } + + /* call ActivityThread.currentApplication().getCacheDir().getAbsolutePath() and set it to SQLCIPHER_TMP*/ + if ( + (activity = env->FindClass("android/app/ActivityThread")) + && (context = env->FindClass("android/content/Context")) + && (file = env->FindClass("java/io/File")) + && (getCurrentApp = env->GetStaticMethodID(activity, "currentApplication", "()Landroid/app/Application;")) + && (getCacheDir = env->GetMethodID(context, "getCacheDir", "()Ljava/io/File;")) + && (getAbsolutePath = env->GetMethodID(file, "getAbsolutePath", "()Ljava/lang/String;")) + && (app = env->CallStaticObjectMethod(activity, getCurrentApp)) + && (cache = env->CallObjectMethod(app, getCacheDir)) + && (path = (jstring) env->CallObjectMethod(cache, getAbsolutePath)) + && (pathUtf8 = env->GetStringUTFChars(path, NULL)) + ) { + setenv(envar, pathUtf8, 1); + } else { + ALOGE("%s unable to obtain cache directory from JNIEnv", __func__); + } + + /* cleanup */ + if(pathUtf8) env->ReleaseStringUTFChars(path, pathUtf8); + if(path) env->DeleteLocalRef(path); + if(cache) env->DeleteLocalRef(cache); + if(app) env->DeleteLocalRef(app); + if(file) env->DeleteLocalRef(file); + if(context) env->DeleteLocalRef(context); + if(activity) env->DeleteLocalRef(activity); +} + + extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv *env = 0; android::gpJavaVM = vm; vm->GetEnv((void**)&env, JNI_VERSION_1_4); - + setEnvarToCacheDirectory(env, "SQLCIPHER_TMP"); android::register_android_database_SQLiteConnection(env); android::register_android_database_SQLiteDebug(env); android::register_android_database_SQLiteGlobal(env); android::register_android_database_CursorWindow(env); + return JNI_VERSION_1_4; } diff --git a/sqlcipher/src/main/jni/sqlcipher/src b/sqlcipher/src/main/jni/sqlcipher/src new file mode 160000 index 0000000..0b4d160 --- /dev/null +++ b/sqlcipher/src/main/jni/sqlcipher/src @@ -0,0 +1 @@ +Subproject commit 0b4d16090a71579c4c88220b7fb67bb7396f1434