Merge branch 'development' into detached-sigs-api
Conflicts: OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
This commit is contained in:
@@ -34,7 +34,7 @@ public class CertifyActionsParcel implements Parcelable {
|
||||
final public long mMasterKeyId;
|
||||
public CertifyLevel mLevel;
|
||||
|
||||
public ArrayList<CertifyAction> mCertifyActions = new ArrayList<CertifyAction>();
|
||||
public ArrayList<CertifyAction> mCertifyActions = new ArrayList<>();
|
||||
|
||||
public CertifyActionsParcel(long masterKeyId) {
|
||||
mMasterKeyId = masterKeyId;
|
||||
|
||||
@@ -30,9 +30,11 @@ import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.operations.CertifyOperation;
|
||||
import org.sufficientlysecure.keychain.operations.DeleteOperation;
|
||||
import org.sufficientlysecure.keychain.operations.EditKeyOperation;
|
||||
import org.sufficientlysecure.keychain.operations.PromoteKeyOperation;
|
||||
import org.sufficientlysecure.keychain.operations.results.DeleteResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.ExportResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
|
||||
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||
@@ -90,6 +92,8 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
|
||||
public static final String ACTION_EDIT_KEYRING = Constants.INTENT_PREFIX + "EDIT_KEYRING";
|
||||
|
||||
public static final String ACTION_PROMOTE_KEYRING = Constants.INTENT_PREFIX + "PROMOTE_KEYRING";
|
||||
|
||||
public static final String ACTION_IMPORT_KEYRING = Constants.INTENT_PREFIX + "IMPORT_KEYRING";
|
||||
public static final String ACTION_EXPORT_KEYRING = Constants.INTENT_PREFIX + "EXPORT_KEYRING";
|
||||
|
||||
@@ -160,6 +164,10 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
// certify key
|
||||
public static final String CERTIFY_PARCEL = "certify_parcel";
|
||||
|
||||
// promote key
|
||||
public static final String PROMOTE_MASTER_KEY_ID = "promote_master_key_id";
|
||||
public static final String PROMOTE_TYPE = "promote_type";
|
||||
|
||||
// consolidate
|
||||
public static final String CONSOLIDATE_RECOVERY = "consolidate_recovery";
|
||||
|
||||
@@ -223,301 +231,326 @@ public class KeychainIntentService extends IntentService implements Progressable
|
||||
String action = intent.getAction();
|
||||
|
||||
// executeServiceMethod action from extra bundle
|
||||
if (ACTION_CERTIFY_KEYRING.equals(action)) {
|
||||
|
||||
// Input
|
||||
CertifyActionsParcel parcel = data.getParcelable(CERTIFY_PARCEL);
|
||||
String keyServerUri = data.getString(UPLOAD_KEY_SERVER);
|
||||
|
||||
// Operation
|
||||
CertifyOperation op = new CertifyOperation(this, providerHelper, this, mActionCanceled);
|
||||
CertifyResult result = op.certify(parcel, keyServerUri);
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
|
||||
} else if (ACTION_CONSOLIDATE.equals(action)) {
|
||||
|
||||
// Operation
|
||||
ConsolidateResult result;
|
||||
if (data.containsKey(CONSOLIDATE_RECOVERY) && data.getBoolean(CONSOLIDATE_RECOVERY)) {
|
||||
result = new ProviderHelper(this).consolidateDatabaseStep2(this);
|
||||
} else {
|
||||
result = new ProviderHelper(this).consolidateDatabaseStep1(this);
|
||||
}
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
|
||||
} else if (ACTION_DECRYPT_METADATA.equals(action)) {
|
||||
|
||||
try {
|
||||
/* Input */
|
||||
String passphrase = data.getString(DECRYPT_PASSPHRASE);
|
||||
byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY);
|
||||
|
||||
InputData inputData = createDecryptInputData(data);
|
||||
|
||||
/* Operation */
|
||||
|
||||
Bundle resultData = new Bundle();
|
||||
|
||||
// verifyText and decrypt returning additional resultData values for the
|
||||
// verification of signatures
|
||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
||||
this, new ProviderHelper(this), this, inputData, null
|
||||
);
|
||||
builder.setAllowSymmetricDecryption(true)
|
||||
.setPassphrase(passphrase)
|
||||
.setDecryptMetadataOnly(true)
|
||||
.setNfcState(nfcDecryptedSessionKey);
|
||||
|
||||
DecryptVerifyResult decryptVerifyResult = builder.build().execute();
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, decryptVerifyResult);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
|
||||
} else if (ACTION_DECRYPT_VERIFY.equals(action)) {
|
||||
|
||||
try {
|
||||
/* Input */
|
||||
String passphrase = data.getString(DECRYPT_PASSPHRASE);
|
||||
byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY);
|
||||
|
||||
InputData inputData = createDecryptInputData(data);
|
||||
OutputStream outStream = createCryptOutputStream(data);
|
||||
|
||||
/* Operation */
|
||||
|
||||
Bundle resultData = new Bundle();
|
||||
|
||||
// verifyText and decrypt returning additional resultData values for the
|
||||
// verification of signatures
|
||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
||||
this, new ProviderHelper(this), this,
|
||||
inputData, outStream
|
||||
);
|
||||
builder.setAllowSymmetricDecryption(true)
|
||||
.setPassphrase(passphrase)
|
||||
.setNfcState(nfcDecryptedSessionKey);
|
||||
|
||||
DecryptVerifyResult decryptVerifyResult = builder.build().execute();
|
||||
|
||||
outStream.close();
|
||||
|
||||
resultData.putParcelable(DecryptVerifyResult.EXTRA_RESULT, decryptVerifyResult);
|
||||
|
||||
/* Output */
|
||||
|
||||
finalizeDecryptOutputStream(data, resultData, outStream);
|
||||
|
||||
Log.logDebugBundle(resultData, "resultData");
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
|
||||
} else if (ACTION_DELETE.equals(action)) {
|
||||
|
||||
// Input
|
||||
long[] masterKeyIds = data.getLongArray(DELETE_KEY_LIST);
|
||||
boolean isSecret = data.getBoolean(DELETE_IS_SECRET);
|
||||
|
||||
// Operation
|
||||
DeleteOperation op = new DeleteOperation(this, new ProviderHelper(this), this);
|
||||
DeleteResult result = op.execute(masterKeyIds, isSecret);
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
|
||||
} else if (ACTION_EDIT_KEYRING.equals(action)) {
|
||||
|
||||
// Input
|
||||
SaveKeyringParcel saveParcel = data.getParcelable(EDIT_KEYRING_PARCEL);
|
||||
String passphrase = data.getString(EDIT_KEYRING_PASSPHRASE);
|
||||
|
||||
// Operation
|
||||
EditKeyOperation op = new EditKeyOperation(this, providerHelper, this, mActionCanceled);
|
||||
EditKeyResult result = op.execute(saveParcel, passphrase);
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
|
||||
} else if (ACTION_EXPORT_KEYRING.equals(action)) {
|
||||
|
||||
// Input
|
||||
boolean exportSecret = data.getBoolean(EXPORT_SECRET, false);
|
||||
String outputFile = data.getString(EXPORT_FILENAME);
|
||||
Uri outputUri = data.getParcelable(EXPORT_URI);
|
||||
|
||||
boolean exportAll = data.getBoolean(EXPORT_ALL);
|
||||
long[] masterKeyIds = exportAll ? null : data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID);
|
||||
|
||||
// Operation
|
||||
ImportExportOperation importExportOperation = new ImportExportOperation(this, new ProviderHelper(this), this);
|
||||
ExportResult result;
|
||||
if (outputFile != null) {
|
||||
result = importExportOperation.exportToFile(masterKeyIds, exportSecret, outputFile);
|
||||
} else {
|
||||
result = importExportOperation.exportToUri(masterKeyIds, exportSecret, outputUri);
|
||||
}
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
|
||||
} else if (ACTION_IMPORT_KEYRING.equals(action)) {
|
||||
|
||||
try {
|
||||
switch (action) {
|
||||
case ACTION_CERTIFY_KEYRING: {
|
||||
|
||||
// Input
|
||||
String keyServer = data.getString(IMPORT_KEY_SERVER);
|
||||
Iterator<ParcelableKeyRing> entries;
|
||||
int numEntries;
|
||||
if (data.containsKey(IMPORT_KEY_LIST)) {
|
||||
// get entries from intent
|
||||
ArrayList<ParcelableKeyRing> list = data.getParcelableArrayList(IMPORT_KEY_LIST);
|
||||
entries = list.iterator();
|
||||
numEntries = list.size();
|
||||
} else {
|
||||
// get entries from cached file
|
||||
ParcelableFileCache<ParcelableKeyRing> cache =
|
||||
new ParcelableFileCache<ParcelableKeyRing>(this, "key_import.pcl");
|
||||
IteratorWithSize<ParcelableKeyRing> it = cache.readCache();
|
||||
entries = it;
|
||||
numEntries = it.getSize();
|
||||
}
|
||||
CertifyActionsParcel parcel = data.getParcelable(CERTIFY_PARCEL);
|
||||
String keyServerUri = data.getString(UPLOAD_KEY_SERVER);
|
||||
|
||||
// Operation
|
||||
ImportExportOperation importExportOperation = new ImportExportOperation(
|
||||
this, providerHelper, this, mActionCanceled);
|
||||
ImportKeyResult result = importExportOperation.importKeyRings(entries, numEntries, keyServer);
|
||||
|
||||
// Special: consolidate on secret key import (cannot be cancelled!)
|
||||
if (result.mSecret > 0) {
|
||||
// TODO move this into the import operation
|
||||
providerHelper.consolidateDatabaseStep1(this);
|
||||
}
|
||||
|
||||
// Special: make sure new data is synced into contacts
|
||||
ContactSyncAdapterService.requestSync();
|
||||
CertifyOperation op = new CertifyOperation(this, providerHelper, this, mActionCanceled);
|
||||
CertifyResult result = op.certify(parcel, keyServerUri);
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
|
||||
break;
|
||||
}
|
||||
case ACTION_CONSOLIDATE: {
|
||||
|
||||
} else if (ACTION_SIGN_ENCRYPT.equals(action)) {
|
||||
// Operation
|
||||
ConsolidateResult result;
|
||||
if (data.containsKey(CONSOLIDATE_RECOVERY) && data.getBoolean(CONSOLIDATE_RECOVERY)) {
|
||||
result = new ProviderHelper(this).consolidateDatabaseStep2(this);
|
||||
} else {
|
||||
result = new ProviderHelper(this).consolidateDatabaseStep1(this);
|
||||
}
|
||||
|
||||
try {
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
|
||||
break;
|
||||
}
|
||||
case ACTION_DECRYPT_METADATA:
|
||||
|
||||
try {
|
||||
/* Input */
|
||||
int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET);
|
||||
Bundle resultData = new Bundle();
|
||||
String passphrase = data.getString(DECRYPT_PASSPHRASE);
|
||||
byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY);
|
||||
|
||||
long sigMasterKeyId = data.getLong(ENCRYPT_SIGNATURE_MASTER_ID);
|
||||
String sigKeyPassphrase = data.getString(ENCRYPT_SIGNATURE_KEY_PASSPHRASE);
|
||||
InputData inputData = createDecryptInputData(data);
|
||||
|
||||
byte[] nfcHash = data.getByteArray(ENCRYPT_SIGNATURE_NFC_HASH);
|
||||
Date nfcTimestamp = (Date) data.getSerializable(ENCRYPT_SIGNATURE_NFC_TIMESTAMP);
|
||||
/* Operation */
|
||||
|
||||
String symmetricPassphrase = data.getString(ENCRYPT_SYMMETRIC_PASSPHRASE);
|
||||
Bundle resultData = new Bundle();
|
||||
|
||||
boolean useAsciiArmor = data.getBoolean(ENCRYPT_USE_ASCII_ARMOR);
|
||||
long encryptionKeyIds[] = data.getLongArray(ENCRYPT_ENCRYPTION_KEYS_IDS);
|
||||
int compressionId = data.getInt(ENCRYPT_COMPRESSION_ID);
|
||||
int urisCount = data.containsKey(ENCRYPT_INPUT_URIS) ? data.getParcelableArrayList(ENCRYPT_INPUT_URIS).size() : 1;
|
||||
for (int i = 0; i < urisCount; i++) {
|
||||
data.putInt(SELECTED_URI, i);
|
||||
InputData inputData = createEncryptInputData(data);
|
||||
OutputStream outStream = createCryptOutputStream(data);
|
||||
String originalFilename = getOriginalFilename(data);
|
||||
|
||||
/* Operation */
|
||||
PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
|
||||
this, new ProviderHelper(this), this, inputData, outStream
|
||||
// verifyText and decrypt returning additional resultData values for the
|
||||
// verification of signatures
|
||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
||||
this, new ProviderHelper(this), this, inputData, null
|
||||
);
|
||||
builder.setEnableAsciiArmorOutput(useAsciiArmor)
|
||||
.setVersionHeader(PgpHelper.getVersionForHeader(this))
|
||||
.setCompressionId(compressionId)
|
||||
.setSymmetricEncryptionAlgorithm(
|
||||
Preferences.getPreferences(this).getDefaultEncryptionAlgorithm())
|
||||
.setEncryptionMasterKeyIds(encryptionKeyIds)
|
||||
.setSymmetricPassphrase(symmetricPassphrase)
|
||||
.setOriginalFilename(originalFilename);
|
||||
builder.setAllowSymmetricDecryption(true)
|
||||
.setPassphrase(passphrase)
|
||||
.setDecryptMetadataOnly(true)
|
||||
.setNfcState(nfcDecryptedSessionKey);
|
||||
|
||||
try {
|
||||
DecryptVerifyResult decryptVerifyResult = builder.build().execute();
|
||||
|
||||
// Find the appropriate subkey to sign with
|
||||
CachedPublicKeyRing signingRing =
|
||||
new ProviderHelper(this).getCachedPublicKeyRing(sigMasterKeyId);
|
||||
long sigSubKeyId = signingRing.getSecretSignId();
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, decryptVerifyResult);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
|
||||
// Set signature settings
|
||||
builder.setSignatureMasterKeyId(sigMasterKeyId)
|
||||
.setSignatureSubKeyId(sigSubKeyId)
|
||||
.setSignaturePassphrase(sigKeyPassphrase)
|
||||
.setSignatureHashAlgorithm(
|
||||
Preferences.getPreferences(this).getDefaultHashAlgorithm())
|
||||
.setAdditionalEncryptId(sigMasterKeyId);
|
||||
if (nfcHash != null && nfcTimestamp != null) {
|
||||
builder.setNfcState(nfcHash, nfcTimestamp);
|
||||
}
|
||||
break;
|
||||
case ACTION_DECRYPT_VERIFY:
|
||||
|
||||
} catch (PgpKeyNotFoundException e) {
|
||||
// encrypt-only
|
||||
// TODO Just silently drop the requested signature? Shouldn't we throw here?
|
||||
}
|
||||
try {
|
||||
/* Input */
|
||||
String passphrase = data.getString(DECRYPT_PASSPHRASE);
|
||||
byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY);
|
||||
|
||||
// this assumes that the bytes are cleartext (valid for current implementation!)
|
||||
if (source == IO_BYTES) {
|
||||
builder.setCleartextSignature(true);
|
||||
}
|
||||
InputData inputData = createDecryptInputData(data);
|
||||
OutputStream outStream = createCryptOutputStream(data);
|
||||
|
||||
SignEncryptResult result = builder.build().execute();
|
||||
resultData.putParcelable(SignEncryptResult.EXTRA_RESULT, result);
|
||||
/* Operation */
|
||||
|
||||
Bundle resultData = new Bundle();
|
||||
|
||||
// verifyText and decrypt returning additional resultData values for the
|
||||
// verification of signatures
|
||||
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(
|
||||
this, new ProviderHelper(this), this,
|
||||
inputData, outStream
|
||||
);
|
||||
builder.setAllowSymmetricDecryption(true)
|
||||
.setPassphrase(passphrase)
|
||||
.setNfcState(nfcDecryptedSessionKey);
|
||||
|
||||
DecryptVerifyResult decryptVerifyResult = builder.build().execute();
|
||||
|
||||
outStream.close();
|
||||
|
||||
/* Output */
|
||||
resultData.putParcelable(DecryptVerifyResult.EXTRA_RESULT, decryptVerifyResult);
|
||||
|
||||
finalizeEncryptOutputStream(data, resultData, outStream);
|
||||
/* Output */
|
||||
|
||||
finalizeDecryptOutputStream(data, resultData, outStream);
|
||||
|
||||
Log.logDebugBundle(resultData, "resultData");
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
|
||||
Log.logDebugBundle(resultData, "resultData");
|
||||
break;
|
||||
case ACTION_DELETE: {
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
// Input
|
||||
long[] masterKeyIds = data.getLongArray(DELETE_KEY_LIST);
|
||||
boolean isSecret = data.getBoolean(DELETE_IS_SECRET);
|
||||
|
||||
// Operation
|
||||
DeleteOperation op = new DeleteOperation(this, new ProviderHelper(this), this);
|
||||
DeleteResult result = op.execute(masterKeyIds, isSecret);
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
|
||||
break;
|
||||
}
|
||||
case ACTION_EDIT_KEYRING: {
|
||||
|
||||
} else if (ACTION_UPLOAD_KEYRING.equals(action)) {
|
||||
// Input
|
||||
SaveKeyringParcel saveParcel = data.getParcelable(EDIT_KEYRING_PARCEL);
|
||||
String passphrase = data.getString(EDIT_KEYRING_PASSPHRASE);
|
||||
|
||||
try {
|
||||
// Operation
|
||||
EditKeyOperation op = new EditKeyOperation(this, providerHelper, this, mActionCanceled);
|
||||
EditKeyResult result = op.execute(saveParcel, passphrase);
|
||||
|
||||
/* Input */
|
||||
String keyServer = data.getString(UPLOAD_KEY_SERVER);
|
||||
// and dataUri!
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
|
||||
/* Operation */
|
||||
HkpKeyserver server = new HkpKeyserver(keyServer);
|
||||
break;
|
||||
}
|
||||
case ACTION_PROMOTE_KEYRING: {
|
||||
|
||||
CanonicalizedPublicKeyRing keyring = providerHelper.getCanonicalizedPublicKeyRing(dataUri);
|
||||
// Input
|
||||
long keyRingId = data.getInt(EXPORT_KEY_RING_MASTER_KEY_ID);
|
||||
|
||||
// Operation
|
||||
PromoteKeyOperation op = new PromoteKeyOperation(this, providerHelper, this, mActionCanceled);
|
||||
PromoteKeyResult result = op.execute(keyRingId);
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
|
||||
break;
|
||||
}
|
||||
case ACTION_EXPORT_KEYRING: {
|
||||
|
||||
// Input
|
||||
boolean exportSecret = data.getBoolean(EXPORT_SECRET, false);
|
||||
String outputFile = data.getString(EXPORT_FILENAME);
|
||||
Uri outputUri = data.getParcelable(EXPORT_URI);
|
||||
|
||||
boolean exportAll = data.getBoolean(EXPORT_ALL);
|
||||
long[] masterKeyIds = exportAll ? null : data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID);
|
||||
|
||||
// Operation
|
||||
ImportExportOperation importExportOperation = new ImportExportOperation(this, new ProviderHelper(this), this);
|
||||
ExportResult result;
|
||||
if (outputFile != null) {
|
||||
result = importExportOperation.exportToFile(masterKeyIds, exportSecret, outputFile);
|
||||
} else {
|
||||
result = importExportOperation.exportToUri(masterKeyIds, exportSecret, outputUri);
|
||||
}
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
|
||||
break;
|
||||
}
|
||||
case ACTION_IMPORT_KEYRING:
|
||||
|
||||
try {
|
||||
importExportOperation.uploadKeyRingToServer(server, keyring);
|
||||
} catch (Keyserver.AddKeyException e) {
|
||||
throw new PgpGeneralException("Unable to export key to selected server");
|
||||
|
||||
// Input
|
||||
String keyServer = data.getString(IMPORT_KEY_SERVER);
|
||||
Iterator<ParcelableKeyRing> entries;
|
||||
int numEntries;
|
||||
if (data.containsKey(IMPORT_KEY_LIST)) {
|
||||
// get entries from intent
|
||||
ArrayList<ParcelableKeyRing> list = data.getParcelableArrayList(IMPORT_KEY_LIST);
|
||||
entries = list.iterator();
|
||||
numEntries = list.size();
|
||||
} else {
|
||||
// get entries from cached file
|
||||
ParcelableFileCache<ParcelableKeyRing> cache =
|
||||
new ParcelableFileCache<>(this, "key_import.pcl");
|
||||
IteratorWithSize<ParcelableKeyRing> it = cache.readCache();
|
||||
entries = it;
|
||||
numEntries = it.getSize();
|
||||
}
|
||||
|
||||
// Operation
|
||||
ImportExportOperation importExportOperation = new ImportExportOperation(
|
||||
this, providerHelper, this, mActionCanceled);
|
||||
ImportKeyResult result = importExportOperation.importKeyRings(entries, numEntries, keyServer);
|
||||
|
||||
// Special: consolidate on secret key import (cannot be cancelled!)
|
||||
if (result.mSecret > 0) {
|
||||
// TODO move this into the import operation
|
||||
providerHelper.consolidateDatabaseStep1(this);
|
||||
}
|
||||
|
||||
// Special: make sure new data is synced into contacts
|
||||
ContactSyncAdapterService.requestSync();
|
||||
|
||||
// Result
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
break;
|
||||
case ACTION_SIGN_ENCRYPT:
|
||||
|
||||
try {
|
||||
/* Input */
|
||||
int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET);
|
||||
Bundle resultData = new Bundle();
|
||||
|
||||
long sigMasterKeyId = data.getLong(ENCRYPT_SIGNATURE_MASTER_ID);
|
||||
String sigKeyPassphrase = data.getString(ENCRYPT_SIGNATURE_KEY_PASSPHRASE);
|
||||
|
||||
byte[] nfcHash = data.getByteArray(ENCRYPT_SIGNATURE_NFC_HASH);
|
||||
Date nfcTimestamp = (Date) data.getSerializable(ENCRYPT_SIGNATURE_NFC_TIMESTAMP);
|
||||
|
||||
String symmetricPassphrase = data.getString(ENCRYPT_SYMMETRIC_PASSPHRASE);
|
||||
|
||||
boolean useAsciiArmor = data.getBoolean(ENCRYPT_USE_ASCII_ARMOR);
|
||||
long encryptionKeyIds[] = data.getLongArray(ENCRYPT_ENCRYPTION_KEYS_IDS);
|
||||
int compressionId = data.getInt(ENCRYPT_COMPRESSION_ID);
|
||||
int urisCount = data.containsKey(ENCRYPT_INPUT_URIS) ? data.getParcelableArrayList(ENCRYPT_INPUT_URIS).size() : 1;
|
||||
for (int i = 0; i < urisCount; i++) {
|
||||
data.putInt(SELECTED_URI, i);
|
||||
InputData inputData = createEncryptInputData(data);
|
||||
OutputStream outStream = createCryptOutputStream(data);
|
||||
String originalFilename = getOriginalFilename(data);
|
||||
|
||||
/* Operation */
|
||||
PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
|
||||
this, new ProviderHelper(this), this, inputData, outStream
|
||||
);
|
||||
builder.setEnableAsciiArmorOutput(useAsciiArmor)
|
||||
.setVersionHeader(PgpHelper.getVersionForHeader(this))
|
||||
.setCompressionId(compressionId)
|
||||
.setSymmetricEncryptionAlgorithm(
|
||||
Preferences.getPreferences(this).getDefaultEncryptionAlgorithm())
|
||||
.setEncryptionMasterKeyIds(encryptionKeyIds)
|
||||
.setSymmetricPassphrase(symmetricPassphrase)
|
||||
.setOriginalFilename(originalFilename);
|
||||
|
||||
try {
|
||||
|
||||
// Find the appropriate subkey to sign with
|
||||
CachedPublicKeyRing signingRing =
|
||||
new ProviderHelper(this).getCachedPublicKeyRing(sigMasterKeyId);
|
||||
long sigSubKeyId = signingRing.getSecretSignId();
|
||||
|
||||
// Set signature settings
|
||||
builder.setSignatureMasterKeyId(sigMasterKeyId)
|
||||
.setSignatureSubKeyId(sigSubKeyId)
|
||||
.setSignaturePassphrase(sigKeyPassphrase)
|
||||
.setSignatureHashAlgorithm(
|
||||
Preferences.getPreferences(this).getDefaultHashAlgorithm())
|
||||
.setAdditionalEncryptId(sigMasterKeyId);
|
||||
if (nfcHash != null && nfcTimestamp != null) {
|
||||
builder.setNfcState(nfcHash, nfcTimestamp);
|
||||
}
|
||||
|
||||
} catch (PgpKeyNotFoundException e) {
|
||||
// encrypt-only
|
||||
// TODO Just silently drop the requested signature? Shouldn't we throw here?
|
||||
}
|
||||
|
||||
SignEncryptResult result = builder.build().execute();
|
||||
resultData.putParcelable(SignEncryptResult.EXTRA_RESULT, result);
|
||||
|
||||
outStream.close();
|
||||
|
||||
/* Output */
|
||||
|
||||
finalizeEncryptOutputStream(data, resultData, outStream);
|
||||
|
||||
}
|
||||
|
||||
Log.logDebugBundle(resultData, "resultData");
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
|
||||
break;
|
||||
case ACTION_UPLOAD_KEYRING:
|
||||
|
||||
try {
|
||||
|
||||
/* Input */
|
||||
String keyServer = data.getString(UPLOAD_KEY_SERVER);
|
||||
// and dataUri!
|
||||
|
||||
/* Operation */
|
||||
HkpKeyserver server = new HkpKeyserver(keyServer);
|
||||
|
||||
CanonicalizedPublicKeyRing keyring = providerHelper.getCanonicalizedPublicKeyRing(dataUri);
|
||||
ImportExportOperation importExportOperation = new ImportExportOperation(this, new ProviderHelper(this), this);
|
||||
|
||||
try {
|
||||
importExportOperation.uploadKeyRingToServer(server, keyring);
|
||||
} catch (Keyserver.AddKeyException e) {
|
||||
throw new PgpGeneralException("Unable to export key to selected server");
|
||||
}
|
||||
|
||||
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY);
|
||||
} catch (Exception e) {
|
||||
sendErrorToHandler(e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ import android.support.v4.util.LongSparseArray;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
|
||||
import org.sufficientlysecure.keychain.util.Preferences;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
|
||||
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
|
||||
@@ -103,7 +102,7 @@ public class PassphraseCacheService extends Service {
|
||||
|
||||
private BroadcastReceiver mIntentReceiver;
|
||||
|
||||
private LongSparseArray<CachedPassphrase> mPassphraseCache = new LongSparseArray<CachedPassphrase>();
|
||||
private LongSparseArray<CachedPassphrase> mPassphraseCache = new LongSparseArray<>();
|
||||
|
||||
Context mContext;
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.service;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -49,6 +50,7 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
public ChangeUnlockParcel mNewUnlock;
|
||||
|
||||
public ArrayList<String> mAddUserIds;
|
||||
public ArrayList<WrappedUserAttribute> mAddUserAttribute;
|
||||
public ArrayList<SubkeyAdd> mAddSubKeys;
|
||||
|
||||
public ArrayList<SubkeyChange> mChangeSubKeys;
|
||||
@@ -56,7 +58,6 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
|
||||
public ArrayList<String> mRevokeUserIds;
|
||||
public ArrayList<Long> mRevokeSubKeys;
|
||||
public ArrayList<Long> mStripSubKeys;
|
||||
|
||||
public SaveKeyringParcel() {
|
||||
reset();
|
||||
@@ -70,13 +71,30 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
|
||||
public void reset() {
|
||||
mNewUnlock = null;
|
||||
mAddUserIds = new ArrayList<String>();
|
||||
mAddSubKeys = new ArrayList<SubkeyAdd>();
|
||||
mAddUserIds = new ArrayList<>();
|
||||
mAddUserAttribute = new ArrayList<>();
|
||||
mAddSubKeys = new ArrayList<>();
|
||||
mChangePrimaryUserId = null;
|
||||
mChangeSubKeys = new ArrayList<SubkeyChange>();
|
||||
mRevokeUserIds = new ArrayList<String>();
|
||||
mRevokeSubKeys = new ArrayList<Long>();
|
||||
mStripSubKeys = new ArrayList<Long>();
|
||||
mChangeSubKeys = new ArrayList<>();
|
||||
mRevokeUserIds = new ArrayList<>();
|
||||
mRevokeSubKeys = new ArrayList<>();
|
||||
}
|
||||
|
||||
/** Returns true iff this parcel does not contain any operations which require a passphrase. */
|
||||
public boolean isRestrictedOnly() {
|
||||
if (mNewUnlock != null || !mAddUserIds.isEmpty() || !mAddUserAttribute.isEmpty()
|
||||
|| !mAddSubKeys.isEmpty() || mChangePrimaryUserId != null || !mRevokeSubKeys .isEmpty()
|
||||
|| !mRevokeSubKeys.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (SubkeyChange change : mChangeSubKeys) {
|
||||
if (change.mRecertify || change.mFlags != null || change.mExpiry != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// performance gain for using Parcelable here would probably be negligible,
|
||||
@@ -109,26 +127,53 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
}
|
||||
|
||||
public static class SubkeyChange implements Serializable {
|
||||
public long mKeyId;
|
||||
public final long mKeyId;
|
||||
public Integer mFlags;
|
||||
// this is a long unix timestamp, in seconds (NOT MILLISECONDS!)
|
||||
public Long mExpiry;
|
||||
// if this flag is true, the key will be recertified even if all above
|
||||
// values are no-ops
|
||||
public boolean mRecertify;
|
||||
// if this flag is true, the subkey should be changed to a stripped key
|
||||
public boolean mDummyStrip;
|
||||
// if this is non-null, the subkey will be changed to a divert-to-card
|
||||
// key for the given serial number
|
||||
public byte[] mDummyDivert;
|
||||
|
||||
public SubkeyChange(long keyId) {
|
||||
mKeyId = keyId;
|
||||
}
|
||||
|
||||
public SubkeyChange(long keyId, boolean recertify) {
|
||||
mKeyId = keyId;
|
||||
mRecertify = recertify;
|
||||
}
|
||||
|
||||
public SubkeyChange(long keyId, Integer flags, Long expiry) {
|
||||
mKeyId = keyId;
|
||||
mFlags = flags;
|
||||
mExpiry = expiry;
|
||||
}
|
||||
|
||||
public SubkeyChange(long keyId, boolean dummyStrip, byte[] dummyDivert) {
|
||||
this(keyId, null, null);
|
||||
|
||||
// these flags are mutually exclusive!
|
||||
if (dummyStrip && dummyDivert != null) {
|
||||
throw new AssertionError(
|
||||
"cannot set strip and divert flags at the same time - this is a bug!");
|
||||
}
|
||||
mDummyStrip = dummyStrip;
|
||||
mDummyDivert = dummyDivert;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String out = "mKeyId: " + mKeyId + ", ";
|
||||
out += "mFlags: " + mFlags + ", ";
|
||||
out += "mExpiry: " + mExpiry;
|
||||
out += "mExpiry: " + mExpiry + ", ";
|
||||
out += "mDummyStrip: " + mDummyStrip + ", ";
|
||||
out += "mDummyDivert: [" + (mDummyDivert == null ? 0 : mDummyDivert.length) + " bytes]";
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -162,6 +207,7 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
mNewUnlock = source.readParcelable(getClass().getClassLoader());
|
||||
|
||||
mAddUserIds = source.createStringArrayList();
|
||||
mAddUserAttribute = (ArrayList<WrappedUserAttribute>) source.readSerializable();
|
||||
mAddSubKeys = (ArrayList<SubkeyAdd>) source.readSerializable();
|
||||
|
||||
mChangeSubKeys = (ArrayList<SubkeyChange>) source.readSerializable();
|
||||
@@ -169,7 +215,6 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
|
||||
mRevokeUserIds = source.createStringArrayList();
|
||||
mRevokeSubKeys = (ArrayList<Long>) source.readSerializable();
|
||||
mStripSubKeys = (ArrayList<Long>) source.readSerializable();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -184,6 +229,7 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
destination.writeParcelable(mNewUnlock, 0);
|
||||
|
||||
destination.writeStringList(mAddUserIds);
|
||||
destination.writeSerializable(mAddUserAttribute);
|
||||
destination.writeSerializable(mAddSubKeys);
|
||||
|
||||
destination.writeSerializable(mChangeSubKeys);
|
||||
@@ -191,7 +237,6 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
|
||||
destination.writeStringList(mRevokeUserIds);
|
||||
destination.writeSerializable(mRevokeSubKeys);
|
||||
destination.writeSerializable(mStripSubKeys);
|
||||
}
|
||||
|
||||
public static final Creator<SaveKeyringParcel> CREATOR = new Creator<SaveKeyringParcel>() {
|
||||
@@ -214,12 +259,12 @@ public class SaveKeyringParcel implements Parcelable {
|
||||
String out = "mMasterKeyId: " + mMasterKeyId + "\n";
|
||||
out += "mNewUnlock: " + mNewUnlock + "\n";
|
||||
out += "mAddUserIds: " + mAddUserIds + "\n";
|
||||
out += "mAddUserAttribute: " + mAddUserAttribute + "\n";
|
||||
out += "mAddSubKeys: " + mAddSubKeys + "\n";
|
||||
out += "mChangeSubKeys: " + mChangeSubKeys + "\n";
|
||||
out += "mChangePrimaryUserId: " + mChangePrimaryUserId + "\n";
|
||||
out += "mRevokeUserIds: " + mRevokeUserIds + "\n";
|
||||
out += "mRevokeSubKeys: " + mRevokeSubKeys + "\n";
|
||||
out += "mStripSubKeys: " + mStripSubKeys;
|
||||
out += "mRevokeSubKeys: " + mRevokeSubKeys;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user