aboutsummaryrefslogtreecommitdiffstats
path: root/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
diff options
context:
space:
mode:
Diffstat (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java')
-rw-r--r--OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java230
1 files changed, 159 insertions, 71 deletions
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
index 807444d78..e0cf6b6c5 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
@@ -18,11 +18,17 @@
package org.sufficientlysecure.keychain.provider;
import android.content.Context;
+import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;
+import org.spongycastle.openpgp.PGPKeyRing;
+import org.spongycastle.openpgp.PGPPublicKeyRing;
+import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
+import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsAccountsColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingsColumns;
@@ -30,51 +36,72 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeysColumns;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIdsColumns;
import org.sufficientlysecure.keychain.util.Log;
+import java.io.IOException;
+import java.util.Arrays;
+
public class KeychainDatabase extends SQLiteOpenHelper {
- private static final String DATABASE_NAME = "apg.db";
- private static final int DATABASE_VERSION = 8;
+ private static final String DATABASE_NAME = "openkeychain.db";
+ private static final int DATABASE_VERSION = 1;
+ static Boolean apg_hack = false;
public interface Tables {
- String KEY_RINGS = "key_rings";
+ String KEY_RINGS_PUBLIC = "keyrings_public";
+ String KEY_RINGS_SECRET = "keyrings_secret";
String KEYS = "keys";
String USER_IDS = "user_ids";
String API_APPS = "api_apps";
String API_ACCOUNTS = "api_accounts";
}
- private static final String CREATE_KEY_RINGS = "CREATE TABLE IF NOT EXISTS " + Tables.KEY_RINGS
- + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + KeyRingsColumns.MASTER_KEY_ID + " INT64, "
- + KeyRingsColumns.TYPE + " INTEGER, "
- + KeyRingsColumns.KEY_RING_DATA + " BLOB)";
-
- private static final String CREATE_KEYS = "CREATE TABLE IF NOT EXISTS " + Tables.KEYS + " ("
- + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + KeysColumns.KEY_ID + " INT64, "
- + KeysColumns.TYPE + " INTEGER, "
- + KeysColumns.IS_MASTER_KEY + " INTEGER, "
- + KeysColumns.ALGORITHM + " INTEGER, "
- + KeysColumns.KEY_SIZE + " INTEGER, "
- + KeysColumns.CAN_CERTIFY + " INTEGER, "
- + KeysColumns.CAN_SIGN + " INTEGER, "
- + KeysColumns.CAN_ENCRYPT + " INTEGER, "
- + KeysColumns.IS_REVOKED + " INTEGER, "
- + KeysColumns.CREATION + " INTEGER, "
- + KeysColumns.EXPIRY + " INTEGER, "
- + KeysColumns.KEY_DATA + " BLOB,"
- + KeysColumns.RANK + " INTEGER, "
- + KeysColumns.FINGERPRINT + " BLOB, "
- + KeysColumns.KEY_RING_ROW_ID + " INTEGER NOT NULL, "
- + "FOREIGN KEY(" + KeysColumns.KEY_RING_ROW_ID + ") REFERENCES "
- + Tables.KEY_RINGS + "(" + BaseColumns._ID + ") ON DELETE CASCADE)";
-
- private static final String CREATE_USER_IDS = "CREATE TABLE IF NOT EXISTS " + Tables.USER_IDS
- + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
- + UserIdsColumns.USER_ID + " TEXT, "
- + UserIdsColumns.RANK + " INTEGER, "
- + UserIdsColumns.KEY_RING_ROW_ID + " INTEGER NOT NULL, "
- + "FOREIGN KEY(" + UserIdsColumns.KEY_RING_ROW_ID + ") REFERENCES "
- + Tables.KEY_RINGS + "(" + BaseColumns._ID + ") ON DELETE CASCADE)";
+ private static final String CREATE_KEYRINGS_PUBLIC =
+ "CREATE TABLE IF NOT EXISTS keyrings_public ("
+ + KeyRingsColumns.MASTER_KEY_ID + " INTEGER PRIMARY KEY,"
+ + KeyRingsColumns.KEY_RING_DATA + " BLOB"
+ + ")";
+
+ private static final String CREATE_KEYRINGS_SECRET =
+ "CREATE TABLE IF NOT EXISTS keyrings_secret ("
+ + KeyRingsColumns.MASTER_KEY_ID + " INTEGER PRIMARY KEY,"
+ + KeyRingsColumns.KEY_RING_DATA + " BLOB,"
+ + "FOREIGN KEY(" + KeyRingsColumns.MASTER_KEY_ID + ") "
+ + "REFERENCES keyrings_public(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE"
+ + ")";
+
+ private static final String CREATE_KEYS =
+ "CREATE TABLE IF NOT EXISTS " + Tables.KEYS + " ("
+ + KeysColumns.MASTER_KEY_ID + " INTEGER, "
+ + KeysColumns.RANK + " INTEGER, "
+
+ + KeysColumns.KEY_ID + " INTEGER, "
+ + KeysColumns.KEY_SIZE + " INTEGER, "
+ + KeysColumns.ALGORITHM + " INTEGER, "
+ + KeysColumns.FINGERPRINT + " BLOB, "
+
+ + KeysColumns.CAN_CERTIFY + " BOOLEAN, "
+ + KeysColumns.CAN_SIGN + " BOOLEAN, "
+ + KeysColumns.CAN_ENCRYPT + " BOOLEAN, "
+ + KeysColumns.IS_REVOKED + " BOOLEAN, "
+
+ + KeysColumns.CREATION + " INTEGER, "
+ + KeysColumns.EXPIRY + " INTEGER, "
+
+ + "PRIMARY KEY(" + KeysColumns.MASTER_KEY_ID + ", " + KeysColumns.RANK + "),"
+ + "FOREIGN KEY(" + KeysColumns.MASTER_KEY_ID + ") REFERENCES "
+ + Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE"
+ + ")";
+
+ private static final String CREATE_USER_IDS =
+ "CREATE TABLE IF NOT EXISTS " + Tables.USER_IDS + "("
+ + UserIdsColumns.MASTER_KEY_ID + " INTEGER, "
+ + UserIdsColumns.USER_ID + " CHARMANDER, "
+
+ + UserIdsColumns.IS_PRIMARY + " BOOLEAN, "
+ + UserIdsColumns.RANK+ " INTEGER, "
+
+ + "PRIMARY KEY(" + UserIdsColumns.MASTER_KEY_ID + ", " + UserIdsColumns.USER_ID + "),"
+ + "FOREIGN KEY(" + UserIdsColumns.MASTER_KEY_ID + ") REFERENCES "
+ + Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE"
+ + ")";
private static final String CREATE_API_APPS = "CREATE TABLE IF NOT EXISTS " + Tables.API_APPS
+ " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
@@ -96,13 +123,27 @@ public class KeychainDatabase extends SQLiteOpenHelper {
KeychainDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
+
+
+ // make sure this is only done once, on the first instance!
+ boolean iAmIt = false;
+ synchronized(apg_hack) {
+ if(!apg_hack) {
+ iAmIt = true;
+ apg_hack = true;
+ }
+ }
+ // if it's us, do the import
+ if(iAmIt)
+ checkAndImportApg(context);
}
@Override
public void onCreate(SQLiteDatabase db) {
Log.w(Constants.TAG, "Creating database...");
- db.execSQL(CREATE_KEY_RINGS);
+ db.execSQL(CREATE_KEYRINGS_PUBLIC);
+ db.execSQL(CREATE_KEYRINGS_SECRET);
db.execSQL(CREATE_KEYS);
db.execSQL(CREATE_USER_IDS);
db.execSQL(CREATE_API_APPS);
@@ -119,44 +160,91 @@ public class KeychainDatabase extends SQLiteOpenHelper {
}
@Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- Log.w(Constants.TAG, "Upgrading database from version " + oldVersion + " to " + newVersion);
-
- // Upgrade from oldVersion through all cases to newest one
- for (int version = oldVersion; version < newVersion; ++version) {
- Log.w(Constants.TAG, "Upgrading database to version " + version);
-
- switch (version) {
- case 3:
- db.execSQL("ALTER TABLE " + Tables.KEYS + " ADD COLUMN " + KeysColumns.CAN_CERTIFY
- + " INTEGER DEFAULT 0;");
- db.execSQL("UPDATE " + Tables.KEYS + " SET " + KeysColumns.CAN_CERTIFY
- + " = 1 WHERE " + KeysColumns.IS_MASTER_KEY + "= 1;");
- break;
- case 4:
- db.execSQL(CREATE_API_APPS);
- break;
- case 5:
- // new column: package_signature
- db.execSQL("DROP TABLE IF EXISTS " + Tables.API_APPS);
- db.execSQL(CREATE_API_APPS);
- break;
- case 6:
- // new column: fingerprint
- db.execSQL("ALTER TABLE " + Tables.KEYS + " ADD COLUMN " + KeysColumns.FINGERPRINT
- + " BLOB;");
- break;
- case 7:
- // new db layout for api apps
- db.execSQL("DROP TABLE IF EXISTS " + Tables.API_APPS);
- db.execSQL(CREATE_API_APPS);
- db.execSQL(CREATE_API_APPS_ACCOUNTS);
- break;
- default:
+ public void onUpgrade(SQLiteDatabase db, int old, int nu) {
+ // don't care (this is version 1)
+ }
+
+ /** This method tries to import data from a provided database.
+ *
+ * The sole assumptions made on this db are that there is a key_rings table
+ * with a key_ring_data and a type column, the latter of which should be bigger
+ * for secret keys.
+ */
+ public void checkAndImportApg(Context context) {
+
+ boolean hasApgDb = false; {
+ // It's the Java way =(
+ String[] dbs = context.databaseList();
+ for(String db : dbs) {
+ if(db.equals("apg.db")) {
+ hasApgDb = true;
break;
+ }
+ }
+ }
+
+ if(!hasApgDb)
+ return;
+
+ Log.d(Constants.TAG, "apg.db exists! Importing...");
+
+ SQLiteDatabase db = new SQLiteOpenHelper(context, "apg.db", null, 1) {
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ // should never happen
+ assert false;
+ }
+ @Override
+ public void onDowngrade(SQLiteDatabase db, int old, int nu) {
+ // don't care
+ }
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int old, int nu) {
+ // don't care either
+ }
+ }.getReadableDatabase();
+
+ // kill current!
+ { // TODO don't kill current.
+ Log.d(Constants.TAG, "Truncating db...");
+ SQLiteDatabase d = getWritableDatabase();
+ d.execSQL("DELETE FROM keyrings_public");
+ d.close();
+ Log.d(Constants.TAG, "Ok.");
+ }
+ Cursor c = db.rawQuery("SELECT key_ring_data FROM key_rings ORDER BY type ASC", null);
+ try {
+ // import from old database
+ Log.d(Constants.TAG, "Importing " + c.getCount() + " keyrings from apg.db...");
+ for(int i = 0; i < c.getCount(); i++) {
+ c.moveToPosition(i);
+ byte[] data = c.getBlob(0);
+ PGPKeyRing ring = PgpConversionHelper.BytesToPGPKeyRing(data);
+ if(ring instanceof PGPPublicKeyRing)
+ ProviderHelper.saveKeyRing(context, (PGPPublicKeyRing) ring);
+ else if(ring instanceof PGPSecretKeyRing)
+ ProviderHelper.saveKeyRing(context, (PGPSecretKeyRing) ring);
+ else {
+ Log.e(Constants.TAG, "Unknown blob data type!");
+ }
}
+
+ } catch(IOException e) {
+ Log.e(Constants.TAG, "Error importing apg db!", e);
+ return;
+ } finally {
+ if(c != null)
+ c.close();
+ if(db != null)
+ db.close();
}
+
+ // TODO delete old db, if we are sure this works
+ // context.deleteDatabase("apg.db");
+ Log.d(Constants.TAG, "All done, (not) deleting apg.db");
+
+
}
}