Make asciiArmor a parameter, extend advanced app settings
This commit is contained in:
@@ -24,7 +24,6 @@ import org.sufficientlysecure.keychain.Id;
|
||||
public class AppSettings {
|
||||
private String packageName;
|
||||
private long keyId = Id.key.none;
|
||||
private boolean asciiArmor;
|
||||
private int encryptionAlgorithm;
|
||||
private int hashAlgorithm;
|
||||
private int compression;
|
||||
@@ -37,10 +36,9 @@ public class AppSettings {
|
||||
super();
|
||||
this.packageName = packageName;
|
||||
// defaults:
|
||||
this.asciiArmor = true;
|
||||
this.encryptionAlgorithm = PGPEncryptedData.AES_128; // AES-128
|
||||
this.hashAlgorithm = HashAlgorithmTags.SHA512; // SHA-512
|
||||
this.compression = Id.choice.compression.zlib; // zlib
|
||||
this.encryptionAlgorithm = PGPEncryptedData.AES_128;
|
||||
this.hashAlgorithm = HashAlgorithmTags.SHA256;
|
||||
this.compression = Id.choice.compression.zlib;
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
@@ -59,14 +57,6 @@ public class AppSettings {
|
||||
this.keyId = scretKeyId;
|
||||
}
|
||||
|
||||
public boolean isAsciiArmor() {
|
||||
return asciiArmor;
|
||||
}
|
||||
|
||||
public void setAsciiArmor(boolean asciiArmor) {
|
||||
this.asciiArmor = asciiArmor;
|
||||
}
|
||||
|
||||
public int getEncryptionAlgorithm() {
|
||||
return encryptionAlgorithm;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.remote_api;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.spongycastle.bcpg.HashAlgorithmTags;
|
||||
import org.spongycastle.openpgp.PGPEncryptedData;
|
||||
import org.spongycastle.openpgp.PGPSecretKey;
|
||||
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
@@ -25,6 +29,7 @@ import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.helper.PgpHelper;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.ui.SelectSecretKeyActivity;
|
||||
import org.sufficientlysecure.keychain.util.KeyValueSpinnerAdapter;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import android.app.Activity;
|
||||
@@ -41,12 +46,12 @@ import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AlphaAnimation;
|
||||
import android.view.animation.Animation;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemSelectedListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class AppSettingsFragment extends Fragment {
|
||||
@@ -62,7 +67,13 @@ public class AppSettingsFragment extends Fragment {
|
||||
private TextView mKeyUserId;
|
||||
private TextView mKeyUserIdRest;
|
||||
private Button mSelectKeyButton;
|
||||
private CheckBox mAsciiArmorCheckBox;
|
||||
private Spinner mEncryptionAlgorithm;
|
||||
private Spinner mHashAlgorithm;
|
||||
private Spinner mCompression;
|
||||
|
||||
KeyValueSpinnerAdapter encryptionAdapter;
|
||||
KeyValueSpinnerAdapter hashAdapter;
|
||||
KeyValueSpinnerAdapter compressionAdapter;
|
||||
|
||||
public AppSettings getAppSettings() {
|
||||
return appSettings;
|
||||
@@ -72,7 +83,10 @@ public class AppSettingsFragment extends Fragment {
|
||||
this.appSettings = appSettings;
|
||||
setPackage(appSettings.getPackageName());
|
||||
updateSelectedKeyView(appSettings.getKeyId());
|
||||
mAsciiArmorCheckBox.setChecked(appSettings.isAsciiArmor());
|
||||
mEncryptionAlgorithm.setSelection(encryptionAdapter.getPosition(appSettings
|
||||
.getEncryptionAlgorithm()));
|
||||
mHashAlgorithm.setSelection(hashAdapter.getPosition(appSettings.getHashAlgorithm()));
|
||||
mCompression.setSelection(compressionAdapter.getPosition(appSettings.getCompression()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,7 +109,80 @@ public class AppSettingsFragment extends Fragment {
|
||||
mKeyUserId = (TextView) view.findViewById(R.id.api_app_settings_user_id);
|
||||
mKeyUserIdRest = (TextView) view.findViewById(R.id.api_app_settings_user_id_rest);
|
||||
mSelectKeyButton = (Button) view.findViewById(R.id.api_app_settings_select_key_button);
|
||||
mAsciiArmorCheckBox = (CheckBox) view.findViewById(R.id.api_app_ascii_armor);
|
||||
mEncryptionAlgorithm = (Spinner) view
|
||||
.findViewById(R.id.api_app_settings_encryption_algorithm);
|
||||
mHashAlgorithm = (Spinner) view.findViewById(R.id.api_app_settings_hash_algorithm);
|
||||
mCompression = (Spinner) view.findViewById(R.id.api_app_settings_compression);
|
||||
|
||||
HashMap<Integer, String> encryptionMap = new HashMap<Integer, String>();
|
||||
encryptionMap.put(PGPEncryptedData.AES_128, "AES-128");
|
||||
encryptionMap.put(PGPEncryptedData.AES_192, "AES-192");
|
||||
encryptionMap.put(PGPEncryptedData.AES_256, "AES-256");
|
||||
encryptionMap.put(PGPEncryptedData.BLOWFISH, "Blowfish");
|
||||
encryptionMap.put(PGPEncryptedData.TWOFISH, "Twofish");
|
||||
encryptionMap.put(PGPEncryptedData.CAST5, "CAST5");
|
||||
encryptionMap.put(PGPEncryptedData.DES, "DES");
|
||||
encryptionMap.put(PGPEncryptedData.TRIPLE_DES, "Triple DES");
|
||||
encryptionMap.put(PGPEncryptedData.IDEA, "IDEA");
|
||||
|
||||
encryptionAdapter = new KeyValueSpinnerAdapter(getActivity(), encryptionMap);
|
||||
mEncryptionAlgorithm.setAdapter(encryptionAdapter);
|
||||
mEncryptionAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() {
|
||||
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
appSettings.setEncryptionAlgorithm((int) id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
});
|
||||
|
||||
HashMap<Integer, String> hashMap = new HashMap<Integer, String>();
|
||||
hashMap.put(HashAlgorithmTags.MD5, "MD5");
|
||||
hashMap.put(HashAlgorithmTags.RIPEMD160, "RIPEMD-160");
|
||||
hashMap.put(HashAlgorithmTags.SHA1, "SHA-1");
|
||||
hashMap.put(HashAlgorithmTags.SHA224, "SHA-224");
|
||||
hashMap.put(HashAlgorithmTags.SHA256, "SHA-256");
|
||||
hashMap.put(HashAlgorithmTags.SHA384, "SHA-384");
|
||||
hashMap.put(HashAlgorithmTags.SHA512, "SHA-512");
|
||||
|
||||
hashAdapter = new KeyValueSpinnerAdapter(getActivity(), hashMap);
|
||||
mHashAlgorithm.setAdapter(hashAdapter);
|
||||
mHashAlgorithm.setOnItemSelectedListener(new OnItemSelectedListener() {
|
||||
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
appSettings.setHashAlgorithm((int) id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
});
|
||||
|
||||
HashMap<Integer, String> compressionMap = new HashMap<Integer, String>();
|
||||
compressionMap.put(Id.choice.compression.none, getString(R.string.choice_none) + " ("
|
||||
+ getString(R.string.fast) + ")");
|
||||
compressionMap.put(Id.choice.compression.zip, "ZIP (" + getString(R.string.fast) + ")");
|
||||
compressionMap.put(Id.choice.compression.zlib, "ZLIB (" + getString(R.string.fast) + ")");
|
||||
compressionMap.put(Id.choice.compression.bzip2, "BZIP2 (" + getString(R.string.very_slow)
|
||||
+ ")");
|
||||
|
||||
compressionAdapter = new KeyValueSpinnerAdapter(getActivity(), compressionMap);
|
||||
mCompression.setAdapter(compressionAdapter);
|
||||
mCompression.setOnItemSelectedListener(new OnItemSelectedListener() {
|
||||
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
appSettings.setCompression((int) id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
});
|
||||
|
||||
mSelectKeyButton.setOnClickListener(new OnClickListener() {
|
||||
|
||||
@@ -105,14 +192,6 @@ public class AppSettingsFragment extends Fragment {
|
||||
}
|
||||
});
|
||||
|
||||
mAsciiArmorCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
|
||||
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
appSettings.setAsciiArmor(isChecked);
|
||||
}
|
||||
});
|
||||
|
||||
final Animation visibleAnimation = new AlphaAnimation(0.0f, 1.0f);
|
||||
visibleAnimation.setDuration(250);
|
||||
final Animation invisibleAnimation = new AlphaAnimation(1.0f, 0.0f);
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import org.openintents.crypto.CryptoError;
|
||||
import org.openintents.crypto.CryptoSignatureResult;
|
||||
@@ -233,7 +234,8 @@ public class CryptoService extends Service {
|
||||
};
|
||||
|
||||
private synchronized void encryptAndSignSafe(byte[] inputBytes, String[] encryptionUserIds,
|
||||
ICryptoCallback callback, AppSettings appSettings, boolean sign) throws RemoteException {
|
||||
boolean asciiArmor, ICryptoCallback callback, AppSettings appSettings, boolean sign)
|
||||
throws RemoteException {
|
||||
try {
|
||||
// build InputData and write into OutputStream
|
||||
InputStream inputStream = new ByteArrayInputStream(inputBytes);
|
||||
@@ -252,13 +254,13 @@ public class CryptoService extends Service {
|
||||
return;
|
||||
}
|
||||
|
||||
PgpMain.encryptAndSign(mContext, null, inputData, outputStream,
|
||||
appSettings.isAsciiArmor(), appSettings.getCompression(), keyIds, null,
|
||||
PgpMain.encryptAndSign(mContext, null, inputData, outputStream, asciiArmor,
|
||||
appSettings.getCompression(), keyIds, null,
|
||||
appSettings.getEncryptionAlgorithm(), appSettings.getKeyId(),
|
||||
appSettings.getHashAlgorithm(), true, passphrase);
|
||||
} else {
|
||||
PgpMain.encryptAndSign(mContext, null, inputData, outputStream,
|
||||
appSettings.isAsciiArmor(), appSettings.getCompression(), keyIds, null,
|
||||
PgpMain.encryptAndSign(mContext, null, inputData, outputStream, asciiArmor,
|
||||
appSettings.getCompression(), keyIds, null,
|
||||
appSettings.getEncryptionAlgorithm(), Id.key.none,
|
||||
appSettings.getHashAlgorithm(), true, null);
|
||||
}
|
||||
@@ -280,6 +282,7 @@ public class CryptoService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: asciiArmor?!
|
||||
private void signSafe(byte[] inputBytes, ICryptoCallback callback, AppSettings appSettings)
|
||||
throws RemoteException {
|
||||
try {
|
||||
@@ -327,19 +330,50 @@ public class CryptoService extends Service {
|
||||
InputStream inputStream = new ByteArrayInputStream(inputBytes);
|
||||
long inputLength = inputBytes.length;
|
||||
InputData inputData = new InputData(inputStream, inputLength);
|
||||
|
||||
Log.d(Constants.TAG, "in: " + new String(inputBytes));
|
||||
|
||||
OutputStream outputStream = new ByteArrayOutputStream();
|
||||
|
||||
String message = new String(inputBytes);
|
||||
Log.d(Constants.TAG, "in: " + message);
|
||||
|
||||
// checked if signed only
|
||||
boolean signedOnly = false;
|
||||
Matcher matcher = PgpMain.PGP_SIGNED_MESSAGE.matcher(message);
|
||||
if (matcher.matches()) {
|
||||
signedOnly = true;
|
||||
}
|
||||
|
||||
// TODO: This allows to decrypt messages with ALL secret keys, not only the one for the
|
||||
// app, Fix this?
|
||||
long secretKeyId = PgpMain.getDecryptionKeyId(mContext, inputStream);
|
||||
if (secretKeyId == Id.key.none) {
|
||||
throw new PgpMain.PgpGeneralException(getString(R.string.error_noSecretKeyFound));
|
||||
}
|
||||
// long secretKeyId = PgpMain.getDecryptionKeyId(mContext, inputStream);
|
||||
// if (secretKeyId == Id.key.none) {
|
||||
// throw new PgpMain.PgpGeneralException(getString(R.string.error_noSecretKeyFound));
|
||||
// }
|
||||
|
||||
Log.d(Constants.TAG, "Got input:\n" + new String(inputBytes));
|
||||
// TODO: duplicates functions from DecryptActivity!
|
||||
boolean assumeSymmetricEncryption = false;
|
||||
long secretKeyId;
|
||||
try {
|
||||
if (inputStream.markSupported()) {
|
||||
inputStream.mark(200); // should probably set this to the max size of two pgpF
|
||||
// objects, if it even needs to be anything other than 0.
|
||||
}
|
||||
secretKeyId = PgpMain.getDecryptionKeyId(this, inputStream);
|
||||
if (secretKeyId == Id.key.none) {
|
||||
throw new PgpMain.PgpGeneralException(
|
||||
getString(R.string.error_noSecretKeyFound));
|
||||
}
|
||||
assumeSymmetricEncryption = false;
|
||||
} catch (PgpMain.NoAsymmetricEncryptionException e) {
|
||||
if (inputStream.markSupported()) {
|
||||
inputStream.reset();
|
||||
}
|
||||
secretKeyId = Id.key.symmetric;
|
||||
if (!PgpMain.hasSymmetricEncryption(this, inputStream)) {
|
||||
throw new PgpMain.PgpGeneralException(
|
||||
getString(R.string.error_noKnownEncryptionFound));
|
||||
}
|
||||
assumeSymmetricEncryption = true;
|
||||
}
|
||||
|
||||
Log.d(Constants.TAG, "secretKeyId " + secretKeyId);
|
||||
|
||||
@@ -350,17 +384,15 @@ public class CryptoService extends Service {
|
||||
return;
|
||||
}
|
||||
|
||||
// if (signedOnly) {
|
||||
// resultData = PgpMain.verifyText(this, this, inputData, outStream,
|
||||
// lookupUnknownKey);
|
||||
// } else {
|
||||
// resultData = PgpMain.decryptAndVerify(this, this, inputData, outStream,
|
||||
// PassphraseCacheService.getCachedPassphrase(this, secretKeyId),
|
||||
// assumeSymmetricEncryption);
|
||||
// }
|
||||
|
||||
Bundle outputBundle = PgpMain.decryptAndVerify(mContext, null, inputData, outputStream,
|
||||
passphrase, false);
|
||||
Bundle outputBundle;
|
||||
if (signedOnly) {
|
||||
// TODO: download missing keys from keyserver?
|
||||
outputBundle = PgpMain.verifyText(this, null, inputData, outputStream, false);
|
||||
} else {
|
||||
// TODO: assume symmetric: callback to enter symmetric pass
|
||||
outputBundle = PgpMain.decryptAndVerify(this, null, inputData, outputStream,
|
||||
passphrase, false);
|
||||
}
|
||||
|
||||
outputStream.close();
|
||||
|
||||
@@ -377,8 +409,11 @@ public class CryptoService extends Service {
|
||||
boolean signatureUnknown = outputBundle
|
||||
.getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN);
|
||||
|
||||
CryptoSignatureResult sigResult = new CryptoSignatureResult(signatureUserId, signature,
|
||||
signatureSuccess, signatureUnknown);
|
||||
CryptoSignatureResult sigResult = null;
|
||||
if (signature) {
|
||||
sigResult = new CryptoSignatureResult(signatureUserId, signature, signatureSuccess,
|
||||
signatureUnknown);
|
||||
}
|
||||
|
||||
// return over handler on client side
|
||||
callback.onSuccess(outputBytes, sigResult);
|
||||
@@ -397,7 +432,7 @@ public class CryptoService extends Service {
|
||||
|
||||
@Override
|
||||
public void encrypt(final byte[] inputBytes, final String[] encryptionUserIds,
|
||||
final ICryptoCallback callback) throws RemoteException {
|
||||
final boolean asciiArmor, final ICryptoCallback callback) throws RemoteException {
|
||||
|
||||
final AppSettings settings = getAppSettings();
|
||||
|
||||
@@ -406,7 +441,8 @@ public class CryptoService extends Service {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
encryptAndSignSafe(inputBytes, encryptionUserIds, callback, settings, false);
|
||||
encryptAndSignSafe(inputBytes, encryptionUserIds, asciiArmor, callback,
|
||||
settings, false);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(Constants.TAG, "CryptoService", e);
|
||||
}
|
||||
@@ -418,7 +454,7 @@ public class CryptoService extends Service {
|
||||
|
||||
@Override
|
||||
public void encryptAndSign(final byte[] inputBytes, final String[] encryptionUserIds,
|
||||
final ICryptoCallback callback) throws RemoteException {
|
||||
final boolean asciiArmor, final ICryptoCallback callback) throws RemoteException {
|
||||
|
||||
final AppSettings settings = getAppSettings();
|
||||
|
||||
@@ -427,7 +463,8 @@ public class CryptoService extends Service {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
encryptAndSignSafe(inputBytes, encryptionUserIds, callback, settings, true);
|
||||
encryptAndSignSafe(inputBytes, encryptionUserIds, asciiArmor, callback,
|
||||
settings, true);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(Constants.TAG, "CryptoService", e);
|
||||
}
|
||||
@@ -438,7 +475,7 @@ public class CryptoService extends Service {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sign(final byte[] inputBytes, final ICryptoCallback callback)
|
||||
public void sign(final byte[] inputBytes, boolean asciiArmor, final ICryptoCallback callback)
|
||||
throws RemoteException {
|
||||
final AppSettings settings = getAppSettings();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user