working on externalizing encrypt methods into the service

This commit is contained in:
Dominik
2012-06-09 03:46:30 +03:00
parent 7b61ad24d7
commit 5a51f79126
22 changed files with 650 additions and 280 deletions

View File

@@ -64,6 +64,7 @@ import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
import org.thialfihar.android.apg.Id.return_value;
import org.thialfihar.android.apg.KeyServer.AddKeyException;
import org.thialfihar.android.apg.passphrase.CachedPassPhrase;
import org.thialfihar.android.apg.provider.DataProvider;
import org.thialfihar.android.apg.provider.Database;
import org.thialfihar.android.apg.provider.KeyRings;
@@ -2289,7 +2290,7 @@ public class Apg {
return result;
}
static long getLengthOfStream(InputStream in) throws IOException {
public static long getLengthOfStream(InputStream in) throws IOException {
long size = 0;
long n = 0;
byte dummy[] = new byte[0x10000];

View File

@@ -0,0 +1,18 @@
package org.thialfihar.android.apg;
import org.thialfihar.android.apg.passphrase.PassphraseCacheService;
import android.app.Application;
import android.content.Intent;
public class ApgApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
/** Start passphrase cache service */
PassphraseCacheService.startCacheService(this);
}
}

View File

@@ -19,6 +19,7 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import org.thialfihar.android.apg.R;
import org.thialfihar.android.apg.Apg.GeneralException;
@@ -26,7 +27,10 @@ import org.thialfihar.android.apg.Apg.GeneralException;
import android.content.Context;
import android.os.Environment;
public class DataDestination {
public class DataDestination implements Serializable {
private static final long serialVersionUID = -6478075911319320498L;
private String mStreamFilename;
private String mFilename;
private int mMode = Id.mode.undefined;

View File

@@ -20,6 +20,7 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import org.thialfihar.android.apg.R;
import org.thialfihar.android.apg.Apg.GeneralException;
@@ -28,7 +29,10 @@ import android.content.Context;
import android.net.Uri;
import android.os.Environment;
public class DataSource {
public class DataSource implements Serializable {
private static final long serialVersionUID = 2377217399907415255L;
private Uri mContentUri = null;
private String mText = null;
private byte[] mData = null;
@@ -51,6 +55,10 @@ public class DataSource {
}
}
public Uri getUri() {
return mContentUri;
}
public void setText(String text) {
mText = text;
mData = null;
@@ -71,6 +79,17 @@ public class DataSource {
return mData != null || mContentUri != null;
}
public byte[] getBytes() {
byte[] bytes = null;
if (mData != null) {
bytes = mData;
} else {
bytes = mText.getBytes();
}
return bytes;
}
public InputData getInputData(Context context, boolean withSize) throws GeneralException,
FileNotFoundException, IOException {
InputStream in = null;

View File

@@ -22,6 +22,10 @@ import android.content.SharedPreferences;
import java.util.Vector;
/**
* Singelton Implementation of a Preference Helper
*
*/
public class Preferences {
private static Preferences mPreferences;
private SharedPreferences mSharedPreferences;

View File

@@ -14,12 +14,14 @@
* limitations under the License.
*/
package org.thialfihar.android.apg;
package org.thialfihar.android.apg.passphrase;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPSecretKey;
import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.R;
import android.app.Activity;
@@ -35,7 +37,7 @@ import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class AskForSecretKeyPassPhrase {
public class AskForPassphrase {
public static interface PassPhraseCallbackInterface {
void passPhraseCallback(long keyId, String passPhrase);
}
@@ -107,6 +109,10 @@ public class AskForSecretKeyPassPhrase {
} else {
keyId = Id.key.symmetric;
}
// cache again
Apg.setCachedPassPhrase(keyId, passPhrase);
// return by callback
cb.passPhraseCallback(keyId, passPhrase);
}
});
@@ -126,6 +132,9 @@ public class AskForSecretKeyPassPhrase {
if (testKey != null) {
Log.d("APG", "Key has no passphrase!");
// cache null
Apg.setCachedPassPhrase(secretKey.getKeyID(), null);
// return by callback
cb.passPhraseCallback(secretKey.getKeyID(), null);
return null;

View File

@@ -12,7 +12,7 @@
* limitations under the License.
*/
package org.thialfihar.android.apg;
package org.thialfihar.android.apg.passphrase;
public class CachedPassPhrase {
public final long timestamp;

View File

@@ -12,11 +12,13 @@
* limitations under the License.
*/
package org.thialfihar.android.apg.service;
package org.thialfihar.android.apg.passphrase;
import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Preferences;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
@@ -27,6 +29,12 @@ public class PassphraseCacheService extends Service {
public static final String EXTRA_TTL = "ttl";
public static void startCacheService(Context context) {
Intent intent = new Intent(context, PassphraseCacheService.class);
intent.putExtra(PassphraseCacheService.EXTRA_TTL, Preferences.getPreferences(context).getPassPhraseCacheTtl());
context.startService(intent);
}
private int mPassPhraseCacheTtl = 15;
private Handler mCacheHandler = new Handler();
private Runnable mCacheTask = new Runnable() {

View File

@@ -12,7 +12,7 @@
* limitations under the License.
*/
package org.thialfihar.android.apg.provider;
package org.thialfihar.android.apg.provider.blob;
import org.thialfihar.android.apg.service.ApgService2;
@@ -26,43 +26,47 @@ import android.net.Uri;
import android.util.Log;
public class ApgServiceBlobDatabase extends SQLiteOpenHelper {
private static final String TAG = "ApgServiceBlobDatabase";
private static final int VERSION = 1;
private static final String NAME = "apg_service_blob_data";
private static final String TABLE = "data";
public ApgServiceBlobDatabase(Context context) {
super(context, NAME, null, VERSION);
if(ApgService2.LOCAL_LOGD) Log.d(TAG, "constructor called");
if (ApgService2.LOCAL_LOGD)
Log.d(TAG, "constructor called");
}
@Override
public void onCreate(SQLiteDatabase db) {
if(ApgService2.LOCAL_LOGD) Log.d(TAG, "onCreate() called");
db.execSQL("create table " + TABLE + " ( _id integer primary key autoincrement," +
"key text not null)");
if (ApgService2.LOCAL_LOGD)
Log.d(TAG, "onCreate() called");
db.execSQL("create table " + TABLE + " ( _id integer primary key autoincrement,"
+ "key text not null)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if(ApgService2.LOCAL_LOGD) Log.d(TAG, "onUpgrade() called");
if (ApgService2.LOCAL_LOGD)
Log.d(TAG, "onUpgrade() called");
// no upgrade necessary yet
}
public Uri insert(ContentValues vals) {
if(ApgService2.LOCAL_LOGD) Log.d(TAG, "insert() called");
if (ApgService2.LOCAL_LOGD)
Log.d(TAG, "insert() called");
SQLiteDatabase db = this.getWritableDatabase();
long newId = db.insert(TABLE, null, vals);
return ContentUris.withAppendedId(ApgServiceBlobProvider.CONTENT_URI, newId);
}
public Cursor query(String id, String key) {
if(ApgService2.LOCAL_LOGD) Log.d(TAG, "query() called");
if (ApgService2.LOCAL_LOGD)
Log.d(TAG, "query() called");
SQLiteDatabase db = this.getReadableDatabase();
return db.query(TABLE, new String[] {"_id"},
"_id = ? and key = ?", new String[] {id, key},
null, null, null);
return db.query(TABLE, new String[] { "_id" }, "_id = ? and key = ?", new String[] { id,
key }, null, null, null);
}
}

View File

@@ -12,7 +12,7 @@
* limitations under the License.
*/
package org.thialfihar.android.apg.provider;
package org.thialfihar.android.apg.provider.blob;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.service.ApgService2;

View File

@@ -0,0 +1,42 @@
//package org.thialfihar.android.apg.provider.blob;
//
//import android.net.Uri;
//import android.provider.BaseColumns;
//
//public class BlobContract {
//
// interface BlobColumns {
// String DATA = "data";
// }
//
// public static final String CONTENT_AUTHORITY = "org.thialfihar.android.apg";
//
// private static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
//
// public static final String PATH_BLOB = "blob";
//
// public static class Blobs implements BlobColumns, BaseColumns {
// public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon().appendPath(PATH_BLOB)
// .build();
//
// /** Use if multiple items get returned */
// public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.apg.blob";
//
// /** Use if a single item is returned */
// public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.apg.blob";
//
// /** Default "ORDER BY" clause. */
// public static final String DEFAULT_SORT = BaseColumns._ID + " ASC";
//
// public static Uri buildUri(String id) {
// return CONTENT_URI.buildUpon().appendPath(id).build();
// }
//
// public static String getId(Uri uri) {
// return uri.getLastPathSegment();
// }
// }
//
// private BlobContract() {
// }
//}

View File

@@ -39,10 +39,6 @@ public class ApgHandler extends Handler {
public static final String DATA_MESSAGE = "message";
public static final String DATA_MESSAGE_ID = "message_id";
// possible data keys as result from service
public static final String RESULT_NEW_KEY = "new_key";
public static final String RESULT_NEW_KEY2 = "new_key2";
Activity mActivity;
ProgressDialogFragment mProgressDialogFragment;

View File

@@ -16,19 +16,37 @@
package org.thialfihar.android.apg.service;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.DataDestination;
import org.thialfihar.android.apg.DataSource;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.InputData;
import org.thialfihar.android.apg.Preferences;
import org.thialfihar.android.apg.ProgressDialogUpdater;
import org.thialfihar.android.apg.R;
import org.thialfihar.android.apg.Apg.GeneralException;
import org.thialfihar.android.apg.provider.DataProvider;
import org.thialfihar.android.apg.util.Utils;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
@@ -37,7 +55,7 @@ import android.util.Log;
/**
* This Service contains all important long lasting operations for APG. It receives Intents with
* data from the activities or other apps, queues these intents, executes them, and stops itself
* doing it.
* after doing them.
*/
// TODO: ProgressDialogUpdater rework???
public class ApgService extends IntentService implements ProgressDialogUpdater {
@@ -62,11 +80,40 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
public static final String PASSPHRASE = "passphrase";
public static final String MASTER_KEY = "master_key";
// encrypt
public static final String SECRET_KEY_ID = "secret_key_id";
// public static final String DATA_SOURCE = "data_source";
// public static final String DATA_DESTINATION = "data_destination";
public static final String USE_ASCII_AMOR = "use_ascii_amor";
// public static final String ENCRYPTION_TARGET = "encryption_target";
public static final String ENCRYPTION_KEYS_IDS = "encryption_keys_ids";
public static final String SIGNATURE_KEY_ID = "signature_key_id";
public static final String COMPRESSION_ID = "compression_id";
public static final String GENERATE_SIGNATURE = "generate_signature";
public static final String SIGN_ONLY = "sign_only";
public static final String BYTES = "bytes";
public static final String FILE_URI = "file_uri";
public static final String OUTPUT_FILENAME = "output_filename";
public static final String PROVIDER_URI = "provider_uri";
// possible ints for EXTRA_ACTION
public static final int ACTION_SAVE_KEYRING = 1;
public static final int ACTION_GENERATE_KEY = 2;
public static final int ACTION_GENERATE_DEFAULT_RSA_KEYS = 3;
public static final int ACTION_ENCRYPT_SIGN_BYTES = 4;
public static final int ACTION_ENCRYPT_SIGN_FILE = 5;
public static final int ACTION_ENCRYPT_SIGN_STREAM = 6;
// possible data keys as result
public static final String RESULT_NEW_KEY = "new_key";
public static final String RESULT_NEW_KEY2 = "new_key2";
public static final String RESULT_SIGNATURE_DATA = "signatureData";
public static final String RESULT_SIGNATURE_TEXT = "signatureText";
public static final String RESULT_ENCRYPTED_MESSAGE = "encryptedMessage";
public static final String RESULT_ENCRYPTED_DATA = "encryptedData";
public static final String RESULT_URI = "resultUri";
Messenger mMessenger;
public ApgService() {
@@ -82,26 +129,19 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
if (extras == null) {
Log.e(Constants.TAG, "Extra bundle is null!");
Log.e(Constants.TAG, "Extras bundle is null!");
return;
}
if (!extras.containsKey(EXTRA_MESSENGER)) {
Log.e(Constants.TAG, "Extra bundle must contain a messenger!");
if (!(extras.containsKey(EXTRA_MESSENGER) || extras.containsKey(EXTRA_DATA) || extras
.containsKey(EXTRA_ACTION))) {
Log.e(Constants.TAG,
"Extra bundle must contain a messenger, a data bundle, and an action!");
return;
}
mMessenger = (Messenger) extras.get(EXTRA_MESSENGER);
if (!extras.containsKey(EXTRA_DATA)) {
Log.e(Constants.TAG, "Extra bundle must contain data bundle!");
return;
}
Bundle data = extras.getBundle(EXTRA_DATA);
if (!extras.containsKey(EXTRA_ACTION)) {
Log.e(Constants.TAG, "Extra bundle must contain a action!");
return;
}
int action = extras.getInt(EXTRA_ACTION);
// execute action from extra bundle
@@ -155,9 +195,8 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
// Output
Bundle resultData = new Bundle();
resultData.putByteArray(ApgHandler.RESULT_NEW_KEY,
Utils.PGPSecretKeyRingToBytes(newKeyRing));
sendMessageToHandler(ApgHandler.MESSAGE_OKAY, null, resultData);
resultData.putByteArray(RESULT_NEW_KEY, Utils.PGPSecretKeyRingToBytes(newKeyRing));
sendMessageToHandler(ApgHandler.MESSAGE_OKAY, resultData);
} catch (Exception e) {
sendErrorToHandler(e);
}
@@ -178,13 +217,263 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
// Output
Bundle resultData = new Bundle();
resultData.putByteArray(ApgHandler.RESULT_NEW_KEY,
resultData.putByteArray(RESULT_NEW_KEY,
Utils.PGPSecretKeyRingToBytes(masterKeyRing));
resultData.putByteArray(ApgHandler.RESULT_NEW_KEY2,
Utils.PGPSecretKeyRingToBytes(subKeyRing));
sendMessageToHandler(ApgHandler.MESSAGE_OKAY, null, resultData);
resultData.putByteArray(RESULT_NEW_KEY2, Utils.PGPSecretKeyRingToBytes(subKeyRing));
sendMessageToHandler(ApgHandler.MESSAGE_OKAY, resultData);
} catch (Exception e) {
Log.e(Constants.TAG, "Creating initial key failed: +" + e);
sendErrorToHandler(e);
}
break;
case ACTION_ENCRYPT_SIGN_BYTES:
try {
// Input
long secretKeyId = data.getLong(SECRET_KEY_ID);
String passphrase = data.getString(PASSPHRASE);
byte[] bytes = data.getByteArray(BYTES);
boolean useAsciiArmour = data.getBoolean(USE_ASCII_AMOR);
long encryptionKeyIds[] = data.getLongArray(ENCRYPTION_KEYS_IDS);
long signatureKeyId = data.getLong(SIGNATURE_KEY_ID);
int compressionId = data.getInt(COMPRESSION_ID);
boolean generateSignature = data.getBoolean(GENERATE_SIGNATURE);
boolean signOnly = data.getBoolean(SIGN_ONLY);
// Operation
ByteArrayInputStream inStream = new ByteArrayInputStream(bytes);
int inLength = bytes.length;
InputData inputData = new InputData(inStream, inLength);
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
if (generateSignature) {
Apg.generateSignature(this, inputData, outStream, useAsciiArmour, false,
secretKeyId, Apg.getCachedPassPhrase(secretKeyId), Preferences
.getPreferences(this).getDefaultHashAlgorithm(), Preferences
.getPreferences(this).getForceV3Signatures(), this);
} else if (signOnly) {
Apg.signText(this, inputData, outStream, secretKeyId, Apg
.getCachedPassPhrase(secretKeyId), Preferences.getPreferences(this)
.getDefaultHashAlgorithm(), Preferences.getPreferences(this)
.getForceV3Signatures(), this);
} else {
Apg.encrypt(this, inputData, outStream, useAsciiArmour, encryptionKeyIds,
signatureKeyId, Apg.getCachedPassPhrase(signatureKeyId), this,
Preferences.getPreferences(this).getDefaultEncryptionAlgorithm(),
Preferences.getPreferences(this).getDefaultHashAlgorithm(),
compressionId, Preferences.getPreferences(this).getForceV3Signatures(),
passphrase);
}
outStream.close();
// Output
Bundle resultData = new Bundle();
// if (encryptionTarget != Id.target.file) {
// if (out instanceof ByteArrayOutputStream) {
if (useAsciiArmour) {
String output = new String(outStream.toByteArray());
if (generateSignature) {
resultData.putString(RESULT_SIGNATURE_TEXT, output);
} else {
resultData.putString(RESULT_ENCRYPTED_MESSAGE, output);
}
} else {
byte output[] = outStream.toByteArray();
if (generateSignature) {
resultData.putByteArray(RESULT_SIGNATURE_DATA, output);
} else {
resultData.putByteArray(RESULT_ENCRYPTED_DATA, output);
}
}
// } else if (out instanceof FileOutputStream) {
// String fileName = dataDestination.getStreamFilename();
// String uri = "content://" + DataProvider.AUTHORITY + "/data/" + fileName;
// resultData.putString(RESULT_URI, uri);
// } else {
// sendErrorToHandler(new Apg.GeneralException("No output-data found."));
// }
// }
sendMessageToHandler(ApgHandler.MESSAGE_OKAY, resultData);
} catch (Exception e) {
sendErrorToHandler(e);
}
break;
case ACTION_ENCRYPT_SIGN_FILE:
try {
// Input
long secretKeyId = data.getLong(SECRET_KEY_ID);
String passphrase = data.getString(PASSPHRASE);
Uri fileUri = Uri.parse(data.getString(FILE_URI));
String outputFilename = data.getString(OUTPUT_FILENAME);
boolean useAsciiArmour = data.getBoolean(USE_ASCII_AMOR);
long encryptionKeyIds[] = data.getLongArray(ENCRYPTION_KEYS_IDS);
long signatureKeyId = data.getLong(SIGNATURE_KEY_ID);
int compressionId = data.getInt(COMPRESSION_ID);
boolean generateSignature = data.getBoolean(GENERATE_SIGNATURE);
boolean signOnly = data.getBoolean(SIGN_ONLY);
// InputStream
long inLength = -1;
FileInputStream inStream = null;
if (fileUri.getScheme().equals("file")) {
// get the rest after "file://"
String path = Uri.decode(fileUri.toString().substring(7));
if (path.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) {
if (!Environment.getExternalStorageState()
.equals(Environment.MEDIA_MOUNTED)) {
sendErrorToHandler(new GeneralException(
getString(R.string.error_externalStorageNotReady)));
return;
}
}
inStream = new FileInputStream(path);
File file = new File(path);
inLength = file.length();
}
InputData inputData = new InputData(inStream, inLength);
// OutputStream
if (outputFilename.startsWith(Environment.getExternalStorageDirectory()
.getAbsolutePath())) {
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
sendErrorToHandler(new GeneralException(
getString(R.string.error_externalStorageNotReady)));
return;
}
}
FileOutputStream outStream = new FileOutputStream(outputFilename);
// Operation
if (generateSignature) {
Apg.generateSignature(this, inputData, outStream, useAsciiArmour, true,
secretKeyId, Apg.getCachedPassPhrase(secretKeyId), Preferences
.getPreferences(this).getDefaultHashAlgorithm(), Preferences
.getPreferences(this).getForceV3Signatures(), this);
} else if (signOnly) {
Apg.signText(this, inputData, outStream, secretKeyId, Apg
.getCachedPassPhrase(secretKeyId), Preferences.getPreferences(this)
.getDefaultHashAlgorithm(), Preferences.getPreferences(this)
.getForceV3Signatures(), this);
} else {
Apg.encrypt(this, inputData, outStream, useAsciiArmour, encryptionKeyIds,
signatureKeyId, Apg.getCachedPassPhrase(signatureKeyId), this,
Preferences.getPreferences(this).getDefaultEncryptionAlgorithm(),
Preferences.getPreferences(this).getDefaultHashAlgorithm(),
compressionId, Preferences.getPreferences(this).getForceV3Signatures(),
passphrase);
}
outStream.close();
sendMessageToHandler(ApgHandler.MESSAGE_OKAY);
} catch (Exception e) {
sendErrorToHandler(e);
}
break;
case ACTION_ENCRYPT_SIGN_STREAM:
try {
// Input
long secretKeyId = data.getLong(SECRET_KEY_ID);
String passphrase = data.getString(PASSPHRASE);
Uri providerUri = Uri.parse(data.getString(PROVIDER_URI));
boolean useAsciiArmour = data.getBoolean(USE_ASCII_AMOR);
long encryptionKeyIds[] = data.getLongArray(ENCRYPTION_KEYS_IDS);
long signatureKeyId = data.getLong(SIGNATURE_KEY_ID);
int compressionId = data.getInt(COMPRESSION_ID);
boolean generateSignature = data.getBoolean(GENERATE_SIGNATURE);
boolean signOnly = data.getBoolean(SIGN_ONLY);
// InputStream
InputStream in = getContentResolver().openInputStream(providerUri);
long inLength = Apg.getLengthOfStream(in);
InputData inputData = new InputData(in, inLength);
// OutputStream
String streamFilename = null;
try {
while (true) {
streamFilename = Apg.generateRandomString(32);
if (streamFilename == null) {
throw new Apg.GeneralException("couldn't generate random file name");
}
openFileInput(streamFilename).close();
}
} catch (FileNotFoundException e) {
// found a name that isn't used yet
}
FileOutputStream outStream = openFileOutput(streamFilename, Context.MODE_PRIVATE);
// Operation
if (generateSignature) {
Apg.generateSignature(this, inputData, outStream, useAsciiArmour, true,
secretKeyId, Apg.getCachedPassPhrase(secretKeyId), Preferences
.getPreferences(this).getDefaultHashAlgorithm(), Preferences
.getPreferences(this).getForceV3Signatures(), this);
} else if (signOnly) {
Apg.signText(this, inputData, outStream, secretKeyId, Apg
.getCachedPassPhrase(secretKeyId), Preferences.getPreferences(this)
.getDefaultHashAlgorithm(), Preferences.getPreferences(this)
.getForceV3Signatures(), this);
} else {
Apg.encrypt(this, inputData, outStream, useAsciiArmour, encryptionKeyIds,
signatureKeyId, Apg.getCachedPassPhrase(signatureKeyId), this,
Preferences.getPreferences(this).getDefaultEncryptionAlgorithm(),
Preferences.getPreferences(this).getDefaultHashAlgorithm(),
compressionId, Preferences.getPreferences(this).getForceV3Signatures(),
passphrase);
}
outStream.close();
// Output
Bundle resultData = new Bundle();
// if (encryptionTarget != Id.target.file) {
// if (out instanceof ByteArrayOutputStream) {
// if (useAsciiArmour) {
// String output = new String(outStream.toByteArray());
// if (generateSignature) {
// resultData.putString(RESULT_SIGNATURE_TEXT, output);
// } else {
// resultData.putString(RESULT_ENCRYPTED_MESSAGE, output);
// }
// } else {
// byte output[] = outStream.toByteArray();
// if (generateSignature) {
// resultData.putByteArray(RESULT_SIGNATURE_DATA, output);
// } else {
// resultData.putByteArray(RESULT_ENCRYPTED_DATA, output);
// }
// }
// } else if (out instanceof FileOutputStream) {
// String fileName = dataDestination.getStreamFilename();
String uri = "content://" + DataProvider.AUTHORITY + "/data/" + streamFilename;
resultData.putString(RESULT_URI, uri);
// } else {
// sendErrorToHandler(new Apg.GeneralException("No output-data found."));
// }
// }
sendMessageToHandler(ApgHandler.MESSAGE_OKAY, resultData);
} catch (Exception e) {
sendErrorToHandler(e);
}
break;
@@ -223,6 +512,10 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
}
}
private void sendMessageToHandler(Integer arg1, Bundle data) {
sendMessageToHandler(arg1, null, data);
}
private void sendMessageToHandler(Integer arg1) {
sendMessageToHandler(arg1, null, null);
}

View File

@@ -34,6 +34,7 @@ import org.thialfihar.android.apg.R;
import org.thialfihar.android.apg.service.IApgService2.Stub;
import org.thialfihar.android.apg.Id.database;
import org.thialfihar.android.apg.R.string;
import org.thialfihar.android.apg.passphrase.PassphraseCacheService;
import org.thialfihar.android.apg.provider.KeyRings;
import org.thialfihar.android.apg.provider.Keys;
import org.thialfihar.android.apg.provider.UserIds;
@@ -50,9 +51,8 @@ import android.util.Log;
/**
* ATTENTION:
*
* This is the old ApgService used as remote service over aidl interface.
* It will be reworked!
*
* This is the old ApgService used as remote service over aidl interface. It will be reworked!
*
*/
public class ApgService2 extends PassphraseCacheService {
private final static String TAG = "ApgService";

View File

@@ -22,13 +22,13 @@ import java.io.IOException;
import org.thialfihar.android.apg.R;
import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.AskForSecretKeyPassPhrase;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.PausableThread;
import org.thialfihar.android.apg.Preferences;
import org.thialfihar.android.apg.ProgressDialogUpdater;
import org.thialfihar.android.apg.service.PassphraseCacheService;
import org.thialfihar.android.apg.passphrase.AskForPassphrase;
import org.thialfihar.android.apg.passphrase.PassphraseCacheService;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockActivity;
@@ -50,7 +50,7 @@ import android.support.v4.app.Fragment;
import android.widget.Toast;
public class BaseActivity extends SherlockFragmentActivity implements Runnable,
ProgressDialogUpdater, AskForSecretKeyPassPhrase.PassPhraseCallbackInterface {
ProgressDialogUpdater, AskForPassphrase.PassPhraseCallbackInterface {
private ProgressDialog mProgressDialog = null;
private PausableThread mRunningThread = null;
@@ -76,6 +76,7 @@ public class BaseActivity extends SherlockFragmentActivity implements Runnable,
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(true);
// not needed later:
mPreferences = Preferences.getPreferences(this);
Apg.initialize(this);
@@ -88,14 +89,14 @@ public class BaseActivity extends SherlockFragmentActivity implements Runnable,
}
}
startCacheService(this, mPreferences);
// startCacheService(this, mPreferences);
}
public static void startCacheService(Activity activity, Preferences preferences) {
Intent intent = new Intent(activity, PassphraseCacheService.class);
intent.putExtra(PassphraseCacheService.EXTRA_TTL, preferences.getPassPhraseCacheTtl());
activity.startService(intent);
}
// public static void startCacheService(Activity activity, Preferences preferences) {
// Intent intent = new Intent(activity, PassphraseCacheService.class);
// intent.putExtra(PassphraseCacheService.EXTRA_TTL, preferences.getPassPhraseCacheTtl());
// activity.startService(intent);
// }
@Override
public boolean onOptionsItemSelected(MenuItem item) {
@@ -177,7 +178,7 @@ public class BaseActivity extends SherlockFragmentActivity implements Runnable,
switch (id) {
case Id.dialog.pass_phrase: {
return AskForSecretKeyPassPhrase.createDialog(this, getSecretKeyId(), this);
return AskForPassphrase.createDialog(this, getSecretKeyId(), this);
}
case Id.dialog.pass_phrases_do_not_match: {
@@ -373,6 +374,7 @@ public class BaseActivity extends SherlockFragmentActivity implements Runnable,
}
public void passPhraseCallback(long keyId, String passPhrase) {
// TODO: Not needed anymore, now implemented in AskForSecretKeyPass
Apg.setCachedPassPhrase(keyId, passPhrase);
}

View File

@@ -207,10 +207,10 @@ public class EditKeyActivity extends SherlockFragmentActivity {
Bundle data = message.getData();
PGPSecretKeyRing masterKeyRing = Utils
.BytesToPGPSecretKeyRing(data
.getByteArray(ApgHandler.RESULT_NEW_KEY));
.getByteArray(ApgService.RESULT_NEW_KEY));
PGPSecretKeyRing subKeyRing = Utils
.BytesToPGPSecretKeyRing(data
.getByteArray(ApgHandler.RESULT_NEW_KEY2));
.getByteArray(ApgService.RESULT_NEW_KEY2));
// add master key
Iterator<PGPSecretKey> masterIt = masterKeyRing.getSecretKeys();
@@ -419,14 +419,10 @@ public class EditKeyActivity extends SherlockFragmentActivity {
Bundle data = new Bundle();
data.putString(ApgService.CURRENT_PASSPHRASE, mCurrentPassPhrase);
data.putString(ApgService.NEW_PASSPHRASE, mNewPassPhrase);
data.putSerializable(ApgService.USER_IDS, getUserIds(mUserIdsView));
Vector<PGPSecretKey> keys = getKeys(mKeysView);
data.putByteArray(ApgService.KEYS, Utils.PGPSecretKeyListToBytes(keys));
data.putSerializable(ApgService.KEYS_USAGES, getKeysUsages(mKeysView));
data.putLong(ApgService.MASTER_KEY_ID, getMasterKeyId());
intent.putExtra(ApgService.EXTRA_DATA, data);

View File

@@ -16,7 +16,6 @@
package org.thialfihar.android.apg.ui;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey;
@@ -27,22 +26,28 @@ import org.thialfihar.android.apg.DataDestination;
import org.thialfihar.android.apg.DataSource;
import org.thialfihar.android.apg.FileDialog;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.InputData;
import org.thialfihar.android.apg.provider.DataProvider;
import org.thialfihar.android.apg.Preferences;
import org.thialfihar.android.apg.passphrase.AskForPassphrase;
import org.thialfihar.android.apg.service.ApgHandler;
import org.thialfihar.android.apg.service.ApgService;
import org.thialfihar.android.apg.util.Choice;
import org.thialfihar.android.apg.util.Compatibility;
import org.thialfihar.android.apg.R;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.AnimationUtils;
@@ -57,17 +62,11 @@ import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewFlipper;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SignatureException;
import java.util.Vector;
public class EncryptActivity extends BaseActivity {
public class EncryptActivity extends SherlockFragmentActivity implements
AskForPassphrase.PassPhraseCallbackInterface {
private Intent mIntent = null;
private String mSubject = null;
private String mSendTo = null;
@@ -121,6 +120,10 @@ public class EncryptActivity extends BaseActivity {
private boolean mGenerateSignature = false;
private long mSecretKeyId = 0;
private ProgressDialogFragment mEncryptingDialog;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
@@ -266,7 +269,7 @@ public class EncryptActivity extends BaseActivity {
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mFileCompression.setAdapter(adapter);
int defaultFileCompression = mPreferences.getDefaultFileCompression();
int defaultFileCompression = Preferences.getPreferences(this).getDefaultFileCompression();
for (int i = 0; i < choices.length; ++i) {
if (choices[i].getId() == defaultFileCompression) {
mFileCompression.setSelection(i);
@@ -277,7 +280,7 @@ public class EncryptActivity extends BaseActivity {
mDeleteAfter = (CheckBox) findViewById(R.id.deleteAfterEncryption);
mAsciiArmour = (CheckBox) findViewById(R.id.asciiArmour);
mAsciiArmour.setChecked(mPreferences.getDefaultAsciiArmour());
mAsciiArmour.setChecked(Preferences.getPreferences(this).getDefaultAsciiArmour());
mAsciiArmour.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
guessOutputFilename();
@@ -657,7 +660,7 @@ public class EncryptActivity extends BaseActivity {
@Override
public void passPhraseCallback(long keyId, String passPhrase) {
super.passPhraseCallback(keyId, passPhrase);
// super.passPhraseCallback(keyId, passPhrase);
if (mEncryptTarget == Id.target.file) {
askForOutputFilename();
} else {
@@ -667,122 +670,151 @@ public class EncryptActivity extends BaseActivity {
private void encryptStart() {
showDialog(Id.dialog.encrypting);
startThread();
// startThread();
boolean useAsciiArmour = true;
long encryptionKeyIds[] = null;
long signatureKeyId = 0;
int compressionId = 0;
boolean signOnly = false;
String passPhrase = null;
if (mMode.getCurrentView().getId() == R.id.modeSymmetric) {
passPhrase = mPassPhrase.getText().toString();
if (passPhrase.length() == 0) {
passPhrase = null;
}
} else {
encryptionKeyIds = mEncryptionKeyIds;
signatureKeyId = getSecretKeyId();
signOnly = (mEncryptionKeyIds == null || mEncryptionKeyIds.length == 0);
}
fillDataSource(signOnly && !mReturnResult);
fillDataDestination();
// Send all information needed to service to edit key in other thread
Intent intent = new Intent(this, ApgService.class);
// fill values for this action
Bundle data = new Bundle();
// choose default settings, action and data bundle by target
if (mEncryptTarget == Id.target.file) {
useAsciiArmour = mAsciiArmour.isChecked();
compressionId = ((Choice) mFileCompression.getSelectedItem()).getId();
intent.putExtra(ApgService.EXTRA_ACTION, ApgService.ACTION_ENCRYPT_SIGN_FILE);
data.putString(ApgService.FILE_URI, mDataSource.getUri().toString());
} else {
useAsciiArmour = true;
compressionId = Preferences.getPreferences(this).getDefaultMessageCompression();
intent.putExtra(ApgService.EXTRA_ACTION, ApgService.ACTION_ENCRYPT_SIGN_BYTES);
data.putByteArray(ApgService.BYTES, mDataSource.getBytes());
}
if (mOverrideAsciiArmour) {
useAsciiArmour = mAsciiArmourDemand;
}
data.putLong(ApgService.SECRET_KEY_ID, getSecretKeyId());
data.putBoolean(ApgService.USE_ASCII_AMOR, useAsciiArmour);
data.putLongArray(ApgService.ENCRYPTION_KEYS_IDS, encryptionKeyIds);
data.putLong(ApgService.SIGNATURE_KEY_ID, signatureKeyId);
data.putInt(ApgService.COMPRESSION_ID, compressionId);
data.putBoolean(ApgService.GENERATE_SIGNATURE, mGenerateSignature);
data.putBoolean(ApgService.SIGN_ONLY, signOnly);
intent.putExtra(ApgService.EXTRA_DATA, data);
// show progress dialog
mEncryptingDialog = ProgressDialogFragment.newInstance(R.string.progress_encrypting,
ProgressDialog.STYLE_HORIZONTAL);
// Message is received after saving is done in ApgService
ApgHandler saveHandler = new ApgHandler(this, mEncryptingDialog) {
public void handleMessage(Message message) {
// handle messages by standard ApgHandler first
super.handleMessage(message);
if (message.arg1 == ApgHandler.MESSAGE_OKAY) {
// get returned data bundle
Bundle data = message.getData();
String output;
switch (mEncryptTarget) {
case Id.target.clipboard:
output = data.getString(ApgService.RESULT_ENCRYPTED_MESSAGE);
Log.d(Constants.TAG, "output: " + output);
Compatibility.copyToClipboard(EncryptActivity.this, output);
Toast.makeText(EncryptActivity.this,
R.string.encryptionToClipboardSuccessful, Toast.LENGTH_SHORT)
.show();
break;
case Id.target.email:
if (mReturnResult) {
Intent intent = new Intent();
intent.putExtras(data);
setResult(RESULT_OK, intent);
finish();
return;
}
output = data.getString(ApgService.RESULT_ENCRYPTED_MESSAGE);
Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.setType("text/plain; charset=utf-8");
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, message);
if (mSubject != null) {
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, mSubject);
}
if (mSendTo != null) {
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL,
new String[] { mSendTo });
}
EncryptActivity.this.startActivity(Intent.createChooser(emailIntent,
getString(R.string.title_sendEmail)));
break;
case Id.target.file:
Toast.makeText(EncryptActivity.this, R.string.encryptionSuccessful,
Toast.LENGTH_SHORT).show();
if (mDeleteAfter.isChecked()) {
// TODO: Reimplement that!
// setDeleteFile(mInputFilename);
// showDialog(Id.dialog.delete_file);
}
break;
default:
// shouldn't happen
break;
}
}
};
};
// Create a new Messenger for the communication back
Messenger messenger = new Messenger(saveHandler);
intent.putExtra(ApgService.EXTRA_MESSENGER, messenger);
mEncryptingDialog.show(getSupportFragmentManager(), "dialog");
// start service with intent
startService(intent);
}
@Override
public void run() {
String error = null;
Bundle data = new Bundle();
Message msg = new Message();
public void setSecretKeyId(long id) {
mSecretKeyId = id;
}
try {
InputData in;
OutputStream out;
boolean useAsciiArmour = true;
long encryptionKeyIds[] = null;
long signatureKeyId = 0;
int compressionId = 0;
boolean signOnly = false;
String passPhrase = null;
if (mMode.getCurrentView().getId() == R.id.modeSymmetric) {
passPhrase = mPassPhrase.getText().toString();
if (passPhrase.length() == 0) {
passPhrase = null;
}
} else {
encryptionKeyIds = mEncryptionKeyIds;
signatureKeyId = getSecretKeyId();
signOnly = (mEncryptionKeyIds == null || mEncryptionKeyIds.length == 0);
}
fillDataSource(signOnly && !mReturnResult);
fillDataDestination();
// streams
in = mDataSource.getInputData(this, true);
out = mDataDestination.getOutputStream(this);
if (mEncryptTarget == Id.target.file) {
useAsciiArmour = mAsciiArmour.isChecked();
compressionId = ((Choice) mFileCompression.getSelectedItem()).getId();
} else {
useAsciiArmour = true;
compressionId = mPreferences.getDefaultMessageCompression();
}
if (mOverrideAsciiArmour) {
useAsciiArmour = mAsciiArmourDemand;
}
if (mGenerateSignature) {
Apg.generateSignature(this, in, out, useAsciiArmour, mDataSource.isBinary(),
getSecretKeyId(), Apg.getCachedPassPhrase(getSecretKeyId()),
mPreferences.getDefaultHashAlgorithm(),
mPreferences.getForceV3Signatures(), this);
} else if (signOnly) {
Apg.signText(this, in, out, getSecretKeyId(),
Apg.getCachedPassPhrase(getSecretKeyId()),
mPreferences.getDefaultHashAlgorithm(),
mPreferences.getForceV3Signatures(), this);
} else {
Apg.encrypt(this, in, out, useAsciiArmour, encryptionKeyIds, signatureKeyId,
Apg.getCachedPassPhrase(signatureKeyId), this,
mPreferences.getDefaultEncryptionAlgorithm(),
mPreferences.getDefaultHashAlgorithm(), compressionId,
mPreferences.getForceV3Signatures(), passPhrase);
}
out.close();
if (mEncryptTarget != Id.target.file) {
if (out instanceof ByteArrayOutputStream) {
if (useAsciiArmour) {
String extraData = new String(((ByteArrayOutputStream) out).toByteArray());
if (mGenerateSignature) {
data.putString(Apg.EXTRA_SIGNATURE_TEXT, extraData);
} else {
data.putString(Apg.EXTRA_ENCRYPTED_MESSAGE, extraData);
}
} else {
byte extraData[] = ((ByteArrayOutputStream) out).toByteArray();
if (mGenerateSignature) {
data.putByteArray(Apg.EXTRA_SIGNATURE_DATA, extraData);
} else {
data.putByteArray(Apg.EXTRA_ENCRYPTED_DATA, extraData);
}
}
} else if (out instanceof FileOutputStream) {
String fileName = mDataDestination.getStreamFilename();
String uri = "content://" + DataProvider.AUTHORITY + "/data/" + fileName;
data.putString(Apg.EXTRA_RESULT_URI, uri);
} else {
throw new Apg.GeneralException("No output-data found.");
}
}
} catch (IOException e) {
error = "" + e;
} catch (PGPException e) {
error = "" + e;
} catch (NoSuchProviderException e) {
error = "" + e;
} catch (NoSuchAlgorithmException e) {
error = "" + e;
} catch (SignatureException e) {
error = "" + e;
} catch (Apg.GeneralException e) {
error = "" + e;
}
data.putInt(Constants.extras.STATUS, Id.message.done);
if (error != null) {
data.putString(Apg.EXTRA_ERROR, error);
}
msg.setData(data);
sendMessage(msg);
public long getSecretKeyId() {
return mSecretKeyId;
}
private void updateView() {
@@ -911,68 +943,6 @@ public class EncryptActivity extends BaseActivity {
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public void doneCallback(Message msg) {
super.doneCallback(msg);
removeDialog(Id.dialog.encrypting);
Bundle data = msg.getData();
String error = data.getString(Apg.EXTRA_ERROR);
if (error != null) {
Toast.makeText(this, getString(R.string.errorMessage, error), Toast.LENGTH_SHORT)
.show();
return;
}
switch (mEncryptTarget) {
case Id.target.clipboard: {
String message = data.getString(Apg.EXTRA_ENCRYPTED_MESSAGE);
Compatibility.copyToClipboard(this, message);
Toast.makeText(this, R.string.encryptionToClipboardSuccessful, Toast.LENGTH_SHORT)
.show();
break;
}
case Id.target.email: {
if (mReturnResult) {
Intent intent = new Intent();
intent.putExtras(data);
setResult(RESULT_OK, intent);
finish();
return;
}
String message = data.getString(Apg.EXTRA_ENCRYPTED_MESSAGE);
Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.setType("text/plain; charset=utf-8");
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, message);
if (mSubject != null) {
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, mSubject);
}
if (mSendTo != null) {
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[] { mSendTo });
}
EncryptActivity.this.startActivity(Intent.createChooser(emailIntent,
getString(R.string.title_sendEmail)));
break;
}
case Id.target.file: {
Toast.makeText(this, R.string.encryptionSuccessful, Toast.LENGTH_SHORT).show();
if (mDeleteAfter.isChecked()) {
setDeleteFile(mInputFilename);
showDialog(Id.dialog.delete_file);
}
break;
}
default: {
// shouldn't happen
break;
}
}
}
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {

View File

@@ -22,6 +22,7 @@ import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.Preferences;
import org.thialfihar.android.apg.passphrase.PassphraseCacheService;
import org.thialfihar.android.apg.ui.widget.IntegerListPreference;
import org.thialfihar.android.apg.R;
@@ -67,7 +68,9 @@ public class PreferencesActivity extends SherlockPreferenceActivity {
mPassPhraseCacheTtl.setValue(newValue.toString());
mPassPhraseCacheTtl.setSummary(mPassPhraseCacheTtl.getEntry());
mPreferences.setPassPhraseCacheTtl(Integer.parseInt(newValue.toString()));
BaseActivity.startCacheService(PreferencesActivity.this, mPreferences);
// restart cache service with new ttl
PassphraseCacheService.startCacheService(PreferencesActivity.this);
return false;
}
});

View File

@@ -18,9 +18,9 @@ package org.thialfihar.android.apg.ui;
import org.thialfihar.android.apg.R;
import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.AskForSecretKeyPassPhrase;
import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.passphrase.AskForPassphrase;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
@@ -135,7 +135,7 @@ public class SecretKeyListActivity extends KeyListActivity implements OnChildCli
case Id.dialog.pass_phrase: {
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter())
.getGroupId(mSelectedItem);
return AskForSecretKeyPassPhrase.createDialog(this, keyId, this);
return AskForPassphrase.createDialog(this, keyId, this);
}
default: {

View File

@@ -285,7 +285,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
// get new key from data bundle returned from service
Bundle data = message.getData();
PGPSecretKeyRing newKeyRing = Utils.BytesToPGPSecretKeyRing(data
.getByteArray(ApgHandler.RESULT_NEW_KEY));
.getByteArray(ApgService.RESULT_NEW_KEY));
boolean isMasterKey = (mEditors.getChildCount() == 0);