This commit is contained in:
Daniel Hammann 2014-03-05 17:05:01 +01:00
commit bc5f2a9305
109 changed files with 1849 additions and 2495 deletions

16
.travis.yml Normal file
View File

@ -0,0 +1,16 @@
language: java
jdk: oraclejdk7
before_install:
# Install base Android SDK
- sudo apt-get update -qq
- if [ `uname -m` = x86_64 ]; then sudo apt-get install -qq --force-yes libgd2-xpm ia32-libs; fi
- wget http://dl.google.com/android/android-sdk_r22.3-linux.tgz
- tar xzf android-sdk_r22.3-linux.tgz
- export ANDROID_HOME=$PWD/android-sdk-linux
- export PATH=${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools
# Install required Android components.
- echo "y" | android update sdk -a --filter build-tools-19.0.1,android-19,platform-tools,extra-android-support,extra-android-m2repository,android-17 --no-ui --force
install: echo "Installation done"
script: gradle assemble -S -q

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.sufficientlysecure.keychain.demo" package="org.sufficientlysecure.keychain.demo"
android:versionCode="2" android:versionCode="3"
android:versionName="1.1"> android:versionName="2">
<uses-sdk <uses-sdk
android:minSdkVersion="9" android:minSdkVersion="9"

View File

@ -112,11 +112,11 @@ public class IntentActivity extends PreferenceActivity {
byte[] pubkey = null; byte[] pubkey = null;
try { try {
pubkey = TEST_PUBKEY.getBytes("UTF-8"); pubkey = TEST_PUBKEY.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
intent.putExtra(OpenKeychainIntents.IMPORT_KEY_EXTRA_KEY_BYTES, pubkey); intent.putExtra(OpenKeychainIntents.IMPORT_KEY_EXTRA_KEY_BYTES, pubkey);
startActivity(intent); startActivity(intent);
} catch (UnsupportedEncodingException e) {
Log.e(Constants.TAG, "UnsupportedEncodingException", e);
}
} catch (ActivityNotFoundException e) { } catch (ActivityNotFoundException e) {
Toast.makeText(IntentActivity.this, "Activity not found!", Toast.LENGTH_LONG).show(); Toast.makeText(IntentActivity.this, "Activity not found!", Toast.LENGTH_LONG).show();
} }

View File

@ -33,7 +33,6 @@ import android.widget.Toast;
import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.OpenPgpSignatureResult;
import org.openintents.openpgp.util.OpenPgpApi; import org.openintents.openpgp.util.OpenPgpApi;
import org.openintents.openpgp.util.OpenPgpConstants;
import org.openintents.openpgp.util.OpenPgpServiceConnection; import org.openintents.openpgp.util.OpenPgpServiceConnection;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -73,25 +72,25 @@ public class OpenPgpProviderActivity extends Activity {
mSign.setOnClickListener(new View.OnClickListener() { mSign.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
sign(new Bundle()); sign(new Intent());
} }
}); });
mEncrypt.setOnClickListener(new View.OnClickListener() { mEncrypt.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
encrypt(new Bundle()); encrypt(new Intent());
} }
}); });
mSignAndEncrypt.setOnClickListener(new View.OnClickListener() { mSignAndEncrypt.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
signAndEncrypt(new Bundle()); signAndEncrypt(new Intent());
} }
}); });
mDecryptAndVerify.setOnClickListener(new View.OnClickListener() { mDecryptAndVerify.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
decryptAndVerify(new Bundle()); decryptAndVerify(new Intent());
} }
}); });
@ -169,11 +168,11 @@ public class OpenPgpProviderActivity extends Activity {
} }
@Override @Override
public void onReturn(Bundle result) { public void onReturn(Intent result) {
switch (result.getInt(OpenPgpConstants.RESULT_CODE)) { switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) {
case OpenPgpConstants.RESULT_CODE_SUCCESS: { case OpenPgpApi.RESULT_CODE_SUCCESS: {
try { try {
Log.d(OpenPgpConstants.TAG, "result: " + os.toByteArray().length Log.d(OpenPgpApi.TAG, "result: " + os.toByteArray().length
+ " str=" + os.toString("UTF-8")); + " str=" + os.toString("UTF-8"));
if (returnToCiphertextField) { if (returnToCiphertextField) {
@ -185,15 +184,15 @@ public class OpenPgpProviderActivity extends Activity {
Log.e(Constants.TAG, "UnsupportedEncodingException", e); Log.e(Constants.TAG, "UnsupportedEncodingException", e);
} }
if (result.containsKey(OpenPgpConstants.RESULT_SIGNATURE)) { if (result.hasExtra(OpenPgpApi.RESULT_SIGNATURE)) {
OpenPgpSignatureResult sigResult OpenPgpSignatureResult sigResult
= result.getParcelable(OpenPgpConstants.RESULT_SIGNATURE); = result.getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE);
handleSignature(sigResult); handleSignature(sigResult);
} }
break; break;
} }
case OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED: { case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: {
PendingIntent pi = result.getParcelable(OpenPgpConstants.RESULT_INTENT); PendingIntent pi = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
try { try {
OpenPgpProviderActivity.this.startIntentSenderForResult(pi.getIntentSender(), OpenPgpProviderActivity.this.startIntentSenderForResult(pi.getIntentSender(),
requestCode, null, 0, 0, 0); requestCode, null, 0, 0, 0);
@ -202,8 +201,8 @@ public class OpenPgpProviderActivity extends Activity {
} }
break; break;
} }
case OpenPgpConstants.RESULT_CODE_ERROR: { case OpenPgpApi.RESULT_CODE_ERROR: {
OpenPgpError error = result.getParcelable(OpenPgpConstants.RESULT_ERRORS); OpenPgpError error = result.getParcelableExtra(OpenPgpApi.RESULT_ERRORS);
handleError(error); handleError(error);
break; break;
} }
@ -211,46 +210,50 @@ public class OpenPgpProviderActivity extends Activity {
} }
} }
public void sign(Bundle params) { public void sign(Intent data) {
params.putBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true); data.setAction(OpenPgpApi.ACTION_SIGN);
data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
InputStream is = getInputstream(false); InputStream is = getInputstream(false);
final ByteArrayOutputStream os = new ByteArrayOutputStream(); final ByteArrayOutputStream os = new ByteArrayOutputStream();
OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService()); OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService());
api.sign(params, is, os, new MyCallback(true, os, REQUEST_CODE_SIGN)); api.executeApiAsync(data, is, os, new MyCallback(true, os, REQUEST_CODE_SIGN));
} }
public void encrypt(Bundle params) { public void encrypt(Intent data) {
params.putStringArray(OpenPgpConstants.PARAMS_USER_IDS, mEncryptUserIds.getText().toString().split(",")); data.setAction(OpenPgpApi.ACTION_ENCRYPT);
params.putBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true); data.putExtra(OpenPgpApi.EXTRA_USER_IDS, mEncryptUserIds.getText().toString().split(","));
data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
InputStream is = getInputstream(false); InputStream is = getInputstream(false);
final ByteArrayOutputStream os = new ByteArrayOutputStream(); final ByteArrayOutputStream os = new ByteArrayOutputStream();
OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService()); OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService());
api.encrypt(params, is, os, new MyCallback(true, os, REQUEST_CODE_ENCRYPT)); api.executeApiAsync(data, is, os, new MyCallback(true, os, REQUEST_CODE_ENCRYPT));
} }
public void signAndEncrypt(Bundle params) { public void signAndEncrypt(Intent data) {
params.putStringArray(OpenPgpConstants.PARAMS_USER_IDS, mEncryptUserIds.getText().toString().split(",")); data.setAction(OpenPgpApi.ACTION_SIGN_AND_ENCTYPT);
params.putBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true); data.putExtra(OpenPgpApi.EXTRA_USER_IDS, mEncryptUserIds.getText().toString().split(","));
data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
InputStream is = getInputstream(false); InputStream is = getInputstream(false);
final ByteArrayOutputStream os = new ByteArrayOutputStream(); final ByteArrayOutputStream os = new ByteArrayOutputStream();
OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService()); OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService());
api.signAndEncrypt(params, is, os, new MyCallback(true, os, REQUEST_CODE_SIGN_AND_ENCRYPT)); api.executeApiAsync(data, is, os, new MyCallback(true, os, REQUEST_CODE_SIGN_AND_ENCRYPT));
} }
public void decryptAndVerify(Bundle params) { public void decryptAndVerify(Intent data) {
params.putBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true); data.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
InputStream is = getInputstream(true); InputStream is = getInputstream(true);
final ByteArrayOutputStream os = new ByteArrayOutputStream(); final ByteArrayOutputStream os = new ByteArrayOutputStream();
OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService()); OpenPgpApi api = new OpenPgpApi(this, mServiceConnection.getService());
api.decryptAndVerify(params, is, os, new MyCallback(false, os, REQUEST_CODE_DECRYPT_AND_VERIFY)); api.executeApiAsync(data, is, os, new MyCallback(false, os, REQUEST_CODE_DECRYPT_AND_VERIFY));
} }
@Override @Override
@ -261,29 +264,28 @@ public class OpenPgpProviderActivity extends Activity {
// try again after user interaction // try again after user interaction
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
/* /*
* The params originally given to the pgp method are are again * The data originally given to the pgp method are are again
* returned here to be used when calling again after user interaction. * returned here to be used when calling again after user interaction.
* *
* They also contain results from the user interaction which happened, * They also contain results from the user interaction which happened,
* for example selected key ids. * for example selected key ids.
*/ */
Bundle params = data.getBundleExtra(OpenPgpConstants.PI_RESULT_PARAMS);
switch (requestCode) { switch (requestCode) {
case REQUEST_CODE_SIGN: { case REQUEST_CODE_SIGN: {
sign(params); sign(data);
break; break;
} }
case REQUEST_CODE_ENCRYPT: { case REQUEST_CODE_ENCRYPT: {
encrypt(params); encrypt(data);
break; break;
} }
case REQUEST_CODE_SIGN_AND_ENCRYPT: { case REQUEST_CODE_SIGN_AND_ENCRYPT: {
signAndEncrypt(params); signAndEncrypt(data);
break; break;
} }
case REQUEST_CODE_DECRYPT_AND_VERIFY: { case REQUEST_CODE_DECRYPT_AND_VERIFY: {
decryptAndVerify(params); decryptAndVerify(data);
break; break;
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -2,5 +2,6 @@
<resources> <resources>
<string name="openpgp_list_preference_none">None</string> <string name="openpgp_list_preference_none">None</string>
<string name="openpgp_install_openkeychain_via">Install OpenKeychain via %s</string>
</resources> </resources>

View File

@ -18,68 +18,7 @@ package org.openintents.openpgp;
interface IOpenPgpService { interface IOpenPgpService {
/** // see OpenPgpApi for documentation
* General extras Intent execute(in Intent data, in ParcelFileDescriptor input, in ParcelFileDescriptor output);
* --------------
*
* Bundle params:
* int api_version (required)
* boolean ascii_armor (request ascii armor for ouput)
*
* returned Bundle:
* int result_code (0, 1, or 2 (see OpenPgpConstants))
* OpenPgpError error (if result_code == 0)
* Intent intent (if result_code == 2)
*
*/
/**
* Sign only
*
* optional params:
* String passphrase (for key passphrase)
*/
Bundle sign(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output);
/**
* Encrypt
*
* Bundle params:
* long[] key_ids
* or
* String[] user_ids (= emails of recipients) (if more than one key has this user_id, a PendingIntent is returned)
*
* optional params:
* String passphrase (for key passphrase)
*/
Bundle encrypt(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output);
/**
* Sign and encrypt
*
* Bundle params:
* same as in encrypt()
*/
Bundle signAndEncrypt(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output);
/**
* Decrypts and verifies given input bytes. This methods handles encrypted-only, signed-and-encrypted,
* and also signed-only input.
*
* returned Bundle:
* OpenPgpSignatureResult signature_result
*/
Bundle decryptAndVerify(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output);
/**
* Retrieves key ids based on given user ids (=emails)
*
* Bundle params:
* String[] user_ids
*
* returned Bundle:
* long[] key_ids
*/
Bundle getKeyIds(in Bundle params);
} }

View File

@ -25,10 +25,8 @@ public class OpenPgpSignatureResult implements Parcelable {
// successfully verified signature, with certified public key // successfully verified signature, with certified public key
public static final int SIGNATURE_SUCCESS_CERTIFIED = 1; public static final int SIGNATURE_SUCCESS_CERTIFIED = 1;
// no public key was found for this signature verification // no public key was found for this signature verification
// you can retrieve the key with
// getKeys(new String[] {String.valueOf(signatureResult.getKeyId)}, true, callback)
public static final int SIGNATURE_UNKNOWN_PUB_KEY = 2; public static final int SIGNATURE_UNKNOWN_PUB_KEY = 2;
// successfully verified signature, but with certified public key // successfully verified signature, but with uncertified public key
public static final int SIGNATURE_SUCCESS_UNCERTIFIED = 3; public static final int SIGNATURE_SUCCESS_UNCERTIFIED = 3;
int status; int status;
@ -40,18 +38,34 @@ public class OpenPgpSignatureResult implements Parcelable {
return status; return status;
} }
public void setStatus(int status) {
this.status = status;
}
public boolean isSignatureOnly() { public boolean isSignatureOnly() {
return signatureOnly; return signatureOnly;
} }
public void setSignatureOnly(boolean signatureOnly) {
this.signatureOnly = signatureOnly;
}
public String getUserId() { public String getUserId() {
return userId; return userId;
} }
public void setUserId(String userId) {
this.userId = userId;
}
public long getKeyId() { public long getKeyId() {
return keyId; return keyId;
} }
public void setKeyId(long keyId) {
this.keyId = keyId;
}
public OpenPgpSignatureResult() { public OpenPgpSignatureResult() {
} }

View File

@ -17,9 +17,9 @@
package org.openintents.openpgp.util; package org.openintents.openpgp.util;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Bundle;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.util.Log; import android.util.Log;
@ -31,104 +31,143 @@ import java.io.OutputStream;
public class OpenPgpApi { public class OpenPgpApi {
//TODO: fix this documentation
/**
* General extras
* --------------
*
* Intent extras:
* int api_version (required)
* boolean ascii_armor (request ascii armor for ouput)
*
* returned Bundle:
* int result_code (0, 1, or 2 (see OpenPgpApi))
* OpenPgpError error (if result_code == 0)
* Intent intent (if result_code == 2)
*/
/**
* Sign only
*
* optional params:
* String passphrase (for key passphrase)
*/
/**
* Encrypt
*
* Intent extras:
* long[] key_ids
* or
* String[] user_ids (= emails of recipients) (if more than one key has this user_id, a PendingIntent is returned)
*
* optional extras:
* String passphrase (for key passphrase)
*/
/**
* Sign and encrypt
*
* Intent extras:
* same as in encrypt()
*/
/**
* Decrypts and verifies given input bytes. This methods handles encrypted-only, signed-and-encrypted,
* and also signed-only input.
*
* returned Bundle:
* OpenPgpSignatureResult signature_result
*/
/**
* Retrieves key ids based on given user ids (=emails)
*
* Intent extras:
* String[] user_ids
*
* returned Bundle:
* long[] key_ids
*/
public static final String TAG = "OpenPgp API";
public static final int API_VERSION = 2;
public static final String SERVICE_INTENT = "org.openintents.openpgp.IOpenPgpService";
public static final String ACTION_SIGN = "org.openintents.openpgp.action.SIGN";
public static final String ACTION_ENCRYPT = "org.openintents.openpgp.action.ENCRYPT";
public static final String ACTION_SIGN_AND_ENCTYPT = "org.openintents.openpgp.action.SIGN_AND_ENCRYPT";
public static final String ACTION_DECRYPT_VERIFY = "org.openintents.openpgp.action.DECRYPT_VERIFY";
public static final String ACTION_DOWNLOAD_KEYS = "org.openintents.openpgp.action.DOWNLOAD_KEYS";
public static final String ACTION_GET_KEY_IDS = "org.openintents.openpgp.action.GET_KEY_IDS";
/* Bundle params */
public static final String EXTRA_API_VERSION = "api_version";
// SIGN, ENCRYPT, SIGN_ENCRYPT, DECRYPT_VERIFY
// request ASCII Armor for output
// OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53)
public static final String EXTRA_REQUEST_ASCII_ARMOR = "ascii_armor";
// ENCRYPT, SIGN_ENCRYPT
public static final String EXTRA_USER_IDS = "user_ids";
public static final String EXTRA_KEY_IDS = "key_ids";
// optional parameter:
public static final String EXTRA_PASSPHRASE = "passphrase";
/* Service Bundle returns */
public static final String RESULT_CODE = "result_code";
public static final String RESULT_SIGNATURE = "signature";
public static final String RESULT_ERRORS = "error";
public static final String RESULT_INTENT = "intent";
// get actual error object from RESULT_ERRORS
public static final int RESULT_CODE_ERROR = 0;
// success!
public static final int RESULT_CODE_SUCCESS = 1;
// executeServiceMethod intent and do it again with intent
public static final int RESULT_CODE_USER_INTERACTION_REQUIRED = 2;
IOpenPgpService mService; IOpenPgpService mService;
Context mContext; Context mContext;
private static final int OPERATION_SIGN = 0;
private static final int OPERATION_ENCRYPT = 1;
private static final int OPERATION_SIGN_ENCRYPT = 2;
private static final int OPERATION_DECRYPT_VERIFY = 3;
private static final int OPERATION_GET_KEY_IDS = 4;
public OpenPgpApi(Context context, IOpenPgpService service) { public OpenPgpApi(Context context, IOpenPgpService service) {
this.mContext = context; this.mContext = context;
this.mService = service; this.mService = service;
} }
public Bundle sign(InputStream is, final OutputStream os) {
return executeApi(OPERATION_SIGN, new Bundle(), is, os);
}
public Bundle sign(Bundle params, InputStream is, final OutputStream os) {
return executeApi(OPERATION_SIGN, params, is, os);
}
public void sign(Bundle params, InputStream is, final OutputStream os, IOpenPgpCallback callback) {
executeApiAsync(OPERATION_SIGN, params, is, os, callback);
}
public Bundle encrypt(InputStream is, final OutputStream os) {
return executeApi(OPERATION_ENCRYPT, new Bundle(), is, os);
}
public Bundle encrypt(Bundle params, InputStream is, final OutputStream os) {
return executeApi(OPERATION_ENCRYPT, params, is, os);
}
public void encrypt(Bundle params, InputStream is, final OutputStream os, IOpenPgpCallback callback) {
executeApiAsync(OPERATION_ENCRYPT, params, is, os, callback);
}
public Bundle signAndEncrypt(InputStream is, final OutputStream os) {
return executeApi(OPERATION_SIGN_ENCRYPT, new Bundle(), is, os);
}
public Bundle signAndEncrypt(Bundle params, InputStream is, final OutputStream os) {
return executeApi(OPERATION_SIGN_ENCRYPT, params, is, os);
}
public void signAndEncrypt(Bundle params, InputStream is, final OutputStream os, IOpenPgpCallback callback) {
executeApiAsync(OPERATION_SIGN_ENCRYPT, params, is, os, callback);
}
public Bundle decryptAndVerify(InputStream is, final OutputStream os) {
return executeApi(OPERATION_DECRYPT_VERIFY, new Bundle(), is, os);
}
public Bundle decryptAndVerify(Bundle params, InputStream is, final OutputStream os) {
return executeApi(OPERATION_DECRYPT_VERIFY, params, is, os);
}
public void decryptAndVerify(Bundle params, InputStream is, final OutputStream os, IOpenPgpCallback callback) {
executeApiAsync(OPERATION_DECRYPT_VERIFY, params, is, os, callback);
}
public Bundle getKeyIds(Bundle params) {
return executeApi(OPERATION_GET_KEY_IDS, params, null, null);
}
public interface IOpenPgpCallback { public interface IOpenPgpCallback {
void onReturn(final Bundle result); void onReturn(final Intent result);
} }
private class OpenPgpAsyncTask extends AsyncTask<Void, Integer, Bundle> { private class OpenPgpAsyncTask extends AsyncTask<Void, Integer, Intent> {
int operationId; Intent data;
Bundle params;
InputStream is; InputStream is;
OutputStream os; OutputStream os;
IOpenPgpCallback callback; IOpenPgpCallback callback;
private OpenPgpAsyncTask(int operationId, Bundle params, InputStream is, OutputStream os, IOpenPgpCallback callback) { private OpenPgpAsyncTask(Intent data, InputStream is, OutputStream os, IOpenPgpCallback callback) {
this.operationId = operationId; this.data = data;
this.params = params;
this.is = is; this.is = is;
this.os = os; this.os = os;
this.callback = callback; this.callback = callback;
} }
@Override @Override
protected Bundle doInBackground(Void... unused) { protected Intent doInBackground(Void... unused) {
return executeApi(operationId, params, is, os); return executeApi(data, is, os);
} }
protected void onPostExecute(Bundle result) { protected void onPostExecute(Intent result) {
callback.onReturn(result); callback.onReturn(result);
} }
} }
private void executeApiAsync(int operationId, Bundle params, InputStream is, OutputStream os, IOpenPgpCallback callback) { public void executeApiAsync(Intent data, InputStream is, OutputStream os, IOpenPgpCallback callback) {
OpenPgpAsyncTask task = new OpenPgpAsyncTask(operationId, params, is, os, callback); OpenPgpAsyncTask task = new OpenPgpAsyncTask(data, is, os, callback);
// don't serialize async tasks! // don't serialize async tasks!
// http://commonsware.com/blog/2012/04/20/asynctask-threading-regression-confirmed.html // http://commonsware.com/blog/2012/04/20/asynctask-threading-regression-confirmed.html
@ -139,14 +178,14 @@ public class OpenPgpApi {
} }
} }
private Bundle executeApi(int operationId, Bundle params, InputStream is, OutputStream os) { public Intent executeApi(Intent data, InputStream is, OutputStream os) {
try { try {
params.putInt(OpenPgpConstants.PARAMS_API_VERSION, OpenPgpConstants.API_VERSION); data.putExtra(EXTRA_API_VERSION, OpenPgpApi.API_VERSION);
Bundle result = null; Intent result = null;
if (operationId == OPERATION_GET_KEY_IDS) { if (ACTION_GET_KEY_IDS.equals(data.getAction())) {
result = mService.getKeyIds(params); result = mService.execute(data, null, null);
return result; return result;
} else { } else {
// send the input and output pfds // send the input and output pfds
@ -155,7 +194,7 @@ public class OpenPgpApi {
@Override @Override
public void onThreadFinished(Thread thread) { public void onThreadFinished(Thread thread) {
Log.d(OpenPgpConstants.TAG, "Copy to service finished"); Log.d(OpenPgpApi.TAG, "Copy to service finished");
} }
}); });
ParcelFileDescriptor output = ParcelFileDescriptorUtil.pipeTo(os, ParcelFileDescriptor output = ParcelFileDescriptorUtil.pipeTo(os,
@ -163,45 +202,30 @@ public class OpenPgpApi {
@Override @Override
public void onThreadFinished(Thread thread) { public void onThreadFinished(Thread thread) {
Log.d(OpenPgpConstants.TAG, "Service finished writing!"); Log.d(OpenPgpApi.TAG, "Service finished writing!");
} }
}); });
// blocks until result is ready // blocks until result is ready
switch (operationId) { result = mService.execute(data, input, output);
case OPERATION_SIGN:
result = mService.sign(params, input, output);
break;
case OPERATION_ENCRYPT:
result = mService.encrypt(params, input, output);
break;
case OPERATION_SIGN_ENCRYPT:
result = mService.signAndEncrypt(params, input, output);
break;
case OPERATION_DECRYPT_VERIFY:
result = mService.decryptAndVerify(params, input, output);
break;
}
// close() is required to halt the TransferThread // close() is required to halt the TransferThread
output.close(); output.close();
// set class loader to current context to allow unparcelling // set class loader to current context to allow unparcelling
// of OpenPgpError and OpenPgpSignatureResult // of OpenPgpError and OpenPgpSignatureResult
// http://stackoverflow.com/a/3806769 // http://stackoverflow.com/a/3806769
result.setClassLoader(mContext.getClassLoader()); result.setExtrasClassLoader(mContext.getClassLoader());
return result; return result;
} }
} catch (Exception e) { } catch (Exception e) {
Log.e(OpenPgpConstants.TAG, "Exception", e); Log.e(OpenPgpApi.TAG, "Exception", e);
Bundle result = new Bundle(); Intent result = new Intent();
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); result.putExtra(RESULT_CODE, RESULT_CODE_ERROR);
result.putParcelable(OpenPgpConstants.RESULT_ERRORS, result.putExtra(RESULT_ERRORS,
new OpenPgpError(OpenPgpError.CLIENT_SIDE_ERROR, e.getMessage())); new OpenPgpError(OpenPgpError.CLIENT_SIDE_ERROR, e.getMessage()));
return result; return result;
} }
} }
} }

View File

@ -1,54 +0,0 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openintents.openpgp.util;
public class OpenPgpConstants {
public static final String TAG = "OpenPgp API";
public static final int API_VERSION = 1;
public static final String SERVICE_INTENT = "org.openintents.openpgp.IOpenPgpService";
/* Bundle params */
public static final String PARAMS_API_VERSION = "api_version";
// request ASCII Armor for output
// OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53)
public static final String PARAMS_REQUEST_ASCII_ARMOR = "ascii_armor";
// (for encrypt method)
public static final String PARAMS_USER_IDS = "user_ids";
public static final String PARAMS_KEY_IDS = "key_ids";
// optional parameter:
public static final String PARAMS_PASSPHRASE = "passphrase";
/* Service Bundle returns */
public static final String RESULT_CODE = "result_code";
public static final String RESULT_SIGNATURE = "signature";
public static final String RESULT_ERRORS = "error";
public static final String RESULT_INTENT = "intent";
// get actual error object from RESULT_ERRORS
public static final int RESULT_CODE_ERROR = 0;
// success!
public static final int RESULT_CODE_SUCCESS = 1;
// executeServiceMethod intent and do it again with params from intent
public static final int RESULT_CODE_USER_INTERACTION_REQUIRED = 2;
/* PendingIntent returns */
public static final String PI_RESULT_PARAMS = "params";
}

View File

@ -23,6 +23,7 @@ import android.content.Intent;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.preference.DialogPreference; import android.preference.DialogPreference;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
@ -30,18 +31,24 @@ import android.view.ViewGroup;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.ListAdapter; import android.widget.ListAdapter;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.api.R;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.sufficientlysecure.keychain.api.R;
/** /**
* Does not extend ListPreference, but is very similar to it! * Does not extend ListPreference, but is very similar to it!
* http://grepcode.com/file_/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/preference/ListPreference.java/?v=source * http://grepcode.com/file_/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/preference/ListPreference.java/?v=source
*/ */
public class OpenPgpListPreference extends DialogPreference { public class OpenPgpListPreference extends DialogPreference {
private ArrayList<OpenPgpProviderEntry> mProviderList = new ArrayList<OpenPgpProviderEntry>(); private static final String OPENKEYCHAIN_PACKAGE = "org.sufficientlysecure.keychain";
private static final String MARKET_INTENT_URI_BASE = "market://details?id=%s";
private static final Intent MARKET_INTENT = new Intent(Intent.ACTION_VIEW, Uri.parse(
String.format(MARKET_INTENT_URI_BASE, OPENKEYCHAIN_PACKAGE)));
private ArrayList<OpenPgpProviderEntry> mLegacyList = new ArrayList<OpenPgpProviderEntry>();
private ArrayList<OpenPgpProviderEntry> mList = new ArrayList<OpenPgpProviderEntry>();
private String mSelectedPackage; private String mSelectedPackage;
public OpenPgpListPreference(Context context, AttributeSet attrs) { public OpenPgpListPreference(Context context, AttributeSet attrs) {
@ -59,16 +66,25 @@ public class OpenPgpListPreference extends DialogPreference {
* @param simpleName * @param simpleName
* @param icon * @param icon
*/ */
public void addProvider(int position, String packageName, String simpleName, Drawable icon) { public void addLegacyProvider(int position, String packageName, String simpleName, Drawable icon) {
mProviderList.add(position, new OpenPgpProviderEntry(packageName, simpleName, icon)); mLegacyList.add(position, new OpenPgpProviderEntry(packageName, simpleName, icon));
} }
@Override @Override
protected void onPrepareDialogBuilder(Builder builder) { protected void onPrepareDialogBuilder(Builder builder) {
mList.clear();
// get providers // add "none"-entry
mProviderList.clear(); mList.add(0, new OpenPgpProviderEntry("",
Intent intent = new Intent(OpenPgpConstants.SERVICE_INTENT); getContext().getString(R.string.openpgp_list_preference_none),
getContext().getResources().getDrawable(R.drawable.ic_action_cancel_launchersize)));
// add all additional (legacy) providers
mList.addAll(mLegacyList);
// search for OpenPGP providers...
ArrayList<OpenPgpProviderEntry> providerList = new ArrayList<OpenPgpProviderEntry>();
Intent intent = new Intent(OpenPgpApi.SERVICE_INTENT);
List<ResolveInfo> resInfo = getContext().getPackageManager().queryIntentServices(intent, 0); List<ResolveInfo> resInfo = getContext().getPackageManager().queryIntentServices(intent, 0);
if (!resInfo.isEmpty()) { if (!resInfo.isEmpty()) {
for (ResolveInfo resolveInfo : resInfo) { for (ResolveInfo resolveInfo : resInfo) {
@ -80,25 +96,40 @@ public class OpenPgpListPreference extends DialogPreference {
.getPackageManager())); .getPackageManager()));
Drawable icon = resolveInfo.serviceInfo.loadIcon(getContext().getPackageManager()); Drawable icon = resolveInfo.serviceInfo.loadIcon(getContext().getPackageManager());
mProviderList.add(new OpenPgpProviderEntry(packageName, simpleName, icon)); providerList.add(new OpenPgpProviderEntry(packageName, simpleName, icon));
} }
} }
// add "none"-entry if (providerList.isEmpty()) {
mProviderList.add(0, new OpenPgpProviderEntry("", // add install links if provider list is empty
getContext().getString(R.string.openpgp_list_preference_none), resInfo = getContext().getPackageManager().queryIntentActivities
getContext().getResources().getDrawable(R.drawable.ic_action_cancel_launchersize))); (MARKET_INTENT, 0);
for (ResolveInfo resolveInfo : resInfo) {
Intent marketIntent = new Intent(MARKET_INTENT);
marketIntent.setPackage(resolveInfo.activityInfo.packageName);
Drawable icon = resolveInfo.activityInfo.loadIcon(getContext().getPackageManager());
String marketName = String.valueOf(resolveInfo.activityInfo.applicationInfo
.loadLabel(getContext().getPackageManager()));
String simpleName = String.format(getContext().getString(R.string
.openpgp_install_openkeychain_via), marketName);
mList.add(new OpenPgpProviderEntry(OPENKEYCHAIN_PACKAGE, simpleName,
icon, marketIntent));
}
} else {
// add provider
mList.addAll(providerList);
}
// Init ArrayAdapter with OpenPGP Providers // Init ArrayAdapter with OpenPGP Providers
ListAdapter adapter = new ArrayAdapter<OpenPgpProviderEntry>(getContext(), ListAdapter adapter = new ArrayAdapter<OpenPgpProviderEntry>(getContext(),
android.R.layout.select_dialog_singlechoice, android.R.id.text1, mProviderList) { android.R.layout.select_dialog_singlechoice, android.R.id.text1, mList) {
public View getView(int position, View convertView, ViewGroup parent) { public View getView(int position, View convertView, ViewGroup parent) {
// User super class to create the View // User super class to create the View
View v = super.getView(position, convertView, parent); View v = super.getView(position, convertView, parent);
TextView tv = (TextView) v.findViewById(android.R.id.text1); TextView tv = (TextView) v.findViewById(android.R.id.text1);
// Put the image on the TextView // Put the image on the TextView
tv.setCompoundDrawablesWithIntrinsicBounds(mProviderList.get(position).icon, null, tv.setCompoundDrawablesWithIntrinsicBounds(mList.get(position).icon, null,
null, null); null, null);
// Add margin between image and text (support various screen densities) // Add margin between image and text (support various screen densities)
@ -114,7 +145,22 @@ public class OpenPgpListPreference extends DialogPreference {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
mSelectedPackage = mProviderList.get(which).packageName; OpenPgpProviderEntry entry = mList.get(which);
if (entry.intent != null) {
/*
* Intents are called as activity
*
* Current approach is to assume the user installed the app.
* If he does not, the selected package is not valid.
*
* However applications should always consider this could happen,
* as the user might remove the currently used OpenPGP app.
*/
getContext().startActivity(entry.intent);
}
mSelectedPackage = entry.packageName;
/* /*
* Clicking on an item simulates the positive button click, and dismisses * Clicking on an item simulates the positive button click, and dismisses
@ -144,9 +190,9 @@ public class OpenPgpListPreference extends DialogPreference {
} }
private int getIndexOfProviderList(String packageName) { private int getIndexOfProviderList(String packageName) {
for (OpenPgpProviderEntry app : mProviderList) { for (OpenPgpProviderEntry app : mList) {
if (app.packageName.equals(packageName)) { if (app.packageName.equals(packageName)) {
return mProviderList.indexOf(app); return mList.indexOf(app);
} }
} }
@ -177,7 +223,7 @@ public class OpenPgpListPreference extends DialogPreference {
} }
public String getEntryByValue(String packageName) { public String getEntryByValue(String packageName) {
for (OpenPgpProviderEntry app : mProviderList) { for (OpenPgpProviderEntry app : mList) {
if (app.packageName.equals(packageName)) { if (app.packageName.equals(packageName)) {
return app.simpleName; return app.simpleName;
} }
@ -190,6 +236,7 @@ public class OpenPgpListPreference extends DialogPreference {
private String packageName; private String packageName;
private String simpleName; private String simpleName;
private Drawable icon; private Drawable icon;
private Intent intent;
public OpenPgpProviderEntry(String packageName, String simpleName, Drawable icon) { public OpenPgpProviderEntry(String packageName, String simpleName, Drawable icon) {
this.packageName = packageName; this.packageName = packageName;
@ -197,6 +244,11 @@ public class OpenPgpListPreference extends DialogPreference {
this.icon = icon; this.icon = icon;
} }
public OpenPgpProviderEntry(String packageName, String simpleName, Drawable icon, Intent intent) {
this(packageName, simpleName, icon);
this.intent = intent;
}
@Override @Override
public String toString() { public String toString() {
return simpleName; return simpleName;

View File

@ -52,7 +52,7 @@ public class OpenPgpUtils {
} }
public static boolean isAvailable(Context context) { public static boolean isAvailable(Context context) {
Intent intent = new Intent(OpenPgpConstants.SERVICE_INTENT); Intent intent = new Intent(OpenPgpApi.SERVICE_INTENT);
List<ResolveInfo> resInfo = context.getPackageManager().queryIntentServices(intent, 0); List<ResolveInfo> resInfo = context.getPackageManager().queryIntentServices(intent, 0);
if (!resInfo.isEmpty()) { if (!resInfo.isEmpty()) {
return true; return true;

View File

@ -81,21 +81,21 @@ public class ParcelFileDescriptorUtil {
} }
mOut.flush(); // just to be safe mOut.flush(); // just to be safe
} catch (IOException e) { } catch (IOException e) {
//Log.e(OpenPgpConstants.TAG, "TransferThread" + getId() + ": writing failed", e); //Log.e(OpenPgpApi.TAG, "TransferThread" + getId() + ": writing failed", e);
} finally { } finally {
try { try {
mIn.close(); mIn.close();
} catch (IOException e) { } catch (IOException e) {
//Log.e(OpenPgpConstants.TAG, "TransferThread" + getId(), e); //Log.e(OpenPgpApi.TAG, "TransferThread" + getId(), e);
} }
try { try {
mOut.close(); mOut.close();
} catch (IOException e) { } catch (IOException e) {
//Log.e(OpenPgpConstants.TAG, "TransferThread" + getId(), e); //Log.e(OpenPgpApi.TAG, "TransferThread" + getId(), e);
} }
} }
if (mListener != null) { if (mListener != null) {
//Log.d(OpenPgpConstants.TAG, "TransferThread " + getId() + " finished!"); //Log.d(OpenPgpApi.TAG, "TransferThread " + getId() + " finished!");
mListener.onThreadFinished(this); mListener.onThreadFinished(this);
} }
} }

View File

@ -3,7 +3,7 @@ apply plugin: 'android'
dependencies { dependencies {
compile 'com.android.support:support-v4:19.0.1' compile 'com.android.support:support-v4:19.0.1'
compile 'com.android.support:appcompat-v7:19.0.1' compile 'com.android.support:appcompat-v7:19.0.1'
compile project(':libraries:keychain-api-library') compile project(':OpenPGP-Keychain-API:libraries:keychain-api-library')
compile project(':libraries:HtmlTextView') compile project(':libraries:HtmlTextView')
compile project(':libraries:StickyListHeaders:library') compile project(':libraries:StickyListHeaders:library')
compile project(':libraries:AndroidBootstrap') compile project(':libraries:AndroidBootstrap')

View File

@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.sufficientlysecure.keychain" package="org.sufficientlysecure.keychain"
android:installLocation="auto" android:installLocation="auto"
android:versionCode="23100" android:versionCode="23102"
android:versionName="2.3.1"> android:versionName="2.3.1 beta2">
<!-- <!--
General remarks General remarks
@ -22,7 +22,8 @@
Remarks about the ugly android:pathPattern: Remarks about the ugly android:pathPattern:
- We are matching all files with a specific file ending. - We are matching all files with a specific file ending.
This is done in an ugly way because of Android limitations. This is done in an ugly way because of Android limitations.
Read http://stackoverflow.com/questions/1733195/android-intent-filter-for-a-particular-file-extension and http://stackoverflow.com/questions/3400072/pathpattern-to-match-file-extension-does-not-work-if-a-period-exists-elsewhere-i/8599921 Read http://stackoverflow.com/questions/1733195/android-intent-filter-for-a-particular-file-extension
and http://stackoverflow.com/questions/3400072/pathpattern-to-match-file-extension-does-not-work-if-a-period-exists-elsewhere-i/8599921
for more information. for more information.
- Do _not_ set mimeType for gpg! - Do _not_ set mimeType for gpg!
Cyanogenmod's file manager will only show Keychain for gpg files if no mimeType is set! Cyanogenmod's file manager will only show Keychain for gpg files if no mimeType is set!

View File

@ -18,8 +18,8 @@
package org.sufficientlysecure.keychain.pgp; package org.sufficientlysecure.keychain.pgp;
import android.content.Context; import android.content.Context;
import android.os.Bundle;
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.spongycastle.bcpg.ArmoredInputStream; import org.spongycastle.bcpg.ArmoredInputStream;
import org.spongycastle.bcpg.SignatureSubpacketTags; import org.spongycastle.bcpg.SignatureSubpacketTags;
import org.spongycastle.openpgp.PGPCompressedData; import org.spongycastle.openpgp.PGPCompressedData;
@ -36,6 +36,7 @@ import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPPublicKeyEncryptedData; import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
import org.spongycastle.openpgp.PGPPublicKeyRing; import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureList; import org.spongycastle.openpgp.PGPSignatureList;
import org.spongycastle.openpgp.PGPSignatureSubpacketVector; import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
@ -53,7 +54,7 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
@ -75,9 +76,10 @@ public class PgpDecryptVerify {
private InputData data; private InputData data;
private OutputStream outStream; private OutputStream outStream;
private ProgressDialogUpdater progress; private ProgressDialogUpdater progressDialogUpdater;
boolean assumeSymmetric; private boolean assumeSymmetric;
String passphrase; private String passphrase;
private long enforcedKeyId;
private PgpDecryptVerify(Builder builder) { private PgpDecryptVerify(Builder builder) {
// private Constructor can only be called from Builder // private Constructor can only be called from Builder
@ -85,9 +87,10 @@ public class PgpDecryptVerify {
this.data = builder.data; this.data = builder.data;
this.outStream = builder.outStream; this.outStream = builder.outStream;
this.progress = builder.progress; this.progressDialogUpdater = builder.progressDialogUpdater;
this.assumeSymmetric = builder.assumeSymmetric; this.assumeSymmetric = builder.assumeSymmetric;
this.passphrase = builder.passphrase; this.passphrase = builder.passphrase;
this.enforcedKeyId = builder.enforcedKeyId;
} }
public static class Builder { public static class Builder {
@ -97,9 +100,10 @@ public class PgpDecryptVerify {
private OutputStream outStream; private OutputStream outStream;
// optional // optional
private ProgressDialogUpdater progress = null; private ProgressDialogUpdater progressDialogUpdater = null;
private boolean assumeSymmetric = false; private boolean assumeSymmetric = false;
private String passphrase = ""; private String passphrase = "";
private long enforcedKeyId = 0;
public Builder(Context context, InputData data, OutputStream outStream) { public Builder(Context context, InputData data, OutputStream outStream) {
this.context = context; this.context = context;
@ -107,8 +111,8 @@ public class PgpDecryptVerify {
this.outStream = outStream; this.outStream = outStream;
} }
public Builder progress(ProgressDialogUpdater progress) { public Builder progressDialogUpdater(ProgressDialogUpdater progressDialogUpdater) {
this.progress = progress; this.progressDialogUpdater = progressDialogUpdater;
return this; return this;
} }
@ -122,20 +126,32 @@ public class PgpDecryptVerify {
return this; return this;
} }
/**
* Allow this key id alone for decryption.
* This means only ciphertexts encrypted for this private key can be decrypted.
*
* @param enforcedKeyId
* @return
*/
public Builder enforcedKeyId(long enforcedKeyId) {
this.enforcedKeyId = enforcedKeyId;
return this;
}
public PgpDecryptVerify build() { public PgpDecryptVerify build() {
return new PgpDecryptVerify(this); return new PgpDecryptVerify(this);
} }
} }
public void updateProgress(int message, int current, int total) { public void updateProgress(int message, int current, int total) {
if (progress != null) { if (progressDialogUpdater != null) {
progress.setProgress(message, current, total); progressDialogUpdater.setProgress(message, current, total);
} }
} }
public void updateProgress(int current, int total) { public void updateProgress(int current, int total) {
if (progress != null) { if (progressDialogUpdater != null) {
progress.setProgress(current, total); progressDialogUpdater.setProgress(current, total);
} }
} }
@ -177,9 +193,8 @@ public class PgpDecryptVerify {
* @throws PGPException * @throws PGPException
* @throws SignatureException * @throws SignatureException
*/ */
public Bundle execute() public PgpDecryptVerifyResult execute()
throws IOException, PgpGeneralException, PGPException, SignatureException { throws IOException, PgpGeneralException, PGPException, SignatureException {
// automatically works with ascii armor input and binary // automatically works with ascii armor input and binary
InputStream in = PGPUtil.getDecoderStream(data.getInputStream()); InputStream in = PGPUtil.getDecoderStream(data.getInputStream());
if (in instanceof ArmoredInputStream) { if (in instanceof ArmoredInputStream) {
@ -207,9 +222,9 @@ public class PgpDecryptVerify {
* @throws PGPException * @throws PGPException
* @throws SignatureException * @throws SignatureException
*/ */
private Bundle decryptVerify(InputStream in) private PgpDecryptVerifyResult decryptVerify(InputStream in)
throws IOException, PgpGeneralException, PGPException, SignatureException { throws IOException, PgpGeneralException, PGPException, SignatureException {
Bundle returnData = new Bundle(); PgpDecryptVerifyResult returnData = new PgpDecryptVerifyResult();
PGPObjectFactory pgpF = new PGPObjectFactory(in); PGPObjectFactory pgpF = new PGPObjectFactory(in);
PGPEncryptedDataList enc; PGPEncryptedDataList enc;
@ -277,9 +292,40 @@ public class PgpDecryptVerify {
PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj; PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, encData.getKeyID()); secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, encData.getKeyID());
if (secretKey != null) { if (secretKey != null) {
// secret key exists in database
// allow only a specific key for decryption?
if (enforcedKeyId != 0) {
// TODO: improve this code! get master key directly!
PGPSecretKeyRing secretKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, encData.getKeyID());
long masterKeyId = PgpKeyHelper.getMasterKey(secretKeyRing).getKeyID();
Log.d(Constants.TAG, "encData.getKeyID():" + encData.getKeyID());
Log.d(Constants.TAG, "enforcedKeyId: " + enforcedKeyId);
Log.d(Constants.TAG, "masterKeyId: " + masterKeyId);
if (enforcedKeyId != masterKeyId) {
throw new PgpGeneralException(context.getString(R.string.error_no_secret_key_found));
}
}
pbe = encData; pbe = encData;
// if no passphrase was explicitly set try to get it from the cache service
if (passphrase == null) {
// returns "" if key has no passphrase
passphrase = PassphraseCacheService.getCachedPassphrase(context, encData.getKeyID());
// if passphrase was not cached, return here indicating that a passphrase is missing!
if (passphrase == null) {
returnData.setKeyPassphraseNeeded(true);
return returnData;
}
}
break; break;
} }
} }
} }
@ -317,6 +363,7 @@ public class PgpDecryptVerify {
PGPObjectFactory plainFact = new PGPObjectFactory(clear); PGPObjectFactory plainFact = new PGPObjectFactory(clear);
Object dataChunk = plainFact.nextObject(); Object dataChunk = plainFact.nextObject();
PGPOnePassSignature signature = null; PGPOnePassSignature signature = null;
OpenPgpSignatureResult signatureResult = null;
PGPPublicKey signatureKey = null; PGPPublicKey signatureKey = null;
int signatureIndex = -1; int signatureIndex = -1;
@ -334,7 +381,7 @@ public class PgpDecryptVerify {
if (dataChunk instanceof PGPOnePassSignatureList) { if (dataChunk instanceof PGPOnePassSignatureList) {
updateProgress(R.string.progress_processing_signature, currentProgress, 100); updateProgress(R.string.progress_processing_signature, currentProgress, 100);
returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE, true); signatureResult = new OpenPgpSignatureResult();
PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk; PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk;
for (int i = 0; i < sigList.size(); ++i) { for (int i = 0; i < sigList.size(); ++i) {
signature = sigList.get(i); signature = sigList.get(i);
@ -354,12 +401,12 @@ public class PgpDecryptVerify {
if (signKeyRing != null) { if (signKeyRing != null) {
userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing)); userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing));
} }
returnData.putString(KeychainIntentService.RESULT_SIGNATURE_USER_ID, userId); signatureResult.setUserId(userId);
break; break;
} }
} }
returnData.putLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, signatureKeyId); signatureResult.setKeyId(signatureKeyId);
if (signature != null) { if (signature != null) {
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider() JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
@ -367,7 +414,7 @@ public class PgpDecryptVerify {
signature.init(contentVerifierBuilderProvider, signatureKey); signature.init(contentVerifierBuilderProvider, signatureKey);
} else { } else {
returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, true); signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY);
} }
dataChunk = plainFact.nextObject(); dataChunk = plainFact.nextObject();
@ -405,8 +452,7 @@ public class PgpDecryptVerify {
try { try {
signature.update(buffer, 0, n); signature.update(buffer, 0, n);
} catch (SignatureException e) { } catch (SignatureException e) {
returnData signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR);
.putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, false);
signature = null; signature = null;
} }
} }
@ -430,17 +476,20 @@ public class PgpDecryptVerify {
PGPSignature messageSignature = signatureList.get(signatureIndex); PGPSignature messageSignature = signatureList.get(signatureIndex);
// these are not cleartext signatures! // these are not cleartext signatures!
returnData.putBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, false); // TODO: what about binary signatures?
signatureResult.setSignatureOnly(false);
//Now check binding signatures //Now check binding signatures
boolean keyBinding_isok = verifyKeyBinding(context, messageSignature, signatureKey); boolean validKeyBinding = verifyKeyBinding(context, messageSignature, signatureKey);
boolean sig_isok = signature.verify(messageSignature); boolean validSignature = signature.verify(messageSignature);
returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, keyBinding_isok & sig_isok); // TODO: implement CERTIFIED!
if (validKeyBinding & validSignature) {
signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED);
}
} }
} }
// TODO: test if this integrity really check works!
if (encryptedData.isIntegrityProtected()) { if (encryptedData.isIntegrityProtected()) {
updateProgress(R.string.progress_verifying_integrity, 95, 100); updateProgress(R.string.progress_verifying_integrity, 95, 100);
@ -455,9 +504,12 @@ public class PgpDecryptVerify {
} else { } else {
// no integrity check // no integrity check
Log.e(Constants.TAG, "Encrypted data was not integrity protected!"); Log.e(Constants.TAG, "Encrypted data was not integrity protected!");
// TODO: inform user?
} }
updateProgress(R.string.progress_done, 100, 100); updateProgress(R.string.progress_done, 100, 100);
returnData.setSignatureResult(signatureResult);
return returnData; return returnData;
} }
@ -474,11 +526,12 @@ public class PgpDecryptVerify {
* @throws PGPException * @throws PGPException
* @throws SignatureException * @throws SignatureException
*/ */
private Bundle verifyCleartextSignature(ArmoredInputStream aIn) private PgpDecryptVerifyResult verifyCleartextSignature(ArmoredInputStream aIn)
throws IOException, PgpGeneralException, PGPException, SignatureException { throws IOException, PgpGeneralException, PGPException, SignatureException {
Bundle returnData = new Bundle(); PgpDecryptVerifyResult returnData = new PgpDecryptVerifyResult();
OpenPgpSignatureResult signatureResult = new OpenPgpSignatureResult();
// cleartext signatures are never encrypted ;) // cleartext signatures are never encrypted ;)
returnData.putBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, true); signatureResult.setSignatureOnly(true);
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
@ -504,8 +557,6 @@ public class PgpDecryptVerify {
byte[] clearText = out.toByteArray(); byte[] clearText = out.toByteArray();
outStream.write(clearText); outStream.write(clearText);
returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE, true);
updateProgress(R.string.progress_processing_signature, 60, 100); updateProgress(R.string.progress_processing_signature, 60, 100);
PGPObjectFactory pgpFact = new PGPObjectFactory(aIn); PGPObjectFactory pgpFact = new PGPObjectFactory(aIn);
@ -533,15 +584,15 @@ public class PgpDecryptVerify {
if (signKeyRing != null) { if (signKeyRing != null) {
userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing)); userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing));
} }
returnData.putString(KeychainIntentService.RESULT_SIGNATURE_USER_ID, userId); signatureResult.setUserId(userId);
break; break;
} }
} }
returnData.putLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, signatureKeyId); signatureResult.setKeyId(signatureKeyId);
if (signature == null) { if (signature == null) {
returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, true); signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY);
updateProgress(R.string.progress_done, 100, 100); updateProgress(R.string.progress_done, 100, 100);
return returnData; return returnData;
} }
@ -569,47 +620,52 @@ public class PgpDecryptVerify {
} while (lookAhead != -1); } while (lookAhead != -1);
} }
boolean sig_isok = signature.verify();
//Now check binding signatures //Now check binding signatures
boolean keyBinding_isok = verifyKeyBinding(context, signature, signatureKey); boolean validKeyBinding = verifyKeyBinding(context, signature, signatureKey);
boolean validSignature = signature.verify();
returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, sig_isok & keyBinding_isok); if (validSignature & validKeyBinding) {
signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED);
}
// TODO: what about SIGNATURE_SUCCESS_CERTIFIED and SIGNATURE_ERROR????
updateProgress(R.string.progress_done, 100, 100); updateProgress(R.string.progress_done, 100, 100);
returnData.setSignatureResult(signatureResult);
return returnData; return returnData;
} }
private static boolean verifyKeyBinding(Context context, PGPSignature signature, PGPPublicKey signatureKey) { private static boolean verifyKeyBinding(Context context, PGPSignature signature, PGPPublicKey signatureKey) {
long signatureKeyId = signature.getKeyID(); long signatureKeyId = signature.getKeyID();
boolean keyBinding_isok = false; boolean validKeyBinding = false;
String userId = null;
PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(context, PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(context,
signatureKeyId); signatureKeyId);
PGPPublicKey mKey = null; PGPPublicKey mKey = null;
if (signKeyRing != null) { if (signKeyRing != null) {
mKey = PgpKeyHelper.getMasterKey(signKeyRing); mKey = PgpKeyHelper.getMasterKey(signKeyRing);
} }
if (signature.getKeyID() != mKey.getKeyID()) { if (signature.getKeyID() != mKey.getKeyID()) {
keyBinding_isok = verifyKeyBinding(mKey, signatureKey); validKeyBinding = verifyKeyBinding(mKey, signatureKey);
} else { //if the key used to make the signature was the master key, no need to check binding sigs } else { //if the key used to make the signature was the master key, no need to check binding sigs
keyBinding_isok = true; validKeyBinding = true;
} }
return keyBinding_isok; return validKeyBinding;
} }
private static boolean verifyKeyBinding(PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) { private static boolean verifyKeyBinding(PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) {
boolean subkeyBinding_isok = false; boolean validSubkeyBinding = false;
boolean tmp_subkeyBinding_isok = false; boolean validTempSubkeyBinding = false;
boolean primkeyBinding_isok = false; boolean validPrimaryKeyBinding = false;
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
new JcaPGPContentVerifierBuilderProvider()
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
Iterator<PGPSignature> itr = signingPublicKey.getSignatures(); Iterator<PGPSignature> itr = signingPublicKey.getSignatures();
subkeyBinding_isok = false;
tmp_subkeyBinding_isok = false;
primkeyBinding_isok = false;
while (itr.hasNext()) { //what does gpg do if the subkey binding is wrong? while (itr.hasNext()) { //what does gpg do if the subkey binding is wrong?
//gpg has an invalid subkey binding error on key import I think, but doesn't shout //gpg has an invalid subkey binding error on key import I think, but doesn't shout
//about keys without subkey signing. Can't get it to import a slightly broken one //about keys without subkey signing. Can't get it to import a slightly broken one
@ -619,31 +675,35 @@ public class PgpDecryptVerify {
//check and if ok, check primary key binding. //check and if ok, check primary key binding.
try { try {
sig.init(contentVerifierBuilderProvider, masterPublicKey); sig.init(contentVerifierBuilderProvider, masterPublicKey);
tmp_subkeyBinding_isok = sig.verifyCertification(masterPublicKey, signingPublicKey); validTempSubkeyBinding = sig.verifyCertification(masterPublicKey, signingPublicKey);
} catch (PGPException e) { } catch (PGPException e) {
continue; continue;
} catch (SignatureException e) { } catch (SignatureException e) {
continue; continue;
} }
if (tmp_subkeyBinding_isok) if (validTempSubkeyBinding)
subkeyBinding_isok = true; validSubkeyBinding = true;
if (tmp_subkeyBinding_isok) { if (validTempSubkeyBinding) {
primkeyBinding_isok = verifyPrimaryBinding(sig.getUnhashedSubPackets(), masterPublicKey, signingPublicKey); validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getUnhashedSubPackets(),
if (primkeyBinding_isok) masterPublicKey, signingPublicKey);
if (validPrimaryKeyBinding)
break; break;
primkeyBinding_isok = verifyPrimaryBinding(sig.getHashedSubPackets(), masterPublicKey, signingPublicKey); validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getHashedSubPackets(),
if (primkeyBinding_isok) masterPublicKey, signingPublicKey);
if (validPrimaryKeyBinding)
break; break;
} }
} }
} }
return (subkeyBinding_isok & primkeyBinding_isok); return (validSubkeyBinding & validPrimaryKeyBinding);
} }
private static boolean verifyPrimaryBinding(PGPSignatureSubpacketVector Pkts, PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) { private static boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector Pkts,
boolean primkeyBinding_isok = false; PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) {
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider() boolean validPrimaryKeyBinding = false;
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
new JcaPGPContentVerifierBuilderProvider()
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureList eSigList; PGPSignatureList eSigList;
@ -660,8 +720,8 @@ public class PgpDecryptVerify {
if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) { if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) {
try { try {
emSig.init(contentVerifierBuilderProvider, signingPublicKey); emSig.init(contentVerifierBuilderProvider, signingPublicKey);
primkeyBinding_isok = emSig.verifyCertification(masterPublicKey, signingPublicKey); validPrimaryKeyBinding = emSig.verifyCertification(masterPublicKey, signingPublicKey);
if (primkeyBinding_isok) if (validPrimaryKeyBinding)
break; break;
} catch (PGPException e) { } catch (PGPException e) {
continue; continue;
@ -671,7 +731,8 @@ public class PgpDecryptVerify {
} }
} }
} }
return primkeyBinding_isok;
return validPrimaryKeyBinding;
} }
/** /**

View File

@ -0,0 +1,88 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.pgp;
import android.os.Parcel;
import android.os.Parcelable;
import org.openintents.openpgp.OpenPgpSignatureResult;
public class PgpDecryptVerifyResult implements Parcelable {
boolean symmetricPassphraseNeeded;
boolean keyPassphraseNeeded;
OpenPgpSignatureResult signatureResult;
public boolean isSymmetricPassphraseNeeded() {
return symmetricPassphraseNeeded;
}
public void setSymmetricPassphraseNeeded(boolean symmetricPassphraseNeeded) {
this.symmetricPassphraseNeeded = symmetricPassphraseNeeded;
}
public boolean isKeyPassphraseNeeded() {
return keyPassphraseNeeded;
}
public void setKeyPassphraseNeeded(boolean keyPassphraseNeeded) {
this.keyPassphraseNeeded = keyPassphraseNeeded;
}
public OpenPgpSignatureResult getSignatureResult() {
return signatureResult;
}
public void setSignatureResult(OpenPgpSignatureResult signatureResult) {
this.signatureResult = signatureResult;
}
public PgpDecryptVerifyResult() {
}
public PgpDecryptVerifyResult(PgpDecryptVerifyResult b) {
this.symmetricPassphraseNeeded = b.symmetricPassphraseNeeded;
this.keyPassphraseNeeded = b.keyPassphraseNeeded;
this.signatureResult = b.signatureResult;
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeByte((byte) (symmetricPassphraseNeeded ? 1 : 0));
dest.writeByte((byte) (keyPassphraseNeeded ? 1 : 0));
dest.writeParcelable(signatureResult, 0);
}
public static final Creator<PgpDecryptVerifyResult> CREATOR = new Creator<PgpDecryptVerifyResult>() {
public PgpDecryptVerifyResult createFromParcel(final Parcel source) {
PgpDecryptVerifyResult vr = new PgpDecryptVerifyResult();
vr.symmetricPassphraseNeeded = source.readByte() == 1;
vr.keyPassphraseNeeded = source.readByte() == 1;
vr.signatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader());
return vr;
}
public PgpDecryptVerifyResult[] newArray(final int size) {
return new PgpDecryptVerifyResult[size];
}
};
}

View File

@ -44,6 +44,7 @@ import org.sufficientlysecure.keychain.helper.OtherHelper;
import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpImportExport; import org.sufficientlysecure.keychain.pgp.PgpImportExport;
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation; import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
@ -181,13 +182,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
// decrypt/verify // decrypt/verify
public static final String RESULT_DECRYPTED_STRING = "decrypted_message"; public static final String RESULT_DECRYPTED_STRING = "decrypted_message";
public static final String RESULT_DECRYPTED_BYTES = "decrypted_data"; public static final String RESULT_DECRYPTED_BYTES = "decrypted_data";
public static final String RESULT_SIGNATURE = "signature"; public static final String RESULT_DECRYPT_VERIFY_RESULT = "signature";
public static final String RESULT_SIGNATURE_KEY_ID = "signature_key_id";
public static final String RESULT_SIGNATURE_USER_ID = "signature_user_id";
public static final String RESULT_CLEARTEXT_SIGNATURE_ONLY = "signature_only";
public static final String RESULT_SIGNATURE_SUCCESS = "signature_success";
public static final String RESULT_SIGNATURE_UNKNOWN = "signature_unknown";
// import // import
public static final String RESULT_IMPORT_ADDED = "added"; public static final String RESULT_IMPORT_ADDED = "added";
@ -203,8 +198,16 @@ public class KeychainIntentService extends IntentService implements ProgressDial
Messenger mMessenger; Messenger mMessenger;
private boolean mIsCanceled;
public KeychainIntentService() { public KeychainIntentService() {
super("ApgService"); super("KeychainIntentService");
}
@Override
public void onDestroy() {
super.onDestroy();
this.mIsCanceled = true;
} }
/** /**
@ -481,15 +484,17 @@ public class KeychainIntentService extends IntentService implements ProgressDial
// verifyText and decrypt returning additional resultData values for the // verifyText and decrypt returning additional resultData values for the
// verification of signatures // verification of signatures
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, outStream); PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, outStream);
builder.progress(this); builder.progressDialogUpdater(this);
builder.assumeSymmetric(assumeSymmetricEncryption) builder.assumeSymmetric(assumeSymmetricEncryption)
.passphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId)); .passphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
resultData = builder.build().execute(); PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute();
outStream.close(); outStream.close();
resultData.putParcelable(RESULT_DECRYPT_VERIFY_RESULT, decryptVerifyResult);
/* Output */ /* Output */
switch (target) { switch (target) {
@ -815,6 +820,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial
} }
private void sendErrorToHandler(Exception e) { private void sendErrorToHandler(Exception e) {
// Service was canceled. Do not send error to handler.
if (this.mIsCanceled)
return;
Log.e(Constants.TAG, "ApgService Exception: ", e); Log.e(Constants.TAG, "ApgService Exception: ", e);
e.printStackTrace(); e.printStackTrace();
@ -824,6 +833,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial
} }
private void sendMessageToHandler(Integer arg1, Integer arg2, Bundle data) { private void sendMessageToHandler(Integer arg1, Integer arg2, Bundle data) {
// Service was canceled. Do not send message to handler.
if (this.mIsCanceled)
return;
Message msg = Message.obtain(); Message msg = Message.obtain();
msg.arg1 = arg1; msg.arg1 = arg1;
if (arg2 != null) { if (arg2 != null) {
@ -851,10 +864,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial
} }
/** /**
* Set progress of ProgressDialog by sending message to handler on UI thread * Set progressDialogUpdater of ProgressDialog by sending message to handler on UI thread
*/ */
public void setProgress(String message, int progress, int max) { public void setProgress(String message, int progress, int max) {
Log.d(Constants.TAG, "Send message by setProgress with progress=" + progress + ", max=" Log.d(Constants.TAG, "Send message by setProgress with progressDialogUpdater=" + progress + ", max="
+ max); + max);
Bundle data = new Bundle(); Bundle data = new Bundle();

View File

@ -21,6 +21,8 @@ import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import android.app.Activity; import android.app.Activity;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
@ -55,9 +57,15 @@ public class KeychainIntentServiceHandler extends Handler {
} }
public KeychainIntentServiceHandler(Activity activity, int progressDialogMessageId, int progressDialogStyle) { public KeychainIntentServiceHandler(Activity activity, int progressDialogMessageId, int progressDialogStyle) {
this(activity, progressDialogMessageId, progressDialogStyle, false, null);
}
public KeychainIntentServiceHandler(Activity activity, int progressDialogMessageId,
int progressDialogStyle, boolean cancelable,
OnCancelListener onCancelListener) {
this.mActivity = activity; this.mActivity = activity;
this.mProgressDialogFragment = ProgressDialogFragment.newInstance(progressDialogMessageId, this.mProgressDialogFragment = ProgressDialogFragment.newInstance(progressDialogMessageId,
progressDialogStyle); progressDialogStyle, cancelable, onCancelListener);
} }
public void showProgressDialog(FragmentActivity activity) { public void showProgressDialog(FragmentActivity activity) {

View File

@ -21,21 +21,21 @@ import android.app.PendingIntent;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import org.openintents.openpgp.IOpenPgpService; import org.openintents.openpgp.IOpenPgpService;
import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.OpenPgpSignatureResult;
import org.openintents.openpgp.util.OpenPgpConstants; import org.openintents.openpgp.util.OpenPgpApi;
import org.spongycastle.util.Arrays; import org.spongycastle.util.Arrays;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt; import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
@ -48,7 +48,7 @@ public class OpenPgpService extends RemoteService {
private static final int PRIVATE_REQUEST_CODE_PASSPHRASE = 551; private static final int PRIVATE_REQUEST_CODE_PASSPHRASE = 551;
private static final int PRIVATE_REQUEST_CODE_USER_IDS = 552; private static final int PRIVATE_REQUEST_CODE_USER_IDS = 552;
private static final int PRIVATE_REQUEST_CODE_GET_KEYS = 553;
/** /**
* Search database for key ids based on emails. * Search database for key ids based on emails.
@ -56,7 +56,7 @@ public class OpenPgpService extends RemoteService {
* @param encryptionUserIds * @param encryptionUserIds
* @return * @return
*/ */
private Bundle getKeyIdsFromEmails(Bundle params, String[] encryptionUserIds) { private Intent getKeyIdsFromEmails(Intent data, String[] encryptionUserIds) {
// find key ids to given emails in database // find key ids to given emails in database
ArrayList<Long> keyIds = new ArrayList<Long>(); ArrayList<Long> keyIds = new ArrayList<Long>();
@ -91,20 +91,20 @@ public class OpenPgpService extends RemoteService {
// allow the user to verify pub key selection // allow the user to verify pub key selection
if (missingUserIdsCheck || dublicateUserIdsCheck) { if (missingUserIdsCheck || dublicateUserIdsCheck) {
// build PendingIntent for passphrase input // build PendingIntent
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
intent.setAction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS); intent.setAction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS);
intent.putExtra(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray); intent.putExtra(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray);
intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds); intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds);
intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, dublicateUserIds); intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, dublicateUserIds);
intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params); intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_USER_IDS, intent, 0); PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_USER_IDS, intent, 0);
// return PendingIntent to be executed by client // return PendingIntent to be executed by client
Bundle result = new Bundle(); Intent result = new Intent();
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi); result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
return result; return result;
} }
@ -113,44 +113,44 @@ public class OpenPgpService extends RemoteService {
return null; return null;
} }
Bundle result = new Bundle(); Intent result = new Intent();
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
result.putLongArray(OpenPgpConstants.PARAMS_KEY_IDS, keyIdsArray); result.putExtra(OpenPgpApi.EXTRA_KEY_IDS, keyIdsArray);
return result; return result;
} }
private Bundle getPassphraseBundleIntent(Bundle params, long keyId) { private Intent getPassphraseBundleIntent(Intent data, long keyId) {
// build PendingIntent for passphrase input // build PendingIntent for passphrase input
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
intent.setAction(RemoteServiceActivity.ACTION_CACHE_PASSPHRASE); intent.setAction(RemoteServiceActivity.ACTION_CACHE_PASSPHRASE);
intent.putExtra(RemoteServiceActivity.EXTRA_SECRET_KEY_ID, keyId); intent.putExtra(RemoteServiceActivity.EXTRA_SECRET_KEY_ID, keyId);
// pass params through to activity that it can be returned again later to repeat pgp operation // pass params through to activity that it can be returned again later to repeat pgp operation
intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params); intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_PASSPHRASE, intent, 0); PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_PASSPHRASE, intent, 0);
// return PendingIntent to be executed by client // return PendingIntent to be executed by client
Bundle result = new Bundle(); Intent result = new Intent();
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi); result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
return result; return result;
} }
private Bundle signImpl(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output, private Intent signImpl(Intent data, ParcelFileDescriptor input,
AppSettings appSettings) { ParcelFileDescriptor output, AppSettings appSettings) {
try { try {
boolean asciiArmor = params.getBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true); boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
// get passphrase from cache, if key has "no" passphrase, this returns an empty String // get passphrase from cache, if key has "no" passphrase, this returns an empty String
String passphrase; String passphrase;
if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) { if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE); passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
} else { } else {
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId()); passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId());
} }
if (passphrase == null) { if (passphrase == null) {
// get PendingIntent for passphrase input, add it to given params and return to client // get PendingIntent for passphrase input, add it to given params and return to client
Bundle passphraseBundle = getPassphraseBundleIntent(params, appSettings.getKeyId()); Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId());
return passphraseBundle; return passphraseBundle;
} }
@ -174,43 +174,42 @@ public class OpenPgpService extends RemoteService {
os.close(); os.close();
} }
Bundle result = new Bundle(); Intent result = new Intent();
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
return result; return result;
} catch (Exception e) { } catch (Exception e) {
Bundle result = new Bundle(); Intent result = new Intent();
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
result.putParcelable(OpenPgpConstants.RESULT_ERRORS, result.putExtra(OpenPgpApi.RESULT_ERRORS,
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
return result; return result;
} }
} }
private Bundle encryptAndSignImpl(Bundle params, ParcelFileDescriptor input, private Intent encryptAndSignImpl(Intent data, ParcelFileDescriptor input,
ParcelFileDescriptor output, AppSettings appSettings, ParcelFileDescriptor output, AppSettings appSettings, boolean sign) {
boolean sign) {
try { try {
boolean asciiArmor = params.getBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true); boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
long[] keyIds; long[] keyIds;
if (params.containsKey(OpenPgpConstants.PARAMS_KEY_IDS)) { if (data.hasExtra(OpenPgpApi.EXTRA_KEY_IDS)) {
keyIds = params.getLongArray(OpenPgpConstants.PARAMS_KEY_IDS); keyIds = data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS);
} else if (params.containsKey(OpenPgpConstants.PARAMS_USER_IDS)) { } else if (data.hasExtra(OpenPgpApi.EXTRA_USER_IDS)) {
// get key ids based on given user ids // get key ids based on given user ids
String[] userIds = params.getStringArray(OpenPgpConstants.PARAMS_USER_IDS); String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS);
// give params through to activity... // give params through to activity...
Bundle result = getKeyIdsFromEmails(params, userIds); Intent result = getKeyIdsFromEmails(data, userIds);
if (result.getInt(OpenPgpConstants.RESULT_CODE, 0) == OpenPgpConstants.RESULT_CODE_SUCCESS) { if (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0) == OpenPgpApi.RESULT_CODE_SUCCESS) {
keyIds = result.getLongArray(OpenPgpConstants.PARAMS_KEY_IDS); keyIds = result.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS);
} else { } else {
// if not success -> result contains a PendingIntent for user interaction // if not success -> result contains a PendingIntent for user interaction
return result; return result;
} }
} else { } else {
Bundle result = new Bundle(); Intent result = new Intent();
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
result.putParcelable(OpenPgpConstants.RESULT_ERRORS, result.putExtra(OpenPgpApi.RESULT_ERRORS,
new OpenPgpError(OpenPgpError.GENERIC_ERROR, "Missing parameter user_ids or key_ids!")); new OpenPgpError(OpenPgpError.GENERIC_ERROR, "Missing parameter user_ids or key_ids!"));
return result; return result;
} }
@ -235,15 +234,15 @@ public class OpenPgpService extends RemoteService {
if (sign) { if (sign) {
String passphrase; String passphrase;
if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) { if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) {
passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE); passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
} else { } else {
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), passphrase = PassphraseCacheService.getCachedPassphrase(getContext(),
appSettings.getKeyId()); appSettings.getKeyId());
} }
if (passphrase == null) { if (passphrase == null) {
// get PendingIntent for passphrase input, add it to given params and return to client // get PendingIntent for passphrase input, add it to given params and return to client
Bundle passphraseBundle = getPassphraseBundleIntent(params, appSettings.getKeyId()); Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId());
return passphraseBundle; return passphraseBundle;
} }
@ -263,144 +262,88 @@ public class OpenPgpService extends RemoteService {
os.close(); os.close();
} }
Bundle result = new Bundle(); Intent result = new Intent();
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
return result; return result;
} catch (Exception e) { } catch (Exception e) {
Bundle result = new Bundle(); Intent result = new Intent();
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
result.putParcelable(OpenPgpConstants.RESULT_ERRORS, result.putExtra(OpenPgpApi.RESULT_ERRORS,
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
return result; return result;
} }
} }
private Bundle decryptAndVerifyImpl(Bundle params, ParcelFileDescriptor input, private Intent decryptAndVerifyImpl(Intent data, ParcelFileDescriptor input,
ParcelFileDescriptor output, AppSettings appSettings) { ParcelFileDescriptor output, AppSettings appSettings) {
try { try {
// Get Input- and OutputStream from ParcelFileDescriptor // Get Input- and OutputStream from ParcelFileDescriptor
InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input);
OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output); OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
Bundle result = new Bundle(); Intent result = new Intent();
try { try {
// TODO: String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
// fix the mess: http://stackoverflow.com/questions/148130/how-do-i-peek-at-the-first-two-bytes-in-an-inputstream
// should we allow to decrypt everything under every key id or only the one set?
// TODO: instead of trying to get the passphrase before
// pause stream when passphrase is missing and then resume
// TODO: put this code into PgpDecryptVerify class
// TODO: This allows to decrypt messages with ALL secret keys, not only the one for the
// app, Fix this?
// String passphrase = null;
// if (!signedOnly) {
// // BEGIN Get key
// // TODO: this input stream is consumed after PgpMain.getDecryptionKeyId()... do it
// // better!
// InputStream inputStream2 = new ByteArrayInputStream(inputBytes);
//
// // TODO: duplicates functions from DecryptActivity!
// long secretKeyId;
// try {
// if (inputStream2.markSupported()) {
// // should probably set this to the max size of two
// // pgpF objects, if it even needs to be anything other
// // than 0.
// inputStream2.mark(200);
// }
// secretKeyId = PgpHelper.getDecryptionKeyId(this, inputStream2);
// if (secretKeyId == Id.key.none) {
// throw new PgpGeneralException(getString(R.string.error_no_secret_key_found));
// }
// } catch (NoAsymmetricEncryptionException e) {
// if (inputStream2.markSupported()) {
// inputStream2.reset();
// }
// secretKeyId = Id.key.symmetric;
// if (!PgpDecryptVerify.hasSymmetricEncryption(this, inputStream2)) {
// throw new PgpGeneralException(
// getString(R.string.error_no_known_encryption_found));
// }
// // we do not support symmetric decryption from the API!
// throw new Exception("Symmetric decryption is not supported!");
// }
//
// Log.d(Constants.TAG, "secretKeyId " + secretKeyId);
// NOTE: currently this only gets the passphrase for the key set for this client
String passphrase;
if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) {
passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE);
} else {
passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId());
}
if (passphrase == null) {
// get PendingIntent for passphrase input, add it to given params and return to client
Bundle passphraseBundle = getPassphraseBundleIntent(params, appSettings.getKeyId());
return passphraseBundle;
}
long inputLength = is.available(); long inputLength = is.available();
InputData inputData = new InputData(is, inputLength); InputData inputData = new InputData(is, inputLength);
Bundle outputBundle;
PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os); PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os);
builder.assumeSymmetric(false) // no support for symmetric encryption
builder.assumeSymmetric(false) .enforcedKeyId(appSettings.getKeyId()) // allow only the private key for this app for decryption
.passphrase(passphrase); .passphrase(passphrase);
// TODO: this also decrypts with other secret keys that have no passphrase!!! // TODO: currently does not support binary signed-only content
outputBundle = builder.build().execute(); PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute();
//TODO: instead of using all these wrapping use OpenPgpSignatureResult directly if (decryptVerifyResult.isKeyPassphraseNeeded()) {
// in DecryptVerify class and then in DecryptActivity // get PendingIntent for passphrase input, add it to given params and return to client
boolean signature = outputBundle.getBoolean(KeychainIntentService.RESULT_SIGNATURE, false); Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId());
if (signature) { return passphraseBundle;
long signatureKeyId = outputBundle } else if (decryptVerifyResult.isSymmetricPassphraseNeeded()) {
.getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, 0); throw new PgpGeneralException("Decryption of symmetric content not supported by API!");
String signatureUserId = outputBundle
.getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID);
boolean signatureSuccess = outputBundle
.getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, false);
boolean signatureUnknown = outputBundle
.getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, false);
boolean signatureOnly = outputBundle
.getBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, false);
int signatureStatus = OpenPgpSignatureResult.SIGNATURE_ERROR;
if (signatureSuccess) {
signatureStatus = OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED;
} else if (signatureUnknown) {
signatureStatus = OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY;
} }
OpenPgpSignatureResult sigResult = new OpenPgpSignatureResult(signatureStatus, OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult();
signatureUserId, signatureOnly, signatureKeyId); if (signatureResult != null) {
result.putParcelable(OpenPgpConstants.RESULT_SIGNATURE, sigResult); if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY) {
// If signature is unknown we return an additional PendingIntent
// to retrieve the missing key
// TODO!!!
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE);
intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, "todo");
intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
PendingIntent pi = PendingIntent.getActivity(getBaseContext(),
PRIVATE_REQUEST_CODE_GET_KEYS, intent, 0);
result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
} }
result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult);
}
} finally { } finally {
is.close(); is.close();
os.close(); os.close();
} }
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
return result; return result;
} catch (Exception e) { } catch (Exception e) {
Bundle result = new Bundle(); Intent result = new Intent();
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
result.putParcelable(OpenPgpConstants.RESULT_ERRORS, result.putExtra(OpenPgpApi.RESULT_ERRORS,
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
return result; return result;
} }
} }
private Bundle getKeyIdsImpl(Bundle params) { private Intent getKeyIdsImpl(Intent data) {
// get key ids based on given user ids // get key ids based on given user ids
String[] userIds = params.getStringArray(OpenPgpConstants.PARAMS_USER_IDS); String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS);
Bundle result = getKeyIdsFromEmails(params, userIds); Intent result = getKeyIdsFromEmails(data, userIds);
return result; return result;
} }
@ -410,30 +353,30 @@ public class OpenPgpService extends RemoteService {
* - has supported API version * - has supported API version
* - is allowed to call the service (access has been granted) * - is allowed to call the service (access has been granted)
* *
* @param params * @param data
* @return null if everything is okay, or a Bundle with an error/PendingIntent * @return null if everything is okay, or a Bundle with an error/PendingIntent
*/ */
private Bundle checkRequirements(Bundle params) { private Intent checkRequirements(Intent data) {
// params Bundle is required! // params Bundle is required!
if (params == null) { if (data == null) {
Bundle result = new Bundle(); Intent result = new Intent();
OpenPgpError error = new OpenPgpError(OpenPgpError.GENERIC_ERROR, "params Bundle required!"); OpenPgpError error = new OpenPgpError(OpenPgpError.GENERIC_ERROR, "params Bundle required!");
result.putParcelable(OpenPgpConstants.RESULT_ERRORS, error); result.putExtra(OpenPgpApi.RESULT_ERRORS, error);
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
return result; return result;
} }
// version code is required and needs to correspond to version code of service! // version code is required and needs to correspond to version code of service!
if (params.getInt(OpenPgpConstants.PARAMS_API_VERSION) != OpenPgpConstants.API_VERSION) { if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != OpenPgpApi.API_VERSION) {
Bundle result = new Bundle(); Intent result = new Intent();
OpenPgpError error = new OpenPgpError(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!"); OpenPgpError error = new OpenPgpError(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!");
result.putParcelable(OpenPgpConstants.RESULT_ERRORS, error); result.putExtra(OpenPgpApi.RESULT_ERRORS, error);
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
return result; return result;
} }
// check if caller is allowed to access openpgp keychain // check if caller is allowed to access openpgp keychain
Bundle result = isAllowed(params); Intent result = isAllowed(data);
if (result != null) { if (result != null) {
return result; return result;
} }
@ -445,61 +388,31 @@ public class OpenPgpService extends RemoteService {
private final IOpenPgpService.Stub mBinder = new IOpenPgpService.Stub() { private final IOpenPgpService.Stub mBinder = new IOpenPgpService.Stub() {
@Override @Override
public Bundle sign(Bundle params, final ParcelFileDescriptor input, final ParcelFileDescriptor output) { public Intent execute(Intent data, ParcelFileDescriptor input, ParcelFileDescriptor output) {
Intent errorResult = checkRequirements(data);
if (errorResult != null) {
return errorResult;
}
final AppSettings appSettings = getAppSettings(); final AppSettings appSettings = getAppSettings();
Bundle errorResult = checkRequirements(params); String action = data.getAction();
if (errorResult != null) { if (OpenPgpApi.ACTION_SIGN.equals(action)) {
return errorResult; return signImpl(data, input, output, appSettings);
} else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) {
return encryptAndSignImpl(data, input, output, appSettings, false);
} else if (OpenPgpApi.ACTION_SIGN_AND_ENCTYPT.equals(action)) {
return encryptAndSignImpl(data, input, output, appSettings, true);
} else if (OpenPgpApi.ACTION_DECRYPT_VERIFY.equals(action)) {
return decryptAndVerifyImpl(data, input, output, appSettings);
} else if (OpenPgpApi.ACTION_DOWNLOAD_KEYS.equals(action)) {
// TODO!
return null;
} else if (OpenPgpApi.ACTION_GET_KEY_IDS.equals(action)) {
return getKeyIdsImpl(data);
} else {
return null;
} }
return signImpl(params, input, output, appSettings);
}
@Override
public Bundle encrypt(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output) {
final AppSettings appSettings = getAppSettings();
Bundle errorResult = checkRequirements(params);
if (errorResult != null) {
return errorResult;
}
return encryptAndSignImpl(params, input, output, appSettings, false);
}
@Override
public Bundle signAndEncrypt(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output) {
final AppSettings appSettings = getAppSettings();
Bundle errorResult = checkRequirements(params);
if (errorResult != null) {
return errorResult;
}
return encryptAndSignImpl(params, input, output, appSettings, true);
}
@Override
public Bundle decryptAndVerify(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output) {
final AppSettings appSettings = getAppSettings();
Bundle errorResult = checkRequirements(params);
if (errorResult != null) {
return errorResult;
}
return decryptAndVerifyImpl(params, input, output, appSettings);
}
@Override
public Bundle getKeyIds(Bundle params) {
Bundle errorResult = checkRequirements(params);
if (errorResult != null) {
return errorResult;
}
return getKeyIdsImpl(params);
} }
}; };

View File

@ -21,7 +21,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.util.OpenPgpConstants; import org.openintents.openpgp.util.OpenPgpApi;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract;
@ -38,10 +38,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature; import android.content.pm.Signature;
import android.net.Uri; import android.net.Uri;
import android.os.Binder; import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
/** /**
* Abstract service class for remote APIs that handle app registration and user input. * Abstract service class for remote APIs that handle app registration and user input.
@ -57,7 +53,7 @@ public abstract class RemoteService extends Service {
return mContext; return mContext;
} }
protected Bundle isAllowed(Bundle params) { protected Intent isAllowed(Intent data) {
try { try {
if (isCallerAllowed(false)) { if (isCallerAllowed(false)) {
@ -74,9 +70,9 @@ public abstract class RemoteService extends Service {
} catch (NameNotFoundException e) { } catch (NameNotFoundException e) {
Log.e(Constants.TAG, "Should not happen, returning!", e); Log.e(Constants.TAG, "Should not happen, returning!", e);
// return error // return error
Bundle result = new Bundle(); Intent result = new Intent();
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
result.putParcelable(OpenPgpConstants.RESULT_ERRORS, result.putExtra(OpenPgpApi.RESULT_ERRORS,
new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage()));
return result; return result;
} }
@ -86,14 +82,14 @@ public abstract class RemoteService extends Service {
intent.setAction(RemoteServiceActivity.ACTION_REGISTER); intent.setAction(RemoteServiceActivity.ACTION_REGISTER);
intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_NAME, packageName); intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_NAME, packageName);
intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_SIGNATURE, packageSignature); intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_SIGNATURE, packageSignature);
intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params); intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_REGISTER, intent, 0); PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_REGISTER, intent, 0);
// return PendingIntent to be executed by client // return PendingIntent to be executed by client
Bundle result = new Bundle(); Intent result = new Intent();
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi); result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
return result; return result;
} }
@ -103,14 +99,14 @@ public abstract class RemoteService extends Service {
Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE); intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE);
intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, getString(R.string.api_error_wrong_signature)); intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, getString(R.string.api_error_wrong_signature));
intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params); intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_ERROR, intent, 0); PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_ERROR, intent, 0);
// return PendingIntent to be executed by client // return PendingIntent to be executed by client
Bundle result = new Bundle(); Intent result = new Intent();
result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED);
result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi); result.putExtra(OpenPgpApi.RESULT_INTENT, pi);
return result; return result;
} }

View File

@ -25,7 +25,7 @@ import android.os.Messenger;
import android.support.v7.app.ActionBarActivity; import android.support.v7.app.ActionBarActivity;
import android.view.View; import android.view.View;
import org.openintents.openpgp.util.OpenPgpConstants; import org.openintents.openpgp.util.OpenPgpApi;
import org.sufficientlysecure.htmltextview.HtmlTextView; import org.sufficientlysecure.htmltextview.HtmlTextView;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
@ -51,6 +51,8 @@ public class RemoteServiceActivity extends ActionBarActivity {
public static final String EXTRA_MESSENGER = "messenger"; public static final String EXTRA_MESSENGER = "messenger";
public static final String EXTRA_DATA = "data";
// passphrase action // passphrase action
public static final String EXTRA_SECRET_KEY_ID = "secret_key_id"; public static final String EXTRA_SECRET_KEY_ID = "secret_key_id";
// register action // register action
@ -100,12 +102,9 @@ public class RemoteServiceActivity extends ActionBarActivity {
ProviderHelper.insertApiApp(RemoteServiceActivity.this, ProviderHelper.insertApiApp(RemoteServiceActivity.this,
mSettingsFragment.getAppSettings()); mSettingsFragment.getAppSettings());
// give params through for new service call // give data through for new service call
Bundle oldParams = extras.getBundle(OpenPgpConstants.PI_RESULT_PARAMS); Intent resultData = extras.getParcelable(EXTRA_DATA);
RemoteServiceActivity.this.setResult(RESULT_OK, resultData);
Intent finishIntent = new Intent();
finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, oldParams);
RemoteServiceActivity.this.setResult(RESULT_OK, finishIntent);
RemoteServiceActivity.this.finish(); RemoteServiceActivity.this.finish();
} }
} }
@ -128,9 +127,9 @@ public class RemoteServiceActivity extends ActionBarActivity {
mSettingsFragment.setAppSettings(settings); mSettingsFragment.setAppSettings(settings);
} else if (ACTION_CACHE_PASSPHRASE.equals(action)) { } else if (ACTION_CACHE_PASSPHRASE.equals(action)) {
long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID); long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID);
Bundle oldParams = extras.getBundle(OpenPgpConstants.PI_RESULT_PARAMS); Intent resultData = extras.getParcelable(EXTRA_DATA);
showPassphraseDialog(oldParams, secretKeyId); showPassphraseDialog(resultData, secretKeyId);
} else if (ACTION_SELECT_PUB_KEYS.equals(action)) { } else if (ACTION_SELECT_PUB_KEYS.equals(action)) {
long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS); long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS);
ArrayList<String> missingUserIds = intent ArrayList<String> missingUserIds = intent
@ -167,13 +166,11 @@ public class RemoteServiceActivity extends ActionBarActivity {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
// add key ids to params Bundle for new request // add key ids to params Bundle for new request
Bundle params = extras.getBundle(OpenPgpConstants.PI_RESULT_PARAMS); Intent resultData = extras.getParcelable(EXTRA_DATA);
params.putLongArray(OpenPgpConstants.PARAMS_KEY_IDS, resultData.putExtra(OpenPgpApi.EXTRA_KEY_IDS,
mSelectFragment.getSelectedMasterKeyIds()); mSelectFragment.getSelectedMasterKeyIds());
Intent finishIntent = new Intent(); RemoteServiceActivity.this.setResult(RESULT_OK, resultData);
finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
RemoteServiceActivity.this.setResult(RESULT_OK, finishIntent);
RemoteServiceActivity.this.finish(); RemoteServiceActivity.this.finish();
} }
}, R.string.btn_do_not_save, new View.OnClickListener() { }, R.string.btn_do_not_save, new View.OnClickListener() {
@ -222,7 +219,7 @@ public class RemoteServiceActivity extends ActionBarActivity {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
RemoteServiceActivity.this.setResult(RESULT_OK); RemoteServiceActivity.this.setResult(RESULT_CANCELED);
RemoteServiceActivity.this.finish(); RemoteServiceActivity.this.finish();
} }
}); });
@ -244,16 +241,14 @@ public class RemoteServiceActivity extends ActionBarActivity {
* encryption. Based on mSecretKeyId it asks for a passphrase to open a private key or it asks * encryption. Based on mSecretKeyId it asks for a passphrase to open a private key or it asks
* for a symmetric passphrase * for a symmetric passphrase
*/ */
private void showPassphraseDialog(final Bundle params, long secretKeyId) { private void showPassphraseDialog(final Intent data, long secretKeyId) {
// Message is received after passphrase is cached // Message is received after passphrase is cached
Handler returnHandler = new Handler() { Handler returnHandler = new Handler() {
@Override @Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
// return given params again, for calling the service method again // return given params again, for calling the service method again
Intent finishIntent = new Intent(); RemoteServiceActivity.this.setResult(RESULT_OK, data);
finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
RemoteServiceActivity.this.setResult(RESULT_OK, finishIntent);
} else { } else {
RemoteServiceActivity.this.setResult(RESULT_CANCELED); RemoteServiceActivity.this.setResult(RESULT_CANCELED);
} }
@ -273,9 +268,7 @@ public class RemoteServiceActivity extends ActionBarActivity {
} catch (PgpGeneralException e) { } catch (PgpGeneralException e) {
Log.d(Constants.TAG, "No passphrase for this secret key, do pgp operation directly!"); Log.d(Constants.TAG, "No passphrase for this secret key, do pgp operation directly!");
// return given params again, for calling the service method again // return given params again, for calling the service method again
Intent finishIntent = new Intent(); setResult(RESULT_OK, data);
finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params);
setResult(RESULT_OK, finishIntent);
finish(); finish();
} }
} }

View File

@ -25,6 +25,7 @@ import java.io.FileNotFoundException;
import java.io.InputStream; import java.io.InputStream;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.spongycastle.openpgp.PGPPublicKeyRing; import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
@ -32,6 +33,7 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
import org.sufficientlysecure.keychain.helper.ActionBarHelper; import org.sufficientlysecure.keychain.helper.ActionBarHelper;
import org.sufficientlysecure.keychain.helper.FileHelper; import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
@ -690,11 +692,15 @@ public class DecryptActivity extends DrawerActivity {
} }
if (returnData.getBoolean(KeychainIntentService.RESULT_SIGNATURE)) { PgpDecryptVerifyResult decryptVerifyResult =
String userId = returnData returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT);
.getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID);
mSignatureKeyId = returnData OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult();
.getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID);
if (signatureResult != null) {
String userId = signatureResult.getUserId();
mSignatureKeyId = signatureResult.getKeyId();
mUserIdRest.setText("id: " mUserIdRest.setText("id: "
+ PgpKeyHelper.convertKeyIdToHex(mSignatureKeyId)); + PgpKeyHelper.convertKeyIdToHex(mSignatureKeyId));
if (userId == null) { if (userId == null) {
@ -707,19 +713,32 @@ public class DecryptActivity extends DrawerActivity {
} }
mUserId.setText(userId); mUserId.setText(userId);
if (returnData.getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS)) { switch (signatureResult.getStatus()) {
case OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED: {
mSignatureStatusImage.setImageResource(R.drawable.overlay_ok); mSignatureStatusImage.setImageResource(R.drawable.overlay_ok);
mLookupKey.setVisibility(View.GONE); mLookupKey.setVisibility(View.GONE);
} else if (returnData break;
.getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN)) { }
// TODO!
// case OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED: {
// break;
// }
case OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY: {
mSignatureStatusImage.setImageResource(R.drawable.overlay_error); mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
mLookupKey.setVisibility(View.VISIBLE); mLookupKey.setVisibility(View.VISIBLE);
AppMsg.makeText(DecryptActivity.this, AppMsg.makeText(DecryptActivity.this,
R.string.unknown_signature, R.string.unknown_signature,
AppMsg.STYLE_ALERT).show(); AppMsg.STYLE_ALERT).show();
} else { break;
}
default: {
mSignatureStatusImage.setImageResource(R.drawable.overlay_error); mSignatureStatusImage.setImageResource(R.drawable.overlay_error);
mLookupKey.setVisibility(View.GONE); mLookupKey.setVisibility(View.GONE);
break;
}
} }
mSignatureLayout.setVisibility(View.VISIBLE); mSignatureLayout.setVisibility(View.VISIBLE);
} }

View File

@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.ui;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.service.remote.RegisteredAppsListActivity; import org.sufficientlysecure.keychain.service.remote.RegisteredAppsListActivity;
import org.sufficientlysecure.keychain.util.Log;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
@ -52,6 +53,7 @@ public class DrawerActivity extends ActionBarActivity {
private static Class[] mItemsClass = new Class[] { KeyListPublicActivity.class, private static Class[] mItemsClass = new Class[] { KeyListPublicActivity.class,
EncryptActivity.class, DecryptActivity.class, ImportKeysActivity.class, EncryptActivity.class, DecryptActivity.class, ImportKeysActivity.class,
KeyListSecretActivity.class, RegisteredAppsListActivity.class }; KeyListSecretActivity.class, RegisteredAppsListActivity.class };
private Class mSelectedItem;
private static final int MENU_ID_PREFERENCE = 222; private static final int MENU_ID_PREFERENCE = 222;
private static final int MENU_ID_HELP = 223; private static final int MENU_ID_HELP = 223;
@ -94,6 +96,17 @@ public class DrawerActivity extends ActionBarActivity {
getSupportActionBar().setTitle(mTitle); getSupportActionBar().setTitle(mTitle);
// creates call to onPrepareOptionsMenu() // creates call to onPrepareOptionsMenu()
supportInvalidateOptionsMenu(); supportInvalidateOptionsMenu();
// call intent activity if selected
if(mSelectedItem != null) {
finish();
overridePendingTransition(0, 0);
Intent intent = new Intent(DrawerActivity.this, mSelectedItem);
startActivity(intent);
// disable animation of activity start
overridePendingTransition(0, 0);
}
} }
public void onDrawerOpened(View drawerView) { public void onDrawerOpened(View drawerView) {
@ -182,14 +195,8 @@ public class DrawerActivity extends ActionBarActivity {
mDrawerList.setItemChecked(position, true); mDrawerList.setItemChecked(position, true);
// setTitle(mDrawerTitles[position]); // setTitle(mDrawerTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList); mDrawerLayout.closeDrawer(mDrawerList);
// set selected class
finish(); mSelectedItem = mItemsClass[position];
overridePendingTransition(0, 0);
Intent intent = new Intent(this, mItemsClass[position]);
startActivity(intent);
// disable animation of activity start
overridePendingTransition(0, 0);
} }
/** /**

View File

@ -44,8 +44,10 @@ import org.sufficientlysecure.keychain.ui.widget.UserIdEditor;
import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import android.app.Activity;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
@ -173,7 +175,7 @@ public class EditKeyActivity extends ActionBarActivity {
if (generateDefaultKeys) { if (generateDefaultKeys) {
// Send all information needed to service generate keys in other thread // Send all information needed to service generate keys in other thread
Intent serviceIntent = new Intent(this, KeychainIntentService.class); final Intent serviceIntent = new Intent(this, KeychainIntentService.class);
serviceIntent.setAction(KeychainIntentService.ACTION_GENERATE_DEFAULT_RSA_KEYS); serviceIntent.setAction(KeychainIntentService.ACTION_GENERATE_DEFAULT_RSA_KEYS);
// fill values for this action // fill values for this action
@ -185,7 +187,19 @@ public class EditKeyActivity extends ActionBarActivity {
// Message is received after generating is done in ApgService // Message is received after generating is done in ApgService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
this, R.string.progress_generating, ProgressDialog.STYLE_SPINNER) { this, R.string.progress_generating, ProgressDialog.STYLE_SPINNER, true,
new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
// Stop key generation on cancel
stopService(serviceIntent);
EditKeyActivity.this.setResult(Activity.RESULT_CANCELED);
EditKeyActivity.this.finish();
}
}) {
@Override
public void handleMessage(Message message) { public void handleMessage(Message message) {
// handle messages by standard ApgHandler first // handle messages by standard ApgHandler first
super.handleMessage(message); super.handleMessage(message);

View File

@ -17,22 +17,9 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import java.util.ArrayList;
import java.util.Locale;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
import org.sufficientlysecure.keychain.util.Log;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.nfc.NdefMessage; import android.nfc.NdefMessage;
@ -51,6 +38,18 @@ import android.widget.ArrayAdapter;
import com.beardedhen.androidbootstrap.BootstrapButton; import com.beardedhen.androidbootstrap.BootstrapButton;
import com.devspark.appmsg.AppMsg; import com.devspark.appmsg.AppMsg;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
import org.sufficientlysecure.keychain.ui.dialog.BadImportKeyDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
import java.util.ArrayList;
import java.util.Locale;
public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNavigationListener { public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNavigationListener {
public static final String ACTION_IMPORT_KEY = Constants.INTENT_PREFIX + "IMPORT_KEY"; public static final String ACTION_IMPORT_KEY = Constants.INTENT_PREFIX + "IMPORT_KEY";
public static final String ACTION_IMPORT_KEY_FROM_QR_CODE = Constants.INTENT_PREFIX public static final String ACTION_IMPORT_KEY_FROM_QR_CODE = Constants.INTENT_PREFIX
@ -236,10 +235,10 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
* inside your Activity." * inside your Activity."
* <p/> * <p/>
* from http://stackoverflow.com/questions/10983396/fragment-oncreateview-and-onactivitycreated-called-twice/14295474#14295474 * from http://stackoverflow.com/questions/10983396/fragment-oncreateview-and-onactivitycreated-called-twice/14295474#14295474
* * <p/>
* In our case, if we start ImportKeysActivity with parameters to directly search using a fingerprint, * In our case, if we start ImportKeysActivity with parameters to directly search using a fingerprint,
* the fragment would be loaded twice resulting in the query being empty after the second load. * the fragment would be loaded twice resulting in the query being empty after the second load.
* * <p/>
* Our solution: * Our solution:
* To prevent that a fragment will be loaded again even if it was already loaded loadNavFragment * To prevent that a fragment will be loaded again even if it was already loaded loadNavFragment
* checks against mCurrentNavPostition. * checks against mCurrentNavPostition.
@ -395,23 +394,8 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa
AppMsg.makeText(ImportKeysActivity.this, toastMessage, AppMsg.STYLE_INFO) AppMsg.makeText(ImportKeysActivity.this, toastMessage, AppMsg.STYLE_INFO)
.show(); .show();
if (bad > 0) { if (bad > 0) {
AlertDialog.Builder alert = new AlertDialog.Builder( BadImportKeyDialogFragment badImportKeyDialogFragment = BadImportKeyDialogFragment.newInstance(bad);
ImportKeysActivity.this); badImportKeyDialogFragment.show(getSupportFragmentManager(), "badKeyDialog");
alert.setIcon(android.R.drawable.ic_dialog_alert);
alert.setTitle(R.string.warning);
alert.setMessage(ImportKeysActivity.this.getResources()
.getQuantityString(R.plurals.bad_keys_encountered, bad, bad));
alert.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
alert.setCancelable(true);
alert.create().show();
} }
} }
} }

View File

@ -27,11 +27,13 @@ import java.util.List;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.ui.adapter.AsyncTaskResultWrapper;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListLoader; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListLoader;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListServerLoader; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListServerLoader;
import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.KeyServer;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import android.app.Activity; import android.app.Activity;
@ -42,10 +44,11 @@ import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader; import android.support.v4.content.Loader;
import android.view.View; import android.view.View;
import android.widget.ListView; import android.widget.ListView;
import android.widget.Toast;
import com.devspark.appmsg.AppMsg;
public class ImportKeysListFragment extends ListFragment implements public class ImportKeysListFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<List<ImportKeysListEntry>> { LoaderManager.LoaderCallbacks<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
private static final String ARG_DATA_URI = "uri"; private static final String ARG_DATA_URI = "uri";
private static final String ARG_BYTES = "bytes"; private static final String ARG_BYTES = "bytes";
private static final String ARG_SERVER_QUERY = "query"; private static final String ARG_SERVER_QUERY = "query";
@ -181,11 +184,10 @@ public class ImportKeysListFragment extends ListFragment implements
} }
@Override @Override
public Loader<List<ImportKeysListEntry>> onCreateLoader(int id, Bundle args) { public Loader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> onCreateLoader(int id, Bundle args) {
switch (id) { switch (id) {
case LOADER_ID_BYTES: { case LOADER_ID_BYTES: {
InputData inputData = getInputData(mKeyBytes, mDataUri); InputData inputData = getInputData(mKeyBytes, mDataUri);
return new ImportKeysListLoader(mActivity, inputData); return new ImportKeysListLoader(mActivity, inputData);
} }
case LOADER_ID_SERVER_QUERY: { case LOADER_ID_SERVER_QUERY: {
@ -198,15 +200,15 @@ public class ImportKeysListFragment extends ListFragment implements
} }
@Override @Override
public void onLoadFinished(Loader<List<ImportKeysListEntry>> loader, public void onLoadFinished(Loader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> loader,
List<ImportKeysListEntry> data) { AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> data) {
// Swap the new cursor in. (The framework will take care of closing the // Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.) // old cursor once we return.)
Log.d(Constants.TAG, "data: " + data); Log.d(Constants.TAG, "data: " + data.getResult());
// swap in the real data! // swap in the real data!
mAdapter.setData(data); mAdapter.setData(data.getResult());
mAdapter.notifyDataSetChanged(); mAdapter.notifyDataSetChanged();
setListAdapter(mAdapter); setListAdapter(mAdapter);
@ -222,11 +224,25 @@ public class ImportKeysListFragment extends ListFragment implements
break; break;
case LOADER_ID_SERVER_QUERY: case LOADER_ID_SERVER_QUERY:
Toast.makeText(
Exception error = data.getError();
if(error == null){
AppMsg.makeText(
getActivity(), getResources().getQuantityString(R.plurals.keys_found, getActivity(), getResources().getQuantityString(R.plurals.keys_found,
mAdapter.getCount(), mAdapter.getCount()), mAdapter.getCount(), mAdapter.getCount()),
Toast.LENGTH_SHORT AppMsg.STYLE_INFO
).show(); ).show();
} else if(error instanceof KeyServer.InsufficientQuery){
AppMsg.makeText(getActivity(), R.string.error_keyserver_insufficient_query,
AppMsg.STYLE_ALERT).show();
}else if(error instanceof KeyServer.QueryException){
AppMsg.makeText(getActivity(), R.string.error_keyserver_query,
AppMsg.STYLE_ALERT).show();
}else if(error instanceof KeyServer.TooManyResponses){
AppMsg.makeText(getActivity(), R.string.error_keyserver_too_many_responses,
AppMsg.STYLE_ALERT).show();
}
break; break;
default: default:
@ -235,7 +251,7 @@ public class ImportKeysListFragment extends ListFragment implements
} }
@Override @Override
public void onLoaderReset(Loader<List<ImportKeysListEntry>> loader) { public void onLoaderReset(Loader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> loader) {
switch (loader.getId()) { switch (loader.getId()) {
case LOADER_ID_BYTES: case LOADER_ID_BYTES:
// Clear the data in the adapter. // Clear the data in the adapter.

View File

@ -33,6 +33,7 @@ import se.emilsjolander.stickylistheaders.ApiLevelTooLowException;
import se.emilsjolander.stickylistheaders.StickyListHeadersListView; import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
@ -277,6 +278,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte
startActivity(viewIntent); startActivity(viewIntent);
} }
@TargetApi(11)
public void encrypt(ActionMode mode, long[] keyRingRowIds) { public void encrypt(ActionMode mode, long[] keyRingRowIds) {
// get master key ids from row ids // get master key ids from row ids
long[] keyRingIds = new long[keyRingRowIds.length]; long[] keyRingIds = new long[keyRingRowIds.length];
@ -298,6 +300,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte
* *
* @param keyRingRowIds * @param keyRingRowIds
*/ */
@TargetApi(11)
public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) { public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) {
// Message is received after key is deleted // Message is received after key is deleted
Handler returnHandler = new Handler() { Handler returnHandler = new Handler() {

View File

@ -29,6 +29,7 @@ import org.sufficientlysecure.keychain.ui.adapter.KeyListSecretAdapter;
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
@ -209,6 +210,7 @@ public class KeyListSecretFragment extends ListFragment implements
* *
* @param keyRingRowIds * @param keyRingRowIds
*/ */
@TargetApi(11)
public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) { public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) {
// Message is received after key is deleted // Message is received after key is deleted
Handler returnHandler = new Handler() { Handler returnHandler = new Handler() {

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui.adapter;
/**
* The AsyncTaskResultWrapper is used to wrap a result from a AsyncTask (for example: Loader).
* You can pass the result and an exception in it if an error occurred.
* Concept found at:
* https://stackoverflow.com/questions/19593577/how-to-handle-errors-in-custom-asynctaskloader
* @param <T> - Typ of the result which is wrapped
*/
public class AsyncTaskResultWrapper <T>{
private final T result;
private final Exception error;
public AsyncTaskResultWrapper(T result, Exception error){
this.result = result;
this.error = error;
}
public T getResult() {
return result;
}
public Exception getError() {
return error;
}
}

View File

@ -33,12 +33,13 @@ import org.sufficientlysecure.keychain.util.PositionAwareInputStream;
import android.content.Context; import android.content.Context;
import android.support.v4.content.AsyncTaskLoader; import android.support.v4.content.AsyncTaskLoader;
public class ImportKeysListLoader extends AsyncTaskLoader<List<ImportKeysListEntry>> { public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
Context mContext; Context mContext;
InputData mInputData; InputData mInputData;
ArrayList<ImportKeysListEntry> data = new ArrayList<ImportKeysListEntry>(); ArrayList<ImportKeysListEntry> data = new ArrayList<ImportKeysListEntry>();
AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> entryListWrapper;
public ImportKeysListLoader(Context context, InputData inputData) { public ImportKeysListLoader(Context context, InputData inputData) {
super(context); super(context);
@ -47,15 +48,18 @@ public class ImportKeysListLoader extends AsyncTaskLoader<List<ImportKeysListEnt
} }
@Override @Override
public List<ImportKeysListEntry> loadInBackground() { public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() {
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(data, null);
if (mInputData == null) { if (mInputData == null) {
Log.e(Constants.TAG, "Input data is null!"); Log.e(Constants.TAG, "Input data is null!");
return data; return entryListWrapper;
} }
generateListOfKeyrings(mInputData); generateListOfKeyrings(mInputData);
return data; return entryListWrapper;
} }
@Override @Override
@ -77,7 +81,7 @@ public class ImportKeysListLoader extends AsyncTaskLoader<List<ImportKeysListEnt
} }
@Override @Override
public void deliverResult(List<ImportKeysListEntry> data) { public void deliverResult(AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> data) {
super.deliverResult(data); super.deliverResult(data);
} }

View File

@ -26,15 +26,15 @@ import org.sufficientlysecure.keychain.util.KeyServer;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
public class ImportKeysListServerLoader extends AsyncTaskLoader<List<ImportKeysListEntry>> { public class ImportKeysListServerLoader extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
Context mContext; Context mContext;
String mServerQuery; String mServerQuery;
String mKeyServer; String mKeyServer;
ArrayList<ImportKeysListEntry> data = new ArrayList<ImportKeysListEntry>(); private ArrayList<ImportKeysListEntry> entryList = new ArrayList<ImportKeysListEntry>();
private AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> entryListWrapper;
public ImportKeysListServerLoader(Context context, String serverQuery, String keyServer) { public ImportKeysListServerLoader(Context context, String serverQuery, String keyServer) {
super(context); super(context);
@ -44,15 +44,18 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<List<ImportKeysL
} }
@Override @Override
public List<ImportKeysListEntry> loadInBackground() { public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() {
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, null);
if (mServerQuery == null) { if (mServerQuery == null) {
Log.e(Constants.TAG, "mServerQuery is null!"); Log.e(Constants.TAG, "mServerQuery is null!");
return data; return entryListWrapper;
} }
queryServer(mServerQuery, mKeyServer); queryServer(mServerQuery, mKeyServer);
return data; return entryListWrapper;
} }
@Override @Override
@ -74,7 +77,7 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<List<ImportKeysL
} }
@Override @Override
public void deliverResult(List<ImportKeysListEntry> data) { public void deliverResult(AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> data) {
super.deliverResult(data); super.deliverResult(data);
} }
@ -87,13 +90,17 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<List<ImportKeysL
ArrayList<ImportKeysListEntry> searchResult = server.search(query); ArrayList<ImportKeysListEntry> searchResult = server.search(query);
// add result to data // add result to data
data.addAll(searchResult); entryList.addAll(searchResult);
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, null);
} catch (KeyServer.InsufficientQuery e) { } catch (KeyServer.InsufficientQuery e) {
Log.e(Constants.TAG, "InsufficientQuery", e); Log.e(Constants.TAG, "InsufficientQuery", e);
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e);
} catch (KeyServer.QueryException e) { } catch (KeyServer.QueryException e) {
Log.e(Constants.TAG, "QueryException", e); Log.e(Constants.TAG, "QueryException", e);
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e);
} catch (KeyServer.TooManyResponses e) { } catch (KeyServer.TooManyResponses e) {
Log.e(Constants.TAG, "TooManyResponses", e); Log.e(Constants.TAG, "TooManyResponses", e);
entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e);
} }
} }

View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import org.sufficientlysecure.keychain.R;
public class BadImportKeyDialogFragment extends DialogFragment {
private static final String ARG_BAD_IMPORT = "bad_import";
/**
* Creates a new instance of this Bad Import Key DialogFragment
*
* @param bad
* @return
*/
public static BadImportKeyDialogFragment newInstance(int bad) {
BadImportKeyDialogFragment frag = new BadImportKeyDialogFragment();
Bundle args = new Bundle();
args.putInt(ARG_BAD_IMPORT, bad);
frag.setArguments(args);
return frag;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final FragmentActivity activity = getActivity();
final int badImport = getArguments().getInt(ARG_BAD_IMPORT);
AlertDialog.Builder alert = new AlertDialog.Builder(activity);
alert.setIcon(R.drawable.ic_dialog_alert_holo_light);
alert.setTitle(R.string.warning);
alert.setMessage(activity.getResources()
.getQuantityString(R.plurals.bad_keys_encountered, badImport, badImport));
alert.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
alert.setCancelable(true);
return alert.create();
}
}

View File

@ -0,0 +1,152 @@
/*
* Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.Choice;
import java.util.Vector;
public class CreateKeyDialogFragment extends DialogFragment {
public interface OnAlgorithmSelectedListener {
public void onAlgorithmSelected(Choice algorithmChoice, int keySize);
}
private static final String ARG_EDITOR_CHILD_COUNT = "child_count";
private int mNewKeySize;
private Choice mNewKeyAlgorithmChoice;
private OnAlgorithmSelectedListener mAlgorithmSelectedListener;
public void setOnAlgorithmSelectedListener(OnAlgorithmSelectedListener listener) {
mAlgorithmSelectedListener = listener;
}
public static CreateKeyDialogFragment newInstance(int mEditorChildCount) {
CreateKeyDialogFragment frag = new CreateKeyDialogFragment();
Bundle args = new Bundle();
args.putInt(ARG_EDITOR_CHILD_COUNT, mEditorChildCount);
frag.setArguments(args);
return frag;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final FragmentActivity context = getActivity();
final LayoutInflater mInflater;
final int childCount = getArguments().getInt(ARG_EDITOR_CHILD_COUNT);
mInflater = context.getLayoutInflater();
AlertDialog.Builder dialog = new AlertDialog.Builder(context);
View view = mInflater.inflate(R.layout.create_key_dialog, null);
dialog.setView(view);
dialog.setTitle(R.string.title_create_key);
boolean wouldBeMasterKey = (childCount == 0);
final Spinner algorithm = (Spinner) view.findViewById(R.id.create_key_algorithm);
Vector<Choice> choices = new Vector<Choice>();
choices.add(new Choice(Id.choice.algorithm.dsa, getResources().getString(
R.string.dsa)));
if (!wouldBeMasterKey) {
choices.add(new Choice(Id.choice.algorithm.elgamal, getResources().getString(
R.string.elgamal)));
}
choices.add(new Choice(Id.choice.algorithm.rsa, getResources().getString(
R.string.rsa)));
ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(context,
android.R.layout.simple_spinner_item, choices);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
algorithm.setAdapter(adapter);
// make RSA the default
for (int i = 0; i < choices.size(); ++i) {
if (choices.get(i).getId() == Id.choice.algorithm.rsa) {
algorithm.setSelection(i);
break;
}
}
final Spinner keySize = (Spinner) view.findViewById(R.id.create_key_size);
ArrayAdapter<CharSequence> keySizeAdapter = ArrayAdapter.createFromResource(
context, R.array.key_size_spinner_values,
android.R.layout.simple_spinner_item);
keySizeAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
keySize.setAdapter(keySizeAdapter);
keySize.setSelection(3); // Default to 4096 for the key length
dialog.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface di, int id) {
di.dismiss();
try {
int nKeyIndex = keySize.getSelectedItemPosition();
switch (nKeyIndex) {
case 0:
mNewKeySize = 512;
break;
case 1:
mNewKeySize = 1024;
break;
case 2:
mNewKeySize = 2048;
break;
case 3:
mNewKeySize = 4096;
break;
}
} catch (NumberFormatException e) {
mNewKeySize = 0;
}
mNewKeyAlgorithmChoice = (Choice) algorithm.getSelectedItem();
mAlgorithmSelectedListener.onAlgorithmSelected(mNewKeyAlgorithmChoice, mNewKeySize);
}
});
dialog.setCancelable(true);
dialog.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface di, int id) {
di.dismiss();
}
});
return dialog.create();
}
}

View File

@ -83,7 +83,7 @@ public class DeleteFileDialogFragment extends DialogFragment {
intent.putExtra(KeychainIntentService.EXTRA_DATA, data); intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
ProgressDialogFragment deletingDialog = ProgressDialogFragment.newInstance( ProgressDialogFragment deletingDialog = ProgressDialogFragment.newInstance(
R.string.progress_deleting_securely, ProgressDialog.STYLE_HORIZONTAL); R.string.progress_deleting_securely, ProgressDialog.STYLE_HORIZONTAL, false, null);
// Message is received after deleting is done in ApgService // Message is received after deleting is done in ApgService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(activity, deletingDialog) { KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(activity, deletingDialog) {

View File

@ -17,17 +17,6 @@
package org.sufficientlysecure.keychain.ui.dialog; package org.sufficientlysecure.keychain.ui.dialog;
import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.Log;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.content.DialogInterface; import android.content.DialogInterface;
@ -40,6 +29,14 @@ import android.os.RemoteException;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.Log;
import java.util.ArrayList; import java.util.ArrayList;
public class DeleteKeyDialogFragment extends DialogFragment { public class DeleteKeyDialogFragment extends DialogFragment {

View File

@ -21,28 +21,40 @@ import android.app.Activity;
import android.app.Dialog; import android.app.Dialog;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnKeyListener; import android.content.DialogInterface.OnKeyListener;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.view.KeyEvent; import android.view.KeyEvent;
import org.sufficientlysecure.keychain.R;
public class ProgressDialogFragment extends DialogFragment { public class ProgressDialogFragment extends DialogFragment {
private static final String ARG_MESSAGE_ID = "message_id"; private static final String ARG_MESSAGE_ID = "message_id";
private static final String ARG_STYLE = "style"; private static final String ARG_STYLE = "style";
private static final String ARG_CANCELABLE = "cancelable";
private OnCancelListener mOnCancelListener;
/** /**
* Creates new instance of this fragment * Creates new instance of this fragment
* *
* @param id * @param messageId
* @param style
* @param cancelable
* @return * @return
*/ */
public static ProgressDialogFragment newInstance(int messageId, int style) { public static ProgressDialogFragment newInstance(int messageId, int style, boolean cancelable,
OnCancelListener onCancelListener) {
ProgressDialogFragment frag = new ProgressDialogFragment(); ProgressDialogFragment frag = new ProgressDialogFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putInt(ARG_MESSAGE_ID, messageId); args.putInt(ARG_MESSAGE_ID, messageId);
args.putInt(ARG_STYLE, style); args.putInt(ARG_STYLE, style);
args.putBoolean(ARG_CANCELABLE, cancelable);
frag.setArguments(args); frag.setArguments(args);
frag.mOnCancelListener = onCancelListener;
return frag; return frag;
} }
@ -60,7 +72,6 @@ public class ProgressDialogFragment extends DialogFragment {
/** /**
* Updates progress of dialog * Updates progress of dialog
* *
* @param messageId
* @param progress * @param progress
* @param max * @param max
*/ */
@ -74,7 +85,7 @@ public class ProgressDialogFragment extends DialogFragment {
/** /**
* Updates progress of dialog * Updates progress of dialog
* *
* @param messageId * @param message
* @param progress * @param progress
* @param max * @param max
*/ */
@ -86,12 +97,20 @@ public class ProgressDialogFragment extends DialogFragment {
dialog.setMax(max); dialog.setMax(max);
} }
@Override
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
if (this.mOnCancelListener != null)
this.mOnCancelListener.onCancel(dialog);
}
/** /**
* Creates dialog * Creates dialog
*/ */
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
Activity activity = getActivity(); final Activity activity = getActivity();
ProgressDialog dialog = new ProgressDialog(activity); ProgressDialog dialog = new ProgressDialog(activity);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
@ -100,10 +119,22 @@ public class ProgressDialogFragment extends DialogFragment {
int messageId = getArguments().getInt(ARG_MESSAGE_ID); int messageId = getArguments().getInt(ARG_MESSAGE_ID);
int style = getArguments().getInt(ARG_STYLE); int style = getArguments().getInt(ARG_STYLE);
boolean cancelable = getArguments().getBoolean(ARG_CANCELABLE);
dialog.setMessage(getString(messageId)); dialog.setMessage(getString(messageId));
dialog.setProgressStyle(style); dialog.setProgressStyle(style);
if (cancelable) {
dialog.setButton(DialogInterface.BUTTON_NEGATIVE,
activity.getString(R.string.progress_cancel),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
}
// Disable the back button // Disable the back button
OnKeyListener keyListener = new OnKeyListener() { OnKeyListener keyListener = new OnKeyListener() {

View File

@ -17,28 +17,26 @@
package org.sufficientlysecure.keychain.ui.dialog; package org.sufficientlysecure.keychain.ui.dialog;
import java.util.ArrayList;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.QrCodeUtils;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.QrCodeUtils;
import java.util.ArrayList;
public class ShareQrCodeDialogFragment extends DialogFragment { public class ShareQrCodeDialogFragment extends DialogFragment {
private static final String ARG_KEY_URI = "uri"; private static final String ARG_KEY_URI = "uri";
private static final String ARG_FINGERPRINT_ONLY = "fingerprint_only"; private static final String ARG_FINGERPRINT_ONLY = "fingerprint_only";

View File

@ -16,20 +16,6 @@
package org.sufficientlysecure.keychain.ui.widget; package org.sufficientlysecure.keychain.ui.widget;
import java.util.Vector;
import org.spongycastle.openpgp.PGPSecretKey;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener;
import org.sufficientlysecure.keychain.util.Choice;
import android.app.AlertDialog;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
@ -43,13 +29,25 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import com.beardedhen.androidbootstrap.BootstrapButton; import com.beardedhen.androidbootstrap.BootstrapButton;
import org.spongycastle.openpgp.PGPSecretKey;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.ui.dialog.CreateKeyDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener;
import org.sufficientlysecure.keychain.util.Choice;
import java.util.Vector;
public class SectionView extends LinearLayout implements OnClickListener, EditorListener { public class SectionView extends LinearLayout implements OnClickListener, EditorListener {
private LayoutInflater mInflater; private LayoutInflater mInflater;
private BootstrapButton mPlusButton; private BootstrapButton mPlusButton;
@ -149,84 +147,16 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
} }
case Id.type.key: { case Id.type.key: {
AlertDialog.Builder dialog = new AlertDialog.Builder(getContext()); CreateKeyDialogFragment mCreateKeyDialogFragment = CreateKeyDialogFragment.newInstance(mEditors.getChildCount());
mCreateKeyDialogFragment.setOnAlgorithmSelectedListener(new CreateKeyDialogFragment.OnAlgorithmSelectedListener() {
View view = mInflater.inflate(R.layout.create_key_dialog, null); @Override
dialog.setView(view); public void onAlgorithmSelected(Choice algorithmChoice, int keySize) {
dialog.setTitle(R.string.title_create_key); mNewKeyAlgorithmChoice = algorithmChoice;
mNewKeySize = keySize;
boolean wouldBeMasterKey = (mEditors.getChildCount() == 0);
final Spinner algorithm = (Spinner) view.findViewById(R.id.create_key_algorithm);
Vector<Choice> choices = new Vector<Choice>();
choices.add(new Choice(Id.choice.algorithm.dsa, getResources().getString(
R.string.dsa)));
if (!wouldBeMasterKey) {
choices.add(new Choice(Id.choice.algorithm.elgamal, getResources().getString(
R.string.elgamal)));
}
choices.add(new Choice(Id.choice.algorithm.rsa, getResources().getString(
R.string.rsa)));
ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(getContext(),
android.R.layout.simple_spinner_item, choices);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
algorithm.setAdapter(adapter);
// make RSA the default
for (int i = 0; i < choices.size(); ++i) {
if (choices.get(i).getId() == Id.choice.algorithm.rsa) {
algorithm.setSelection(i);
break;
}
}
final Spinner keySize = (Spinner) view.findViewById(R.id.create_key_size);
ArrayAdapter<CharSequence> keySizeAdapter = ArrayAdapter.createFromResource(
getContext(), R.array.key_size_spinner_values,
android.R.layout.simple_spinner_item);
keySizeAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
keySize.setAdapter(keySizeAdapter);
keySize.setSelection(3); // Default to 4096 for the key length
dialog.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface di, int id) {
di.dismiss();
try {
int nKeyIndex = keySize.getSelectedItemPosition();
switch (nKeyIndex) {
case 0:
mNewKeySize = 512;
break;
case 1:
mNewKeySize = 1024;
break;
case 2:
mNewKeySize = 2048;
break;
case 3:
mNewKeySize = 4096;
break;
}
} catch (NumberFormatException e) {
mNewKeySize = 0;
}
mNewKeyAlgorithmChoice = (Choice) algorithm.getSelectedItem();
createKey(); createKey();
} }
}); });
mCreateKeyDialogFragment.show(mActivity.getSupportFragmentManager(), "createKeyDialog");
dialog.setCancelable(true);
dialog.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface di, int id) {
di.dismiss();
}
});
dialog.create().show();
break; break;
} }
@ -282,7 +212,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
private void createKey() { private void createKey() {
// Send all information needed to service to edit key in other thread // Send all information needed to service to edit key in other thread
Intent intent = new Intent(mActivity, KeychainIntentService.class); final Intent intent = new Intent(mActivity, KeychainIntentService.class);
intent.setAction(KeychainIntentService.ACTION_GENERATE_KEY); intent.setAction(KeychainIntentService.ACTION_GENERATE_KEY);
@ -309,7 +239,12 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
// show progress dialog // show progress dialog
mGeneratingDialog = ProgressDialogFragment.newInstance(R.string.progress_generating, mGeneratingDialog = ProgressDialogFragment.newInstance(R.string.progress_generating,
ProgressDialog.STYLE_SPINNER); ProgressDialog.STYLE_SPINNER, true, new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
mActivity.stopService(intent);
}
});
// Message is received after generating is done in ApgService // Message is received after generating is done in ApgService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(mActivity, KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(mActivity,

View File

@ -1,4 +1,6 @@
/* /*
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2011 Thialfihar <thi@thialfihar.org>
* Copyright (C) 2011 Senecaso * Copyright (C) 2011 Senecaso
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -32,6 +34,7 @@ import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.Locale;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
@ -172,11 +175,11 @@ public class HkpKeyServer extends KeyServer {
if (e.getCode() == 404) { if (e.getCode() == 404) {
return results; return results;
} else { } else {
if (e.getData().toLowerCase().contains("no keys found")) { if (e.getData().toLowerCase(Locale.US).contains("no keys found")) {
return results; return results;
} else if (e.getData().toLowerCase().contains("too many")) { } else if (e.getData().toLowerCase(Locale.US).contains("too many")) {
throw new TooManyResponses(); throw new TooManyResponses();
} else if (e.getData().toLowerCase().contains("insufficient")) { } else if (e.getData().toLowerCase(Locale.US).contains("insufficient")) {
throw new InsufficientQuery(); throw new InsufficientQuery();
} }
} }

View File

@ -1,4 +1,6 @@
/* /*
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2011 Thialfihar <thi@thialfihar.org>
* Copyright (C) 2011 Senecaso * Copyright (C) 2011 Senecaso
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -16,14 +18,8 @@
package org.sufficientlysecure.keychain.util; package org.sufficientlysecure.keychain.util;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import android.os.Parcel;
import android.os.Parcelable;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
public abstract class KeyServer { public abstract class KeyServer {

View File

@ -6,7 +6,7 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:padding="16dp" android:padding="16dp"
android:orientation="vertical"> android:orientation="vertical">

View File

@ -6,7 +6,7 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:padding="16dp" android:padding="16dp"
android:orientation="vertical"> android:orientation="vertical">

View File

@ -71,7 +71,7 @@
<LinearLayout <LinearLayout
android:id="@+id/editors" android:id="@+id/editors"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="wrap_content"
android:orientation="vertical" /> android:orientation="vertical" />
</ScrollView> </ScrollView>

View File

@ -1,11 +1,11 @@
<html> <html>
<head></head> <head></head>
<body> <body>
<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p> <p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> ist eine OpenPGP-Implementierung für Android. Die Entwicklung begann als ein Fork von Android Privacy Guard (APG).</p> <p><a href="http://www.openkeychain.org">OpenKeychain</a> ist eine OpenPGP implementation für Android.</p>
<p>Lizenz: GPLv3+</p> <p>Lizenz: GPLv3+</p>
<h2>Entwickler OpenPGP Keychain</h2> <h2>Entwickler OpenKeychain</h2>
<ul> <ul>
<li>Dominik Schürmann (Leitender Entwickler)</li> <li>Dominik Schürmann (Leitender Entwickler)</li>
<li>Ash Hughes (crypto patches)</li> <li>Ash Hughes (crypto patches)</li>
@ -23,9 +23,9 @@
<h2>Bibliotheken</h2> <h2>Bibliotheken</h2>
<ul> <ul>
<li> <li>
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li> <a href="http://developer.android.com/tools/support-library/index.html">Android Support Bibliothek v4</a> (Apache Lizenz v2)</li>
<li> <li>
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li> <a href="http://developer.android.com/tools/support-library/index.html">Android Support Bibliothek v7 'appcompat'</a> (Apache Lizenz v2)</li>
<li> <li>
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache Lizenz v2)</li> <a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache Lizenz v2)</li>
<li> <li>
@ -36,6 +36,8 @@
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 Lizenz)</li> <a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 Lizenz)</li>
<li> <li>
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache Lizenz v2)</li> <a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache Lizenz v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Bibliothek</a> (Apache Lizenz v2)</li>
<li>Icons von <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike Lizenz 3.0)</li> <li>Icons von <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike Lizenz 3.0)</li>
<li>Icons von <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li> <li>Icons von <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul> </ul>

View File

@ -16,12 +16,12 @@
<h2>2.2</h2> <h2>2.2</h2>
<ul> <ul>
<li>new design with navigation drawer</li> <li>new design with navigation drawer</li>
<li>new public key list design</li> <li>Neus Design für die Liste der öffentlichen Schlüssel</li>
<li>new public key view</li> <li>new public key view</li>
<li>bug fixes for importing of keys</li> <li>Fehler beim Schlüsselimport behoben</li>
<li>key cross-certification (thanks to Ash Hughes)</li> <li>key cross-certification (thanks to Ash Hughes)</li>
<li>handle UTF-8 passwords properly (thanks to Ash Hughes)</li> <li>handle UTF-8 passwords properly (thanks to Ash Hughes)</li>
<li>first version with new languages (thanks to the contributors on Transifex)</li> <li>Erste Version mit neuen Sprachen (Danke an die Mitwirkenden bei Transifex)</li>
<li>sharing of keys via QR Codes fixed and improved</li> <li>sharing of keys via QR Codes fixed and improved</li>
<li>package signature verification for API</li> <li>package signature verification for API</li>
</ul> </ul>
@ -31,16 +31,16 @@
</ul> </ul>
<h2>2.1</h2> <h2>2.1</h2>
<ul> <ul>
<li>lots of bug fixes</li> <li>Viele Fehler behoben</li>
<li>new API for developers</li> <li>Neue API für Entwickler</li>
<li>PRNG bug fix by Google</li> <li>PRNG Bugfix von Google</li>
</ul> </ul>
<h2>2.0</h2> <h2>2.0</h2>
<ul> <ul>
<li>complete redesign</li> <li>Komlett neu designd</li>
<li>share public keys via qr codes, nfc beam</li> <li>share public keys via qr codes, nfc beam</li>
<li>sign keys</li> <li>Schlüssel signieren</li>
<li>upload keys to server</li> <li>Schlüssel auf den Server hochladen</li>
<li>fixes import issues</li> <li>fixes import issues</li>
<li>new AIDL API</li> <li>new AIDL API</li>
</ul> </ul>
@ -56,25 +56,25 @@
<h2>1.0.7</h2> <h2>1.0.7</h2>
<ul> <ul>
<li>fixed problem with signature verification of texts with trailing newline</li> <li>fixed problem with signature verification of texts with trailing newline</li>
<li>more options for pass phrase cache time to live (20, 40, 60 mins)</li> <li>weitere Optionen für die Time-to-live des Passphrasencaches (20, 40, 60 mins)</li>
</ul> </ul>
<h2>1.0.6</h2> <h2>1.0.6</h2>
<ul> <ul>
<li>account adding crash on Froyo fixed</li> <li>crash beim Hinzufügen eines Kontos auf Froyo repariert</li>
<li>sichere Dateilöschung</li> <li>sichere Dateilöschung</li>
<li>option to delete key file after import</li> <li>Option, um Schlüsseldatei nach dem Import zu löschen</li>
<li>Streamverschlüsselung/-entschlüsselung (Galerie, etc.)</li> <li>Streamverschlüsselung/-entschlüsselung (Galerie, etc.)</li>
<li>new options (language, force v3 signatures)</li> <li>neue Optionen (Sprache, v3-Unterschriften erzwingen)</li>
<li>interface changes</li> <li>Interfaceänderungen</li>
<li>Fehlerbehebungen</li> <li>Fehlerbehebungen</li>
</ul> </ul>
<h2>1.0.5</h2> <h2>1.0.5</h2>
<ul> <ul>
<li>Deutsche und Italienische Übersetzung</li> <li>Deutsche und Italienische Übersetzung</li>
<li>much smaller package, due to reduced BC sources</li> <li>viel kleineres Paket, dank reduzierter BC Quellen</li>
<li>new preferences GUI</li> <li>Neues Einstellungs-GUI</li>
<li>layout adjustment for localization</li> <li>Lay-Out-Anpassung für die Lokalisierung</li>
<li>signature bugfix</li> <li>Fehler bei Signatur behoben</li>
</ul> </ul>
<h2>1.0.4</h2> <h2>1.0.4</h2>
<ul> <ul>
@ -82,11 +82,11 @@
</ul> </ul>
<h2>1.0.3</h2> <h2>1.0.3</h2>
<ul> <ul>
<li>fixed crashes during encryption/signing and possibly key export</li> <li>Absturz während der Verschlüsselung/Signierung und möglicherweise Schlüsselexport behoben.</li>
</ul> </ul>
<h2>1.0.2</h2> <h2>1.0.2</h2>
<ul> <ul>
<li>filterable key lists</li> <li>Filterbare Schlüsselliste</li>
<li>smarter pre-selection of encryption keys</li> <li>smarter pre-selection of encryption keys</li>
<li>new Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers</li> <li>new Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers</li>
<li>fixes and additional features (key preselection) for K-9 Mail, new beta build available</li> <li>fixes and additional features (key preselection) for K-9 Mail, new beta build available</li>
@ -100,7 +100,7 @@
<li>K-9 Mail integration, APG supporting beta build of K-9 Mail</li> <li>K-9 Mail integration, APG supporting beta build of K-9 Mail</li>
<li>support of more file managers (including ASTRO)</li> <li>support of more file managers (including ASTRO)</li>
<li>Slovenian translation</li> <li>Slovenian translation</li>
<li>new database, much faster, less memory usage</li> <li>Neue Datenbank, viel schneller, weniger Speicherbedarf</li>
<li>defined Intents and content provider for other apps</li> <li>defined Intents and content provider for other apps</li>
<li>Fehlerbehebungen</li> <li>Fehlerbehebungen</li>
</ul> </ul>

View File

@ -6,14 +6,14 @@
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p> <p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
<h2>I found a bug in OpenPGP Keychain!</h2> <h2>Ich habe einen Fehler in OpenKeychain gefunden!</h2>
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p> <p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
<h2>Contribute</h2> <h2>Contribute</h2>
<p>If you want to help us developing OpenPGP Keychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p> <p>If you want to help us developing OpenKeychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
<h2>Translations</h2> <h2>Übersetzungen</h2>
<p>Help translating OpenPGP Keychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p> <p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain on Transifex</a>.</p>
</body> </body>
</html> </html>

View File

@ -1,11 +1,11 @@
<html> <html>
<head></head> <head></head>
<body> <body>
<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p> <p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> is an OpenPGP implementation for Android. The development began as a fork of Android Privacy Guard (APG).</p> <p><a href="http://www.openkeychain.org">OpenKeychain</a> is an OpenPGP implementation for Android.</p>
<p>License: GPLv3+</p> <p>License: GPLv3+</p>
<h2>Developers OpenPGP Keychain</h2> <h2>Developers OpenKeychain</h2>
<ul> <ul>
<li>Dominik Schürmann (Lead developer)</li> <li>Dominik Schürmann (Lead developer)</li>
<li>Ash Hughes (crypto patches)</li> <li>Ash Hughes (crypto patches)</li>
@ -36,6 +36,8 @@
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li> <a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
<li> <li>
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li> <a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li> <li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li> <li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul> </ul>

View File

@ -6,14 +6,14 @@
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p> <p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
<h2>I found a bug in OpenPGP Keychain!</h2> <h2>I found a bug in OpenKeychain!</h2>
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p> <p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
<h2>Contribute</h2> <h2>Contribute</h2>
<p>If you want to help us developing OpenPGP Keychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p> <p>If you want to help us developing OpenKeychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
<h2>Translations</h2> <h2>Translations</h2>
<p>Help translating OpenPGP Keychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p> <p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain on Transifex</a>.</p>
</body> </body>
</html> </html>

View File

@ -1,11 +1,11 @@
<html> <html>
<head></head> <head></head>
<body> <body>
<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p> <p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> es una implementación de OpenPGP para Android. Su desarrollo comenzó como un fork de Android Privacy Guard (APG).</p> <p><a href="http://www.openkeychain.org">OpenKeychain</a> es una implementación de OpenPGP para Android.</p>
<p>Licencia: GPLv3+</p> <p>Licencia: GPLv3+</p>
<h2>Desarrolladores de OpenPGP Keychain</h2> <h2>Desarrolladores OpenKeychain</h2>
<ul> <ul>
<li>Dominik Schürmann (Desarrollador principal)</li> <li>Dominik Schürmann (Desarrollador principal)</li>
<li>Ash Hughes (Parches cryptográficos)</li> <li>Ash Hughes (Parches cryptográficos)</li>
@ -36,6 +36,8 @@
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (Licencia MIT X11)</li> <a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (Licencia MIT X11)</li>
<li> <li>
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Licencia Apache v2)</li> <a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Licencia Apache v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Librería Android AppMsg</a> (Licencia Apache v2)</li>
<li>Icons de <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Compartir-Igual licencia 3.0)</li> <li>Icons de <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Compartir-Igual licencia 3.0)</li>
<li>Iconos de <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Dominio Público)</li> <li>Iconos de <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Dominio Público)</li>
</ul> </ul>

View File

@ -6,14 +6,14 @@
<p>Es recomendable que instales <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> para una mejor selección de archivos y <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> para escanear los códigos QR generados. Pulsando en los enlaces se abrirá Google Play o F-Droid.</p> <p>Es recomendable que instales <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> para una mejor selección de archivos y <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> para escanear los códigos QR generados. Pulsando en los enlaces se abrirá Google Play o F-Droid.</p>
<h2>¡He encontrado un bug en OpenPGP Keychain!</h2> <h2>¡He encontrado un bug en OpenKeychain!</h2>
<p>Por favor, informa de errores usando el <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">seguimiento de incidencias de OpenPGP Keychain</a>.</p> <p>Por favor, informa de errores usando el <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">seguimiento de incidencias de OpenKeychain</a>.</p>
<h2>Aportar</h2> <h2>Aportar</h2>
<p>Si quieres ayudarnos con el desarrollo de OpenPGP Keychain aportando código <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">sigue nuestra pequeña guía en Github</a>.</p> <p>Si quieres ayudarnos con el desarrollo de OpenKeychain aportando código <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">sigue nuestra pequeña guía en Github</a>.</p>
<h2>Traducciones</h2> <h2>Traducciones</h2>
<p>¡Ayúdanos a traducir OpenPGP Keychain! Todo el mundo es bienvenido en <a href="https://www.transifex.com/projects/p/openpgp-keychain/">Transifex - OpenPGP Keychain</a>.</p> <p>¡Ayúdanos a traducir OpenKeychain! Todo el mundo es bienvenido en <a href="https://www.transifex.com/projects/p/openpgp-keychain/">Transifex - OpenKeychain</a>.</p>
</body> </body>
</html> </html>

View File

@ -1,11 +1,11 @@
<html> <html>
<head></head> <head></head>
<body> <body>
<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p> <p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
<p><a href="http://sufficientlysecure.org/keychain">Le porte-clefs OpenPGP</a> est une implémentation d'OpenPGP pour Android. Le développement a commencé comme bifurcation d'Android Privacy Guard (APG).</p> <p><a href="http://www.openkeychain.org">OpenKeychain</a> est une implémentation d'OpenPGP pour Android.</p>
<p>Licence : GPLv3+</p> <p>Licence : GPLv3+</p>
<h2>Les développeurs du Porte-clefs OpenPGP</h2> <h2>Les développeurs d'OpenKeychain</h2>
<ul> <ul>
<li>Dominik Schürmann (développeur principal)</li> <li>Dominik Schürmann (développeur principal)</li>
<li>Ash Hughes (correctif crypto)</li> <li>Ash Hughes (correctif crypto)</li>
@ -36,6 +36,8 @@
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (Licence MIT X11)</li> <a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (Licence MIT X11)</li>
<li> <li>
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Licence Apache v2)</li> <a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Licence Apache v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Bibliothèque Android AppMsg</a> (Licence Apache v2)</li>
<li>Icônes du <a href="http://rrze-icon-set.berlios.de/">jeu d'icônes RRZE</a> (Licence Creative Commons Paternité - Partage des Conditions Initiales à l'Identique 3.0)</li> <li>Icônes du <a href="http://rrze-icon-set.berlios.de/">jeu d'icônes RRZE</a> (Licence Creative Commons Paternité - Partage des Conditions Initiales à l'Identique 3.0)</li>
<li>Icônes du <a href="http://tango.freedesktop.org/">jeu d'icônes Tango</a> (domaine public)</li> <li>Icônes du <a href="http://tango.freedesktop.org/">jeu d'icônes Tango</a> (domaine public)</li>
</ul> </ul>

View File

@ -6,14 +6,14 @@
<p>Il vous est recommendé d'installer le <a href="market://details?id=org.openintents.filemanager">gestionnaire de fichiers OI</a> pour sa fonction améliorée de séléction des fichiers et le <a href="market://details?id=com.google.zxing.client.android">lecteur de codes à barres</a> pour balayer les codes QR générés. Cliquer sur les liens ouvrira Google Play Store ou F-Droid pour l'installation.</p> <p>Il vous est recommendé d'installer le <a href="market://details?id=org.openintents.filemanager">gestionnaire de fichiers OI</a> pour sa fonction améliorée de séléction des fichiers et le <a href="market://details?id=com.google.zxing.client.android">lecteur de codes à barres</a> pour balayer les codes QR générés. Cliquer sur les liens ouvrira Google Play Store ou F-Droid pour l'installation.</p>
<h2>J'ai trouvé un bogue dans le Porte-clefs OpenPGP !</h2> <h2>J'ai trouvé un bogue dans OpenKeychain !</h2>
<p>Veuillez rapporter le bogue en utilisant le <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">gestionnaire de bogues du Porte-clefs OpenPGP</a>.</p> <p>Veuillez rapporter le bogue en utilisant le <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">gestionnaire de bogue d'OpenKeychain</a>.</p>
<h2>Contribuer</h2> <h2>Contribuer</h2>
<p>Si vous voulez nous aider à développer le Porte-clefs OpenPGP en y contribuant par du code, <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">veuillez suivre notre petit guide sur Github</a>.</p> <p>Si vous voulez nous aider à développer OpenKeychain en y contribuant par du code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">veuillez suivre notre petit guide sur Github</a>.</p>
<h2>Traductions</h2> <h2>Traductions</h2>
<p>Aidez-nous à traduire le Porte-clefs OpenPGP ! Tout le monde peut y participer sur la <a href="https://www.transifex.com/projects/p/openpgp-keychain/">page Transifex du Porte-clefs OpenPGP Keychain</a>.</p> <p>Aidez-nous à traduire le OpenKeychain ! Tout le monde peut y participer sur la <a href="https://www.transifex.com/projects/p/openpgp-keychain/">page d'OpenKeychain sur Transifex</a>.</p>
</body> </body>
</html> </html>

View File

@ -1,43 +1,45 @@
<html> <html>
<head></head> <head></head>
<body> <body>
<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p> <p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> is an OpenPGP implementation for Android. The development began as a fork of Android Privacy Guard (APG).</p> <p><a href="http://www.openkeychain.org">OpenKeychain</a> un implementazione OpenPGP per Android.</p>
<p>License: GPLv3+</p> <p>Licenza: GPLv3+</p>
<h2>Developers OpenPGP Keychain</h2> <h2>Sviluppatori OpenKeychain</h2>
<ul> <ul>
<li>Dominik Schürmann (Lead developer)</li> <li>Dominik Schürmann (Capo Sviluppatore)</li>
<li>Ash Hughes (crypto patches)</li> <li>Ash Hughes (Patch crittografia)</li>
<li>Brian C. Barnes</li> <li>Brian C. Barnes</li>
<li>Bahtiar 'kalkin' Gadimov (UI)</li> <li>Bahtiar 'kalkin' Gadimov (Interfaccia Utente)</li>
</ul> </ul>
<h2>Developers APG 1.x</h2> <h2>Sviluppatori APG 1.x</h2>
<ul> <ul>
<li>'Thialfihar' (Lead developer)</li> <li>'Thialfihar' (Capo Sviluppatore)</li>
<li>'Senecaso' (QRCode, sign key, upload key)</li> <li>'Senecaso' (QRCode, firma chiavi, caricamento chiavi)</li>
<li>Oliver Runge</li> <li>Oliver Runge</li>
<li>Markus Doits</li> <li>Markus Doits</li>
</ul> </ul>
<h2>Libraries</h2> <h2>Librerie</h2>
<ul> <ul>
<li> <li>
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Apache License v2)</li> <a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v4</a> (Licenza Apache v2)</li>
<li> <li>
<a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Apache License v2)</li> <a href="http://developer.android.com/tools/support-library/index.html">Android Support Library v7 'appcompat'</a> (Licenza Apache v2)</li>
<li> <li>
<a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Apache License v2)</li> <a href="https://github.com/emilsjolander/StickyListHeaders">StickyListHeaders</a> (Licenza Apache v2)</li>
<li> <li>
<a href="https://github.com/Bearded-Hen/Android-Bootstrap">Android-Bootstrap</a> (MIT License)</li> <a href="https://github.com/Bearded-Hen/Android-Bootstrap">Android-Bootstrap</a> (Licenza MIT)</li>
<li> <li>
<a href="http://code.google.com/p/zxing/">ZXing</a> (Apache License v2)</li> <a href="http://code.google.com/p/zxing/">ZXing</a> (Licenza Apache v2)</li>
<li> <li>
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li> <a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (Licenza MIT X11)</li>
<li> <li>
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li> <a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Licenza Apache v2)</li>
<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li> <li>
<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li> <a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Licenza Apache v2)</li>
<li>Icone da <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Licenza Creative Commons Attribution Share-Alike 3.0)</li>
<li>Icone da <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Pubblico Dominio)</li>
</ul> </ul>
</body> </body>
</html> </html>

View File

@ -3,106 +3,106 @@
<body> <body>
<h2>2.3</h2> <h2>2.3</h2>
<ul> <ul>
<li>remove unnecessary export of public keys when exporting secret key (thanks to Ash Hughes)</li> <li>rimossa esportazione non necessaria delle chiavi pubbliche quando si esportano le chiavi private (grazie a Ash Hughes)</li>
<li>fix setting expiry dates on keys (thanks to Ash Hughes)</li> <li>corretto impostazione data di scadenza delle chiavi (grazie a Ash Hughes)</li>
<li>more internal fixes when editing keys (thanks to Ash Hughes)</li> <li>altre correzioni interne quando si modificano le chiavi (grazie a Ash Hughes)</li>
<li>querying keyservers directly from the import screen</li> <li>interrogazione server delle chiavi direttamente dalla schermata di importazione</li>
<li>fix layout and dialog style on Android 2.2-3.0</li> <li>corretto layout e dialog style su Android 2.2-3.0</li>
<li>fix crash on keys with empty user ids</li> <li>corretto crash su chiavi con id utente vuoto</li>
<li>fix crash and empty lists when coming back from signing screen</li> <li>corretto crash e liste vuote quando si torna dalla schermata di firma</li>
<li>Bouncy Castle (cryptography library) updated from 1.47 to 1.50 and build from source</li> <li>Bouncy Castle (libreria crittografica) aggiornata da 1.47 a 1.50 e compilata da sorgente</li>
<li>fix upload of key from signing screen</li> <li>corretto upload delle chiavi dalla schermata di firma</li>
</ul> </ul>
<h2>2.2</h2> <h2>2.2</h2>
<ul> <ul>
<li>new design with navigation drawer</li> <li>nuovo design con drawer di navigazione</li>
<li>new public key list design</li> <li>nuovo design per la lista chiavi pubbliche</li>
<li>new public key view</li> <li>nuova visuale chiavi pubbliche</li>
<li>bug fixes for importing of keys</li> <li>correzione bug per importazione chiavi</li>
<li>key cross-certification (thanks to Ash Hughes)</li> <li>Chiave certificazione incrociata (grazie a Ash Hughes)</li>
<li>handle UTF-8 passwords properly (thanks to Ash Hughes)</li> <li>password UTF-8 gestite correttamente (grazie a Ash Hughes)</li>
<li>first version with new languages (thanks to the contributors on Transifex)</li> <li>Prima versione con nuove lingue (grazie ai contributori su Transifex)</li>
<li>sharing of keys via QR Codes fixed and improved</li> <li>condivisione di chiavi via Codici QR corretta e migliorata</li>
<li>package signature verification for API</li> <li>Verifica firma pacchetto per API</li>
</ul> </ul>
<h2>2.1.1</h2> <h2>2.1.1</h2>
<ul> <ul>
<li>API Updates, preparation for K-9 Mail integration</li> <li>Aggiornamenti API, preparazione per integrazione con K-9 Mail</li>
</ul> </ul>
<h2>2.1</h2> <h2>2.1</h2>
<ul> <ul>
<li>lots of bug fixes</li> <li>molte correzioni di bug</li>
<li>new API for developers</li> <li>nuove API per sviluppatori</li>
<li>PRNG bug fix by Google</li> <li>PRNG bug fix by Google</li>
</ul> </ul>
<h2>2.0</h2> <h2>2.0</h2>
<ul> <ul>
<li>complete redesign</li> <li>completo restyle</li>
<li>share public keys via qr codes, nfc beam</li> <li>condivisione chiavi pubbliche via codici qr, nfc beam</li>
<li>sign keys</li> <li>firma chiavi</li>
<li>upload keys to server</li> <li>Carica chiavi sul server</li>
<li>fixes import issues</li> <li>corrette caratteristiche di importazione</li>
<li>new AIDL API</li> <li>nuova AIDL API</li>
</ul> </ul>
<h2>1.0.8</h2> <h2>1.0.8</h2>
<ul> <ul>
<li>basic keyserver support</li> <li>supporto base per server delle chiavi</li>
<li>app2sd</li> <li>app2sd</li>
<li>more choices for pass phrase cache: 1, 2, 4, 8, hours</li> <li>Aggiunte opzioni per la cache della frase di accesso: 1, 2, 4, 8 ore</li>
<li>translations: Norwegian (thanks, Sander Danielsen), Chinese (thanks, Zhang Fredrick)</li> <li>Traduzioni: Norvegese (grazie, Sander Danielsen), Cinese (grazie, Zhang Fredrick)</li>
<li>bugfixes</li> <li>correzione bug</li>
<li>optimizations</li> <li>ottimizzazioni</li>
</ul> </ul>
<h2>1.0.7</h2> <h2>1.0.7</h2>
<ul> <ul>
<li>fixed problem with signature verification of texts with trailing newline</li> <li>corretto problema con la verifica firma di testi con capo finale</li>
<li>more options for pass phrase cache time to live (20, 40, 60 mins)</li> <li>maggiori opzioni per il tempo di mantenimento della cache della frase di accesso (20, 40, 60 minuti)</li>
</ul> </ul>
<h2>1.0.6</h2> <h2>1.0.6</h2>
<ul> <ul>
<li>account adding crash on Froyo fixed</li> <li>crash della aggiunta degli account risolto su Froyo</li>
<li>secure file deletion</li> <li>Cancellazione sicura dei file</li>
<li>option to delete key file after import</li> <li>opzione per cancellare file delle chiavi dopo l'importazione</li>
<li>stream encryption/decryption (gallery, etc.)</li> <li>flusso codifica/decodifica (galleria, ecc.)</li>
<li>new options (language, force v3 signatures)</li> <li>nuove opzioni (lingua, forza firme v3)</li>
<li>interface changes</li> <li>cambiamenti interfaccia</li>
<li>bugfixes</li> <li>correzione bug</li>
</ul> </ul>
<h2>1.0.5</h2> <h2>1.0.5</h2>
<ul> <ul>
<li>German and Italian translation</li> <li>Traduzione Italiana e Tedesca</li>
<li>much smaller package, due to reduced BC sources</li> <li>dimensioni pacchetto ridotte, a causa della riduzione dei sorgenti BC</li>
<li>new preferences GUI</li> <li>Nuove preferenze GUI</li>
<li>layout adjustment for localization</li> <li>Regolazione layout per la localizzazione</li>
<li>signature bugfix</li> <li>correzione bug firma</li>
</ul> </ul>
<h2>1.0.4</h2> <h2>1.0.4</h2>
<ul> <ul>
<li>fixed another crash caused by some SDK bug with query builder</li> <li>corretto altro crash causato da alcuni bug SDK con query builder</li>
</ul> </ul>
<h2>1.0.3</h2> <h2>1.0.3</h2>
<ul> <ul>
<li>fixed crashes during encryption/signing and possibly key export</li> <li>corretto crash durante codifica/firma e possibilita' di esportare chiave</li>
</ul> </ul>
<h2>1.0.2</h2> <h2>1.0.2</h2>
<ul> <ul>
<li>filterable key lists</li> <li>liste chiavi filtrabili</li>
<li>smarter pre-selection of encryption keys</li> <li>preselezione di chiavi di codifica intelligente</li>
<li>new Intent handling for VIEW and SEND, allows files to be encrypted/decrypted out of file managers</li> <li>nuovo gestore intent per VIEW e SEND, permette la codifica/decodifica file all'infuori di file manager</li>
<li>fixes and additional features (key preselection) for K-9 Mail, new beta build available</li> <li>caratteristiche corrette e aggiunte (preselezione chiavi) per K-9 Mail. nuova build beta disponibile</li>
</ul> </ul>
<h2>1.0.1</h2> <h2>1.0.1</h2>
<ul> <ul>
<li>GMail account listing was broken in 1.0.0, fixed again</li> <li>elencazione account GMail corrotta in 1.0.0, corretta nuovamente</li>
</ul> </ul>
<h2>1.0.0</h2> <h2>1.0.0</h2>
<ul> <ul>
<li>K-9 Mail integration, APG supporting beta build of K-9 Mail</li> <li>integrazione K-9 Mail, APG supporto beta build di K-9 Mail</li>
<li>support of more file managers (including ASTRO)</li> <li>supporto per altri file manager (incluso ASTRO)</li>
<li>Slovenian translation</li> <li>traduzione Slovena</li>
<li>new database, much faster, less memory usage</li> <li>Nuovo database, piu' veloce, utilizzo memoria ridotto</li>
<li>defined Intents and content provider for other apps</li> <li>Definiti Intent e ContentProvider per le altre app</li>
<li>bugfixes</li> <li>correzione bug</li>
</ul> </ul>
</body> </body>
</html> </html>

View File

@ -1,12 +1,12 @@
<html> <html>
<head></head> <head></head>
<body> <body>
<h2>How to receive keys</h2> <h2>Come ricevere le chiavi</h2>
<ol> <ol>
<li>Go to your partners contacts and open the contact you want to share.</li> <li>Vai ai contatti dei tuoi partner e apri il contatto che si desidera condividere.</li>
<li>Hold the two devices back to back (they have to be almost touching) and youll feel a vibration.</li> <li>Mantieni i due dispositivi vicini (devono quasi toccarsi) e sentirai una vibrazione.</li>
<li>After it vibrates youll see the content on your partners device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li> <li>Dopo che ha vibrato, vedrai il contenuto del tuo dispositivo diventare come una scheda e nello sfondo apparirà una animazione come la propulsione a curvatura di Star Trek.</li>
<li>Tap the card and the content will then load on the your device.</li> <li>Tocca la scheda e il contenuto dopo si trasferira' nel dispositivo dell'altra persona.</li>
</ol> </ol>
</body> </body>
</html> </html>

View File

@ -1,19 +1,19 @@
<html> <html>
<head></head> <head></head>
<body> <body>
<h2>Getting started</h2> <h2>Per iniziare</h2>
<p>First you need a personal key pair. Create one via the option menus in "My Keys" or import existing key pairs via "Import Keys". Afterwards, you can download your friends' keys or exchange them via QR Codes or NFC.</p> <p>Per prima cosa hai bisogno di un paio di chiavi personali. Creane una tramite i menu di opzione sotto 'Mie Chiavi' o importane di esistenti attraverso "Importa Chiavi". Dopodiche' puoi scaricare le chiavi dei tuoi amici o scambiarle tramite Codici QR o NFC.</p>
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p> <p>Si raccomanda di installare <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> per una migliore selezione dei file e <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> per scansionare i codici QR. I collegamenti verranno aperti in Google Play Store o F-Droid per l'installazione.</p>
<h2>I found a bug in OpenPGP Keychain!</h2> <h2>Ho trovato un bug in OpenKeychain!</h2>
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p> <p>Per favore riporta i bug usando il <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker di OpenKeychain</a>.</p>
<h2>Contribute</h2> <h2>Contribuire</h2>
<p>If you want to help us developing OpenPGP Keychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p> <p>Se vuoi aiutarci nello sviluppo di OpenKeychain contribuendo al codice <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">segui la nostra breve guida su Github</a>.</p>
<h2>Translations</h2> <h2>Traduzioni</h2>
<p>Help translating OpenPGP Keychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p> <p>Aiutaci a tradurre OpenKeychain! Tutti possono collaborare a <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain su Transifex</a>.</p>
</body> </body>
</html> </html>

View File

@ -2,10 +2,10 @@
<head></head> <head></head>
<body> <body>
<ol> <ol>
<li>Make sure that NFC is turned on in Settings &gt; More &gt; NFC and make sure that Android Beam is also on in the same section.</li> <li>Assicurati che NFC sia acceso in Impostazioni &gt; Altro &gt; NFC a assicurati che Android Beam sia pure su On nella stessa sezione.</li>
<li>Hold the two devices back to back (they have to be almost touching) and you'll feel a vibration.</li> <li>Mantieni i due dispositivi vicini (devono quasi toccarsi) e sentirai una vibrazione.</li>
<li>After it vibrates you'll see the content on your device turn into a card-like object with Star Trek warp speed-looking animation in the background.</li> <li>Dopo che ha vibrato, vedrai il contenuto del tuo dispositivo diventare come una scheda e nello sfondo apparirà una animazione come la propulsione a curvatura di Star Trek.</li>
<li>Tap the card and the content will then load on the other persons device.</li> <li>Tocca la scheda e il contenuto dopo si trasferira' nel dispositivo dell'altra persona.</li>
</ol> </ol>
</body> </body>
</html> </html>

View File

@ -1,11 +1,11 @@
<html> <html>
<head></head> <head></head>
<body> <body>
<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p> <p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> は AndroidにおけるOpenPGP実装の一つです。開発はAndroid Privacy Guard (APG)から分岐して始まりました</p> <p><a href="http://www.openkeychain.org">OpenKeychain</a> は Android における OpenPGP 実装です。</p>
<p>ライセンス: GPLv3以降</p> <p>ライセンス: GPLv3以降</p>
<h2>OpenPGP Keychain開発者</h2> <h2>OpenKeychain開発者</h2>
<ul> <ul>
<li>Dominik Schürmann (主任開発者)</li> <li>Dominik Schürmann (主任開発者)</li>
<li>Ash Hughes (暗号関係パッチ提供)</li> <li>Ash Hughes (暗号関係パッチ提供)</li>
@ -36,6 +36,8 @@
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li> <a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
<li> <li>
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li> <a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li> <li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (パブリックドメイン)</li> <li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (パブリックドメイン)</li>
</ul> </ul>

View File

@ -6,14 +6,14 @@
<p>ファイルの選択を拡張するには<a href="market://details?id=org.openintents.filemanager">OI File Manager</a><a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a>を生成したQRコードのスキャンのため、それぞれのインストールを必要とします。 リンクをクリックして、Google Play Store上かF-Droidからインストールしてください。</p> <p>ファイルの選択を拡張するには<a href="market://details?id=org.openintents.filemanager">OI File Manager</a><a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a>を生成したQRコードのスキャンのため、それぞれのインストールを必要とします。 リンクをクリックして、Google Play Store上かF-Droidからインストールしてください。</p>
<h2>OpenPGP Keychainにバグを発見した!</h2> <h2>OpenKeychainでバグを見付けた!</h2>
<p><a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">OpenPGP KeychainのIssueトラッカー</a>を使ってバグレポートを送ってください。</p> <p><a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">OpenKeychainのIssueトラッカー</a>を使ってバグレポートを送ってください。</p>
<h2>寄贈</h2> <h2>寄贈</h2>
<p>もし、あなたが OpenPGP Keychain の開発を助け、コードを寄贈するというなら、<a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">Githubの寄贈ガイドを確認</a>して下さい。</p> <p>もし、あなたが OpenKeychain の開発を助け、コードを寄贈するというなら、<a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">Githubのミニガイドを確認</a>して下さい。</p>
<h2>翻訳</h2> <h2>翻訳</h2>
<p>OpenPGP Keychainの翻訳を補助してください! だれでも、<a href="https://www.transifex.com/projects/p/openpgp-keychain/">TransifexのOpenPGP Keychainプロジェクト</a>に参加できます。</p> <p>OpenKeychainの翻訳を助けてください! <a href="https://www.transifex.com/projects/p/openpgp-keychain/">TransifexのOpenKeychainプロジェクト</a>誰でも参加できます。</p>
</body> </body>
</html> </html>

View File

@ -1,11 +1,11 @@
<html> <html>
<head></head> <head></head>
<body> <body>
<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p> <p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> is an OpenPGP implementation for Android. The development began as a fork of Android Privacy Guard (APG).</p> <p><a href="http://www.openkeychain.org">OpenKeychain</a> is an OpenPGP implementation for Android.</p>
<p>License: GPLv3+</p> <p>License: GPLv3+</p>
<h2>Developers OpenPGP Keychain</h2> <h2>Developers OpenKeychain</h2>
<ul> <ul>
<li>Dominik Schürmann (Lead developer)</li> <li>Dominik Schürmann (Lead developer)</li>
<li>Ash Hughes (crypto patches)</li> <li>Ash Hughes (crypto patches)</li>
@ -36,6 +36,8 @@
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li> <a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
<li> <li>
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li> <a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li> <li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li> <li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul> </ul>

View File

@ -6,14 +6,14 @@
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p> <p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
<h2>I found a bug in OpenPGP Keychain!</h2> <h2>I found a bug in OpenKeychain!</h2>
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p> <p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
<h2>Contribute</h2> <h2>Contribute</h2>
<p>If you want to help us developing OpenPGP Keychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p> <p>If you want to help us developing OpenKeychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
<h2>Translations</h2> <h2>Translations</h2>
<p>Help translating OpenPGP Keychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p> <p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain on Transifex</a>.</p>
</body> </body>
</html> </html>

View File

@ -1,11 +1,11 @@
<html> <html>
<head></head> <head></head>
<body> <body>
<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p> <p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> is an OpenPGP implementation for Android. The development began as a fork of Android Privacy Guard (APG).</p> <p><a href="http://www.openkeychain.org">OpenKeychain</a> is an OpenPGP implementation for Android.</p>
<p>License: GPLv3+</p> <p>License: GPLv3+</p>
<h2>Developers OpenPGP Keychain</h2> <h2>Developers OpenKeychain</h2>
<ul> <ul>
<li>Dominik Schürmann (Lead developer)</li> <li>Dominik Schürmann (Lead developer)</li>
<li>Ash Hughes (crypto patches)</li> <li>Ash Hughes (crypto patches)</li>
@ -36,6 +36,8 @@
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li> <a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
<li> <li>
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li> <a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li> <li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li> <li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul> </ul>

View File

@ -6,14 +6,14 @@
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p> <p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
<h2>I found a bug in OpenPGP Keychain!</h2> <h2>I found a bug in OpenKeychain!</h2>
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p> <p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
<h2>Contribute</h2> <h2>Contribute</h2>
<p>If you want to help us developing OpenPGP Keychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p> <p>If you want to help us developing OpenKeychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
<h2>Translations</h2> <h2>Translations</h2>
<p>Help translating OpenPGP Keychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p> <p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain on Transifex</a>.</p>
</body> </body>
</html> </html>

View File

@ -1,11 +1,11 @@
<html> <html>
<head></head> <head></head>
<body> <body>
<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p> <p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> - свободная реализация OpenPGP для Android. Разработка начиналась как ответвление Android Privacy Guard (APG).</p> <p><a href="http://www.openkeychain.org">OpenKeychain</a> - реализация OpenPGP для Android.</p>
<p>Лицензия: GPLv3+</p> <p>Лицензия: GPLv3+</p>
<h2>Разработчики OpenPGP Keychain</h2> <h2>Разработчики OpenKeychain</h2>
<ul> <ul>
<li>Dominik Schürmann (главный разработчик)</li> <li>Dominik Schürmann (главный разработчик)</li>
<li>Ash Hughes (патчи криптографии)</li> <li>Ash Hughes (патчи криптографии)</li>
@ -36,6 +36,8 @@
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li> <a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
<li> <li>
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li> <a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Библиотека Android AppMsg</a> (Apache License v2)</li>
<li>Иконки <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li> <li>Иконки <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
<li>Иконки <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li> <li>Иконки <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul> </ul>

View File

@ -6,14 +6,14 @@
<p>Рекомендуется установить <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> для удобного выбора файлов и <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> для распознавания QR кодов. Перейдите по ссылкам на соответствующие страницы Google Play или F-Droid для дальнейшей установки.</p> <p>Рекомендуется установить <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> для удобного выбора файлов и <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> для распознавания QR кодов. Перейдите по ссылкам на соответствующие страницы Google Play или F-Droid для дальнейшей установки.</p>
<h2>Я нашел ошибку в OpenPGP Keychain!</h2> <h2>Я нашел ошибку в OpenKeychain!</h2>
<p>Пожалуйста, сообщайте о возникших проблемах и найденных ошибках в разделе <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">Решение проблем OpenPGP Keychain</a>.</p> <p>Пожалуйста, сообщайте о возникших проблемах и найденных ошибках в разделе <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">Решение проблем OpenKeychain</a>.</p>
<h2>Вклад в развитие</h2> <h2>Вклад в развитие</h2>
<p>Если Вы хотите помочь в разработке OpenPGP Keychain, обратитесь к <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">инструкции на Github</a>.</p> <p>Если Вы хотите помочь в разработке OpenKeychain, обратитесь к <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">инструкции на Github</a>.</p>
<h2>Перевод</h2> <h2>Перевод</h2>
<p>Помогите переводить OpenPGP Keychain! Каждый может принять участие в переводе <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain на Transifex</a>.</p> <p>Помогите переводить OpenKeychain! Каждый может принять участие в переводе <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain на Transifex</a>.</p>
</body> </body>
</html> </html>

View File

@ -1,11 +1,11 @@
<html> <html>
<head></head> <head></head>
<body> <body>
<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p> <p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> is an OpenPGP implementation for Android. The development began as a fork of Android Privacy Guard (APG).</p> <p><a href="http://www.openkeychain.org">OpenKeychain</a> is an OpenPGP implementation for Android.</p>
<p>License: GPLv3+</p> <p>License: GPLv3+</p>
<h2>Developers OpenPGP Keychain</h2> <h2>Developers OpenKeychain</h2>
<ul> <ul>
<li>Dominik Schürmann (Lead developer)</li> <li>Dominik Schürmann (Lead developer)</li>
<li>Ash Hughes (crypto patches)</li> <li>Ash Hughes (crypto patches)</li>
@ -36,6 +36,8 @@
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li> <a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
<li> <li>
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li> <a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li> <li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li> <li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul> </ul>

View File

@ -6,14 +6,14 @@
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p> <p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
<h2>I found a bug in OpenPGP Keychain!</h2> <h2>I found a bug in OpenKeychain!</h2>
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p> <p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
<h2>Contribute</h2> <h2>Contribute</h2>
<p>If you want to help us developing OpenPGP Keychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p> <p>If you want to help us developing OpenKeychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
<h2>Translations</h2> <h2>Translations</h2>
<p>Help translating OpenPGP Keychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p> <p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain on Transifex</a>.</p>
</body> </body>
</html> </html>

View File

@ -1,11 +1,11 @@
<html> <html>
<head></head> <head></head>
<body> <body>
<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p> <p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> Android için bir OpenPGP uygulamasıdır. </p> <p><a href="http://www.openkeychain.org">OpenKeychain</a> is an OpenPGP implementation for Android.</p>
<p>Lisans: GPLv3+</p> <p>Lisans: GPLv3+</p>
<h2>Geliştiriciler OpenPGP Keychain</h2> <h2>Developers OpenKeychain</h2>
<ul> <ul>
<li>Dominik Schürmann (Baş geliştirici)</li> <li>Dominik Schürmann (Baş geliştirici)</li>
<li>Ash Hughes (kripto yamaları)</li> <li>Ash Hughes (kripto yamaları)</li>
@ -36,6 +36,8 @@
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li> <a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
<li> <li>
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li> <a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
<li>İkonlar <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li> <li>İkonlar <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
<li>İkonlar <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li> <li>İkonlar <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul> </ul>

View File

@ -6,14 +6,14 @@
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p> <p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
<h2>I found a bug in OpenPGP Keychain!</h2> <h2>I found a bug in OpenKeychain!</h2>
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p> <p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
<h2>Contribute</h2> <h2>Contribute</h2>
<p>If you want to help us developing OpenPGP Keychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p> <p>If you want to help us developing OpenKeychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
<h2>Translations</h2> <h2>Translations</h2>
<p>Help translating OpenPGP Keychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p> <p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain on Transifex</a>.</p>
</body> </body>
</html> </html>

View File

@ -1,8 +1,8 @@
<html> <html>
<head></head> <head></head>
<body> <body>
<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p> <p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> - вільна реалізація OpenPGP для Android. Розробка починалася як відгалуження Android Privacy Guard (APG).</p> <p><a href="http://www.openkeychain.org">OpenKeychain</a> імплементація OpenPGP для Андроїду.</p>
<p>Ліцензія: GPLv3+</p> <p>Ліцензія: GPLv3+</p>
<h2>Розробники OpenPGP Keychain</h2> <h2>Розробники OpenPGP Keychain</h2>
@ -36,6 +36,8 @@
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (ліцензія MIT X11)</li> <a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (ліцензія MIT X11)</li>
<li> <li>
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (ліцензія Apache в.2)</li> <a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (ліцензія Apache в.2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Бібліотека Android AppMsg Library</a> (Ліцензія Apache в. 2)</li>
<li>Піктограми із <a href="http://rrze-icon-set.berlios.de/">набору піктограм RRZE</a> (ліцензія Creative Commons - Із зазначенням авторства - Розповсюдження на тих самих умовах - версія 3.0)</li> <li>Піктограми із <a href="http://rrze-icon-set.berlios.de/">набору піктограм RRZE</a> (ліцензія Creative Commons - Із зазначенням авторства - Розповсюдження на тих самих умовах - версія 3.0)</li>
<li>Піктограми із <a href="http://tango.freedesktop.org/">набору піктограм Tango</a> (відкритий домен)</li> <li>Піктограми із <a href="http://tango.freedesktop.org/">набору піктограм Tango</a> (відкритий домен)</li>
</ul> </ul>

View File

@ -13,7 +13,7 @@
<p>Якщо ви хочете допомогти нам у розробці OpenPGP Keychain через редагування коду програми <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">підпишіться на наш невеличкий посібник у Github</a>.</p> <p>Якщо ви хочете допомогти нам у розробці OpenPGP Keychain через редагування коду програми <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">підпишіться на наш невеличкий посібник у Github</a>.</p>
<h2>Переклади</h2> <h2>Переклади</h2>
<p>Допоможіть перекласти OpenPGP Keychain! Кожний може взяти участь у <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain на Transifex</a>.</p> <p>Допоможіть перекласти OpenPGP Keychain! Кожний може взяти участь на <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain на Transifex</a>.</p>
</body> </body>
</html> </html>

View File

@ -1,11 +1,11 @@
<html> <html>
<head></head> <head></head>
<body> <body>
<p><a href="http://sufficientlysecure.org/keychain">http://sufficientlysecure.org/keychain</a></p> <p><a href="http://www.openkeychain.org">http://www.openkeychain.org</a></p>
<p><a href="http://sufficientlysecure.org/keychain">OpenPGP Keychain</a> is an OpenPGP implementation for Android. The development began as a fork of Android Privacy Guard (APG).</p> <p><a href="http://www.openkeychain.org">OpenKeychain</a> is an OpenPGP implementation for Android.</p>
<p>License: GPLv3+</p> <p>License: GPLv3+</p>
<h2>Developers OpenPGP Keychain</h2> <h2>Developers OpenKeychain</h2>
<ul> <ul>
<li>Dominik Schürmann (Lead developer)</li> <li>Dominik Schürmann (Lead developer)</li>
<li>Ash Hughes (crypto patches)</li> <li>Ash Hughes (crypto patches)</li>
@ -36,6 +36,8 @@
<a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li> <a href="http://rtyley.github.com/spongycastle/">SpongyCastle</a> (MIT X11 License)</li>
<li> <li>
<a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li> <a href="https://github.com/dschuermann/html-textview">HtmlTextView</a> (Apache License v2)</li>
<li>
<a href="https://github.com/johnkil/Android-AppMsg">Android AppMsg Library</a> (Apache License v2)</li>
<li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li> <li>Icons from <a href="http://rrze-icon-set.berlios.de/">RRZE Icon Set</a> (Creative Commons Attribution Share-Alike licence 3.0)</li>
<li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li> <li>Icons from <a href="http://tango.freedesktop.org/">Tango Icon Set</a> (Public Domain)</li>
</ul> </ul>

View File

@ -6,14 +6,14 @@
<p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p> <p>It is recommended that you install <a href="market://details?id=org.openintents.filemanager">OI File Manager</a> for enhanced file selection and <a href="market://details?id=com.google.zxing.client.android">Barcode Scanner</a> to scan generated QR Codes. Clicking on the links will open Google Play Store or F-Droid for installation.</p>
<h2>I found a bug in OpenPGP Keychain!</h2> <h2>I found a bug in OpenKeychain!</h2>
<p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenPGP Keychain</a>.</p> <p>Please report the bug using the <a href="https://github.com/openpgp-keychain/openpgp-keychain/issues">issue tracker of OpenKeychain</a>.</p>
<h2>Contribute</h2> <h2>Contribute</h2>
<p>If you want to help us developing OpenPGP Keychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p> <p>If you want to help us developing OpenKeychain by contributing code <a href="https://github.com/openpgp-keychain/openpgp-keychain#contribute-code">follow our small guide on Github</a>.</p>
<h2>Translations</h2> <h2>Translations</h2>
<p>Help translating OpenPGP Keychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenPGP Keychain on Transifex</a>.</p> <p>Help translating OpenKeychain! Everybody can participate at <a href="https://www.transifex.com/projects/p/openpgp-keychain/">OpenKeychain on Transifex</a>.</p>
</body> </body>
</html> </html>

View File

@ -111,6 +111,7 @@
<string name="label_passphrase_cache_ttl">Passwort-Cache</string> <string name="label_passphrase_cache_ttl">Passwort-Cache</string>
<string name="label_message_compression">Nachrichten-Komprimierung</string> <string name="label_message_compression">Nachrichten-Komprimierung</string>
<string name="label_file_compression">Datei-Komprimierung</string> <string name="label_file_compression">Datei-Komprimierung</string>
<string name="label_force_v3_signature">Alte OpenPGPv3 Unterschriften erzwingen</string>
<string name="label_key_servers">Schlüsselserver</string> <string name="label_key_servers">Schlüsselserver</string>
<string name="label_key_id">Schlüssel-ID</string> <string name="label_key_id">Schlüssel-ID</string>
<string name="label_creation">Erstellungsdatum</string> <string name="label_creation">Erstellungsdatum</string>
@ -253,6 +254,7 @@
<string name="error_no_signature_key">kein Signaturschlüssel angegeben</string> <string name="error_no_signature_key">kein Signaturschlüssel angegeben</string>
<string name="error_invalid_data">Verschlüsselte Daten nicht gültig</string> <string name="error_invalid_data">Verschlüsselte Daten nicht gültig</string>
<string name="error_corrupt_data">beschädigte Daten</string> <string name="error_corrupt_data">beschädigte Daten</string>
<string name="error_integrity_check_failed">Integritätscheck fehlgeschlagen! Die Daten wurden modifiziert!</string>
<string name="error_no_symmetric_encryption_packet">Paket mit symmetrischer Verschlüsselung konnte nicht gefunden werden</string> <string name="error_no_symmetric_encryption_packet">Paket mit symmetrischer Verschlüsselung konnte nicht gefunden werden</string>
<string name="error_wrong_passphrase">falsches Passwort</string> <string name="error_wrong_passphrase">falsches Passwort</string>
<string name="error_saving_keys">Es trat ein Fehler beim Speichern einiger Schlüssel auf</string> <string name="error_saving_keys">Es trat ein Fehler beim Speichern einiger Schlüssel auf</string>
@ -262,6 +264,9 @@
<string name="error_nfc_needed">NFC steht auf diesem Gerät nicht zur Verfügung!</string> <string name="error_nfc_needed">NFC steht auf diesem Gerät nicht zur Verfügung!</string>
<string name="error_nothing_import">Nichts zu importieren!</string> <string name="error_nothing_import">Nichts zu importieren!</string>
<string name="error_expiry_must_come_after_creation">Ablaufdatum muss später sein als das Erstellungsdatum</string> <string name="error_expiry_must_come_after_creation">Ablaufdatum muss später sein als das Erstellungsdatum</string>
<string name="error_can_not_delete_contact">Sie können diesen Kontakt nicht löschen, denn es ist ihr eigener.</string>
<string name="error_can_not_delete_contacts">Sie können folgende Kontakte nicht löschen, denn sie gehören Ihnen selbst:\n%s</string>
<string name="error_keyserver_query">Keyserveranfrage fehlgeschlagen</string>
<plurals name="error_can_not_delete_info"> <plurals name="error_can_not_delete_info">
<item quantity="one">Bitte lösche ihn unter \'Meine Schlüssel\'!</item> <item quantity="one">Bitte lösche ihn unter \'Meine Schlüssel\'!</item>
<item quantity="other">Bitte lösche sie unter \'Meine Schlüssel\'!</item> <item quantity="other">Bitte lösche sie unter \'Meine Schlüssel\'!</item>
@ -271,6 +276,7 @@
<string name="progress_saving">speichern...</string> <string name="progress_saving">speichern...</string>
<string name="progress_importing">importieren...</string> <string name="progress_importing">importieren...</string>
<string name="progress_exporting">exportieren...</string> <string name="progress_exporting">exportieren...</string>
<string name="progress_generating">erstelle Schlüssel, dies kann bis zu 3 Minuten dauern...</string>
<string name="progress_building_key">erstelle Schlüssel...</string> <string name="progress_building_key">erstelle Schlüssel...</string>
<string name="progress_preparing_master_key">Hauptschlüssel wird vorbereitet...</string> <string name="progress_preparing_master_key">Hauptschlüssel wird vorbereitet...</string>
<string name="progress_certifying_master_key">Hauptschlüssel wird beglaubigt...</string> <string name="progress_certifying_master_key">Hauptschlüssel wird beglaubigt...</string>
@ -332,11 +338,8 @@
<string name="import_nfc_help_button">Hilfe</string> <string name="import_nfc_help_button">Hilfe</string>
<string name="import_clipboard_button">Füge den Schlüssel aus der Zwischenablage ein</string> <string name="import_clipboard_button">Füge den Schlüssel aus der Zwischenablage ein</string>
<!--Intent labels--> <!--Intent labels-->
<string name="intent_decrypt_file">OpenPGP: Datei entschlüsseln</string>
<string name="intent_import_key">OpenPGP: Schlüssel importieren</string>
<string name="intent_send_encrypt">OpenPGP: Verschlüsseln</string>
<string name="intent_send_decrypt">OpenPGP: Entschlüsseln</string>
<!--Remote API--> <!--Remote API-->
<string name="api_no_apps">Keine registrierten Anwendungen vorhanden!\n\nAnwendungen von Dritten können Zugriff auf OpenKeychain erbitten. Nachdem Zugriff gewährt wurde, werden diese hier aufgelistet.</string>
<string name="api_settings_show_advanced">Erweiterte Einstellungen anzeigen</string> <string name="api_settings_show_advanced">Erweiterte Einstellungen anzeigen</string>
<string name="api_settings_hide_advanced">Erweiterte Einstellungen ausblenden</string> <string name="api_settings_hide_advanced">Erweiterte Einstellungen ausblenden</string>
<string name="api_settings_no_key">Kein Schlüssel ausgewählt</string> <string name="api_settings_no_key">Kein Schlüssel ausgewählt</string>
@ -346,13 +349,14 @@
<string name="api_settings_revoke">Zugriff widerufen</string> <string name="api_settings_revoke">Zugriff widerufen</string>
<string name="api_settings_package_name">Paketname</string> <string name="api_settings_package_name">Paketname</string>
<string name="api_settings_package_signature">SHA-256 der Paketsignatur</string> <string name="api_settings_package_signature">SHA-256 der Paketsignatur</string>
<string name="api_register_text">Folgende Anwendung beantragt Zugriff zur API von OpenKeychain.\nZugriff erlauben?\n\nVORSICHT: Sollten Sie nicht wissen, warum dieses Fenster erscheint, sollten Sie den Zugriff nicht gewähren! Sie können Zugriffe später über das Menü \'Registrierte Anwendungen\' widerrufen.</string>
<string name="api_register_allow">Zugriff erlauben</string> <string name="api_register_allow">Zugriff erlauben</string>
<string name="api_register_disallow">Zugriff verbieten</string> <string name="api_register_disallow">Zugriff verbieten</string>
<string name="api_register_error_select_key">Bitte einen Schlüssel auswählen!</string> <string name="api_register_error_select_key">Bitte einen Schlüssel auswählen!</string>
<string name="api_select_pub_keys_missing_text">Für diese Benutzer-IDs wurden keine öffentlichen Schlüssel gefunden:</string> <string name="api_select_pub_keys_missing_text">Für diese Benutzer-IDs wurden keine öffentlichen Schlüssel gefunden:</string>
<string name="api_select_pub_keys_dublicates_text">Für diese Benutzer-IDs existieren mehrere öffentliche Schlüssel:</string> <string name="api_select_pub_keys_dublicates_text">Für diese Benutzer-IDs existieren mehrere öffentliche Schlüssel:</string>
<string name="api_select_pub_keys_text">Bitte die Liste der Empfänger überprüfen!</string> <string name="api_select_pub_keys_text">Bitte die Liste der Empfänger überprüfen!</string>
<string name="api_error_wrong_signature">Signaturüberprüfung fehlgeschlagen! Haben Sie diese App von einer anderen Quelle installiert? Wenn Sie eine Attacke ausschliessen können, sollten Sie die Registrierung der App in OpenPGP Keychain widerrufen und die App erneut registrieren.</string> <string name="api_error_wrong_signature">Signaturüberprüfung fehlgeschlagen! Haben Sie diese App von einer anderen Quelle installiert? Wenn Sie eine Attacke ausschliessen können, sollten Sie die Registrierung der App in OpenKeychain widerrufen und die App erneut registrieren.</string>
<!--Share--> <!--Share-->
<string name="share_qr_code_dialog_title">Über QR Code teilen</string> <string name="share_qr_code_dialog_title">Über QR Code teilen</string>
<string name="share_qr_code_dialog_start">Mit \'Weiter\' durch alle QR-Codes gehen und diese nacheinander scannen.</string> <string name="share_qr_code_dialog_start">Mit \'Weiter\' durch alle QR-Codes gehen und diese nacheinander scannen.</string>
@ -372,6 +376,8 @@
<!--Key view--> <!--Key view-->
<string name="key_view_action_encrypt">Für diesen Kontakt verschlüsseln</string> <string name="key_view_action_encrypt">Für diesen Kontakt verschlüsseln</string>
<string name="key_view_action_certify">Schlüssel dieses Kontakts beglaubigen</string> <string name="key_view_action_certify">Schlüssel dieses Kontakts beglaubigen</string>
<string name="key_view_tab_main">Info</string>
<string name="key_view_tab_certs">Zertifikationen</string>
<!--Navigation Drawer--> <!--Navigation Drawer-->
<string name="nav_contacts">Kontakte</string> <string name="nav_contacts">Kontakte</string>
<string name="nav_encrypt">Verschlüsseln</string> <string name="nav_encrypt">Verschlüsseln</string>

View File

@ -266,6 +266,9 @@
<string name="error_expiry_must_come_after_creation">la fecha de caducidad debe ser posterior a la fecha de creación</string> <string name="error_expiry_must_come_after_creation">la fecha de caducidad debe ser posterior a la fecha de creación</string>
<string name="error_can_not_delete_contact">no puedes eliminar este contacto porque eres tú mismo.</string> <string name="error_can_not_delete_contact">no puedes eliminar este contacto porque eres tú mismo.</string>
<string name="error_can_not_delete_contacts">no puedes eliminar los siguientes contactos porque son tú mismo:\n%s</string> <string name="error_can_not_delete_contacts">no puedes eliminar los siguientes contactos porque son tú mismo:\n%s</string>
<string name="error_keyserver_insufficient_query">Consulta al servidor insuficiente</string>
<string name="error_keyserver_query">La consulta al servidor de claves ha fallado</string>
<string name="error_keyserver_too_many_responses">Demasiadas respuestas</string>
<plurals name="error_can_not_delete_info"> <plurals name="error_can_not_delete_info">
<item quantity="one">Por favor, bórralo desde la pantalla \'Mis claves\'!</item> <item quantity="one">Por favor, bórralo desde la pantalla \'Mis claves\'!</item>
<item quantity="other">Por favor, bórralos desde la pantalla \'Mis claves\'!</item> <item quantity="other">Por favor, bórralos desde la pantalla \'Mis claves\'!</item>
@ -337,12 +340,12 @@
<string name="import_nfc_help_button">Ayuda</string> <string name="import_nfc_help_button">Ayuda</string>
<string name="import_clipboard_button">Tomar la clave desde el portapapeles</string> <string name="import_clipboard_button">Tomar la clave desde el portapapeles</string>
<!--Intent labels--> <!--Intent labels-->
<string name="intent_decrypt_file">OpenPGP: Descifrar archivo</string> <string name="intent_decrypt_file">Descifrar archivo con OpenKeychain</string>
<string name="intent_import_key">OpenPGP: Importar clave</string> <string name="intent_import_key">Importar clave con OpenKeychain</string>
<string name="intent_send_encrypt">OpenPGP: Cifrar</string> <string name="intent_send_encrypt">Cifrar con OpenKeychain</string>
<string name="intent_send_decrypt">OpenPGP: Descifrar</string> <string name="intent_send_decrypt">Descifrar con OpenKeychain</string>
<!--Remote API--> <!--Remote API-->
<string name="api_no_apps">¡No hay aplicaciones registradas¡\n\nLas aplicaciones de terceros pueden pedir acceso a OpenPGP Keychain. Después de recibir permiso, se mostrarán aquí.</string> <string name="api_no_apps">¡No hay aplicaciones registradas!\n\nLas aplicaciones de terceros pueden pedir permiso de acceso a OpenKeychain. Después de obtener acceso, serán enumeradas aquí.</string>
<string name="api_settings_show_advanced">Mostrar la configuración avanzada</string> <string name="api_settings_show_advanced">Mostrar la configuración avanzada</string>
<string name="api_settings_hide_advanced">Ocultar la configuración avanzada</string> <string name="api_settings_hide_advanced">Ocultar la configuración avanzada</string>
<string name="api_settings_no_key">No se ha seleccionado ninguna clave</string> <string name="api_settings_no_key">No se ha seleccionado ninguna clave</string>
@ -352,14 +355,14 @@
<string name="api_settings_revoke">Revocar acceso</string> <string name="api_settings_revoke">Revocar acceso</string>
<string name="api_settings_package_name">Nombre de paquete</string> <string name="api_settings_package_name">Nombre de paquete</string>
<string name="api_settings_package_signature">SHA-256 de firma de paquete</string> <string name="api_settings_package_signature">SHA-256 de firma de paquete</string>
<string name="api_register_text">La aplicación mostrada pide acceso a OpenPGP Keychain.\n¿Permitir acceso?\n\nAVISO: Si no sabes por qué ha aparecido esta pantalla, ¡deniega el acceso! Puedes revocar el acceso más tarde usando la ventana \'Aplicaciones Registradas\'.</string> <string name="api_register_text">La aplicación mostrada solicita acceso a OpenKeychain.\n¿Permitir el acceso?\n\nAVISO: Si no sabes por qué aparece esta pantalla, ¡deniega el acceso! Puedes revocarlo después usando la pantalla \'Aplicaciones registradas\'.</string>
<string name="api_register_allow">Permitir el acceso</string> <string name="api_register_allow">Permitir el acceso</string>
<string name="api_register_disallow">Denegar el acceso</string> <string name="api_register_disallow">Denegar el acceso</string>
<string name="api_register_error_select_key">¡Por favor, selecciona una clave!</string> <string name="api_register_error_select_key">¡Por favor, selecciona una clave!</string>
<string name="api_select_pub_keys_missing_text">No se han encontrado claves públicas para estas IDs de usuario:</string> <string name="api_select_pub_keys_missing_text">No se han encontrado claves públicas para estas IDs de usuario:</string>
<string name="api_select_pub_keys_dublicates_text">Existe más de una clave pública para estos IDs de usuario:</string> <string name="api_select_pub_keys_dublicates_text">Existe más de una clave pública para estos IDs de usuario:</string>
<string name="api_select_pub_keys_text">¡Por favor, revisa la lista de destinatarios!</string> <string name="api_select_pub_keys_text">¡Por favor, revisa la lista de destinatarios!</string>
<string name="api_error_wrong_signature">¡La comprobación de la firma ha fallado! ¿Has instalado esta app desde una fuente distinta? Si estás seguro de que esto no es un ataque, revoca el registro de esta app en OpenPGP Keychain y regístrala de nuevo.</string> <string name="api_error_wrong_signature">¡La comprobación de la firma ha fallado! ¿Has instalado esta app desde una fuente distinta? Si estás seguro de que esto no es un ataque, revoca el registro de esta app en OpenKeychain y regístrala de nuevo.</string>
<!--Share--> <!--Share-->
<string name="share_qr_code_dialog_title">Compartir con código QR</string> <string name="share_qr_code_dialog_title">Compartir con código QR</string>
<string name="share_qr_code_dialog_start">Pasa por todos los códigos QR usando \'Siguiente\', y escanéalos de uno en uno.</string> <string name="share_qr_code_dialog_start">Pasa por todos los códigos QR usando \'Siguiente\', y escanéalos de uno en uno.</string>

View File

@ -111,6 +111,7 @@
<string name="label_passphrase_cache_ttl">Cache de la phrase de passe</string> <string name="label_passphrase_cache_ttl">Cache de la phrase de passe</string>
<string name="label_message_compression">Compression des messages</string> <string name="label_message_compression">Compression des messages</string>
<string name="label_file_compression">Compression des fichiers</string> <string name="label_file_compression">Compression des fichiers</string>
<string name="label_force_v3_signature">Forcer les anciennes signatures OpenPGP v3</string>
<string name="label_key_servers">Serveurs de clefs</string> <string name="label_key_servers">Serveurs de clefs</string>
<string name="label_key_id">ID de le clef</string> <string name="label_key_id">ID de le clef</string>
<string name="label_creation">Création</string> <string name="label_creation">Création</string>
@ -253,6 +254,7 @@
<string name="error_no_signature_key">aucune clef de signature n\'a été donnée</string> <string name="error_no_signature_key">aucune clef de signature n\'a été donnée</string>
<string name="error_invalid_data">aucune donnée de chiffrement valide</string> <string name="error_invalid_data">aucune donnée de chiffrement valide</string>
<string name="error_corrupt_data">données corrompues</string> <string name="error_corrupt_data">données corrompues</string>
<string name="error_integrity_check_failed">la vérification de l\'intégrité a échoué ! Les données ont été modifiées !</string>
<string name="error_no_symmetric_encryption_packet">paquet avec chiffrement symétrique introuvable</string> <string name="error_no_symmetric_encryption_packet">paquet avec chiffrement symétrique introuvable</string>
<string name="error_wrong_passphrase">phrase de passe erronnée</string> <string name="error_wrong_passphrase">phrase de passe erronnée</string>
<string name="error_saving_keys">erreur lors de la sauvegarde de certaines clefs</string> <string name="error_saving_keys">erreur lors de la sauvegarde de certaines clefs</string>
@ -264,6 +266,9 @@
<string name="error_expiry_must_come_after_creation">la date d\'expiration doit venir après la date de création</string> <string name="error_expiry_must_come_after_creation">la date d\'expiration doit venir après la date de création</string>
<string name="error_can_not_delete_contact">vous ne pouvez pas supprimer ce contact car c\'est le vôtre.</string> <string name="error_can_not_delete_contact">vous ne pouvez pas supprimer ce contact car c\'est le vôtre.</string>
<string name="error_can_not_delete_contacts">vous ne pouvez pas supprimer les contacts suivants car c\'est les vôtres.\n%s</string> <string name="error_can_not_delete_contacts">vous ne pouvez pas supprimer les contacts suivants car c\'est les vôtres.\n%s</string>
<string name="error_keyserver_insufficient_query">Requête serveur insuffisante</string>
<string name="error_keyserver_query">Échec lors de l\'interrogation du serveur de clefs</string>
<string name="error_keyserver_too_many_responses">Trop de réponses</string>
<plurals name="error_can_not_delete_info"> <plurals name="error_can_not_delete_info">
<item quantity="one">Veuillez le supprimer depuis l\'écran « Mes Clefs »!</item> <item quantity="one">Veuillez le supprimer depuis l\'écran « Mes Clefs »!</item>
<item quantity="other">Veuillez les supprimer depuis l\'écran « Mes Clefs »!</item> <item quantity="other">Veuillez les supprimer depuis l\'écran « Mes Clefs »!</item>
@ -335,12 +340,12 @@
<string name="import_nfc_help_button">Aide</string> <string name="import_nfc_help_button">Aide</string>
<string name="import_clipboard_button">Obtenir la clef depuis le presse-papiers</string> <string name="import_clipboard_button">Obtenir la clef depuis le presse-papiers</string>
<!--Intent labels--> <!--Intent labels-->
<string name="intent_decrypt_file">OpenPGP : déchiffrer le ficher</string> <string name="intent_decrypt_file">Déchiffrer le fichier avec OpenKeychain</string>
<string name="intent_import_key">OpenPGP : importer la clef</string> <string name="intent_import_key">Importer la clef avec OpenKeychain</string>
<string name="intent_send_encrypt">OpenPGP : chiffrer</string> <string name="intent_send_encrypt">Chiffrer avec OpenKeychain</string>
<string name="intent_send_decrypt">OpenPGP : déchiffrer</string> <string name="intent_send_decrypt">Déchiffrer avec OpenKeychain</string>
<!--Remote API--> <!--Remote API-->
<string name="api_no_apps">Aucune application enregistrée !\n\nLes applications tierces peuvent demander l\'accès au Porte-clefs OpenPGP. Après avoir autoriser l\'accès, elles seront listées ici.</string> <string name="api_no_apps">Aucune application enregistrée !\n\nLes applications tierces peuvent demander l\'accès à OpenKeychain. Après avoir autorisé l\'accès, elles seront listées ici.</string>
<string name="api_settings_show_advanced">Afficher les paramètres avancés</string> <string name="api_settings_show_advanced">Afficher les paramètres avancés</string>
<string name="api_settings_hide_advanced">Masquer les paramètres avancés</string> <string name="api_settings_hide_advanced">Masquer les paramètres avancés</string>
<string name="api_settings_no_key">Aucune clef choisie</string> <string name="api_settings_no_key">Aucune clef choisie</string>
@ -350,14 +355,14 @@
<string name="api_settings_revoke">Révoquer l\'accès</string> <string name="api_settings_revoke">Révoquer l\'accès</string>
<string name="api_settings_package_name">Nom du paquet</string> <string name="api_settings_package_name">Nom du paquet</string>
<string name="api_settings_package_signature">SHA-256 de la signature du paquet</string> <string name="api_settings_package_signature">SHA-256 de la signature du paquet</string>
<string name="api_register_text">L\'application affichée demande l\'accès au Porte-clefs OpenPGP.\nPermettre l\'accès ?\n\nAvertissement : si vous ne savez pas pourquoi cet écran est apparu, refusé l\'accès ! Vous pourrez révoquer l\'accès plus tard en utilisant l\'écran « Applications enregistrées ».</string> <string name="api_register_text">L\'application affichée demande l\'accès à OpenKeychain.\nPermettre l\'accès ?\n\nAvertissement : si vous ne savez pas pourquoi cet écran est apparu, refusez l\'accès ! Vous pourrez révoquer l\'accès plus tard en utilisant l\'écran « Applications enregistrées ».</string>
<string name="api_register_allow">Permettre l\'accès</string> <string name="api_register_allow">Permettre l\'accès</string>
<string name="api_register_disallow">Enlever l\'accès</string> <string name="api_register_disallow">Enlever l\'accès</string>
<string name="api_register_error_select_key">Veuillez choisir une clef !</string> <string name="api_register_error_select_key">Veuillez choisir une clef !</string>
<string name="api_select_pub_keys_missing_text">Aucune clef publique n\'a été trouvée pour ces IDs utilisateur :</string> <string name="api_select_pub_keys_missing_text">Aucune clef publique n\'a été trouvée pour ces IDs utilisateur :</string>
<string name="api_select_pub_keys_dublicates_text">Plus d\'une clef publique existe pour ces IDs utilisateur</string> <string name="api_select_pub_keys_dublicates_text">Plus d\'une clef publique existe pour ces IDs utilisateur</string>
<string name="api_select_pub_keys_text">Veuillez revoir la liste des destinataires !</string> <string name="api_select_pub_keys_text">Veuillez revoir la liste des destinataires !</string>
<string name="api_error_wrong_signature">La vérification de la signature a échoué ! Avez-vous installé cette appli à partir d\'une source différente ? Si vous êtes sûr que ce n\'est pas une attaque, révoquer l\'enregistrement de cette appli dans le Porte-clefs OpenPGP et l\'enregistrer à nouveau.</string> <string name="api_error_wrong_signature">La vérification de la signature a échoué ! Avez-vous installé cette appli à partir d\'une source différente ? Si vous êtes sûr que ce n\'est pas une attaque, révoquez l\'enregistrement de cette appli dans OpenKeychain et enregistrez-la à nouveau.</string>
<!--Share--> <!--Share-->
<string name="share_qr_code_dialog_title">Partager par un code QR</string> <string name="share_qr_code_dialog_title">Partager par un code QR</string>
<string name="share_qr_code_dialog_start">Balayer tous les codes QR un par un en utilisant « Suivant ».</string> <string name="share_qr_code_dialog_start">Balayer tous les codes QR un par un en utilisant « Suivant ».</string>

View File

@ -1,89 +1,396 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<resources> <resources>
<!--title--> <!--title-->
<string name="title_select_recipients">Selezionare Chiave Pubblica</string> <string name="title_manage_public_keys">Contatti</string>
<string name="title_select_secret_key">Selezionare Chiave Privata</string> <string name="title_manage_secret_keys">Chiavi Private</string>
<string name="title_encrypt">Cifrare</string> <string name="title_select_recipients">Seleziona Chiave Pubblica</string>
<string name="title_decrypt">Decifrare</string> <string name="title_select_secret_key">Seleziona Chiave Privata</string>
<string name="title_authentication">Passphrase</string> <string name="title_encrypt">Codifica</string>
<string name="title_create_key">Creare Chiave</string> <string name="title_decrypt">Decodifica</string>
<string name="title_edit_key">Modificare Chiave</string> <string name="title_authentication">Frase di accesso</string>
<string name="title_create_key">Crea Chiave</string>
<string name="title_edit_key">Modifica Chiave</string>
<string name="title_preferences">Preferenze</string> <string name="title_preferences">Preferenze</string>
<string name="title_set_passphrase">Impostare Passphrase</string> <string name="title_api_registered_apps">App Registrate</string>
<string name="title_send_email">Inviare Mail...</string> <string name="title_key_server_preference">Preferenze Server delle Chiavi</string>
<string name="title_import_keys">Importare Chiavi</string> <string name="title_change_pass_phrase">Cambia Frase di Accesso</string>
<string name="title_export_key">Esportare Chiave</string> <string name="title_set_passphrase">Imposta Frase di Accesso</string>
<string name="title_export_keys">Esportare Chiavi</string> <string name="title_send_email">Invia Mail...</string>
<string name="title_encrypt_to_file">Codifica File</string>
<string name="title_decrypt_to_file">Decodifica File</string>
<string name="title_import_keys">Importa Chiavi</string>
<string name="title_export_key">Esporta Chiave</string>
<string name="title_export_keys">Esporta Chiavi</string>
<string name="title_key_not_found">Chiave Non Trovata</string> <string name="title_key_not_found">Chiave Non Trovata</string>
<string name="title_key_server_query">Interroga Server delle Chiavi</string>
<string name="title_send_key">Carica sul Server delle Chiavi</string>
<string name="title_unknown_signature_key">Chiave di Firma Sconosciuta</string>
<string name="title_certify_key">Certifica Chiave</string>
<string name="title_key_details">Dettagli Chiave</string>
<string name="title_help">Aiuto</string> <string name="title_help">Aiuto</string>
<!--section--> <!--section-->
<string name="section_user_ids">ID Utente</string> <string name="section_user_ids">ID Utente</string>
<string name="section_keys">Chiavi</string> <string name="section_keys">Chiavi</string>
<string name="section_general">Generale</string> <string name="section_general">Generale</string>
<string name="section_defaults">Predefiniti</string>
<string name="section_advanced">Avanzato</string> <string name="section_advanced">Avanzato</string>
<string name="section_master_key">Chiave Principale</string>
<string name="section_master_user_id">ID Utente Principale</string>
<string name="section_actions">Azioni</string>
<string name="section_certification_key">La Tua Chiave usata per la certificazione</string>
<string name="section_upload_key">Carica Chiave</string>
<string name="section_key_server">Server delle Chiavi</string>
<string name="section_encrypt_and_or_sign">Codifica e/o Firma</string>
<string name="section_decrypt_verify">Decodifica e Verifica</string>
<!--button--> <!--button-->
<string name="btn_sign">Firmare</string> <string name="btn_sign">Firma</string>
<string name="btn_decrypt">Decifrare</string> <string name="btn_certify">Certifica</string>
<string name="btn_encrypt_file">Cifrare File</string> <string name="btn_decrypt">Decodifica</string>
<string name="btn_decrypt_verify">Decodifica e Verifica</string>
<string name="btn_select_encrypt_keys">Seleziona Destinatari</string>
<string name="btn_encrypt_file">Codifica File</string>
<string name="btn_save">Salva</string> <string name="btn_save">Salva</string>
<string name="btn_do_not_save">Cancella</string> <string name="btn_do_not_save">Annulla</string>
<string name="btn_delete">Eliminare</string> <string name="btn_delete">Elimina</string>
<string name="btn_no_date">Nessuno</string> <string name="btn_no_date">Nessuno</string>
<string name="btn_okay">Okay</string> <string name="btn_okay">Okay</string>
<string name="btn_change_passphrase">Cambiare passphrase</string> <string name="btn_change_passphrase">Cambia Frase Di Accesso</string>
<string name="btn_search">Cercare</string> <string name="btn_set_passphrase">Imposta Frase di Accesso</string>
<string name="btn_search">Cerca</string>
<string name="btn_export_to_server">Carica sul Server delle Chiavi</string>
<string name="btn_next">Prossimo</string>
<string name="btn_back">Precedente</string>
<string name="btn_clipboard">Appunti</string>
<string name="btn_share">Condividi con...</string>
<string name="btn_lookup_key">Chiave di ricerca</string>
<!--menu--> <!--menu-->
<string name="menu_preferences">Impostazioni</string> <string name="menu_preferences">Impostazioni</string>
<string name="menu_import_from_file">Importare da file</string> <string name="menu_help">Aiuto</string>
<string name="menu_import_from_qr_code">Importare da QR Code</string> <string name="menu_import_from_file">Importa da file</string>
<string name="menu_delete_key">Eliminare chiave</string> <string name="menu_import_from_qr_code">Importa da Codice QR</string>
<string name="menu_create_key">Creare chiave</string> <string name="menu_import">Importa</string>
<string name="menu_search">Cercare</string> <string name="menu_import_from_nfc">Importa tramite NFC</string>
<string name="menu_export_keys">Esporta tutte le chiavi</string>
<string name="menu_export_key">Esporta su un file</string>
<string name="menu_delete_key">Cancella chiave</string>
<string name="menu_create_key">Crea chiave</string>
<string name="menu_create_key_expert">Crea chiave (esperto)</string>
<string name="menu_search">Cerca</string>
<string name="menu_key_server">Importa dal server delle chiavi</string>
<string name="menu_update_key">Aggiorna dal server delle chiavi</string>
<string name="menu_export_key_to_server">Carica chiave nel server</string>
<string name="menu_share">Condividi</string>
<string name="menu_share_title_fingerprint">Condivi impronta...</string>
<string name="menu_share_title">Condividi intera chiave...</string>
<string name="menu_share_default_fingerprint">con..</string>
<string name="menu_share_default">con...</string>
<string name="menu_share_qr_code">con Codice QR</string>
<string name="menu_share_qr_code_fingerprint">con Codice QR</string>
<string name="menu_share_nfc">con NFC</string>
<string name="menu_copy_to_clipboard">Copia negli appunti</string>
<string name="menu_sign_key">Firma chiave</string>
<string name="menu_beam_preferences">Impostazioni Beam</string>
<string name="menu_key_edit_cancel">Annulla</string>
<string name="menu_encrypt_to">Codifica su...</string>
<!--label--> <!--label-->
<string name="label_sign">Firma</string>
<string name="label_message">Messaggio</string>
<string name="label_file">File</string>
<string name="label_no_passphrase">Nessuna Frase di Accesso</string>
<string name="label_passphrase">Frase di Accesso</string>
<string name="label_passphrase_again">Ancora</string>
<string name="label_algorithm">Algortimo</string>
<string name="label_ascii_armor">Armatura ASCII</string>
<string name="label_select_public_keys">Destinatari</string>
<string name="label_delete_after_encryption">Cancella Dopo Codifica</string>
<string name="label_delete_after_decryption">Cancella Dopo Decodifica</string>
<string name="label_encryption_algorithm">Algoritmo di Codifica</string>
<string name="label_hash_algorithm">Algoritmo di Hash</string>
<string name="label_asymmetric">Chiave Pubblica</string>
<string name="label_symmetric">Frase di Accesso</string>
<string name="label_passphrase_cache_ttl">Cache Frase di Accesso</string>
<string name="label_message_compression">Compressione Messaggio</string>
<string name="label_file_compression">Compressione File</string>
<string name="label_force_v3_signature">Forza vecchie Firme OpenPGPv3</string>
<string name="label_key_servers">Server Chiavi</string>
<string name="label_key_id">ID Chiave</string>
<string name="label_creation">Creazione</string>
<string name="label_expiry">Scadenza</string>
<string name="label_usage">Utilizzo</string>
<string name="label_key_size">Dimensione Chiave</string>
<string name="label_main_user_id">ID Utente Principale</string>
<string name="label_name">Nome</string>
<string name="label_comment">Commento</string>
<string name="label_email">Email</string>
<string name="label_send_key">Carica chiave nel server delle chiavi selezionati dopo la certificazione</string>
<string name="label_fingerprint">Impronta</string>
<string name="select_keys_button_default">Seleziona</string>
<plurals name="select_keys_button">
<item quantity="one">%d selezionato</item>
<item quantity="other">%d selezionati</item>
</plurals>
<string name="user_id_no_name">&lt;nessun nome&gt;</string>
<string name="none">&lt;nessuno&gt;</string>
<string name="no_key">&lt;nessuna chiave&gt;</string>
<string name="unknown_status"></string> <string name="unknown_status"></string>
<string name="can_encrypt">puo\'; codificare</string>
<string name="can_sign">puo\' firmare</string>
<string name="expired">scaduto</string>
<string name="revoked">revocato</string>
<plurals name="n_key_servers">
<item quantity="one">%d server delle chiavi</item>
<item quantity="other">%d server delle chiavi</item>
</plurals>
<string name="fingerprint">Impronta:</string>
<string name="secret_key">Chiave Privata:</string>
<!--choice--> <!--choice-->
<string name="choice_none">Nessuno</string>
<string name="choice_sign_only">Firma soltanto</string>
<string name="choice_encrypt_only">Codifica soltanto</string>
<string name="choice_sign_and_encrypt">Firma e Codifica</string>
<string name="choice_15secs">15 sec</string>
<string name="choice_1min">1 min</string>
<string name="choice_3mins">3 min</string>
<string name="choice_5mins">5 min</string>
<string name="choice_10mins">10 min</string>
<string name="choice_20mins">20 min</string>
<string name="choice_40mins">40 min</string>
<string name="choice_1hour">1 ora</string> <string name="choice_1hour">1 ora</string>
<string name="choice_2hours">2 ore</string> <string name="choice_2hours">2 ore</string>
<string name="choice_4hours">4 ore</string> <string name="choice_4hours">4 ore</string>
<string name="choice_8hours">8 ore</string> <string name="choice_8hours">8 ore</string>
<string name="choice_forever">sempre</string>
<string name="dsa">DSA</string> <string name="dsa">DSA</string>
<string name="elgamal">ElGamal</string> <string name="elgamal">ElGamal</string>
<string name="rsa">RSA</string> <string name="rsa">RSA</string>
<string name="filemanager_title_open">Apri...</string>
<string name="warning">Attenzione</string> <string name="warning">Attenzione</string>
<string name="error">Errore</string> <string name="error">Errore</string>
<string name="error_message">Errore: %s</string> <string name="error_message">Errore: %s</string>
<!--sentences--> <!--sentences-->
<string name="wrong_passphrase">Frase di Accesso errata</string>
<string name="using_clipboard_content">Utilizzo il contenuto degli appunti.</string>
<string name="set_a_passphrase">Imposta prima una frase di accesso.</string>
<string name="no_filemanager_installed">Nessun gestore file compatibile installato.</string>
<string name="passphrases_do_not_match">Le frasi di accesso non corrispondono.</string>
<string name="passphrase_must_not_be_empty">Frasi di accesso vuote non consentite.</string>
<string name="passphrase_for_symmetric_encryption">Codifica Simmetrica.</string>
<string name="passphrase_for">Inserisci la frase di accesso per \'%s\'</string>
<string name="file_delete_confirmation">Sei sicuro di voler cancellare\n%s?</string>
<string name="file_delete_successful">Eliminato correttamente.</string>
<string name="no_file_selected">Seleziona un file prima.</string>
<string name="decryption_successful">Decodificato correttamente.</string>
<string name="encryption_successful">Codificato correttamente.</string>
<string name="encryption_to_clipboard_successful">Codificato correttamente negli appunti.</string>
<string name="enter_passphrase_twice">Inserisci la frase di accesso due volte.</string>
<string name="select_encryption_key">Seleziona almeno una chiave di codifica.</string>
<string name="select_encryption_or_signature_key">Seleziona almeno una chiave di codifica o di firma.</string>
<string name="specify_file_to_encrypt_to">Perfavore specifica quale file codificare.\nATTENZIONE: Il file sara\' sovrascritto se esistente.</string>
<string name="specify_file_to_decrypt_to">Perfavore specifica quale file decodificare.\nATTENZIONE: Il file sara\' sovrascritto se esistente.</string>
<string name="specify_file_to_export_to">Perfavore specifica su quale file esportare.\nATTENZIONE: Il file sara\' sovrascritto se esistente.</string>
<string name="specify_file_to_export_secret_keys_to">Perfavore specifica quale file esportare.\nATTENZIONE: Stai esportanto chiavi PRIVATE.\nATTENZIONE: Il file sara\' sovrascritto se esistente.</string>
<string name="key_deletion_confirmation">Vuoi veramente eliminare la chiave \'%s\'?\nNon potrai annullare!</string>
<string name="key_deletion_confirmation_multi">Vuoi veramente eliminare le chiavi selezionate?\nNon potrai annullare!</string>
<string name="secret_key_deletion_confirmation">Vuoi veramente eliminare la chiave PRIVATA \'%s\'?\nNon potrai annullare!</string>
<plurals name="keys_added_and_updated_1">
<item quantity="one">%d chiave aggiunta correttamente</item>
<item quantity="other">%d chiavi aggiunte correttamente</item>
</plurals>
<plurals name="keys_added_and_updated_2">
<item quantity="one">e %d chiave aggiornata.</item>
<item quantity="other">e %d chiavi aggiornate.</item>
</plurals>
<plurals name="keys_added">
<item quantity="one">%d chiave aggiunta correttamente.</item>
<item quantity="other">%d chiavi aggiunte correttamente.</item>
</plurals>
<plurals name="keys_updated">
<item quantity="one">%d chiave aggiornata correttamente.</item>
<item quantity="other">%d chiavi aggiornate correttamente.</item>
</plurals>
<string name="no_keys_added_or_updated">Nessuna chiave aggiunta o aggiornata.</string>
<string name="key_exported">1 chiave esportata correttamente.</string>
<string name="keys_exported">%d chiavi esportate correttamente.</string>
<string name="no_keys_exported">Nessuna chiave esportata.</string>
<string name="key_creation_el_gamal_info">Nota: solo le sottochiavi supportano ElGamal, e per ElGamal verra\' usata la grandezza chiave piu\' vicina a 1536, 2048, 3072, 4096 o 8192.</string>
<string name="key_not_found">Impossibile trovare la chiave %08X.</string>
<plurals name="keys_found">
<item quantity="one">Trovata %d chiave.</item>
<item quantity="other">Trovate %d chiavi.</item>
</plurals>
<string name="unknown_signature">Firma sconosciuta, clicca il pulsante per ricercare la chiave mancante.</string>
<plurals name="bad_keys_encountered">
<item quantity="one">%d chiave segreta non valida ignorata. Forse hai esportato con opzione\n--export-secret-subkeys\nAssicurati di esportare con\n--export-secret-keys\ninvece.</item>
<item quantity="other">%d chiavi private non valide ignorate. Forse hai esportato con opzione\n--export-secret-subkeys\nAssicurati di esportare con\n--export-secret-keys\ninvece.</item>
</plurals>
<string name="key_send_success">Chiave caricata con successo sul server</string>
<string name="key_sign_success">Chiave firmata correttamente</string>
<string name="list_empty">Lista vuota!</string>
<string name="nfc_successfull">Chiave inviata tramite NFC Beam!</string>
<string name="key_copied_to_clipboard">Chiave copiata negli appunti!</string>
<string name="key_has_already_been_signed">La chiave e\' gia\' firmata!</string>
<string name="select_key_to_sign">Per favore seleziona la chiave per la firma!</string>
<string name="key_too_big_for_sharing">Chiave troppo grande per essere condivisa in questo modo!</string>
<!--errors <!--errors
no punctuation, all lowercase, no punctuation, all lowercase,
they will be put after "error_message", e.g. "Error: file not found"--> they will be put after "error_message", e.g. "Error: file not found"-->
<string name="error_file_delete_failed">Cancellazione di \'%s\' fallita</string>
<string name="error_file_not_found">File non trovato</string>
<string name="error_no_secret_key_found">nessuna chiave privata adatta trovata</string>
<string name="error_no_known_encryption_found">nessun tipo conosciuto di codifica trovata</string>
<string name="error_external_storage_not_ready">memoria esterna non pronta</string>
<string name="error_invalid_email">email non valida \'%s\'</string>
<string name="error_key_size_minimum512bit">La grandezza della chiave deve essere almeno di 512bit</string>
<string name="error_master_key_must_not_be_el_gamal">La chiave principale non puo\' essere ElGamal</string>
<string name="error_unknown_algorithm_choice">opzione algoritmo sconosciuta</string>
<string name="error_user_id_needs_a_name">devi specificare un nome</string>
<string name="error_user_id_needs_an_email_address">devi specificare un indirizzo email</string>
<string name="error_key_needs_a_user_id">necessario almeno un id utente</string>
<string name="error_main_user_id_must_not_be_empty">id utente principale non puo\' essere vuoto</string>
<string name="error_key_needs_master_key">necessaria almeno una chiave principale</string>
<string name="error_no_encryption_keys_or_passphrase">nessuna chiave di codifica o frase di accesso fornita</string>
<string name="error_signature_failed">firma fallita</string>
<string name="error_no_signature_passphrase">nessuna frase di accesso inserita</string>
<string name="error_no_signature_key">nessuna chiave di firma inserita</string>
<string name="error_invalid_data">dati di codifica non validi</string>
<string name="error_corrupt_data">dati corrotti</string>
<string name="error_integrity_check_failed">Controllo di integrita\' fallito! I dati sono stati modificati!</string>
<string name="error_no_symmetric_encryption_packet">impossibile trovare una pacchetto con codifica simmetrica</string>
<string name="error_wrong_passphrase">frase di accesso errata</string>
<string name="error_saving_keys">errore nel salvataggio di alcune chiavi</string>
<string name="error_could_not_extract_private_key">impossibile estrarre la chiave privata</string>
<string name="error_only_files_are_supported">Flusso di dati diretto senza file corrispettivo nel filesystem non e\' supportato. Supportato soltanto da ACTION_ENCRYPT_STREAM_AND_RETURN.</string>
<string name="error_jelly_bean_needed">Devi avere Android 4.1 alias Jelly Bean per usare Android NFC Beam!</string>
<string name="error_nfc_needed">NFC non disponibile nel tuo dispositivo!</string>
<string name="error_nothing_import">Niente da importare!</string>
<string name="error_expiry_must_come_after_creation">La data di scadenza deve essere postuma quella di creazione</string>
<string name="error_can_not_delete_contact">Non è possibile eliminare questo contatto, perché è il proprio.</string>
<string name="error_can_not_delete_contacts">Non è possibile eliminare i seguenti contatti perché sono i propri:\n%s</string>
<string name="error_keyserver_insufficient_query">Query di server insufficiente</string>
<string name="error_keyserver_query">Interrogazione del server delle chiavi fallita</string>
<string name="error_keyserver_too_many_responses">Troppi responsi</string>
<plurals name="error_can_not_delete_info">
<item quantity="one">Per favore cancellala dalla schermata \'Mie Chavi\'</item>
<item quantity="other">Per favore cancellatele dalla schermata \'Mie Chavi\'</item>
</plurals>
<!--progress dialogs, usually ending in '…'--> <!--progress dialogs, usually ending in '…'-->
<string name="progress_done">fatto.</string>
<string name="progress_saving">salvataggio...</string>
<string name="progress_importing">importazione...</string>
<string name="progress_exporting">esportazione...</string>
<string name="progress_generating">generazione chiave, richiede fino a 3 minuti...</string>
<string name="progress_building_key">fabbricazione chiave...</string>
<string name="progress_preparing_master_key">preparazione chiave principale...</string>
<string name="progress_certifying_master_key">certificazione chiave principale...</string>
<string name="progress_building_master_key">fabbricazione portachiavi principale...</string>
<string name="progress_adding_sub_keys">aggiunta sottochiavi...</string>
<string name="progress_saving_key_ring">salvataggio chiavi...</string>
<plurals name="progress_exporting_key">
<item quantity="one">esportazione chiave...</item>
<item quantity="other">esportazione chiavi...</item>
</plurals>
<string name="progress_extracting_signature_key">estrazione chiavi di firma...</string>
<string name="progress_extracting_key">estrazione chiave...</string>
<string name="progress_preparing_streams">preparazione flussi...</string>
<string name="progress_encrypting">codifica dati...</string>
<string name="progress_decrypting">decodifica dati...</string>
<string name="progress_preparing_signature">preparazione firma...</string>
<string name="progress_generating_signature">generazione firma...</string>
<string name="progress_processing_signature">elaborazione firma...</string>
<string name="progress_verifying_signature">verifica firma...</string>
<string name="progress_signing">firma...</string>
<string name="progress_reading_data">lettura dati...</string>
<string name="progress_finding_key">ricerca chiave...</string>
<string name="progress_decompressing_data">decompressione dati...</string>
<string name="progress_verifying_integrity">verifica integrita\'...</string>
<string name="progress_deleting_securely">eliminazione sicura di \'%s\'...</string>
<string name="progress_querying">interrogazione...</string>
<!--action strings--> <!--action strings-->
<string name="hint_public_keys">Ricerca Chiavi Pubbliche</string>
<string name="hint_secret_keys">Cerca Chiave Privata</string>
<string name="action_share_key_with">Condividi chiave con...</string>
<!--key bit length selections--> <!--key bit length selections-->
<string name="key_size_512">512</string> <string name="key_size_512">512</string>
<string name="key_size_1024">1024</string> <string name="key_size_1024">1024</string>
<string name="key_size_2048">2048</string> <string name="key_size_2048">2048</string>
<string name="key_size_4096">4096</string> <string name="key_size_4096">4096</string>
<!--compression--> <!--compression-->
<string name="compression_fast">veloce</string>
<string name="compression_very_slow">molto lento</string>
<!--Help--> <!--Help-->
<string name="help_tab_start">Inizia</string>
<string name="help_tab_nfc_beam">NFC Beam</string> <string name="help_tab_nfc_beam">NFC Beam</string>
<string name="help_tab_changelog">Changelog</string> <string name="help_tab_changelog">Novita\'</string>
<string name="help_tab_about">About</string> <string name="help_tab_about">Info</string>
<string name="help_about_version">Versione:</string> <string name="help_about_version">Versione:</string>
<!--Import--> <!--Import-->
<string name="import_import">Importa chiavi selezionate</string>
<string name="import_sign_and_upload">Importa, Firma e carica le chiavi selezionate</string>
<string name="import_from_clipboard">Importa dagli appunti</string>
<plurals name="import_qr_code_missing">
<item quantity="one">Codice QR con ID %s mancante</item>
<item quantity="other">Codici QR con ID %s mancanti</item>
</plurals>
<string name="import_qr_code_start_with_one">Perfavore inizia col Codice QR con ID 1</string>
<string name="import_qr_code_wrong">Codica QR deformato! Prova di nuovo!</string>
<string name="import_qr_code_finished">Scansione codice QR completata!</string>
<string name="import_qr_code_too_short_fingerprint">Impronta contenuta nel Codice QR troppo corta (&lt; 16 caratteri)</string>
<string name="import_qr_scan_button">Scansiona il Codice QR con \'Barcode Scanner\'</string>
<string name="import_nfc_text">Per ricevere le chiavi via NFC, il dispositivo deve essere sbloccato.</string>
<string name="import_nfc_help_button">Aiuto</string>
<string name="import_clipboard_button">Ottieni chiave dagli appunti</string>
<!--Intent labels--> <!--Intent labels-->
<string name="intent_send_encrypt">OpenPGP: Cifrare</string> <string name="intent_decrypt_file">Decodifica File con OpenKeychain</string>
<string name="intent_send_decrypt">OpenPGP: Decifrare</string> <string name="intent_import_key">Importa Chiave con OpenKeychain</string>
<string name="intent_send_encrypt">Codifica con OpenKeychain</string>
<string name="intent_send_decrypt">Decodifica con OpenKeychain</string>
<!--Remote API--> <!--Remote API-->
<string name="api_no_apps">Nessuna app registrata!\n\nApp di terza parti possono richiedere accesso a OpenKeychain. Dopo aver concesso l\'accesso, saranno elencate qui.</string>
<string name="api_settings_show_advanced">Mostra impostazioni avanzate</string>
<string name="api_settings_hide_advanced">Nascondi impostazioni avanzate</string>
<string name="api_settings_no_key">Nessuna chiave selezionata</string> <string name="api_settings_no_key">Nessuna chiave selezionata</string>
<string name="api_settings_select_key">Selezionare chiave</string> <string name="api_settings_select_key">Seleziona chiave</string>
<string name="api_settings_save">Salvare</string> <string name="api_settings_save">Salva</string>
<string name="api_settings_cancel">Cancellare</string> <string name="api_settings_cancel">Annulla</string>
<string name="api_settings_revoke">Revocare l\'accesso</string> <string name="api_settings_revoke">Revoca accesso</string>
<string name="api_register_allow">Permettere l\'accesso</string> <string name="api_settings_package_name">Nome Pacchetto</string>
<string name="api_register_disallow">Disabilitare l\'accesso</string> <string name="api_settings_package_signature">SHA-256 della Firma del Pacchetto</string>
<string name="api_register_text">Le app visualizzate hanno richiesto l\'accesso a OpenKeychain.\nPermetti accesso?\n\nATTENZIONE: Se non sai perche\' questo schermata e\' apparsa, nega l\'accesso! Puoi revocare l\'accesso dopo, usando la schermata \'App Registrate\'.</string>
<string name="api_register_allow">Permetti accesso</string>
<string name="api_register_disallow">Nega accesso</string>
<string name="api_register_error_select_key">Per favore selezionare una chiave!</string> <string name="api_register_error_select_key">Per favore selezionare una chiave!</string>
<string name="api_select_pub_keys_missing_text">Nessuna chiave pubblica trovata per id utente:</string>
<string name="api_select_pub_keys_dublicates_text">Esistono piu\' di una chiave pubblica per gli id utenti:</string>
<string name="api_select_pub_keys_text">Per favore ricontrolla la lista destinatari!</string>
<string name="api_error_wrong_signature">Controllo della firma fallito! Hai installato questa app da una fonte diversa? Se sei sicuro che non sia un attacco, revoca la registrazione di questa app in OpenKeychain e dopo registra di nuovo l\'app.</string>
<!--Share--> <!--Share-->
<string name="share_qr_code_dialog_title">Condividi tramite Codice QR</string>
<string name="share_qr_code_dialog_start">Scorri tutti i Codici QR usando \'Prossimo\', a scansionali uno ad uno.</string>
<string name="share_qr_code_dialog_fingerprint_text">Impronta:</string>
<string name="share_qr_code_dialog_progress">Codice QR con ID %1$d di %2$d</string>
<string name="share_nfc_dialog">Condividi tramite NFC</string>
<!--Key list--> <!--Key list-->
<plurals name="key_list_selected_keys">
<item quantity="one">1 chiave selezionata.</item>
<item quantity="other">%d chiavi selezionate.</item>
</plurals>
<string name="key_list_empty_text1">Nessuna chiave disponibile...</string>
<string name="key_list_empty_text2">Puoi iniziare da</string>
<string name="key_list_empty_text3">o</string>
<string name="key_list_empty_button_create">creazione della tua chiave</string>
<string name="key_list_empty_button_import">importazione chiavi.</string>
<!--Key view--> <!--Key view-->
<string name="key_view_action_encrypt">Codifica a questo contatto</string>
<string name="key_view_action_certify">Certifica la chiave di questo contatto</string>
<string name="key_view_tab_main">Info</string>
<string name="key_view_tab_certs">Certificazioni</string>
<!--Navigation Drawer--> <!--Navigation Drawer-->
<string name="nav_contacts">Contatti</string>
<string name="nav_encrypt">Codifica</string>
<string name="nav_decrypt">Decodifica</string>
<string name="nav_import">Importare Chiavi</string>
<string name="nav_secret_keys">Le Mie Chiavi</string>
<string name="nav_apps">App Registrate</string>
<string name="drawer_open">Apri drawer di navigazione</string>
<string name="drawer_close">Chiudi drawer di navigazione</string>
</resources> </resources>

View File

@ -258,6 +258,9 @@
<string name="error_expiry_must_come_after_creation">期限日時は生成日時より後である必要があります</string> <string name="error_expiry_must_come_after_creation">期限日時は生成日時より後である必要があります</string>
<string name="error_can_not_delete_contact">この連絡先はあなたなので削除できません。</string> <string name="error_can_not_delete_contact">この連絡先はあなたなので削除できません。</string>
<string name="error_can_not_delete_contacts">この連絡先はあなたなので削除できません。:\n%s</string> <string name="error_can_not_delete_contacts">この連絡先はあなたなので削除できません。:\n%s</string>
<string name="error_keyserver_insufficient_query">サーバへのクエリーが不足しています</string>
<string name="error_keyserver_query">鍵サーバへのクエリーが失敗</string>
<string name="error_keyserver_too_many_responses">レスポンスが多すぎます</string>
<plurals name="error_can_not_delete_info"> <plurals name="error_can_not_delete_info">
<item quantity="other">\'自分の鍵\'画面から削除してください!</item> <item quantity="other">\'自分の鍵\'画面から削除してください!</item>
</plurals> </plurals>
@ -326,12 +329,12 @@
<string name="import_nfc_help_button">ヘルプ</string> <string name="import_nfc_help_button">ヘルプ</string>
<string name="import_clipboard_button">クリップボードから鍵を取得</string> <string name="import_clipboard_button">クリップボードから鍵を取得</string>
<!--Intent labels--> <!--Intent labels-->
<string name="intent_decrypt_file">OpenPGP: ファイル復号</string> <string name="intent_decrypt_file">OpenKeychainでファイルを復号化</string>
<string name="intent_import_key">OpenPGP: 鍵のインポート</string> <string name="intent_import_key">OpenKeychainに鍵をインポート</string>
<string name="intent_send_encrypt">OpenPGP: 暗号化</string> <string name="intent_send_encrypt">OpenKeychainで暗号化</string>
<string name="intent_send_decrypt">OpenPGP: 復号化</string> <string name="intent_send_decrypt">OpenKeychainで復号化</string>
<!--Remote API--> <!--Remote API-->
<string name="api_no_apps">登録されていないアプリケーション!\n\nサードパーティアプリケーションはOpenPGP Keychainにアクセスを要求できます。アクセスを与えた後、それらはここにリストされます。</string> <string name="api_no_apps">登録されていないアプリケーション!\n\nサードパーティアプリケーションはOpenKeychainにアクセスを要求できます。アクセスを与えた後、それらはここにリストされます。</string>
<string name="api_settings_show_advanced">拡張設定を表示</string> <string name="api_settings_show_advanced">拡張設定を表示</string>
<string name="api_settings_hide_advanced">拡張設定を非表示</string> <string name="api_settings_hide_advanced">拡張設定を非表示</string>
<string name="api_settings_no_key">鍵が選択されていない</string> <string name="api_settings_no_key">鍵が選択されていない</string>
@ -341,14 +344,14 @@
<string name="api_settings_revoke">破棄されたアクセス</string> <string name="api_settings_revoke">破棄されたアクセス</string>
<string name="api_settings_package_name">パッケージ名</string> <string name="api_settings_package_name">パッケージ名</string>
<string name="api_settings_package_signature">パッケージの署名 SHA-256</string> <string name="api_settings_package_signature">パッケージの署名 SHA-256</string>
<string name="api_register_text">表示されているアプリケーションはOpenPGP Keychainへのアクセスを要求しています。\nアクセスを許可しますか?\n\n注意: もしなぜスクリーンに表れたかわからないなら、アクセスを許可しないでください! あなたは\'登録済みアプリケーション\'スクリーンを使って、以降のアクセスを破棄するこもできます。</string> <string name="api_register_text">表示されているアプリケーションはOpenKeychainへのアクセスを要求しています。\nアクセスを許可しますか?\n\n注意: もしなぜスクリーンに表れたかわからないなら、アクセスを許可しないでください! あなたは\'登録済みアプリケーション\'スクリーンを使って、以降のアクセスを破棄するこもできます。</string>
<string name="api_register_allow">許可されたアクセス</string> <string name="api_register_allow">許可されたアクセス</string>
<string name="api_register_disallow">許可されないアクセス</string> <string name="api_register_disallow">許可されないアクセス</string>
<string name="api_register_error_select_key">鍵を選択してください!</string> <string name="api_register_error_select_key">鍵を選択してください!</string>
<string name="api_select_pub_keys_missing_text">このユーザIDについて公開鍵が見付かりません:</string> <string name="api_select_pub_keys_missing_text">このユーザIDについて公開鍵が見付かりません:</string>
<string name="api_select_pub_keys_dublicates_text">このユーザIDについて1つ以上の公開鍵が存在します:</string> <string name="api_select_pub_keys_dublicates_text">このユーザIDについて1つ以上の公開鍵が存在します:</string>
<string name="api_select_pub_keys_text">受信者リストを確認してください!</string> <string name="api_select_pub_keys_text">受信者リストを確認してください!</string>
<string name="api_error_wrong_signature">署名チェックが失敗! 違うところからこのアプリをインストールしましたか? もし攻撃されてでなくそうであるなら、OpenPGP Keychainにあるこのアプリの登録を破棄し、再度アプリを登録してください。</string> <string name="api_error_wrong_signature">署名チェックが失敗! 違うところからこのアプリをインストールしましたか? もし攻撃されてでなくそうであるなら、OpenKeychainにあるこのアプリの登録を破棄し、再度アプリを登録してください。</string>
<!--Share--> <!--Share-->
<string name="share_qr_code_dialog_title">QRコードで共有</string> <string name="share_qr_code_dialog_title">QRコードで共有</string>
<string name="share_qr_code_dialog_start">すべてのQRコードを見る場合、\'次\' を押して一つ一つスキャンしてください。</string> <string name="share_qr_code_dialog_start">すべてのQRコードを見る場合、\'次\' を押して一つ一つスキャンしてください。</string>

View File

@ -220,10 +220,6 @@
<string name="import_qr_code_wrong">QR-code ongeldig. Probeer het opnieuw</string> <string name="import_qr_code_wrong">QR-code ongeldig. Probeer het opnieuw</string>
<string name="import_qr_code_finished">QR-code gescand</string> <string name="import_qr_code_finished">QR-code gescand</string>
<!--Intent labels--> <!--Intent labels-->
<string name="intent_decrypt_file">OpenPGP: bestand ontsleutelen</string>
<string name="intent_import_key">OpenPGP: sleutel importeren</string>
<string name="intent_send_encrypt">OpenPGP: versleutelen</string>
<string name="intent_send_decrypt">OpenPGP: ontsleutelen</string>
<!--Remote API--> <!--Remote API-->
<string name="api_settings_no_key">Geen sleutel geselecteerd</string> <string name="api_settings_no_key">Geen sleutel geselecteerd</string>
<string name="api_settings_select_key">Sleutel selecteren</string> <string name="api_settings_select_key">Sleutel selecteren</string>

View File

@ -111,6 +111,7 @@
<string name="label_passphrase_cache_ttl">Помнить пароль</string> <string name="label_passphrase_cache_ttl">Помнить пароль</string>
<string name="label_message_compression">Сжатие сообщения</string> <string name="label_message_compression">Сжатие сообщения</string>
<string name="label_file_compression">Сжатие файла</string> <string name="label_file_compression">Сжатие файла</string>
<string name="label_force_v3_signature">Использовать старые OpenPGPV3 подписи</string>
<string name="label_key_servers">Серверы ключей</string> <string name="label_key_servers">Серверы ключей</string>
<string name="label_key_id">ID ключа</string> <string name="label_key_id">ID ключа</string>
<string name="label_creation">Создан</string> <string name="label_creation">Создан</string>
@ -261,6 +262,7 @@
<string name="error_no_signature_key">ключ для подписи не задан</string> <string name="error_no_signature_key">ключ для подписи не задан</string>
<string name="error_invalid_data">некорректное шифрование</string> <string name="error_invalid_data">некорректное шифрование</string>
<string name="error_corrupt_data">данные повреждены</string> <string name="error_corrupt_data">данные повреждены</string>
<string name="error_integrity_check_failed">Проверка целостности не удалась! Данные изменились!</string>
<string name="error_no_symmetric_encryption_packet">не найден блок симметричного шифрования</string> <string name="error_no_symmetric_encryption_packet">не найден блок симметричного шифрования</string>
<string name="error_wrong_passphrase">неправильный пароль</string> <string name="error_wrong_passphrase">неправильный пароль</string>
<string name="error_saving_keys">ошибка сохранения ключей</string> <string name="error_saving_keys">ошибка сохранения ключей</string>
@ -272,6 +274,9 @@
<string name="error_expiry_must_come_after_creation">срок годности не может быть раньше даты создания</string> <string name="error_expiry_must_come_after_creation">срок годности не может быть раньше даты создания</string>
<string name="error_can_not_delete_contact">нельзя удалить свой собственный контакт. Пожалуйста, удалите его в разделе \'Мои ключи\'!</string> <string name="error_can_not_delete_contact">нельзя удалить свой собственный контакт. Пожалуйста, удалите его в разделе \'Мои ключи\'!</string>
<string name="error_can_not_delete_contacts">это ваши собственные контакты, их нельзя удалить:\n%s</string> <string name="error_can_not_delete_contacts">это ваши собственные контакты, их нельзя удалить:\n%s</string>
<string name="error_keyserver_insufficient_query">Ограничение запроса сервера</string>
<string name="error_keyserver_query">Сбой запроса сервера ключей</string>
<string name="error_keyserver_too_many_responses">Слишком много ответов</string>
<plurals name="error_can_not_delete_info"> <plurals name="error_can_not_delete_info">
<item quantity="one">Пожалуйста, удалите его в разделе \'Мои ключи\'!</item> <item quantity="one">Пожалуйста, удалите его в разделе \'Мои ключи\'!</item>
<item quantity="few">Пожалуйста, удалите их в разделе \'Мои ключи\'!</item> <item quantity="few">Пожалуйста, удалите их в разделе \'Мои ключи\'!</item>
@ -346,12 +351,12 @@
<string name="import_nfc_help_button">Помощь</string> <string name="import_nfc_help_button">Помощь</string>
<string name="import_clipboard_button">Получить ключ из буфера</string> <string name="import_clipboard_button">Получить ключ из буфера</string>
<!--Intent labels--> <!--Intent labels-->
<string name="intent_decrypt_file">OpenPGP: Расшифровать файл</string> <string name="intent_decrypt_file">OpenKeychain: Расшифровать файл</string>
<string name="intent_import_key">OpenPGP: Импортировать ключ</string> <string name="intent_import_key">OpenKeychain: Импортировать ключ</string>
<string name="intent_send_encrypt">OpenPGP: Зашифровать</string> <string name="intent_send_encrypt">OpenKeychain: Зашифровать</string>
<string name="intent_send_decrypt">OpenPGP: Расшифровать</string> <string name="intent_send_decrypt">OpenKeychain: Расшифровать</string>
<!--Remote API--> <!--Remote API-->
<string name="api_no_apps">Нет связанных программ!\n\nСторонние программы могут запросить доступ к OpenPGP Keychain, после чего они будут отражаться здесь.</string> <string name="api_no_apps">Нет связанных программ!\n\nСторонние программы могут запросить доступ к OpenKeychain, после чего они будут отражаться здесь.</string>
<string name="api_settings_show_advanced">Показать расширенные настройки</string> <string name="api_settings_show_advanced">Показать расширенные настройки</string>
<string name="api_settings_hide_advanced">Скрыть расширенные настройки</string> <string name="api_settings_hide_advanced">Скрыть расширенные настройки</string>
<string name="api_settings_no_key">Ключ не выбран</string> <string name="api_settings_no_key">Ключ не выбран</string>
@ -361,14 +366,14 @@
<string name="api_settings_revoke">Отозвать доступ</string> <string name="api_settings_revoke">Отозвать доступ</string>
<string name="api_settings_package_name">Наименование пакета</string> <string name="api_settings_package_name">Наименование пакета</string>
<string name="api_settings_package_signature">SHA-256 подписи пакета</string> <string name="api_settings_package_signature">SHA-256 подписи пакета</string>
<string name="api_register_text">Данное приложение запрашивает доступ к OpenPGP Keychain.\nРазрешить доступ?\n\nВНИМАНИЕ: Если вы не знаете почему возник этот запрос, откажите в доступе!\nПозже вы можете отозвать право доступа в разделе \"Зарегистрированные программы\".</string> <string name="api_register_text">Данное приложение запрашивает доступ к OpenKeychain.\nРазрешить доступ?\n\nВНИМАНИЕ: Если вы не знаете почему возник этот запрос, откажите в доступе!\nПозже вы можете отозвать право доступа в разделе \"Зарегистрированные программы\".</string>
<string name="api_register_allow">Разрешить доступ</string> <string name="api_register_allow">Разрешить доступ</string>
<string name="api_register_disallow">Запретить доступ</string> <string name="api_register_disallow">Запретить доступ</string>
<string name="api_register_error_select_key">Пожалуйста, выберите ключ!</string> <string name="api_register_error_select_key">Пожалуйста, выберите ключ!</string>
<string name="api_select_pub_keys_missing_text">Для этих id не найдены публичные ключи:</string> <string name="api_select_pub_keys_missing_text">Для этих id не найдены публичные ключи:</string>
<string name="api_select_pub_keys_dublicates_text">Для этих id найдено более одного ключа:</string> <string name="api_select_pub_keys_dublicates_text">Для этих id найдено более одного ключа:</string>
<string name="api_select_pub_keys_text">Пожалуйста, проверьте получателей!</string> <string name="api_select_pub_keys_text">Пожалуйста, проверьте получателей!</string>
<string name="api_error_wrong_signature">Проверка подписи пакета не удалась! Если вы установили программу из другого источника, отзовите или обновите право доступа.</string> <string name="api_error_wrong_signature">Проверка подписи пакета не удалась! Если вы установили программу из другого источника, отзовите для неё доступ к этой программе или обновите право доступа.</string>
<!--Share--> <!--Share-->
<string name="share_qr_code_dialog_title">Отправить как QR код</string> <string name="share_qr_code_dialog_title">Отправить как QR код</string>
<string name="share_qr_code_dialog_start">Сканируйте несколько QR подряд, нажимая \'Далее\' после каждого кода.</string> <string name="share_qr_code_dialog_start">Сканируйте несколько QR подряд, нажимая \'Далее\' после каждого кода.</string>

View File

@ -274,6 +274,9 @@
<string name="error_expiry_must_come_after_creation">дата завершення дії має йти після дати створення</string> <string name="error_expiry_must_come_after_creation">дата завершення дії має йти після дати створення</string>
<string name="error_can_not_delete_contact">ви не можете вилучити цей контакт, тому що він ваш власний.</string> <string name="error_can_not_delete_contact">ви не можете вилучити цей контакт, тому що він ваш власний.</string>
<string name="error_can_not_delete_contacts">ви не можете вилучити наступні контакти, тому що вони - ваші власні:\n%s</string> <string name="error_can_not_delete_contacts">ви не можете вилучити наступні контакти, тому що вони - ваші власні:\n%s</string>
<string name="error_keyserver_insufficient_query">Запит обмеженого сервера</string>
<string name="error_keyserver_query">Збій сервера ключа запиту</string>
<string name="error_keyserver_too_many_responses">Забагато відповідей</string>
<plurals name="error_can_not_delete_info"> <plurals name="error_can_not_delete_info">
<item quantity="one">Будь ласка, вилучіть його з екрану „Мої ключі“!</item> <item quantity="one">Будь ласка, вилучіть його з екрану „Мої ключі“!</item>
<item quantity="few">Будь ласка, вилучіть їх з екрану „Мої ключі“!</item> <item quantity="few">Будь ласка, вилучіть їх з екрану „Мої ключі“!</item>
@ -348,10 +351,10 @@
<string name="import_nfc_help_button">Довідка</string> <string name="import_nfc_help_button">Довідка</string>
<string name="import_clipboard_button">Отримати ключ з буфера обміну</string> <string name="import_clipboard_button">Отримати ключ з буфера обміну</string>
<!--Intent labels--> <!--Intent labels-->
<string name="intent_decrypt_file">OpenPGP: розшифрувати файл</string> <string name="intent_decrypt_file">Розшифрувати файл з OpenKeychain</string>
<string name="intent_import_key">OpenPGP: імпортувати ключ</string> <string name="intent_import_key">Імпортувати ключ з OpenKeychain</string>
<string name="intent_send_encrypt">OpenPGP: зашифрувати</string> <string name="intent_send_encrypt">Зашифрувати з OpenKeychain</string>
<string name="intent_send_decrypt">OpenPGP: розшифрувати</string> <string name="intent_send_decrypt">Розшифрувати з OpenKeychain</string>
<!--Remote API--> <!--Remote API-->
<string name="api_no_apps">Нема зареєстрованих програм!\n\nСтороні програми можуть вимагати доступ до OpenPGP Keychain. Після надання доступу вони будуть наведені тут.</string> <string name="api_no_apps">Нема зареєстрованих програм!\n\nСтороні програми можуть вимагати доступ до OpenPGP Keychain. Після надання доступу вони будуть наведені тут.</string>
<string name="api_settings_show_advanced">Показати додаткові налаштування</string> <string name="api_settings_show_advanced">Показати додаткові налаштування</string>
@ -370,7 +373,7 @@
<string name="api_select_pub_keys_missing_text">Не знайдено публічних ключів для цих ІД користувачів:</string> <string name="api_select_pub_keys_missing_text">Не знайдено публічних ключів для цих ІД користувачів:</string>
<string name="api_select_pub_keys_dublicates_text">Більше ніж один публічний ключ існує для цих ІД користувачів:</string> <string name="api_select_pub_keys_dublicates_text">Більше ніж один публічний ключ існує для цих ІД користувачів:</string>
<string name="api_select_pub_keys_text">Будь ласка, перевірте список одержувачів!</string> <string name="api_select_pub_keys_text">Будь ласка, перевірте список одержувачів!</string>
<string name="api_error_wrong_signature">Перевірка підпису пакета не вдалася! Якщо ви встановили програму з іншого джерела, відкличте або поновіть право доступу.</string> <string name="api_error_wrong_signature">Перевірка підпису пакету не вдалася! Може ви встановили програму з іншого джерела? Якщо ви впевнені, що це не атака, то відкличте реєстрацію програми у OpenKeychain та знову зареєструйте її.</string>
<!--Share--> <!--Share-->
<string name="share_qr_code_dialog_title">Відправити як штрих-код</string> <string name="share_qr_code_dialog_title">Відправити як штрих-код</string>
<string name="share_qr_code_dialog_start">Пройдіть через усі штрих-коди за допомогою \"Далі\", а також проскануйте їх по одному.</string> <string name="share_qr_code_dialog_start">Пройдіть через усі штрих-коди за допомогою \"Далі\", а також проскануйте їх по одному.</string>

View File

@ -135,10 +135,6 @@
<string name="import_qr_code_finished">二维码扫描完成!</string> <string name="import_qr_code_finished">二维码扫描完成!</string>
<string name="import_nfc_help_button">帮助</string> <string name="import_nfc_help_button">帮助</string>
<!--Intent labels--> <!--Intent labels-->
<string name="intent_decrypt_file">OpenPGP: 解密文件</string>
<string name="intent_import_key">OpenPGP: 导入密钥</string>
<string name="intent_send_encrypt">OpenPGP: 加密</string>
<string name="intent_send_decrypt">OpenPGP: 解密</string>
<!--Remote API--> <!--Remote API-->
<string name="api_settings_show_advanced">显示高级设置</string> <string name="api_settings_show_advanced">显示高级设置</string>
<string name="api_settings_hide_advanced">隐藏高级设置</string> <string name="api_settings_hide_advanced">隐藏高级设置</string>

View File

@ -286,6 +286,9 @@
<string name="error_expiry_must_come_after_creation">expiry date must come after creation date</string> <string name="error_expiry_must_come_after_creation">expiry date must come after creation date</string>
<string name="error_can_not_delete_contact">you can not delete this contact because it is your own.</string> <string name="error_can_not_delete_contact">you can not delete this contact because it is your own.</string>
<string name="error_can_not_delete_contacts">you can not delete the following contacts because they are your own:\n%s</string> <string name="error_can_not_delete_contacts">you can not delete the following contacts because they are your own:\n%s</string>
<string name="error_keyserver_insufficient_query">Insufficient server query</string>
<string name="error_keyserver_query">Querying keyserver failed</string>
<string name="error_keyserver_too_many_responses">Too many responses</string>
<plurals name="error_can_not_delete_info"> <plurals name="error_can_not_delete_info">
<item quantity="one">Please delete it from the \'My Keys\' screen!</item> <item quantity="one">Please delete it from the \'My Keys\' screen!</item>
<item quantity="other">Please delete them from the \'My Keys\' screen!</item> <item quantity="other">Please delete them from the \'My Keys\' screen!</item>
@ -293,6 +296,7 @@
<!-- progress dialogs, usually ending in '…' --> <!-- progress dialogs, usually ending in '…' -->
<string name="progress_done">done.</string> <string name="progress_done">done.</string>
<string name="progress_cancel">cancel</string>
<string name="progress_saving">saving…</string> <string name="progress_saving">saving…</string>
<string name="progress_importing">importing…</string> <string name="progress_importing">importing…</string>
<string name="progress_exporting">exporting…</string> <string name="progress_exporting">exporting…</string>
@ -368,10 +372,10 @@
<string name="import_clipboard_button">Get key from clipboard</string> <string name="import_clipboard_button">Get key from clipboard</string>
<!-- Intent labels --> <!-- Intent labels -->
<string name="intent_decrypt_file">OpenKeychain: Decrypt File</string> <string name="intent_decrypt_file">Decrypt File with OpenKeychain</string>
<string name="intent_import_key">OpenKeychain: Import Key</string> <string name="intent_import_key">Import Key with OpenKeychain</string>
<string name="intent_send_encrypt">OpenKeychain: Encrypt</string> <string name="intent_send_encrypt">Encrypt with OpenKeychain</string>
<string name="intent_send_decrypt">OpenKeychain: Decrypt</string> <string name="intent_send_decrypt">Decrypt with OpenKeychain</string>
<!-- Remote API --> <!-- Remote API -->
<string name="api_no_apps">No registered applications!\n\nThird-party applications can request access to OpenKeychain. After granting access, they will be listed here.</string> <string name="api_no_apps">No registered applications!\n\nThird-party applications can request access to OpenKeychain. After granting access, they will be listed here.</string>

View File

@ -1,9 +1,11 @@
# OpenKeychain (for Android) # OpenKeychain (for Android)
OpenKeychain is an OpenPGP implementation for Android. OpenKeychain is an OpenPGP implementation for Android.
The development began as a fork of Android Privacy Guard (APG). For a more detailed description and installation instructions go to http://www.openkeychain.org .
see http://sufficientlysecure.org/keychain ### Travis CI Build Status
[![Build Status](https://travis-ci.org/openpgp-keychain/openpgp-keychain.png?branch=master)](https://travis-ci.org/openpgp-keychain/openpgp-keychain)
## How to help the project? ## How to help the project?
@ -53,65 +55,17 @@ I am using the newest [Android Studio](http://developer.android.com/sdk/installi
* Select the "OpenPGP-Keychain-API" folder if you want to develop on the API example * Select the "OpenPGP-Keychain-API" folder if you want to develop on the API example
3. Import project from external model -> choose Gradle 3. Import project from external model -> choose Gradle
## Keychain API ## OpenKeychain's API
### Intent API OpenKeychain provides two APIs, namely the Intent API and the Remote OpenPGP API.
All Intents require user interaction, e.g. to finally encrypt the user needs to press the "Encrypt" button. The Intent API can be used without permissions to start OpenKeychain's activities for cryptographic operations, import of keys, etc.
To do automatic encryption/decryption/sign/verify use the OpenPGP Remote API. However, it always requires user input, so that no malicious application can use this API without user intervention.
The Remote OpenPGP API is more sophisticated and allows to to operations without user interaction in the background.
When utilizing this API, OpenKeychain asks the user on first use to grant access for the calling client application.
#### Android Intent actions: More technical information and examples about these APIs can be found in the project's wiki:
* [Intent API](https://github.com/openpgp-keychain/openpgp-keychain/wiki/Intent-API)
* ``android.intent.action.VIEW`` connected to .gpg and .asc files: Import Key and Decrypt * [Remote OpenPGP API](https://github.com/openpgp-keychain/openpgp-keychain/wiki/OpenPGP-API)
* ``android.intent.action.SEND`` connected to all mime types (text/plain and every binary data like files and images): Encrypt and Decrypt
#### OpenKeychain Intent actions:
* ``org.sufficientlysecure.keychain.action.ENCRYPT``
* To encrypt or sign text, use extra ``text`` (type: ``String``)
* or set data ``Uri`` (``intent.setData()``) pointing to a file
* Enable ASCII Armor for file encryption (encoding to Radix-64, 33% overhead) by adding the extra ``ascii_armor`` with value ``true``
* ``org.sufficientlysecure.keychain.action.DECRYPT``
* To decrypt or verify text, use extra ``text`` (type: ``String``)
* or set data ``Uri`` (``intent.setData()``) pointing to a file
* ``org.sufficientlysecure.keychain.action.IMPORT_KEY``
* Extras: ``key_bytes`` (type: ``byte[]``)
* or set data ``Uri`` (``intent.setData()``) pointing to a file
* ``org.sufficientlysecure.keychain.action.IMPORT_KEY_FROM_KEYSERVER``
* Extras: ``query`` (type: ``String``)
* or ``fingerprint`` (type: ``String``)
* ``org.sufficientlysecure.keychain.action.IMPORT_KEY_FROM_QR_CODE``
* without extras, starts Barcode Scanner to get QR Code
#### OpenKeychain special registered Intents:
* ``android.intent.action.VIEW`` with URIs following the ``openpgp4fpr`` schema. For example: ``openpgp4fpr:73EE2314F65FA92EC2390D3A718C070100012282``. This is used in QR Codes, but could also be embedded into your website. (compatible with Monkeysphere's and Guardian Project's QR Codes)
* NFC (``android.nfc.action.NDEF_DISCOVERED``) on mime type ``application/pgp-keys`` (as specified in http://tools.ietf.org/html/rfc3156, section 7)
### OpenPGP Remote API
To do fast encryption/decryption/sign/verify operations without user interaction bind to the OpenPGP remote service.
#### Try out the API
Keychain: https://play.google.com/store/apps/details?id=org.sufficientlysecure.keychain
API Demo: https://play.google.com/store/apps/details?id=org.sufficientlysecure.keychain.demo
#### Design
All apps wanting to use this generic API
just need to include the AIDL files and connect to the service. Other
OpenPGP apps can implement a service based on this AIDL definition.
The API is designed to be as easy as possible to use by apps like K-9 Mail.
The service definition defines sign, encrypt, signAndEncrypt, decryptAndVerify, and getKeyIds.
As can be seen in the API Demo, the apps themselves never need to handle key ids directly.
You can use user ids (emails) to define recipients.
If more than one public key exists for an email, OpenKeychain will handle the problem by showing a selection screen. Additionally, it is also possible to use key ids.
Also app devs never need to fiddle with private keys.
On first operation, OpenKeychain shows an activity to allow or disallow access, while also allowing to choose the private key used for this app.
Please try the Demo app out to see how it works.
#### Integration
Copy the api library from "libraries/keychain-api-library" to your project and add it as an dependency to your gradle build.
Inspect the ode found in "OpenPGP-Keychain-API" to understand how to use the API.
## Libraries ## Libraries

View File

@ -11,5 +11,5 @@
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target. # Project target.
target=android-17 target=android-19
android.library=true android.library=true

View File

@ -1,29 +0,0 @@
#Android specific
bin
gen
obj
lint.xml
local.properties
release.properties
ant.properties
*.class
*.apk
#Gradle
.gradle
build
gradle.properties
#Maven
target
pom.xml.*
#Eclipse
.project
.classpath
.settings
.metadata
#IntelliJ IDEA
.idea
*.iml

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.sufficientlysecure.keychain.api"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="19" />
<application/>
</manifest>

View File

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,15 +0,0 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-19
android.library=true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="openpgp_list_preference_none">None</string>
</resources>

View File

@ -1,85 +0,0 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openintents.openpgp;
interface IOpenPgpService {
/**
* General extras
* --------------
*
* Bundle params:
* int api_version (required)
* boolean ascii_armor (request ascii armor for ouput)
*
* returned Bundle:
* int result_code (0, 1, or 2 (see OpenPgpConstants))
* OpenPgpError error (if result_code == 0)
* Intent intent (if result_code == 2)
*
*/
/**
* Sign only
*
* optional params:
* String passphrase (for key passphrase)
*/
Bundle sign(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output);
/**
* Encrypt
*
* Bundle params:
* long[] key_ids
* or
* String[] user_ids (= emails of recipients) (if more than one key has this user_id, a PendingIntent is returned)
*
* optional params:
* String passphrase (for key passphrase)
*/
Bundle encrypt(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output);
/**
* Sign and encrypt
*
* Bundle params:
* same as in encrypt()
*/
Bundle signAndEncrypt(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output);
/**
* Decrypts and verifies given input bytes. This methods handles encrypted-only, signed-and-encrypted,
* and also signed-only input.
*
* returned Bundle:
* OpenPgpSignatureResult signature_result
*/
Bundle decryptAndVerify(in Bundle params, in ParcelFileDescriptor input, in ParcelFileDescriptor output);
/**
* Retrieves key ids based on given user ids (=emails)
*
* Bundle params:
* String[] user_ids
*
* returned Bundle:
* long[] key_ids
*/
Bundle getKeyIds(in Bundle params);
}

View File

@ -1,84 +0,0 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openintents.openpgp;
import android.os.Parcel;
import android.os.Parcelable;
public class OpenPgpError implements Parcelable {
public static final int CLIENT_SIDE_ERROR = -1;
public static final int GENERIC_ERROR = 0;
public static final int INCOMPATIBLE_API_VERSIONS = 1;
public static final int NO_OR_WRONG_PASSPHRASE = 2;
public static final int NO_USER_IDS = 3;
int errorId;
String message;
public OpenPgpError() {
}
public OpenPgpError(int errorId, String message) {
this.errorId = errorId;
this.message = message;
}
public OpenPgpError(OpenPgpError b) {
this.errorId = b.errorId;
this.message = b.message;
}
public int getErrorId() {
return errorId;
}
public void setErrorId(int errorId) {
this.errorId = errorId;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(errorId);
dest.writeString(message);
}
public static final Creator<OpenPgpError> CREATOR = new Creator<OpenPgpError>() {
public OpenPgpError createFromParcel(final Parcel source) {
OpenPgpError error = new OpenPgpError();
error.errorId = source.readInt();
error.message = source.readString();
return error;
}
public OpenPgpError[] newArray(final int size) {
return new OpenPgpError[size];
}
};
}

Some files were not shown because too many files have changed in this diff Show More