Merge branch 'master' into yubikey

Conflicts:
	OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
	OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
	OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
	OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java
This commit is contained in:
Dominik Schürmann
2014-08-14 13:31:01 +02:00
116 changed files with 2406 additions and 3259 deletions

View File

@@ -25,6 +25,7 @@ import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import org.openintents.openpgp.IOpenPgpService;
import org.openintents.openpgp.OpenPgpMetadata;
import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.openintents.openpgp.util.OpenPgpApi;
@@ -184,7 +185,13 @@ public class OpenPgpService extends RemoteService {
if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
} else {
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), accSettings.getKeyId());
try {
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), accSettings.getKeyId());
} catch (PassphraseCacheService.KeyNotFoundException e) {
// secret key that is set for this account is deleted?
// show account config again!
return getCreateAccountIntent(data, data.getStringExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME));
}
}
if (passphrase == null) {
// get PendingIntent for passphrase input, add it to given params and return to client
@@ -204,9 +211,9 @@ public class OpenPgpService extends RemoteService {
// sign-only
PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
new ProviderHelper(getContext()),
PgpHelper.getFullVersion(getContext()),
inputData, os);
builder.setEnableAsciiArmorOutput(asciiArmor)
.setVersionHeader(PgpHelper.getVersionForHeader(this))
.setSignatureHashAlgorithm(accSettings.getHashAlgorithm())
.setSignatureMasterKeyId(accSettings.getKeyId())
.setSignaturePassphrase(passphrase)
@@ -257,6 +264,10 @@ public class OpenPgpService extends RemoteService {
boolean sign) {
try {
boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
String originalFilename = data.getStringExtra(OpenPgpApi.EXTRA_ORIGINAL_FILENAME);
if (originalFilename == null) {
originalFilename = "";
}
long[] keyIds;
if (data.hasExtra(OpenPgpApi.EXTRA_KEY_IDS)) {
@@ -297,12 +308,13 @@ public class OpenPgpService extends RemoteService {
PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(
new ProviderHelper(getContext()),
PgpHelper.getFullVersion(getContext()),
inputData, os);
builder.setEnableAsciiArmorOutput(asciiArmor)
.setVersionHeader(PgpHelper.getVersionForHeader(this))
.setCompressionId(accSettings.getCompression())
.setSymmetricEncryptionAlgorithm(accSettings.getEncryptionAlgorithm())
.setEncryptionMasterKeyIds(keyIds);
.setEncryptionMasterKeyIds(keyIds)
.setOriginalFilename(originalFilename);
if (sign) {
String passphrase;
@@ -359,11 +371,18 @@ public class OpenPgpService extends RemoteService {
}
private Intent decryptAndVerifyImpl(Intent data, ParcelFileDescriptor input,
ParcelFileDescriptor output, Set<Long> allowedKeyIds) {
ParcelFileDescriptor output, Set<Long> allowedKeyIds,
boolean decryptMetadataOnly) {
try {
// Get Input- and OutputStream from ParcelFileDescriptor
InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
OutputStream os;
if (decryptMetadataOnly) {
os = null;
} else {
os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
}
Intent result = new Intent();
try {
@@ -376,17 +395,24 @@ public class OpenPgpService extends RemoteService {
new ProviderHelper(this),
new PgpDecryptVerify.PassphraseCache() {
@Override
public String getCachedPassphrase(long masterKeyId) {
return PassphraseCacheService.getCachedPassphrase(
OpenPgpService.this, masterKeyId);
public String getCachedPassphrase(long masterKeyId) throws PgpDecryptVerify.NoSecretKeyException {
try {
return PassphraseCacheService.getCachedPassphrase(
OpenPgpService.this, masterKeyId);
} catch (PassphraseCacheService.KeyNotFoundException e) {
throw new PgpDecryptVerify.NoSecretKeyException();
}
}
},
inputData, os
);
builder.setAllowSymmetricDecryption(false) // no support for symmetric encryption
.setAllowedKeyIds(allowedKeyIds) // allow only private keys associated with
// accounts of this app
.setPassphrase(passphrase);
// allow only private keys associated with accounts of this app
// no support for symmetric encryption
builder.setPassphrase(passphrase)
.setAllowSymmetricDecryption(false)
.setAllowedKeyIds(allowedKeyIds)
.setDecryptMetadataOnly(decryptMetadataOnly);
PgpDecryptVerifyResult decryptVerifyResult;
try {
@@ -409,8 +435,7 @@ public class OpenPgpService extends RemoteService {
if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
// get PendingIntent for passphrase input, add it to given params and return to client
return getPassphraseIntent(data, decryptVerifyResult.getKeyIdPassphraseNeeded());
} else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED ==
decryptVerifyResult.getStatus()) {
} else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) {
throw new PgpGeneralException("Decryption of symmetric content not supported by API!");
}
@@ -434,9 +459,18 @@ public class OpenPgpService extends RemoteService {
}
}
if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) >= 4) {
OpenPgpMetadata metadata = decryptVerifyResult.getDecryptMetadata();
if (metadata != null) {
result.putExtra(OpenPgpApi.RESULT_METADATA, metadata);
}
}
} finally {
is.close();
os.close();
if (os != null) {
os.close();
}
}
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
@@ -492,6 +526,7 @@ public class OpenPgpService extends RemoteService {
return result;
}
} catch (Exception e) {
Log.d(Constants.TAG, "getKeyImpl", e);
Intent result = new Intent();
result.putExtra(OpenPgpApi.RESULT_ERROR,
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
@@ -537,10 +572,15 @@ public class OpenPgpService extends RemoteService {
}
// version code is required and needs to correspond to version code of service!
if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != OpenPgpApi.API_VERSION) {
// History of versions in org.openintents.openpgp.util.OpenPgpApi
// we support 3 and 4
if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 3
&& data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 4) {
Intent result = new Intent();
OpenPgpError error = new OpenPgpError
(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!");
(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!\n"
+ "used API version: " + data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) + "\n"
+ "supported API versions: 3, 4");
result.putExtra(OpenPgpApi.RESULT_ERROR, error);
result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
return result;
@@ -588,7 +628,13 @@ public class OpenPgpService extends RemoteService {
Set<Long> allowedKeyIds =
mProviderHelper.getAllKeyIdsForApp(
ApiAccounts.buildBaseUri(currentPkg));
return decryptAndVerifyImpl(data, input, output, allowedKeyIds);
return decryptAndVerifyImpl(data, input, output, allowedKeyIds, false);
} else if (OpenPgpApi.ACTION_DECRYPT_METADATA.equals(action)) {
String currentPkg = getCurrentCallingPackage();
Set<Long> allowedKeyIds =
mProviderHelper.getAllKeyIdsForApp(
ApiAccounts.buildBaseUri(currentPkg));
return decryptAndVerifyImpl(data, input, output, allowedKeyIds, true);
} else if (OpenPgpApi.ACTION_GET_KEY.equals(action)) {
return getKeyImpl(data);
} else if (OpenPgpApi.ACTION_GET_KEY_IDS.equals(action)) {

View File

@@ -102,7 +102,7 @@ public class AccountSettingsActivity extends ActionBarActivity {
}
private void save() {
new ProviderHelper(this).updateApiAccount(mAccountSettingsFragment.getAccSettings(), mAccountUri);
new ProviderHelper(this).updateApiAccount(mAccountUri, mAccountSettingsFragment.getAccSettings());
finish();
}

View File

@@ -18,11 +18,13 @@
package org.sufficientlysecure.keychain.remote.ui;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.TextView;
import org.openintents.openpgp.util.OpenPgpApi;
import org.sufficientlysecure.htmltextview.HtmlTextView;
@@ -37,6 +39,7 @@ import org.sufficientlysecure.keychain.ui.SelectPublicKeyFragment;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
import java.security.Provider;
import java.util.ArrayList;
public class RemoteServiceActivity extends ActionBarActivity {
@@ -76,10 +79,17 @@ public class RemoteServiceActivity extends ActionBarActivity {
// select pub keys view
private SelectPublicKeyFragment mSelectFragment;
private ProviderHelper mProviderHelper;
// for ACTION_CREATE_ACCOUNT
boolean mUpdateExistingAccount;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mProviderHelper = new ProviderHelper(this);
handleActions(getIntent(), savedInstanceState);
}
@@ -94,6 +104,14 @@ public class RemoteServiceActivity extends ActionBarActivity {
final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE);
Log.d(Constants.TAG, "ACTION_REGISTER packageName: " + packageName);
setContentView(R.layout.api_remote_register_app);
mAppSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById(
R.id.api_app_settings_fragment);
AppSettings settings = new AppSettings(packageName, packageSignature);
mAppSettingsFragment.setAppSettings(settings);
// Inflate a "Done"/"Cancel" custom action bar view
ActionBarHelper.setTwoButtonView(getSupportActionBar(),
R.string.api_register_allow, R.drawable.ic_action_done,
@@ -102,8 +120,7 @@ public class RemoteServiceActivity extends ActionBarActivity {
public void onClick(View v) {
// Allow
new ProviderHelper(RemoteServiceActivity.this).insertApiApp(
mAppSettingsFragment.getAppSettings());
mProviderHelper.insertApiApp(mAppSettingsFragment.getAppSettings());
// give data through for new service call
Intent resultData = extras.getParcelable(EXTRA_DATA);
@@ -120,18 +137,34 @@ public class RemoteServiceActivity extends ActionBarActivity {
}
}
);
setContentView(R.layout.api_remote_register_app);
mAppSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById(
R.id.api_app_settings_fragment);
AppSettings settings = new AppSettings(packageName, packageSignature);
mAppSettingsFragment.setAppSettings(settings);
} else if (ACTION_CREATE_ACCOUNT.equals(action)) {
final String packageName = extras.getString(EXTRA_PACKAGE_NAME);
final String accName = extras.getString(EXTRA_ACC_NAME);
setContentView(R.layout.api_remote_create_account);
mAccSettingsFragment = (AccountSettingsFragment) getSupportFragmentManager().findFragmentById(
R.id.api_account_settings_fragment);
TextView text = (TextView) findViewById(R.id.api_remote_create_account_text);
// update existing?
Uri uri = KeychainContract.ApiAccounts.buildByPackageAndAccountUri(packageName, accName);
AccountSettings settings = mProviderHelper.getApiAccountSettings(uri);
if (settings == null) {
// create new account
settings = new AccountSettings(accName);
mUpdateExistingAccount = false;
text.setText(R.string.api_create_account_text);
} else {
// update existing account
mUpdateExistingAccount = true;
text.setText(R.string.api_update_account_text);
}
mAccSettingsFragment.setAccSettings(settings);
// Inflate a "Done"/"Cancel" custom action bar view
ActionBarHelper.setTwoButtonView(getSupportActionBar(),
R.string.api_settings_save, R.drawable.ic_action_done,
@@ -145,9 +178,17 @@ public class RemoteServiceActivity extends ActionBarActivity {
mAccSettingsFragment.setErrorOnSelectKeyFragment(
getString(R.string.api_register_error_select_key));
} else {
new ProviderHelper(RemoteServiceActivity.this).insertApiAccount(
KeychainContract.ApiAccounts.buildBaseUri(packageName),
mAccSettingsFragment.getAccSettings());
if (mUpdateExistingAccount) {
Uri baseUri = KeychainContract.ApiAccounts.buildBaseUri(packageName);
Uri accountUri = baseUri.buildUpon().appendEncodedPath(accName).build();
mProviderHelper.updateApiAccount(
accountUri,
mAccSettingsFragment.getAccSettings());
} else {
mProviderHelper.insertApiAccount(
KeychainContract.ApiAccounts.buildBaseUri(packageName),
mAccSettingsFragment.getAccSettings());
}
// give data through for new service call
Intent resultData = extras.getParcelable(EXTRA_DATA);
@@ -166,13 +207,6 @@ public class RemoteServiceActivity extends ActionBarActivity {
}
);
setContentView(R.layout.api_remote_create_account);
mAccSettingsFragment = (AccountSettingsFragment) getSupportFragmentManager().findFragmentById(
R.id.api_account_settings_fragment);
AccountSettings settings = new AccountSettings(accName);
mAccSettingsFragment.setAccSettings(settings);
} else if (ACTION_CACHE_PASSPHRASE.equals(action)) {
long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID);
final Intent resultData = extras.getParcelable(EXTRA_DATA);
@@ -190,7 +224,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
RemoteServiceActivity.this.finish();
}
});
}
);
} else if (ACTION_SELECT_PUB_KEYS.equals(action)) {
long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS);
@@ -286,7 +321,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
RemoteServiceActivity.this.setResult(RESULT_CANCELED);
RemoteServiceActivity.this.finish();
}
});
}
);
setContentView(R.layout.api_remote_error_message);