Skip to content

Commit

Permalink
clear char[] passphrase after use
Browse files Browse the repository at this point in the history
  • Loading branch information
commonsguy committed Oct 5, 2019
1 parent fb7309c commit 8b5d7c8
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 0 deletions.
1 change: 1 addition & 0 deletions saferoom/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ dependencies {
androidTestImplementation "com.commonsware.misc:support-db-tests:0.4.5"
androidTestImplementation "android.arch.persistence.room:runtime:$roomVer"
androidTestImplementation "com.android.support:support-annotations:28.0.0"
androidTestImplementation "junit:junit:4.12"
}

if (project.hasProperty('PUBLISH_GROUP_ID')) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package com.commonsware.cwac.saferoom.test;

import android.arch.persistence.db.SupportSQLiteDatabase;
import android.arch.persistence.db.SupportSQLiteOpenHelper;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import com.commonsware.cwac.saferoom.SafeHelperFactory;

import net.sqlcipher.database.SQLiteDatabase;

import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.File;
import java.io.IOException;

import static org.junit.Assert.assertArrayEquals;

@RunWith(AndroidJUnit4.class)
public class PassphraseClearTest {
private static final String DB_NAME="db";
private static final String PASSPHRASE="Call me Ishmael. Some years ago—never mind how long precisely—having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. It is a way I have of driving off the spleen and regulating the circulation. Whenever I find myself growing grim about the mouth; whenever it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before coffin warehouses, and bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me, that it requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking people’s hats off—then, I account it high time to get to sea as soon as I can. This is my substitute for pistol and ball. With a philosophical flourish Cato throws himself upon his sword; I quietly take to the ship. There is nothing surprising in this. If they but knew it, almost all men in their degree, some time or other, cherish very nearly the same feelings towards the ocean with me.";

@After
public void tearDown() {
Context ctxt=InstrumentationRegistry.getTargetContext();
File db=ctxt.getDatabasePath(DB_NAME);

for (File f : db.getParentFile().listFiles()) {
f.delete();
}
}

@Test
public void charArrayCleared() throws IOException {
char[] charArray = PASSPHRASE.toCharArray();
SafeHelperFactory factory=new SafeHelperFactory(charArray);
SupportSQLiteOpenHelper helper=
factory.create(InstrumentationRegistry.getTargetContext(), DB_NAME,
new Callback(1));
SupportSQLiteDatabase db=helper.getWritableDatabase();

helper.close();

char[] expected = new char[charArray.length];

for (int i=0;i<expected.length;i++) {
expected[i]=(char)0;
}

assertArrayEquals(expected, charArray);
}

@Test
public void byteArrayCleared() throws IOException {
char[] charArray = PASSPHRASE.toCharArray();
byte[] byteArray = SQLiteDatabase.getBytes(charArray);
SafeHelperFactory factory=new SafeHelperFactory(byteArray);
SupportSQLiteOpenHelper helper=
factory.create(InstrumentationRegistry.getTargetContext(), DB_NAME,
new Callback(1));
SupportSQLiteDatabase db=helper.getWritableDatabase();

helper.close();

byte[] expected = new byte[byteArray.length];

for (int i=0;i<expected.length;i++) {
expected[i]=(byte)0;
}

assertArrayEquals(expected, byteArray);
}

private static final class Callback extends SupportSQLiteOpenHelper.Callback {
public Callback(int version) {
super(version);
}

@Override
public void onCreate(SupportSQLiteDatabase db) {
db.execSQL("CREATE TABLE foo (bar, goo);");
db.execSQL("INSERT INTO foo (bar, goo) VALUES (?, ?)",
new Object[] {1, "two"});
}

@Override
public void onUpgrade(SupportSQLiteDatabase db, int oldVersion,
int newVersion) {

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ public SafeHelperFactory(char[] passphrase) {
*/
public SafeHelperFactory(char[] passphrase, String postKeySql) {
this(SQLiteDatabase.getBytes(passphrase), postKeySql);

if (options.clearPassphrase) { clearPassphrase(passphrase); }
}

/**
Expand All @@ -177,6 +179,8 @@ public SafeHelperFactory(char[] passphrase, String postKeySql) {
*/
public SafeHelperFactory(char[] passphrase, Options options) {
this(SQLiteDatabase.getBytes(passphrase), options);

if (options.clearPassphrase) { clearPassphrase(passphrase); }
}

/**
Expand Down Expand Up @@ -241,6 +245,12 @@ public SupportSQLiteOpenHelper create(Context context, String name,
return(new Helper(context, name, callback, passphrase, options));
}

private void clearPassphrase(char[] passphrase) {
for (int i = 0; i < passphrase.length; i++) {
passphrase[i] = (byte) 0;
}
}

/**
* Class for encapsulating pre- and post-key SQL statements to be executed as
* part of opening the database. Use the static builder() method to get a Builder
Expand Down

0 comments on commit 8b5d7c8

Please sign in to comment.