Skip to content

Commit b58e433

Browse files
Allow SupportFactory and SupportHelper to clear passphrase storage
1 parent 8b1cca2 commit b58e433

File tree

2 files changed

+35
-5
lines changed

2 files changed

+35
-5
lines changed

android-database-sqlcipher/src/main/java/net/sqlcipher/database/SupportFactory.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,25 @@
2121
public class SupportFactory implements SupportSQLiteOpenHelper.Factory {
2222
private final byte[] passphrase;
2323
private final SQLiteDatabaseHook hook;
24+
private final boolean clearPassphrase;
2425

2526
public SupportFactory(byte[] passphrase) {
2627
this(passphrase, (SQLiteDatabaseHook)null);
2728
}
2829

2930
public SupportFactory(byte[] passphrase, SQLiteDatabaseHook hook) {
31+
this(passphrase, hook, true);
32+
}
33+
34+
public SupportFactory(byte[] passphrase, SQLiteDatabaseHook hook,
35+
boolean clearPassphrase) {
3036
this.passphrase = passphrase;
3137
this.hook = hook;
38+
this.clearPassphrase = clearPassphrase;
3239
}
3340

3441
@Override
3542
public SupportSQLiteOpenHelper create(SupportSQLiteOpenHelper.Configuration configuration) {
36-
return new SupportHelper(configuration, passphrase, hook);
43+
return new SupportHelper(configuration, passphrase, hook, clearPassphrase);
3744
}
3845
}

android-database-sqlcipher/src/main/java/net/sqlcipher/database/SupportHelper.java

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*
1+
/*
22
* Copyright (C) 2019 Mark L. Murphy
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,21 @@
1616

1717
package net.sqlcipher.database;
1818

19+
import net.sqlcipher.database.SQLiteException;
1920
import androidx.sqlite.db.SupportSQLiteDatabase;
2021
import androidx.sqlite.db.SupportSQLiteOpenHelper;
2122

2223
public class SupportHelper implements SupportSQLiteOpenHelper {
2324
private SQLiteOpenHelper standardHelper;
2425
private byte[] passphrase;
26+
private final boolean clearPassphrase;
2527

2628
SupportHelper(final SupportSQLiteOpenHelper.Configuration configuration,
27-
byte[] passphrase, final SQLiteDatabaseHook hook) {
29+
byte[] passphrase, final SQLiteDatabaseHook hook,
30+
boolean clearPassphrase) {
2831
SQLiteDatabase.loadLibs(configuration.context);
2932
this.passphrase = passphrase;
33+
this.clearPassphrase = clearPassphrase;
3034

3135
standardHelper =
3236
new SQLiteOpenHelper(configuration.context, configuration.name,
@@ -74,8 +78,27 @@ public void setWriteAheadLoggingEnabled(boolean enabled) {
7478

7579
@Override
7680
public SupportSQLiteDatabase getWritableDatabase() {
77-
SQLiteDatabase result = standardHelper.getWritableDatabase(passphrase);
78-
if(passphrase != null) {
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) {
79102
for (int i = 0; i < passphrase.length; i++) {
80103
passphrase[i] = (byte)0;
81104
}

0 commit comments

Comments
 (0)