8000 Fix encoding of key material from modified UTF-8 to UTF-8 · s1h/android-database-sqlcipher@a989659 · GitHub
[go: up one dir, main page]

Skip to content

Commit a989659

Browse files
Fix encoding of key material from modified UTF-8 to UTF-8
1 parent 920c1f6 commit a989659

File tree

2 files changed

+152
-66
lines changed

2 files changed

+152
-66
lines changed

jni/net_sqlcipher_database_SQLiteDatabase.cpp

Lines changed: 40 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -31,27 +31,13 @@
3131
#include "sqlite3_exception.h"
3232
#include "sqlcipher_loading.h"
3333

34-
// #include <utils/Log.h>
35-
// #include <JNIHelp.h>
36-
// #include <android_runtime/AndroidRuntime.h>
37-
// #include <sqlite3_android.h>
38-
// #include <utils/Log.h>
39-
// #include <utils/threads.h>
40-
// #include <utils/List.h>
41-
// #include <utils/Errors.h>
42-
// #include <unicode/utypes.h>
43-
// #include <unicode/ucnv.h>
44-
// #include <unicode/ucnv_err.h>
45-
4634
#define UTF16_STORAGE 0
4735
#define INVALID_VERSION -1
4836
#define SQLITE_SOFT_HEAP_LIMIT (4 * 1024 * 1024)
4937
#define ANDROID_TABLE "android_metadata"
5038
/* uncomment the next line to force-enable logging of all statements */
5139
// #define DB_LOG_STATEMENTS
5240

53-
54-
5541
namespace sqlcipher {
5642

5743

@@ -107,7 +93,42 @@ namespace sqlcipher {
10793
return value;
10894
}
10995

110-
void native_key_char(JNIEnv* env, jobject object, jcharArray jKey) {
96+
void native_key(JNIEnv* env, jobject object, jbyteArray jKey) {
97+
int rc = 0;
98+
int index = 0;
99+
jsize size = 0;
100+
jbyte *key = 0;
101+
sqlite3 *handle = NULL;
102+
handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
103+
key = env->GetByteArrayElements(jKey, NULL);
104+
size = env->GetArrayLength(jKey);
105+
if(key == NULL || size == 0) goto done;
106+
rc = sqlite3_key(handle, key, size);
107+
if(rc != SQLITE_OK) {
108+
throw_sqlite3_exception(env, handle);
109+
}
110+
done:
111+
if(key) env->ReleaseByteArrayElements(jKey, key, JNI_ABORT);
112+
}
113+
114+
void native_rekey(JNIEnv* env, jobject object, jbyteArray jKey) {
115+
int rc = 0;
116+
jsize size = 0;
117+
jbyte *key = 0;
118+
sqlite3 *handle = NULL;
119+
handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
120+
key = env->GetByteArrayElements(jKey, NULL);
121+
size = env->GetArrayLength(jKey);
122+
if(key == NULL || size == 0) goto done;
123+
rc = sqlite3_rekey(handle, key, size);
124+
if(rc != SQLITE_OK) {
125+
throw_sqlite3_exception(env, handle);
126+
}
127+
done:
128+
if(key) env->ReleaseByteArrayElements(jKey, key, JNI_ABORT);
129+
}
130+
131+
void native_key_mutf8(JNIEnv* env, jobject object, jcharArray jKey) {
111132
int rc;
112133
int idx;
113134
jint releaseElements = 0;
@@ -126,21 +147,7 @@ namespace sqlcipher {
126147
}
127148
env->ReleaseStringUTFChars(key, password);
128149
}
129-
130-
void native_rekey_str(JNIEnv* env, jobject object, jstring jKey) {
131-
sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
132-
char const * key = env->GetStringUTFChars(jKey, NULL);
133-
jsize keyLen = env->GetStringUTFLength(jKey);
134-
135-
if ( keyLen > 0 ) {
136-
int status = sqlite3_rekey(handle, key, keyLen);
137-
if ( status != SQLITE_OK ) {
138-
throw_sqlite3_exception(env, handle);
139-
}
140-
}
141-
env->ReleaseStringUTFChars(jKey, key);
142-
}
143-
150+
144151
void native_rawExecSQL(JNIEnv* env, jobject object, jstring sql)
145152
{
146153
sqlite3 * handle = (sqlite3 *)env->GetIntField(object, offset_db_handle);
@@ -523,15 +530,13 @@ namespace sqlcipher {
523530
{"native_execSQL", "(Ljava/lang/String;)V", (void *)native_execSQL},
524531
{"lastInsertRow", "()J", (void *)lastInsertRow},
525532
{"lastChangeCount", "()I", (void *)lastChangeCount},
526-
// {"native_setLocale", "(Ljava/lang/String;I)V", (void *)native_setLocale},
527533
{"native_getDbLookaside", "()I", (void *)native_getDbLookaside},
528534
{"releaseMemory", "()I", (void *)native_releaseMemory},
529-
// {"setICURoot", "(Ljava/lang/String;)V", (void *)setICURoot},
530535
{"native_rawExecSQL", "(Ljava/lang/String;)V", (void *)native_rawExecSQL},
531536
{"native_status", "(IZ)I", (void *)native_status},
532-
{"native_key", "([C)V", (void *)native_key_char},
533-
// {"native_rekey", "([C)V", (void *)native_rekey_char},
534-
{"native_rekey", "(Ljava/lang/String;)V", (void *)native_rekey_str},
537+
{"key_mutf8", "([C)V", (void *)native_key_mutf8},
538+
{"key", "([B)V", (void *)native_key},
539+
{"rekey", "([B)V", (void *)native_rekey},
535540
};
536541

537542
int register_android_database_SQLiteDatabase(JNIEnv *env)

src/net/sqlcipher/database/SQLiteDatabase.java

Lines changed: 112 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
import java.io.FileOutputStream;
3030
import java.io.IOException;
3131
import java.io.OutputStream;
32+
import java.io.UnsupportedEncodingException;
33+
import java.nio.ByteBuffer;
34+
import java.nio.CharBuffer;
35+
import java.nio.charset.Charset;
3236
import java.text.SimpleDateFormat;
3337
import java.util.ArrayList;
3438
import java.util.HashMap;
@@ -54,6 +58,8 @@
5458
import android.util.Log;
5559
import android.util.Pair;
5660

61+
import java.io.UnsupportedEncodingException;
62+
5763
/**
5864
* Exposes methods to manage a SQLCipher database.
5965
* <p>SQLiteDatabase has methods to create, delete, execute SQL commands, and
@@ -68,6 +74,7 @@ public class SQLiteDatabase extends SQLiteClosable {
6874
private static final String TAG = "Database";
6975
private static final int EVENT_DB_OPERATION = 52000;
7076
private static final int EVENT_DB_CORRUPT = 75004;
77+
private static final String KEY_ENCODING = "UTF-8";
7178

7279
/**
7380
* The version number of the SQLCipher for Android Java client library.
@@ -101,7 +108,11 @@ public void changePassword(String password) throws SQLiteException {
101108
throw new SQLiteException("database not open");
102109
}
103110
if (password != null) {
104-
native_rekey(password);
111+
byte[] keyMaterial = getBytes(password.toCharArray());
112+
rekey(keyMaterial);
113+
for(byte data : keyMaterial) {
114+
data = 0;
115+
}
105116
}
106117
}
107118

10000
@@ -122,8 +133,12 @@ public void changePassword(char[] password) throws SQLiteException {
122133
throw new SQLiteException("database not open");
123134
}
124135
if (password != null) {
125-
native_rekey(String.valueOf(password));
126-
}
136+
byte[] keyMaterial = getBytes(password);
137+
rekey(keyMaterial);
138+
for(byte data : keyMaterial) {
139+
data = 0;
140+
}
141+
}
127142
}
128143

129144
private static void loadICUData(Context context, File workingDir) {
@@ -2332,41 +2347,94 @@ private SQLiteDatabase(String path, CursorFactory factory, int flags, DatabaseEr
23322347
mErrorHandler = errorHandler;
23332348
}
23342349

2335-
private void openDatabaseInternal(char[] password, SQLiteDatabaseHook databaseHook) {
2336-
dbopen(mPath, mFlags);
2337-
2338-
if(databaseHook != null) {
2339-
databaseHook.preKey(this);
2350+
private void openDatabaseInternal(final char[] password, SQLiteDatabaseHook hook) {
2351+
boolean shouldCloseConnection = true;
2352+
final byte[] keyMaterial = getBytes(password);
2353+
dbopen(mPath, mFlags);
2354+
try {
2355+
2356+
keyDatabase(hook, new Runnable() {
2357+
public void run() {
2358+
if(keyMaterial != null && keyMaterial.length > 0) {
2359+
key(keyMaterial);
2360+
}
2361+
}
2362+
});
2363+
shouldCloseConnection = false;
2364+
2365+
} catch(RuntimeException ex) {
2366+
2367+
if(containsNull(password)) {
2368+
keyDatabase(hook, new Runnable() {
2369+
public void run() {
2370+
if(password != null) {
2371+
key_mutf8(password);
2372+
}
2373+
}
2374+
});
2375+
if(keyMaterial != null && keyMaterial.length > 0) {
2376+
rekey(keyMaterial);
23402377
}
2378+
shouldCloseConnection = false;
2379+
} else {
2380+
throw ex;
2381+
}
23412382

2342-
if(password != null){
2343-
native_key(password);
2383+
} finally {
2384+
if(shouldCloseConnection) {
2385+
dbclose();
2386+
if (SQLiteDebug.DEBUG_SQL_CACHE) {
2387+
mTimeClosed = getTime();
23442388
}
2345-
2346-
if(databaseHook != null){
2347-
databaseHook.postKey(this);
2389+
}
2390+
if(keyMaterial != null && keyMaterial.length > 0) {
2391+
for(byte data : keyMaterial) {
2392+
data = 0;
23482393
}
2394+
}
2395+
}
2396+
2397+
}
23492398

2350-
if (SQLiteDebug.DEBUG_SQL_CACHE) {
2351-
mTimeOpened = getTime();
2352-
}
2353-
try {
2354-
Cursor cursor = rawQuery("select count(*) from sqlite_master;", new String[]{});
2355-
if(cursor != null){
2356-
cursor.moveToFirst();
2357-
int count = cursor.getInt(0);
2358-
cursor.close();
2359-
}
2360-
//setLocale(Locale.getDefault());
2361-
} catch (RuntimeException e) {
2362-
Log.e(TAG, "Failed to setLocale() when constructing, closing the database", e);
2363-
dbclose();
2364-
if (SQLiteDebug.DEBUG_SQL_CACHE) {
2365-
mTimeClosed = getTime();
2366-
}
2367-
throw e;
2399+
private boolean containsNull(char[] data) {
2400+
char defaultValue = '\u0000';
2401+
boolean status = false;
2402+
if(data != null && data.length > 0) {
2403+
for(char datum : data) {
2404+
if(datum == defaultValue) {
2405+
status = true;
2406+
break;
23682407
}
2408+
}
2409+
}
2410+
return status;
2411+
}
2412+
2413+
private void keyDatabase(SQLiteDatabaseHook databaseHook, Runnable keyOperation) {
2414+
if(databaseHook != null) {
2415+
databaseHook.preKey(this);
2416+
}
2417+
if(keyOperation != null){
2418+
keyOperation.run();
2419+
}
2420+
if(databaseHook != null){
2421+
databaseHook.postKey(this);
23692422
}
2423+
if (SQLiteDebug.DEBUG_SQL_CACHE) {
2424+
mTimeOpened = getTime();
2425+
}
2426+
try {
2427+
Cursor cursor = rawQuery("select count(*) from sqlite_master;", new String[]{});
2428+
if(cursor != null){
2429+
cursor.moveToFirst();
2430+
int count = cursor.getInt(0);
2431+
cursor.close();
2432+
}
2433+
} catch (RuntimeException e) {
2434+
Log.e(TAG, e.getMessage(), e);
2435+
throw e;
2436+
}
2437+
}
23702438

23712439
private String getTime() {
23722440
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS ").format(System.currentTimeMillis());
@@ -2761,6 +2829,15 @@ private static ArrayList<Pair<String, String>> getAttachedDbs(SQLiteDatabase dbO
27612829
return attachedDbs;
27622830
}
27632831

2832+
private byte[] getBytes(char[] data) {
2833+
if(data == null || data.length == 0) return null;
2834+
CharBuffer charBuffer = CharBuffer.wrap(data);
2835+
ByteBuffer byteBuffer = Charset.forName(KEY_ENCODING).encode(charBuffer);
2836+
byte[] result = new byte[byteBuffer.limit()];
2837+
byteBuffer.get(result);
2838+
return result;
2839+
}
2840+
27642841
/**
27652842
* Sets the root directory to search for the ICU data file
27662843
*/
@@ -2836,4 +2913,8 @@ private static ArrayList<Pair<String, String>> getAttachedDbs(SQLiteDatabase dbO
28362913
private native void native_key(char[] key) throws SQLException;
28372914

28382915
private native void native_rekey(String key) throws SQLException;
2916+
2917+
private native void key(byte[] key) throws SQLException;
2918+
private native void key_mutf8(char[] key) throws SQLException;
2919+
private native void rekey(byte[] key) throws SQLException;
28392920
}

0 commit comments

Comments
 (0)
0