Skip to content

Commit 6bd194f

Browse files
Add SQLCipher tests for opening connections with passwords, migrations
1 parent 28edeed commit 6bd194f

File tree

7 files changed

+248
-26
lines changed

7 files changed

+248
-26
lines changed
File renamed without changes.
8 KB
Binary file not shown.
8 KB
Binary file not shown.

sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/AndroidSQLCipherTestCase.java

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.io.IOException;
1919
import java.io.InputStream;
2020
import java.io.OutputStream;
21+
import java.security.SecureRandom;
2122
import java.util.Locale;
2223

2324
@RunWith(AndroidJUnit4.class)
@@ -44,57 +45,64 @@ public void setUp() {
4445

4546
@After
4647
public void tearDown() {
47-
if(database != null){
48+
if (database != null) {
4849
database.close();
4950
}
50-
if(context != null){
51+
if (context != null) {
5152
context.deleteDatabase(DATABASE_NAME);
5253
}
5354
}
5455

5556
public File extractAssetToDatabaseDirectory(String fileName) {
5657
File destinationPath = null;
57-
try {
58-
int length;
59-
InputStream sourceDatabase = context.getAssets().open(fileName);
60-
destinationPath = context.getDatabasePath(fileName);
61-
OutputStream destination = new FileOutputStream(destinationPath);
62-
byte[] buffer = new byte[4096];
63-
while ((length = sourceDatabase.read(buffer)) > 0) {
64-
destination.write(buffer, 0, length);
65-
}
66-
sourceDatabase.close();
67-
destination.flush();
68-
destination.close();
69-
} catch (Exception ex){
70-
throw new RuntimeException(ex);
71-
}
58+
try {
59+
int length;
60+
InputStream sourceDatabase = context.getAssets().open(fileName);
61+
destinationPath = context.getDatabasePath(fileName);
62+
OutputStream destination = new FileOutputStream(destinationPath);
63+
byte[] buffer = new byte[4096];
64+
while ((length = sourceDatabase.read(buffer)) > 0) {
65+
destination.write(buffer, 0, length);
66+
}
67+
sourceDatabase.close();
68+
destination.flush();
69+
destination.close();
70+
} catch (Exception ex) {
71+
throw new RuntimeException(ex);
72+
}
7273
return destinationPath;
7374
}
7475

75-
public void delete(File filePath){
76-
if(filePath == null) return;
77-
if(filePath.exists()){
76+
public void delete(File filePath) {
77+
if (filePath == null) return;
78+
if (filePath.exists()) {
7879
boolean result = filePath.delete();
7980
log("Deleted file:%s result:%s", filePath.getAbsolutePath(), result);
8081
}
8182
}
8283

83-
public void closeAndDelete(SQLiteDatabase database){
84-
if(database == null) return;
84+
public void closeAndDelete(SQLiteDatabase database) {
85+
if (database == null) return;
8586
File path = new File(database.getPath());
8687
database.close();
87-
if(path.exists()){
88+
if (path.exists()) {
8889
boolean result = path.delete();
8990
log("Deleted database:%s result:%s", path.getAbsolutePath(), result);
9091
}
9192
}
9293

93-
protected void log(String message, Object...args){
94+
public byte[] generateRandomBytes(int length) {
95+
SecureRandom random = new SecureRandom();
96+
byte[] data = new byte[length];
97+
random.nextBytes(data);
98+
return data;
99+
}
100+
101+
protected void log(String message, Object... args) {
94102
Log.i(TAG, String.format(Locale.getDefault(), message, args));
95103
}
96104

97-
protected void loge(Exception ex, String message, Object...args){
105+
protected void loge(Exception ex, String message, Object... args) {
98106
Log.e(TAG, String.format(Locale.getDefault(), message, args), ex);
99107
}
100108
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package net.zetetic.database.sqlcipher_cts;
2+
3+
import static org.hamcrest.Matchers.is;
4+
import static org.junit.Assert.assertThat;
5+
6+
import android.database.Cursor;
7+
8+
import net.zetetic.database.sqlcipher.SQLiteConnection;
9+
import net.zetetic.database.sqlcipher.SQLiteDatabase;
10+
import net.zetetic.database.sqlcipher.SQLiteDatabaseHook;
11+
12+
import org.junit.Test;
13+
14+
import java.io.File;
15+
16+
public class MigrateDatabaseFrom1xFormatToCurrentFormatTest extends AndroidSQLCipherTestCase {
17+
18+
@Test
19+
public void shouldPerformMigrationFrom1xFileFormatToCurrent() {
20+
File oldDatabaseFileFormatPath = null;
21+
try {
22+
database.close();
23+
String password = "test", a = "", b = "";
24+
oldDatabaseFileFormatPath = extractAssetToDatabaseDirectory("sqlcipher-1.x-test.db");
25+
SQLiteDatabaseHook hook = new SQLiteDatabaseHook() {
26+
public void preKey(SQLiteConnection database) { }
27+
public void postKey(SQLiteConnection database) {
28+
long result = database.executeForLong("PRAGMA cipher_migrate;", null, null);
29+
assertThat("PRAGMA cipher_migrate should return 0 for success", result, is(0L));
30+
}
31+
};
32+
database = SQLiteDatabase.openDatabase(oldDatabaseFileFormatPath.getPath(), password, null, SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.CREATE_IF_NECESSARY, null, hook);
33+
database.close();
34+
database = SQLiteDatabase.openDatabase(oldDatabaseFileFormatPath.getPath(), password, null, SQLiteDatabase.OPEN_READWRITE, null, null);
35+
Cursor result = database.rawQuery("select * from t1", new String[]{});
36+
if (result != null && result.moveToFirst()) {
37+
a = result.getString(0);
38+
b = result.getString(1);
39+
result.close();
40+
}
41+
database.close();
42+
assertThat(a, is("one for the money"));
43+
assertThat(b, is("two for the show"));
44+
} finally {
45+
delete(oldDatabaseFileFormatPath);
46+
}
47+
}
48+
}

sqlcipher/src/androidTest/java/net/zetetic/database/sqlcipher_cts/SQLCipherDatabaseTest.java

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,26 @@
88

99
import net.zetetic.database.sqlcipher.SQLiteDatabase;
1010
import net.zetetic.database.sqlcipher.SQLiteDatabaseConfiguration;
11+
import net.zetetic.database.sqlcipher.SQLiteDatabaseCorruptException;
1112
import net.zetetic.database.sqlcipher.SQLiteException;
1213

1314
import org.junit.Test;
1415

16+
import java.io.File;
17+
import java.nio.charset.StandardCharsets;
18+
1519
public class SQLCipherDatabaseTest extends AndroidSQLCipherTestCase {
1620

1721
@Test
18-
public void testConnectionWithPassword() {
22+
public void testCreateDatabaseConnectionWithStringPassword() {
1923
try {
2024
int a = 0, b = 0;
2125
closeAndDelete(database);
2226
database = SQLiteDatabase.openOrCreateDatabase(context.getDatabasePath("foo.db"), "foo", null, null);
2327
database.execSQL("create table t1(a,b);");
2428
database.execSQL("insert into t1(a,b) values(?,?)", new Object[]{1, 2});
29+
database.close();
30+
database = SQLiteDatabase.openOrCreateDatabase(context.getDatabasePath("foo.db"), "foo", null, null);
2531
Cursor cursor = database.rawQuery("select * from t1;", new String[]{});
2632
if (cursor != null && cursor.moveToFirst()) {
2733
a = cursor.getInt(0);
@@ -35,6 +41,125 @@ public void testConnectionWithPassword() {
3541
}
3642
}
3743

44+
@Test
45+
public void testCreateDatabaseConnectionWithStringByteArray() {
46+
try {
47+
int a = 0, b = 0;
48+
closeAndDelete(database);
49+
byte[] generatedPassword = generateRandomBytes(64);
50+
database = SQLiteDatabase.openOrCreateDatabase(context.getDatabasePath("foo.db"), generatedPassword, null, null);
51+
database.execSQL("create table t1(a,b);");
52+
database.execSQL("insert into t1(a,b) values(?,?)", new Object[]{1, 2});
53+
database.close();
54+
database = SQLiteDatabase.openOrCreateDatabase(context.getDatabasePath("foo.db"), generatedPassword, null, null);
55+
Cursor cursor = database.rawQuery("select * from t1;", new String[]{});
56+
if (cursor != null && cursor.moveToFirst()) {
57+
a = cursor.getInt(0);
58+
b = cursor.getInt(1);
59+
cursor.close();
60+
}
61+
assertThat(a, is(1));
62+
assertThat(b, is(2));
63+
} finally {
64+
delete(context.getDatabasePath("foo.db"));
65+
}
66+
}
67+
68+
@Test(expected = SQLiteDatabaseCorruptException.class)
69+
public void testOpenDatabaseConnectionWithInvalidStringPassword() {
70+
try {
71+
int a = 0, b = 0;
72+
closeAndDelete(database);
73+
database = SQLiteDatabase.openOrCreateDatabase(context.getDatabasePath("foo.db"), "foo", null, null);
74+
database.execSQL("create table t1(a,b);");
75+
database.execSQL("insert into t1(a,b) values(?,?)", new Object[]{1, 2});
76+
database.close();
77+
database = SQLiteDatabase.openDatabase(context.getDatabasePath("foo.db").getPath(), "bar", null, SQLiteDatabase.OPEN_READWRITE, null);
78+
} finally {
79+
delete(context.getDatabasePath("foo.db"));
80+
}
81+
}
82+
83+
@Test(expected = SQLiteDatabaseCorruptException.class)
84+
public void testOpenDatabaseConnectionWithInvalidByteArrayPassword() {
85+
try {
86+
int a = 0, b = 0;
87+
closeAndDelete(database);
88+
byte[] initialPassword = generateRandomBytes(64);
89+
byte[] otherPassword = generateRandomBytes(64);
90+
database = SQLiteDatabase.openOrCreateDatabase(context.getDatabasePath("foo.db"), initialPassword, null, null);
91+
database.execSQL("create table t1(a,b);");
92+
database.execSQL("insert into t1(a,b) values(?,?)", new Object[]{1, 2});
93+
database.close();
94+
database = SQLiteDatabase.openDatabase(context.getDatabasePath("foo.db").getPath(), otherPassword, null, SQLiteDatabase.OPEN_READWRITE, null);
95+
} finally {
96+
delete(context.getDatabasePath("foo.db"));
97+
}
98+
}
99+
100+
@Test
101+
public void openExistingSQLCipherDatabaseWithStringPassword(){
102+
File databasePath = null;
103+
int a = 0, b = 0;
104+
try {
105+
closeAndDelete(database);
106+
databasePath = extractAssetToDatabaseDirectory("sqlcipher-4.x-testkey.db");
107+
database = SQLiteDatabase.openDatabase(databasePath.getPath(), "testkey", null, SQLiteDatabase.OPEN_READWRITE, null);
108+
Cursor cursor = database.rawQuery("SELECT * FROM t1;");
109+
if(cursor != null && cursor.moveToFirst()){
110+
a = cursor.getInt(0);
111+
b = cursor.getInt(1);
112+
cursor.close();
113+
}
114+
assertThat(a, is(1));
115+
assertThat(b, is(2));
116+
} finally {
117+
delete(databasePath);
118+
}
119+
}
120+
121+
@Test
122+
public void openExistingSQLCipherDatabaseWithByteArrayPassword(){
123+
File databasePath = null;
124+
int a = 0, b = 0;
125+
try {
126+
closeAndDelete(database);
127+
databasePath = extractAssetToDatabaseDirectory("sqlcipher-4.x-testkey.db");
128+
database = SQLiteDatabase.openDatabase(databasePath.getPath(), "testkey".getBytes(StandardCharsets.UTF_8), null, SQLiteDatabase.OPEN_READWRITE, null);
129+
Cursor cursor = database.rawQuery("SELECT * FROM t1;");
130+
if(cursor != null && cursor.moveToFirst()){
131+
a = cursor.getInt(0);
132+
b = cursor.getInt(1);
133+
cursor.close();
134+
}
135+
assertThat(a, is(1));
136+
assertThat(b, is(2));
137+
} finally {
138+
delete(databasePath);
139+
}
140+
}
141+
142+
@Test
143+
public void openExistingSQLitePlaintextDatabase(){
144+
File databasePath = null;
145+
int a = 0, b = 0;
146+
try {
147+
closeAndDelete(database);
148+
databasePath = extractAssetToDatabaseDirectory("sqlite-plaintext.db");
149+
database = SQLiteDatabase.openDatabase(databasePath.getPath(), "", null, SQLiteDatabase.OPEN_READWRITE, null);
150+
Cursor cursor = database.rawQuery("SELECT * FROM t1;");
151+
if(cursor != null && cursor.moveToFirst()){
152+
a = cursor.getInt(0);
153+
b = cursor.getInt(1);
154+
cursor.close();
155+
}
156+
assertThat(a, is(1));
157+
assertThat(b, is(2));
158+
} finally {
159+
delete(databasePath);
160+
}
161+
}
162+
38163
@Test
39164
public void insertDataQueryByObjectParams() {
40165
float a = 1.25f, a1 = 0.0f;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package net.zetetic.database.sqlcipher_cts;
2+
3+
import static org.hamcrest.Matchers.notNullValue;
4+
import static org.hamcrest.core.Is.is;
5+
import static org.junit.Assert.assertThat;
6+
7+
import android.content.Context;
8+
9+
import net.zetetic.database.sqlcipher.SQLiteDatabase;
10+
import net.zetetic.database.sqlcipher.SQLiteOpenHelper;
11+
12+
import org.junit.Test;
13+
14+
public class SQLCipherOpenHelperTest extends AndroidSQLCipherTestCase {
15+
16+
@Test
17+
public void shouldAccessReadOnlyDatabaseFromOpenHelper(){
18+
database.close();
19+
DatabaseHelper helper = new DatabaseHelper(context);
20+
SQLiteDatabase db = helper.getReadableDatabase();
21+
assertThat(db, is(notNullValue()));
22+
}
23+
24+
private class DatabaseHelper extends SQLiteOpenHelper {
25+
26+
public DatabaseHelper(Context context){
27+
super(context, "foo.db", "foo", null, 1, 1, null, null);
28+
}
29+
30+
@Override
31+
public void onCreate(SQLiteDatabase db) {
32+
33+
}
34+
35+
@Override
36+
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
37+
38+
}
39+
}
40+
41+
}

0 commit comments

Comments
 (0)