├── .editorconfig ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── config.yml │ └── issue.md ├── PULL_REQUEST_TEMPLATE.md └── stale.yml ├── .gitignore ├── .gitmodules ├── Makefile ├── README.md ├── SQLCIPHER_LICENSE ├── android-database-sqlcipher ├── build-openssl-libraries.sh ├── build.gradle ├── maven.gradle ├── native.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── aidl │ └── net │ │ └── sqlcipher │ │ └── IContentObserver.aidl │ ├── cpp │ ├── Android.mk │ ├── Application32.mk │ ├── Application64.mk │ ├── CursorWindow.cpp │ ├── CursorWindow.h │ ├── jni_elements.h │ ├── jni_exception.cpp │ ├── jni_exception.h │ ├── log.h │ ├── net_sqlcipher_CursorWindow.cpp │ ├── net_sqlcipher_database_SQLiteCompiledSql.cpp │ ├── net_sqlcipher_database_SQLiteDatabase.cpp │ ├── net_sqlcipher_database_SQLiteDebug.cpp │ ├── net_sqlcipher_database_SQLiteProgram.cpp │ ├── net_sqlcipher_database_SQLiteQuery.cpp │ ├── net_sqlcipher_database_SQLiteStatement.cpp │ ├── sqlcipher_loading.h │ └── sqlite3_exception.h │ ├── java │ └── net │ │ └── sqlcipher │ │ ├── AbstractCursor.java │ │ ├── AbstractWindowedCursor.java │ │ ├── BulkCursorNative.java │ │ ├── BulkCursorToCursorAdaptor.java │ │ ├── CrossProcessCursorWrapper.java │ │ ├── Cursor.java │ │ ├── CursorIndexOutOfBoundsException.java │ │ ├── CursorWindow.java │ │ ├── CursorWindowAllocation.java │ │ ├── CursorWrapper.java │ │ ├── CustomCursorWindowAllocation.java │ │ ├── DatabaseErrorHandler.java │ │ ├── DatabaseUtils.java │ │ ├── DefaultCursorWindowAllocation.java │ │ ├── DefaultDatabaseErrorHandler.java │ │ ├── IBulkCursor.java │ │ ├── InvalidRowColumnException.java │ │ ├── MatrixCursor.java │ │ ├── RowAllocationException.java │ │ ├── StaleDataException.java │ │ ├── UnknownTypeException.java │ │ ├── database │ │ ├── DatabaseObjectNotClosedException.java │ │ ├── SQLiteClosable.java │ │ ├── SQLiteCompiledSql.java │ │ ├── SQLiteContentHelper.java │ │ ├── SQLiteCursor.java │ │ ├── SQLiteCursorDriver.java │ │ ├── SQLiteDatabase.java │ │ ├── SQLiteDatabaseHook.java │ │ ├── SQLiteDebug.java │ │ ├── SQLiteDirectCursorDriver.java │ │ ├── SQLiteOpenHelper.java │ │ ├── SQLiteProgram.java │ │ ├── SQLiteQuery.java │ │ ├── SQLiteQueryBuilder.java │ │ ├── SQLiteQueryStats.java │ │ ├── SQLiteStatement.java │ │ ├── SQLiteTransactionListener.java │ │ ├── SqliteWrapper.java │ │ ├── SupportFactory.java │ │ ├── SupportHelper.java │ │ └── package-info.java │ │ └── package-info.java │ └── res │ └── values │ └── android_database_sqlcipher_strings.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | charset = utf-8 4 | 5 | [*.{java,cpp,h,aidl,xml,md}] 6 | indent_style = space 7 | indent_size = 4 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | end_of_line = lf 11 | 12 | [*.gradle] 13 | indent_style = space 14 | indent_size = 2 15 | trim_trailing_whitespace = true 16 | insert_final_newline = true 17 | end_of_line = lf 18 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | We ask that you submit a contributor agreement in order for us to accept this request. More information about this agreement can be found [here](https://www.zetetic.net/contributions/). Pull requests are merged into the `master` branch. Please let us know if you have any further questions. Thanks! 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: 💬 Community support 4 | url: https://discuss.zetetic.net/c/sqlcipher/5 5 | about: Integration problem or question about SQLCipher for Android, feel free to ask here. 6 | - name: 🔨 Build issue 7 | url: https://discuss.zetetic.net/c/sqlcipher/5 8 | about: Experience an issue building SQLCipher for Android? Start here. 9 | - name: 📃 SQLCipher documentation 10 | url: https://www.zetetic.net/sqlcipher/sqlcipher-api/ 11 | about: SQLCipher documentation can be found here. 12 | - name: 📖 Contribution instructions 13 | url: https://www.zetetic.net/contributions/ 14 | about: Want to contribute to SQLCipher for Android? Start here. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🛠️ Bug report 3 | about: Create a report about a software defect 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | ### Expected Behavior 10 | 11 | ### Actual Behavior 12 | 13 | ### Steps to Reproduce 14 | 15 | SQLCipher version (can be identified by executing `PRAGMA cipher_version;`): 16 | 17 | SQLCipher for Android version: 18 | 19 | Are you able to reproduce this issue within the SQLCipher for Android [test suite](https://github.com/sqlcipher/sqlcipher-android-tests)? 20 | 21 | *Note:* If you are not posting a specific issue for the SQLCipher library, please post your question to the SQLCipher [discuss site](https://discuss.zetetic.net/c/sqlcipher). Thanks! 22 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Changes proposed in this pull request: 2 | - 3 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale - https://github.com/probot/stale 2 | # Number of days of inactivity before an issue becomes stale 3 | daysUntilStale: 14 4 | # Number of days of inactivity before a stale issue is closed 5 | daysUntilClose: 14 6 | # Issues with these labels will never be considered stale 7 | exemptLabels: 8 | - bug 9 | - enhancement 10 | - security 11 | # Label to use when marking an issue as stale 12 | staleLabel: stale 13 | # Comment to post when marking an issue as stale. Set to `false` to disable 14 | markComment: > 15 | Hello, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. 16 | You may also label this issue as "bug", "enhancement", or "security" and I will leave it open. 17 | Thank you for your contributions. 18 | # Comment to post when closing a stale issue. Set to `false` to disable 19 | closeComment: > 20 | Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to reopen with up-to-date information. 21 | only: issues 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build 3 | .DS_Store 4 | android-database-sqlcipher/src/main/external/sqlcipher 5 | android-database-sqlcipher/src/main/external/openssl 6 | android-database-sqlcipher/src/main/external/android-libs/ 7 | android-database-sqlcipher/.externalNativeBuild/ 8 | android-database-sqlcipher/src/main/libs* 9 | android-database-sqlcipher/src/main/obj 10 | android-database-sqlcipher/src/main/external/openssl-*/ 11 | android-database-sqlcipher/src/main/cpp/sqlite3.[c,h] 12 | .idea/ 13 | *.iml 14 | local.properties -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqlcipher/android-database-sqlcipher/b3df67d8731bd0ebd987acb561a2c3fdd8e17082/.gitmodules -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .POSIX: 2 | .PHONY: init clean distclean build-openssl build publish-local-snapshot \ 3 | publish-local-release publish-remote-snapshot public-remote-release check 4 | GRADLE = ./gradlew 5 | 6 | clean: 7 | $(GRADLE) clean 8 | 9 | distclean: 10 | $(GRADLE) distclean \ 11 | -PsqlcipherRoot="$(SQLCIPHER_ROOT)" 12 | 13 | build-openssl: 14 | $(GRADLE) buildOpenSSL 15 | 16 | check: 17 | $(GRADLE) check 18 | 19 | format: 20 | $(GRADLE) editorconfigFormat 21 | 22 | build-debug: 23 | $(GRADLE) android-database-sqlcipher:bundleDebugAar \ 24 | -PdebugBuild=true \ 25 | -PsqlcipherRoot="$(SQLCIPHER_ROOT)" \ 26 | -PopensslRoot="$(OPENSSL_ROOT)" \ 27 | -PopensslAndroidNativeRoot="$(OPENSSL_ANDROID_LIB_ROOT)" \ 28 | -PsqlcipherCFlags="$(SQLCIPHER_CFLAGS)" \ 29 | -PsqlcipherAndroidClientVersion="$(SQLCIPHER_ANDROID_VERSION)" 30 | 31 | build-release: 32 | $(GRADLE) android-database-sqlcipher:bundleReleaseAar \ 33 | -PdebugBuild=false \ 34 | -PsqlcipherRoot="$(SQLCIPHER_ROOT)" \ 35 | -PopensslRoot="$(OPENSSL_ROOT)" \ 36 | -PopensslAndroidNativeRoot="$(OPENSSL_ANDROID_LIB_ROOT)" \ 37 | -PsqlcipherCFlags="$(SQLCIPHER_CFLAGS)" \ 38 | -PsqlcipherAndroidClientVersion="$(SQLCIPHER_ANDROID_VERSION)" 39 | 40 | publish-local-snapshot: 41 | @ $(collect-signing-info) \ 42 | $(GRADLE) \ 43 | -PpublishSnapshot=true \ 44 | -PpublishLocal=true \ 45 | -PsigningKeyId="$$gpgKeyId" \ 46 | -PsigningKeyRingFile="$$gpgKeyRingFile" \ 47 | -PsigningKeyPassword="$$gpgPassword" \ 48 | uploadArchives 49 | 50 | publish-local-release: 51 | @ $(collect-signing-info) \ 52 | $(GRADLE) \ 53 | -PpublishSnapshot=false \ 54 | -PpublishLocal=true \ 55 | -PsigningKeyId="$$gpgKeyId" \ 56 | -PsigningKeyRingFile="$$gpgKeyRingFile" \ 57 | -PsigningKeyPassword="$$gpgPassword" \ 58 | uploadArchives 59 | 60 | publish-remote-snapshot: 61 | @ $(collect-signing-info) \ 62 | $(collect-nexus-info) \ 63 | $(GRADLE) \ 64 | -PpublishSnapshot=true \ 65 | -PpublishLocal=false \ 66 | -PsigningKeyId="$$gpgKeyId" \ 67 | -PsigningKeyRingFile="$$gpgKeyRingFile" \ 68 | -PsigningKeyPassword="$$gpgPassword" \ 69 | -PnexusUsername="$$nexusUsername" \ 70 | -PnexusPassword="$$nexusPassword" \ 71 | uploadArchives 72 | 73 | publish-remote-release: 74 | @ $(collect-signing-info) \ 75 | $(collect-nexus-info) \ 76 | $(GRADLE) \ 77 | -PpublishSnapshot=false \ 78 | -PpublishLocal=false \ 79 | -PdebugBuild=false \ 80 | -PsigningKeyId="$$gpgKeyId" \ 81 | -PsigningKeyRingFile="$$gpgKeyRingFile" \ 82 | -PsigningKeyPassword="$$gpgPassword" \ 83 | -PnexusUsername="$$nexusUsername" \ 84 | -PnexusPassword="$$nexusPassword" \ 85 | -PsqlcipherRoot="$(SQLCIPHER_ROOT)" \ 86 | -PopensslRoot="$(OPENSSL_ROOT)" \ 87 | -PopensslAndroidLibRoot="$(OPENSSL_ANDROID_LIB_ROOT)" \ 88 | -PsqlcipherCFlags="$(SQLCIPHER_CFLAGS)" \ 89 | -PsqlcipherAndroidClientVersion="$(SQLCIPHER_ANDROID_VERSION)" \ 90 | android-database-sqlcipher:publish 91 | 92 | collect-nexus-info := \ 93 | read -p "Enter Nexus username:" nexusUsername; \ 94 | stty -echo; read -p "Enter Nexus password:" nexusPassword; stty echo; 95 | 96 | collect-signing-info := \ 97 | read -p "Enter GPG signing key id:" gpgKeyId; \ 98 | read -p "Enter full path to GPG keyring file \ 99 | (possibly ${HOME}/.gnupg/secring.gpg)" gpgKeyRingFile; \ 100 | stty -echo; read -p "Enter GPG password:" gpgPassword; stty echo; 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Deprecated Library 2 | 3 | The `android-database-sqlcipher` project has been [officially deprecated](https://www.zetetic.net/blog/2023/08/31/sqlcipher-4.5.5-release#sqlcipher-android-455). The long-term replacement is [`sqlcipher-android`](https://github.com/sqlcipher/sqlcipher-android). Instructions for migrating from `android-database-sqlcipher` to `sqlcipher-android`may be found [here](https://www.zetetic.net/sqlcipher/sqlcipher-for-android-migration/). 4 | 5 | 6 | ### Download Source and Binaries 7 | 8 | The latest AAR binary package information can be [here](https://www.zetetic.net/sqlcipher/open-source), the source can be found [here](https://github.com/sqlcipher/android-database-sqlcipher). 9 |
10 | 11 | ### Compatibility 12 | 13 | SQLCipher for Android runs on Android from 5.0 (API 21), for `armeabi-v7a`, `x86`, `x86_64`, and `arm64_v8a` architectures. 14 | 15 | ### Contributions 16 | 17 | We welcome contributions, to contribute to SQLCipher for Android, a [contributor agreement](https://www.zetetic.net/contributions/) needs to be submitted. All submissions should be based on the `master` branch. 18 | 19 | ### An Illustrative Terminal Listing 20 | 21 | A typical SQLite database in unencrypted, and visually parseable even as encoded text. The following example shows the difference between hexdumps of a standard SQLite database and one implementing SQLCipher. 22 | 23 | ``` 24 | ~ sjlombardo$ hexdump -C sqlite.db 25 | 00000000 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 |SQLite format 3.| 26 | … 27 | 000003c0 65 74 32 74 32 03 43 52 45 41 54 45 20 54 41 42 |et2t2.CREATE TAB| 28 | 000003d0 4c 45 20 74 32 28 61 2c 62 29 24 01 06 17 11 11 |LE t2(a,b)$…..| 29 | … 30 | 000007e0 20 74 68 65 20 73 68 6f 77 15 01 03 01 2f 01 6f | the show…./.o| 31 | 000007f0 6e 65 20 66 6f 72 20 74 68 65 20 6d 6f 6e 65 79 |ne for the money| 32 | 33 | ~ $ sqlite3 sqlcipher.db 34 | sqlite> PRAGMA KEY=’test123′; 35 | sqlite> CREATE TABLE t1(a,b); 36 | sqlite> INSERT INTO t1(a,b) VALUES (‘one for the money’, ‘two for the show’); 37 | sqlite> .quit 38 | 39 | ~ $ hexdump -C sqlcipher.db 40 | 00000000 84 d1 36 18 eb b5 82 90 c4 70 0d ee 43 cb 61 87 |.?6.?..?p.?C?a.| 41 | 00000010 91 42 3c cd 55 24 ab c6 c4 1d c6 67 b4 e3 96 bb |.B?..?| 42 | 00000bf0 8e 99 ee 28 23 43 ab a4 97 cd 63 42 8a 8e 7c c6 |..?(#C??.?cB..|?| 43 | 44 | ~ $ sqlite3 sqlcipher.db 45 | sqlite> SELECT * FROM t1; 46 | Error: file is encrypted or is not a database 47 | ``` 48 | (example courtesy of SQLCipher) 49 | 50 | ### Application Integration 51 | 52 | You have a two main options for using SQLCipher for Android in your app: 53 | 54 | - Using it with Room or other consumers of the `androidx.sqlite` API 55 | 56 | - Using the native SQLCipher for Android classes 57 | 58 | In both cases, you will need to add a dependency on `net.zetetic:android-database-sqlcipher`, 59 | such as having the following line in your module's `build.gradle` `dependencies` 60 | closure: 61 | 62 | ```gradle 63 | implementation "net.zetetic:android-database-sqlcipher:4.5.3" 64 | implementation "androidx.sqlite:sqlite:2.1.0" 65 | ``` 66 | 67 | (replacing `4.5.3` with the version you want) 68 | 69 |48 | * Returned column types are 49 | *
32 | * If null is specified for DatabaeErrorHandler param in the above calls, then this class is used
33 | * as the default {@link DatabaseErrorHandler}.
34 | */
35 | public final class DefaultDatabaseErrorHandler implements DatabaseErrorHandler {
36 |
37 | private final String TAG = getClass().getSimpleName();
38 |
39 | /**
40 | * defines the default method to be invoked when database corruption is detected.
41 | * @param dbObj the {@link SQLiteDatabase} object representing the database on which corruption
42 | * is detected.
43 | */
44 | public void onCorruption(SQLiteDatabase dbObj) {
45 | // NOTE: Unlike the AOSP, this version does NOT attempt to delete any attached databases.
46 | // TBD: Are we really certain that the attached databases would really be corrupt?
47 | Log.e(TAG, "Corruption reported by sqlite on database, deleting: " + dbObj.getPath());
48 |
49 | if (dbObj.isOpen()) {
50 | Log.e(TAG, "Database object for corrupted database is already open, closing");
51 |
52 | try {
53 | dbObj.close();
54 | } catch (Exception e) {
55 | /* ignored */
56 | Log.e(TAG, "Exception closing Database object for corrupted database, ignored", e);
57 | }
58 | }
59 |
60 | deleteDatabaseFile(dbObj.getPath());
61 | }
62 |
63 | private void deleteDatabaseFile(String fileName) {
64 | if (fileName.equalsIgnoreCase(":memory:") || fileName.trim().length() == 0) {
65 | return;
66 | }
67 | Log.e(TAG, "deleting the database file: " + fileName);
68 | try {
69 | new File(fileName).delete();
70 | } catch (Exception e) {
71 | /* print warning and ignore exception */
72 | Log.w(TAG, "delete failed: " + e.getMessage());
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/android-database-sqlcipher/src/main/java/net/sqlcipher/IBulkCursor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2006 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.sqlcipher;
18 |
19 | import android.os.RemoteException;
20 | import android.os.IBinder;
21 | import android.os.IInterface;
22 | import android.os.Bundle;
23 |
24 | import java.util.Map;
25 |
26 | /**
27 | * This interface provides a low-level way to pass bulk cursor data across
28 | * both process and language boundries. Application code should use the Cursor
29 | * interface directly.
30 | *
31 | * {@hide}
32 | */
33 | public interface IBulkCursor extends IInterface {
34 | /**
35 | * Returns a BulkCursorWindow, which either has a reference to a shared
36 | * memory segment with the rows, or an array of JSON strings.
37 | */
38 | public CursorWindow getWindow(int startPos) throws RemoteException;
39 |
40 | public void onMove(int position) throws RemoteException;
41 |
42 | /**
43 | * Returns the number of rows in the cursor.
44 | *
45 | * @return the number of rows in the cursor.
46 | */
47 | public int count() throws RemoteException;
48 |
49 | /**
50 | * Returns a string array holding the names of all of the columns in the
51 | * cursor in the order in which they were listed in the result.
52 | *
53 | * @return the names of the columns returned in this query.
54 | */
55 | public String[] getColumnNames() throws RemoteException;
56 |
57 | public boolean updateRows(Map extends Long, ? extends Map Note: this method acquires the database lock. The database lock must be held when calling this method.
151 | * @param sql The SQL to compile.
152 | */
153 | private final native void native_compile(String sql);
154 | private final native void native_finalize();
155 | }
156 |
--------------------------------------------------------------------------------
/android-database-sqlcipher/src/main/java/net/sqlcipher/database/SQLiteContentHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.sqlcipher.database;
18 | import net.sqlcipher.*;
19 |
20 | import android.content.res.AssetFileDescriptor;
21 | import android.os.MemoryFile;
22 |
23 | import android.database.Cursor;
24 |
25 | import java.io.FileNotFoundException;
26 | import java.io.IOException;
27 |
28 | /**
29 | * Some helper functions for using SQLite database to implement content providers.
30 | *
31 | * @hide
32 | */
33 | public class SQLiteContentHelper {
34 |
35 | /**
36 | * Runs an SQLite query and returns an AssetFileDescriptor for the
37 | * blob in column 0 of the first row. If the first column does
38 | * not contain a blob, an unspecified exception is thrown.
39 | *
40 | * @param db Handle to a readable database.
41 | * @param sql SQL query, possibly with query arguments.
42 | * @param selectionArgs Query argument values, or {@code null} for no argument.
43 | * @return If no exception is thrown, a non-null AssetFileDescriptor is returned.
44 | * @throws FileNotFoundException If the query returns no results or the
45 | * value of column 0 is NULL, or if there is an error creating the
46 | * asset file descriptor.
47 | */
48 | public static AssetFileDescriptor getBlobColumnAsAssetFile(SQLiteDatabase db, String sql,
49 | String[] selectionArgs) throws FileNotFoundException {
50 | android.os.ParcelFileDescriptor fd = null;
51 |
52 | try {
53 | MemoryFile file = simpleQueryForBlobMemoryFile(db, sql, selectionArgs);
54 | if (file == null) {
55 | throw new FileNotFoundException("No results.");
56 | }
57 | Class c = file.getClass();
58 | try {
59 | java.lang.reflect.Method m = c.getDeclaredMethod("getParcelFileDescriptor");
60 | m.setAccessible(true);
61 | fd = (android.os.ParcelFileDescriptor)m.invoke(file);
62 | } catch (Exception e) {
63 | android.util.Log.i("SQLiteContentHelper", "SQLiteCursor.java: " + e);
64 | }
65 | AssetFileDescriptor afd = new AssetFileDescriptor(fd, 0, file.length());
66 | return afd;
67 | } catch (IOException ex) {
68 | throw new FileNotFoundException(ex.toString());
69 | }
70 | }
71 |
72 | /**
73 | * Runs an SQLite query and returns a MemoryFile for the
74 | * blob in column 0 of the first row. If the first column does
75 | * not contain a blob, an unspecified exception is thrown.
76 | *
77 | * @return A memory file, or {@code null} if the query returns no results
78 | * or the value column 0 is NULL.
79 | * @throws IOException If there is an error creating the memory file.
80 | */
81 | // TODO: make this native and use the SQLite blob API to reduce copying
82 | private static MemoryFile simpleQueryForBlobMemoryFile(SQLiteDatabase db, String sql,
83 | String[] selectionArgs) throws IOException {
84 | Cursor cursor = db.rawQuery(sql, selectionArgs);
85 | if (cursor == null) {
86 | return null;
87 | }
88 | try {
89 | if (!cursor.moveToFirst()) {
90 | return null;
91 | }
92 | byte[] bytes = cursor.getBlob(0);
93 | if (bytes == null) {
94 | return null;
95 | }
96 | MemoryFile file = new MemoryFile(null, bytes.length);
97 | file.writeBytes(bytes, 0, 0, bytes.length);
98 |
99 | // file.deactivate();
100 | return file;
101 | } finally {
102 | cursor.close();
103 | }
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/android-database-sqlcipher/src/main/java/net/sqlcipher/database/SQLiteCursorDriver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.sqlcipher.database;
18 |
19 | import net.sqlcipher.database.SQLiteDatabase.CursorFactory;
20 | import net.sqlcipher.*;
21 |
22 | /**
23 | * A driver for SQLiteCursors that is used to create them and gets notified
24 | * by the cursors it creates on significant events in their lifetimes.
25 | */
26 | public interface SQLiteCursorDriver {
27 | /**
28 | * Executes the query returning a Cursor over the result set.
29 | *
30 | * @param factory The CursorFactory to use when creating the Cursors, or
31 | * null if standard SQLiteCursors should be returned.
32 | * @return a Cursor over the result set
33 | */
34 | Cursor query(CursorFactory factory, String[] bindArgs);
35 |
36 | /**
37 | * Called by a SQLiteCursor when it is released.
38 | */
39 | void cursorDeactivated();
40 |
41 | /**
42 | * Called by a SQLiteCursor when it is requeryed.
43 | *
44 | * @return The new count value.
45 | */
46 | void cursorRequeried(android.database.Cursor cursor);
47 |
48 | /**
49 | * Called by a SQLiteCursor when it it closed to destroy this object as well.
50 | */
51 | void cursorClosed();
52 |
53 | /**
54 | * Set new bind arguments. These will take effect in cursorRequeried().
55 | * @param bindArgs the new arguments
56 | */
57 | public void setBindArguments(String[] bindArgs);
58 | }
59 |
--------------------------------------------------------------------------------
/android-database-sqlcipher/src/main/java/net/sqlcipher/database/SQLiteDatabaseHook.java:
--------------------------------------------------------------------------------
1 | package net.sqlcipher.database;
2 |
3 | /**
4 | * An interface to perform pre and post key operations against a database.
5 | */
6 | public interface SQLiteDatabaseHook {
7 | /**
8 | * Called immediately before opening the database.
9 | */
10 | void preKey(SQLiteDatabase database);
11 | /**
12 | * Called immediately after opening the database.
13 | */
14 | void postKey(SQLiteDatabase database);
15 | }
16 |
--------------------------------------------------------------------------------
/android-database-sqlcipher/src/main/java/net/sqlcipher/database/SQLiteDebug.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.sqlcipher.database;
18 |
19 | import java.util.ArrayList;
20 |
21 | import android.util.Log;
22 |
23 | /**
24 | * Provides debugging info about all SQLite databases running in the current process.
25 | *
26 | * {@hide}
27 | */
28 | public final class SQLiteDebug {
29 | /**
30 | * Controls the printing of SQL statements as they are executed.
31 | */
32 | public static final boolean DEBUG_SQL_STATEMENTS =
33 | Log.isLoggable("SQLiteStatements", Log.VERBOSE);
34 |
35 | /**
36 | * Controls the printing of wall-clock time taken to execute SQL statements
37 | * as they are executed.
38 | */
39 | public static final boolean DEBUG_SQL_TIME =
40 | Log.isLoggable("SQLiteTime", Log.VERBOSE);
41 |
42 | /**
43 | * Controls the printing of compiled-sql-statement cache stats.
44 | */
45 | public static final boolean DEBUG_SQL_CACHE =
46 | Log.isLoggable("SQLiteCompiledSql", Log.VERBOSE);
47 |
48 | /**
49 | * Controls the stack trace reporting of active cursors being
50 | * finalized.
51 | */
52 | public static final boolean DEBUG_ACTIVE_CURSOR_FINALIZATION =
53 | Log.isLoggable("SQLiteCursorClosing", Log.VERBOSE);
54 |
55 | /**
56 | * Controls the tracking of time spent holding the database lock.
57 | */
58 | public static final boolean DEBUG_LOCK_TIME_TRACKING =
59 | Log.isLoggable("SQLiteLockTime", Log.VERBOSE);
60 |
61 | /**
62 | * Controls the printing of stack traces when tracking the time spent holding the database lock.
63 | */
64 | public static final boolean DEBUG_LOCK_TIME_TRACKING_STACK_TRACE =
65 | Log.isLoggable("SQLiteLockStackTrace", Log.VERBOSE);
66 |
67 | /**
68 | * Contains statistics about the active pagers in the current process.
69 | *
70 | * @see #getPagerStats(PagerStats)
71 | */
72 | public static class PagerStats {
73 | /** The total number of bytes in all pagers in the current process
74 | * @deprecated not used any longer
75 | */
76 | @Deprecated
77 | public long totalBytes;
78 | /** The number of bytes in referenced pages in all pagers in the current process
79 | * @deprecated not used any longer
80 | * */
81 | @Deprecated
82 | public long referencedBytes;
83 | /** The number of bytes in all database files opened in the current process
84 | * @deprecated not used any longer
85 | */
86 | @Deprecated
87 | public long databaseBytes;
88 | /** The number of pagers opened in the current process
89 | * @deprecated not used any longer
90 | */
91 | @Deprecated
92 | public int numPagers;
93 |
94 | /** the current amount of memory checked out by sqlite using sqlite3_malloc().
95 | * documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
96 | */
97 | public int memoryUsed;
98 |
99 | /** the number of bytes of page cache allocation which could not be sattisfied by the
100 | * SQLITE_CONFIG_PAGECACHE buffer and where forced to overflow to sqlite3_malloc().
101 | * The returned value includes allocations that overflowed because they where too large
102 | * (they were larger than the "sz" parameter to SQLITE_CONFIG_PAGECACHE) and allocations
103 | * that overflowed because no space was left in the page cache.
104 | * documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
105 | */
106 | public int pageCacheOverflo;
107 |
108 | /** records the largest memory allocation request handed to sqlite3.
109 | * documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
110 | */
111 | public int largestMemAlloc;
112 |
113 | /** a list of {@link DbStats} - one for each main database opened by the applications
114 | * running on the android device
115 | */
116 | public ArrayList The database lock must be held when calling this method.
343 | * @param sql The SQL to compile.
344 | */
345 | @Deprecated
346 | protected final native void native_compile(String sql);
347 |
348 | /**
349 | * @deprecated This method is deprecated and must not be used.
350 | */
351 | @Deprecated
352 | protected final native void native_finalize();
353 |
354 | protected final native void native_bind_null(int index);
355 | protected final native void native_bind_long(int index, long value);
356 | protected final native void native_bind_double(int index, double value);
357 | protected final native void native_bind_string(int index, String value);
358 | protected final native void native_bind_blob(int index, byte[] value);
359 | private final native void native_clear_bindings();
360 | }
361 |
362 |
--------------------------------------------------------------------------------
/android-database-sqlcipher/src/main/java/net/sqlcipher/database/SQLiteQuery.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2006 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.sqlcipher.database;
18 | import net.sqlcipher.*;
19 |
20 | import android.database.sqlite.SQLiteDatabaseCorruptException;
21 | import android.database.sqlite.SQLiteMisuseException;
22 | import android.os.SystemClock;
23 | import android.util.Log;
24 |
25 | /**
26 | * A SQLite program that represents a query that reads the resulting rows into a CursorWindow.
27 | * This class is used by SQLiteCursor and isn't useful itself.
28 | *
29 | * SQLiteQuery is not internally synchronized so code using a SQLiteQuery from multiple
30 | * threads should perform its own synchronization when using the SQLiteQuery.
31 | */
32 | public class SQLiteQuery extends SQLiteProgram {
33 | private static final String TAG = "Cursor";
34 |
35 | /** The index of the unbound OFFSET parameter */
36 | private int mOffsetIndex;
37 |
38 | /** Args to bind on requery */
39 | private String[] mBindArgs;
40 | private Object[] mObjectBindArgs;
41 |
42 | /**
43 | * Create a persistent query object.
44 | *
45 | * @param db The database that this query object is associated with
46 | * @param query The SQL string for this query.
47 | * @param offsetIndex The 1-based index to the OFFSET parameter,
48 | */
49 | /* package */ SQLiteQuery(SQLiteDatabase db, String query, int offsetIndex, String[] bindArgs) {
50 | super(db, query);
51 |
52 | mOffsetIndex = offsetIndex;
53 | mBindArgs = bindArgs;
54 | }
55 |
56 | SQLiteQuery(SQLiteDatabase db, String query, int offsetIndex, Object[] bindArgs) {
57 | super(db, query);
58 | mOffsetIndex = offsetIndex;
59 | mObjectBindArgs = bindArgs;
60 | int length = mObjectBindArgs != null ? mObjectBindArgs.length : 0;
61 | mBindArgs = new String[length];
62 | }
63 |
64 | /**
65 | * Reads rows into a buffer. This method acquires the database lock.
66 | *
67 | * @param window The window to fill into
68 | * @return number of total rows in the query
69 | */
70 | /* package */
71 | int fillWindow(CursorWindow window,
72 | int maxRead, int lastPos) {
73 | long timeStart = SystemClock.uptimeMillis();
74 | mDatabase.lock();
75 | try {
76 | acquireReference();
77 | try {
78 | window.acquireReference();
79 | // if the start pos is not equal to 0, then most likely window is
80 | // too small for the data set, loading by another thread
81 | // is not safe in this situation. the native code will ignore maxRead
82 | int numRows = native_fill_window(window,
83 | window.getStartPosition(),
84 | window.getRequiredPosition(),
85 | mOffsetIndex,
86 | maxRead, lastPos);
87 |
88 | // Logging
89 | if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
90 | Log.d(TAG, "fillWindow(): " + mSql);
91 | }
92 | return numRows;
93 | } catch (IllegalStateException e){
94 | // simply ignore it
95 | return 0;
96 | } catch (SQLiteDatabaseCorruptException e) {
97 | mDatabase.onCorruption();
98 | throw e;
99 | } finally {
100 | window.releaseReference();
101 | }
102 | } finally {
103 | releaseReference();
104 | mDatabase.unlock();
105 | }
106 | }
107 |
108 | /**
109 | * Get the column count for the statement. Only valid on query based
110 | * statements. The database must be locked
111 | * when calling this method.
112 | *
113 | * @return The number of column in the statement's result set.
114 | */
115 | /* package */ int columnCountLocked() {
116 | acquireReference();
117 | try {
118 | return native_column_count();
119 | } finally {
120 | releaseReference();
121 | }
122 | }
123 |
124 | /**
125 | * Retrieves the column name for the given column index. The database must be locked
126 | * when calling this method.
127 | *
128 | * @param columnIndex the index of the column to get the name for
129 | * @return The requested column's name
130 | */
131 | /* package */ String columnNameLocked(int columnIndex) {
132 | acquireReference();
133 | try {
134 | return native_column_name(columnIndex);
135 | } finally {
136 | releaseReference();
137 | }
138 | }
139 |
140 | @Override
141 | public String toString() {
142 | return "SQLiteQuery: " + mSql;
143 | }
144 |
145 | /**
146 | * Called by SQLiteCursor when it is requeried.
147 | */
148 | /* package */ void requery() {
149 | if (mBindArgs != null) {
150 | int len = mBindArgs.length;
151 | try {
152 | if(mObjectBindArgs != null) {
153 | bindArguments(mObjectBindArgs);
154 | } else {
155 | for (int i = 0; i < len; i++) {
156 | super.bindString(i + 1, mBindArgs[i]);
157 | }
158 | }
159 | } catch (SQLiteMisuseException e) {
160 | StringBuilder errMsg = new StringBuilder("mSql " + mSql);
161 | for (int i = 0; i < len; i++) {
162 | errMsg.append(" ");
163 | errMsg.append(mBindArgs[i]);
164 | }
165 | errMsg.append(" ");
166 | IllegalStateException leakProgram = new IllegalStateException(
167 | errMsg.toString(), e);
168 | throw leakProgram;
169 | }
170 | }
171 | }
172 |
173 | @Override
174 | public void bindNull(int index) {
175 | mBindArgs[index - 1] = null;
176 | if (!mClosed) super.bindNull(index);
177 | }
178 |
179 | @Override
180 | public void bindLong(int index, long value) {
181 | mBindArgs[index - 1] = Long.toString(value);
182 | if (!mClosed) super.bindLong(index, value);
183 | }
184 |
185 | @Override
186 | public void bindDouble(int index, double value) {
187 | mBindArgs[index - 1] = Double.toString(value);
188 | if (!mClosed) super.bindDouble(index, value);
189 | }
190 |
191 | @Override
192 | public void bindString(int index, String value) {
193 | mBindArgs[index - 1] = value;
194 | if (!mClosed) super.bindString(index, value);
195 | }
196 |
197 | public void bindArguments(Object[] args){
198 | if(args != null && args.length > 0){
199 | for(int i = 0; i < args.length; i++){
200 | Object value = args[i];
201 | if(value == null){
202 | bindNull(i + 1);
203 | } else if (value instanceof Double) {
204 | bindDouble(i + 1, (Double)value);
205 | } else if (value instanceof Float) {
206 | float number = ((Number)value).floatValue();
207 | bindDouble(i + 1, Double.valueOf(number));
208 | } else if (value instanceof Long) {
209 | bindLong(i + 1, (Long)value);
210 | } else if(value instanceof Integer) {
211 | int number = ((Number) value).intValue();
212 | bindLong(i + 1, Long.valueOf(number));
213 | } else if (value instanceof Boolean) {
214 | bindLong(i + 1, (Boolean)value ? 1 : 0);
215 | } else if (value instanceof byte[]) {
216 | bindBlob(i + 1, (byte[])value);
217 | } else {
218 | bindString(i + 1, value.toString());
219 | }
220 | }
221 | }
222 | }
223 |
224 | private final native int native_fill_window(CursorWindow window,
225 | int startPos, int requiredPos,
226 | int offsetParam, int maxRead,
227 | int lastPos);
228 |
229 | private final native int native_column_count();
230 |
231 | private final native String native_column_name(int columnIndex);
232 | }
233 |
--------------------------------------------------------------------------------
/android-database-sqlcipher/src/main/java/net/sqlcipher/database/SQLiteQueryStats.java:
--------------------------------------------------------------------------------
1 | package net.sqlcipher.database;
2 |
3 | public class SQLiteQueryStats {
4 | long totalQueryResultSize = 0L;
5 | long largestIndividualRowSize = 0L;
6 |
7 | public SQLiteQueryStats(long totalQueryResultSize,
8 | long largestIndividualRowSize) {
9 | this.totalQueryResultSize = totalQueryResultSize;
10 | this.largestIndividualRowSize = largestIndividualRowSize;
11 | }
12 |
13 | public long getTotalQueryResultSize(){
14 | return totalQueryResultSize;
15 | }
16 |
17 | public long getLargestIndividualRowSize(){
18 | return largestIndividualRowSize;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/android-database-sqlcipher/src/main/java/net/sqlcipher/database/SQLiteStatement.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2006 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.sqlcipher.database;
18 |
19 | import android.os.SystemClock;
20 | import androidx.sqlite.db.SupportSQLiteStatement;
21 |
22 | /**
23 | * A pre-compiled statement against a {@link SQLiteDatabase} that can be reused.
24 | * The statement cannot return multiple rows, but 1x1 result sets are allowed.
25 | * Don't use SQLiteStatement constructor directly, please use
26 | * {@link SQLiteDatabase#compileStatement(String)}
27 | *
28 | * SQLiteStatement is not internally synchronized so code using a SQLiteStatement from multiple
29 | * threads should perform its own synchronization when using the SQLiteStatement.
30 | */
31 | public class SQLiteStatement extends SQLiteProgram implements
32 | SupportSQLiteStatement
33 | {
34 | /**
35 | * Don't use SQLiteStatement constructor directly, please use
36 | * {@link SQLiteDatabase#compileStatement(String)}
37 | * @param db
38 | * @param sql
39 | */
40 | /* package */ SQLiteStatement(SQLiteDatabase db, String sql) {
41 | super(db, sql);
42 | }
43 |
44 | /**
45 | * Execute this SQL statement, if it is not a query. For example,
46 | * CREATE TABLE, DELTE, INSERT, etc.
47 | *
48 | * @throws android.database.SQLException If the SQL string is invalid for
49 | * some reason
50 | */
51 | @Override
52 | public void execute() {
53 | if (!mDatabase.isOpen()) {
54 | throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
55 | }
56 | long timeStart = SystemClock.uptimeMillis();
57 | mDatabase.lock();
58 |
59 | acquireReference();
60 | try {
61 | native_execute();
62 | } finally {
63 | releaseReference();
64 | mDatabase.unlock();
65 | }
66 | }
67 |
68 | /**
69 | * Execute this SQL statement and return the ID of the row inserted due to this call.
70 | * The SQL statement should be an INSERT for this to be a useful call.
71 | *
72 | * @return the row ID of the last row inserted, if this insert is successful. -1 otherwise.
73 | *
74 | * @throws android.database.SQLException If the SQL string is invalid for
75 | * some reason
76 | */
77 | @Override
78 | public long executeInsert() {
79 | if (!mDatabase.isOpen()) {
80 | throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
81 | }
82 | long timeStart = SystemClock.uptimeMillis();
83 | mDatabase.lock();
84 |
85 | acquireReference();
86 | try {
87 | native_execute();
88 | return (mDatabase.lastChangeCount() > 0) ? mDatabase.lastInsertRow() : -1;
89 | } finally {
90 | releaseReference();
91 | mDatabase.unlock();
92 | }
93 | }
94 |
95 | @Override
96 | public int executeUpdateDelete() {
97 | if (!mDatabase.isOpen()) {
98 | throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
99 | }
100 | long timeStart = SystemClock.uptimeMillis();
101 | mDatabase.lock();
102 |
103 | acquireReference();
104 | try {
105 | native_execute();
106 | return mDatabase.lastChangeCount();
107 | } finally {
108 | releaseReference();
109 | mDatabase.unlock();
110 | }
111 | }
112 |
113 | /**
114 | * Execute a statement that returns a 1 by 1 table with a numeric value.
115 | * For example, SELECT COUNT(*) FROM table;
116 | *
117 | * @return The result of the query.
118 | *
119 | * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
120 | */
121 | @Override
122 | public long simpleQueryForLong() {
123 | if (!mDatabase.isOpen()) {
124 | throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
125 | }
126 | long timeStart = SystemClock.uptimeMillis();
127 | mDatabase.lock();
128 |
129 | acquireReference();
130 | try {
131 | long retValue = native_1x1_long();
132 | return retValue;
133 | } finally {
134 | releaseReference();
135 | mDatabase.unlock();
136 | }
137 | }
138 |
139 | /**
140 | * Execute a statement that returns a 1 by 1 table with a text value.
141 | * For example, SELECT COUNT(*) FROM table;
142 | *
143 | * @return The result of the query.
144 | *
145 | * @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
146 | */
147 | @Override
148 | public String simpleQueryForString() {
149 | if (!mDatabase.isOpen()) {
150 | throw new IllegalStateException("database " + mDatabase.getPath() + " already closed");
151 | }
152 | long timeStart = SystemClock.uptimeMillis();
153 | mDatabase.lock();
154 |
155 | acquireReference();
156 | try {
157 | String retValue = native_1x1_string();
158 | return retValue;
159 | } finally {
160 | releaseReference();
161 | mDatabase.unlock();
162 | }
163 | }
164 |
165 | private final native void native_execute();
166 | private final native long native_1x1_long();
167 | private final native String native_1x1_string();
168 | }
169 |
--------------------------------------------------------------------------------
/android-database-sqlcipher/src/main/java/net/sqlcipher/database/SQLiteTransactionListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.sqlcipher.database;
18 |
19 | /**
20 | * A listener for transaction events.
21 | */
22 | public interface SQLiteTransactionListener {
23 | /**
24 | * Called immediately after the transaction begins.
25 | */
26 | void onBegin();
27 |
28 | /**
29 | * Called immediately before commiting the transaction.
30 | */
31 | void onCommit();
32 |
33 | /**
34 | * Called if the transaction is about to be rolled back.
35 | */
36 | void onRollback();
37 | }
38 |
--------------------------------------------------------------------------------
/android-database-sqlcipher/src/main/java/net/sqlcipher/database/SqliteWrapper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2008 Esmertec AG.
3 | * Copyright (C) 2008 The Android Open Source Project
4 | *
5 | * Licensed under the Apache License, Version 2.0 (the "License");
6 | * you may not use this file except in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | */
17 |
18 | package net.sqlcipher.database;
19 |
20 | import android.content.ContentResolver;
21 | import android.content.ContentValues;
22 | import android.content.Context;
23 |
24 | import net.sqlcipher.*;
25 |
26 | import android.database.sqlite.SQLiteException;
27 | import android.net.Uri;
28 | import android.util.Log;
29 | import android.widget.Toast;
30 |
31 | /**
32 | * @hide
33 | */
34 |
35 | public final class SqliteWrapper {
36 | private static final String TAG = "SqliteWrapper";
37 | private static final String SQLITE_EXCEPTION_DETAIL_MESSAGE
38 | = "unable to open database file";
39 |
40 | private SqliteWrapper() {
41 | // Forbidden being instantiated.
42 | }
43 |
44 | // FIXME: need to optimize this method.
45 | private static boolean isLowMemory(SQLiteException e) {
46 | return e.getMessage().equals(SQLITE_EXCEPTION_DETAIL_MESSAGE);
47 | }
48 |
49 | public static void checkSQLiteException(Context context, SQLiteException e) {
50 | if (isLowMemory(e)) {
51 | Toast.makeText(context, e.getMessage(),
52 | Toast.LENGTH_SHORT).show();
53 | } else {
54 | throw e;
55 | }
56 | }
57 |
58 | public static Cursor query(Context context, ContentResolver resolver, Uri uri,
59 | String[] projection, String selection, String[] selectionArgs, String sortOrder) {
60 | try {
61 | return (Cursor) resolver.query(uri, projection, selection, selectionArgs, sortOrder);
62 | } catch (SQLiteException e) {
63 | Log.e(TAG, "Catch a SQLiteException when query: ", e);
64 | checkSQLiteException(context, e);
65 | return null;
66 | }
67 | }
68 |
69 | public static boolean requery(Context context, android.database.Cursor cursor) {
70 | try {
71 | return cursor.requery();
72 | } catch (SQLiteException e) {
73 | Log.e(TAG, "Catch a SQLiteException when requery: ", e);
74 | checkSQLiteException(context, e);
75 | return false;
76 | }
77 | }
78 | public static int update(Context context, ContentResolver resolver, Uri uri,
79 | ContentValues values, String where, String[] selectionArgs) {
80 | try {
81 | return resolver.update(uri, values, where, selectionArgs);
82 | } catch (SQLiteException e) {
83 | Log.e(TAG, "Catch a SQLiteException when update: ", e);
84 | checkSQLiteException(context, e);
85 | return -1;
86 | }
87 | }
88 |
89 | public static int delete(Context context, ContentResolver resolver, Uri uri,
90 | String where, String[] selectionArgs) {
91 | try {
92 | return resolver.delete(uri, where, selectionArgs);
93 | } catch (SQLiteException e) {
94 | Log.e(TAG, "Catch a SQLiteException when delete: ", e);
95 | checkSQLiteException(context, e);
96 | return -1;
97 | }
98 | }
99 |
100 | public static Uri insert(Context context, ContentResolver resolver,
101 | Uri uri, ContentValues values) {
102 | try {
103 | return resolver.insert(uri, values);
104 | } catch (SQLiteException e) {
105 | Log.e(TAG, "Catch a SQLiteException when insert: ", e);
106 | checkSQLiteException(context, e);
107 | return null;
108 | }
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/android-database-sqlcipher/src/main/java/net/sqlcipher/database/SupportFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Mark L. Murphy
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.sqlcipher.database;
18 |
19 | import androidx.sqlite.db.SupportSQLiteOpenHelper;
20 |
21 | public class SupportFactory implements SupportSQLiteOpenHelper.Factory {
22 | private final byte[] passphrase;
23 | private final SQLiteDatabaseHook hook;
24 | private final boolean clearPassphrase;
25 |
26 | public SupportFactory(byte[] passphrase) {
27 | this(passphrase, (SQLiteDatabaseHook)null);
28 | }
29 |
30 | public SupportFactory(byte[] passphrase, SQLiteDatabaseHook hook) {
31 | this(passphrase, hook, true);
32 | }
33 |
34 | public SupportFactory(byte[] passphrase, SQLiteDatabaseHook hook,
35 | boolean clearPassphrase) {
36 | this.passphrase = passphrase;
37 | this.hook = hook;
38 | this.clearPassphrase = clearPassphrase;
39 | }
40 |
41 | @Override
42 | public SupportSQLiteOpenHelper create(SupportSQLiteOpenHelper.Configuration configuration) {
43 | return new SupportHelper(configuration, passphrase, hook, clearPassphrase);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/android-database-sqlcipher/src/main/java/net/sqlcipher/database/SupportHelper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2019 Mark L. Murphy
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.sqlcipher.database;
18 |
19 | import android.database.sqlite.SQLiteException;
20 | import androidx.sqlite.db.SupportSQLiteDatabase;
21 | import androidx.sqlite.db.SupportSQLiteOpenHelper;
22 |
23 | public class SupportHelper implements SupportSQLiteOpenHelper {
24 | private SQLiteOpenHelper standardHelper;
25 | private byte[] passphrase;
26 | private final boolean clearPassphrase;
27 |
28 | SupportHelper(final SupportSQLiteOpenHelper.Configuration configuration,
29 | byte[] passphrase, final SQLiteDatabaseHook hook,
30 | boolean clearPassphrase) {
31 | SQLiteDatabase.loadLibs(configuration.context);
32 | this.passphrase = passphrase;
33 | this.clearPassphrase = clearPassphrase;
34 |
35 | standardHelper =
36 | new SQLiteOpenHelper(configuration.context, configuration.name,
37 | null, configuration.callback.version, hook) {
38 | @Override
39 | public void onCreate(SQLiteDatabase db) {
40 | configuration.callback.onCreate(db);
41 | }
42 |
43 | @Override
44 | public void onUpgrade(SQLiteDatabase db, int oldVersion,
45 | int newVersion) {
46 | configuration.callback.onUpgrade(db, oldVersion,
47 | newVersion);
48 | }
49 |
50 | @Override
51 | public void onDowngrade(SQLiteDatabase db, int oldVersion,
52 | int newVersion) {
53 | configuration.callback.onDowngrade(db, oldVersion,
54 | newVersion);
55 | }
56 |
57 | @Override
58 | public void onOpen(SQLiteDatabase db) {
59 | configuration.callback.onOpen(db);
60 | }
61 |
62 | @Override
63 | public void onConfigure(SQLiteDatabase db) {
64 | configuration.callback.onConfigure(db);
65 | }
66 | };
67 | }
68 |
69 | @Override
70 | public String getDatabaseName() {
71 | return standardHelper.getDatabaseName();
72 | }
73 |
74 | @Override
75 | public void setWriteAheadLoggingEnabled(boolean enabled) {
76 | standardHelper.setWriteAheadLoggingEnabled(enabled);
77 | }
78 |
79 | @Override
80 | public SupportSQLiteDatabase getWritableDatabase() {
81 | SQLiteDatabase result;
82 | try {
83 | result = standardHelper.getWritableDatabase(passphrase);
84 | } catch (SQLiteException ex){
85 | if(passphrase != null){
86 | boolean isCleared = true;
87 | for(byte b : passphrase){
88 | isCleared = isCleared && (b == (byte)0);
89 | }
90 | if (isCleared) {
91 | throw new IllegalStateException("The passphrase appears to be cleared. This happens by " +
92 | "default the first time you use the factory to open a database, so we can remove the " +
93 | "cleartext passphrase from memory. If you close the database yourself, please use a " +
94 | "fresh SupportFactory to reopen it. If something else (e.g., Room) closed the " +
95 | "database, and you cannot control that, use SupportFactory boolean constructor option " +
96 | "to opt out of the automatic password clearing step. See the project README for more information.", ex);
97 | }
98 | }
99 | throw ex;
100 | }
101 | if(clearPassphrase && passphrase != null) {
102 | for (int i = 0; i < passphrase.length; i++) {
103 | passphrase[i] = (byte)0;
104 | }
105 | }
106 | return result;
107 | }
108 |
109 | @Override
110 | public SupportSQLiteDatabase getReadableDatabase() {
111 | return getWritableDatabase();
112 | }
113 |
114 | @Override
115 | public void close() {
116 | standardHelper.close();
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/android-database-sqlcipher/src/main/java/net/sqlcipher/database/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Contains the SQLCipher database managements classes that an application would use to manage its own private database.
3 | */
4 | package net.sqlcipher.database;
5 |
--------------------------------------------------------------------------------
/android-database-sqlcipher/src/main/java/net/sqlcipher/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Contains classes to explore data returned from a SQLCipher database.
3 | */
4 | package net.sqlcipher;
5 |
--------------------------------------------------------------------------------
/android-database-sqlcipher/src/main/res/values/android_database_sqlcipher_strings.xml:
--------------------------------------------------------------------------------
1 |
2 |