package org.thoughtcrime.securesms.database.helpers; import android.content.Context; import android.support.annotation.NonNull; import android.util.Log; import net.sqlcipher.database.SQLiteDatabase; import net.sqlcipher.database.SQLiteDatabaseHook; import net.sqlcipher.database.SQLiteOpenHelper; import org.thoughtcrime.securesms.crypto.DatabaseSecret; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.AttachmentDatabase; import org.thoughtcrime.securesms.database.DraftDatabase; import org.thoughtcrime.securesms.database.GroupDatabase; import org.thoughtcrime.securesms.database.GroupReceiptDatabase; import org.thoughtcrime.securesms.database.IdentityDatabase; import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.database.PushDatabase; import org.thoughtcrime.securesms.database.RecipientDatabase; import org.thoughtcrime.securesms.database.SmsDatabase; import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.service.KeyCachingService; import org.thoughtcrime.securesms.util.TextSecurePreferences; public class SQLCipherOpenHelper extends SQLiteOpenHelper { private static final String TAG = SQLCipherOpenHelper.class.getSimpleName(); private static final int DATABASE_VERSION = 1; private static final String DATABASE_NAME = "signal.db"; private final Context context; private final DatabaseSecret databaseSecret; public SQLCipherOpenHelper(@NonNull Context context, @NonNull DatabaseSecret databaseSecret) { super(context, DATABASE_NAME, null, DATABASE_VERSION, new SQLiteDatabaseHook() { @Override public void preKey(SQLiteDatabase db) { db.rawExecSQL("PRAGMA cipher_default_kdf_iter = 1;"); db.rawExecSQL("PRAGMA cipher_default_page_size = 4096;"); } @Override public void postKey(SQLiteDatabase db) { db.rawExecSQL("PRAGMA kdf_iter = '1';"); db.rawExecSQL("PRAGMA cipher_page_size = 4096;"); } }); this.context = context.getApplicationContext(); this.databaseSecret = databaseSecret; } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(SmsDatabase.CREATE_TABLE); db.execSQL(MmsDatabase.CREATE_TABLE); db.execSQL(AttachmentDatabase.CREATE_TABLE); db.execSQL(ThreadDatabase.CREATE_TABLE); db.execSQL(IdentityDatabase.CREATE_TABLE); db.execSQL(DraftDatabase.CREATE_TABLE); db.execSQL(PushDatabase.CREATE_TABLE); db.execSQL(GroupDatabase.CREATE_TABLE); db.execSQL(RecipientDatabase.CREATE_TABLE); db.execSQL(GroupReceiptDatabase.CREATE_TABLE); executeStatements(db, SmsDatabase.CREATE_INDEXS); executeStatements(db, MmsDatabase.CREATE_INDEXS); executeStatements(db, AttachmentDatabase.CREATE_INDEXS); executeStatements(db, ThreadDatabase.CREATE_INDEXS); executeStatements(db, DraftDatabase.CREATE_INDEXS); executeStatements(db, GroupDatabase.CREATE_INDEXS); executeStatements(db, GroupReceiptDatabase.CREATE_INDEXES); if (context.getDatabasePath(ClassicOpenHelper.NAME).exists()) { ClassicOpenHelper legacyHelper = new ClassicOpenHelper(context); android.database.sqlite.SQLiteDatabase legacyDb = legacyHelper.getWritableDatabase(); SQLCipherMigrationHelper.migratePlaintext(context, legacyDb, db); MasterSecret masterSecret = KeyCachingService.getMasterSecret(context); if (masterSecret != null) SQLCipherMigrationHelper.migrateCiphertext(context, masterSecret, legacyDb, db, null); else TextSecurePreferences.setNeedsSqlCipherMigration(context, true); } } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } public SQLiteDatabase getReadableDatabase() { return getReadableDatabase(databaseSecret.asString()); } public SQLiteDatabase getWritableDatabase() { return getWritableDatabase(databaseSecret.asString()); } private void executeStatements(SQLiteDatabase db, String[] statements) { for (String statement : statements) db.execSQL(statement); } }