Make asciiArmor a parameter, extend advanced app settings

This commit is contained in:
Dominik Schürmann 2013-09-09 12:59:53 +02:00
parent c4bf7c5d11
commit 5dc693c64c
14 changed files with 348 additions and 127 deletions

View File

@ -78,7 +78,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:onClick="decryptOnClick" android:onClick="decryptAndVerifyOnClick"
android:text="Decrypt" /> android:text="Decrypt" />
</LinearLayout> </LinearLayout>

View File

@ -34,7 +34,7 @@ interface ICryptoService {
* @param callback * @param callback
* Callback where to return results * Callback where to return results
*/ */
oneway void encrypt(in byte[] inputBytes, in String[] encryptionUserIds, in ICryptoCallback callback); oneway void encrypt(in byte[] inputBytes, in String[] encryptionUserIds, in boolean asciiArmor, in ICryptoCallback callback);
/** /**
* Sign * Sign
@ -44,7 +44,7 @@ interface ICryptoService {
* @param callback * @param callback
* Callback where to return results * Callback where to return results
*/ */
oneway void sign(in byte[] inputBytes, in ICryptoCallback callback); oneway void sign(in byte[] inputBytes, in boolean asciiArmor, in ICryptoCallback callback);
/** /**
* Encrypt and sign * Encrypt and sign
@ -58,7 +58,7 @@ interface ICryptoService {
* @param callback * @param callback
* Callback where to return results * Callback where to return results
*/ */
oneway void encryptAndSign(in byte[] inputBytes, in String[] encryptionUserIds, in ICryptoCallback callback); oneway void encryptAndSign(in byte[] inputBytes, in String[] encryptionUserIds, in boolean asciiArmor, in ICryptoCallback callback);
/** /**
* Decrypts and verifies given input bytes. If no signature is present this method * Decrypts and verifies given input bytes. If no signature is present this method
@ -71,10 +71,4 @@ interface ICryptoService {
*/ */
oneway void decryptAndVerify(in byte[] inputBytes, in ICryptoCallback callback); oneway void decryptAndVerify(in byte[] inputBytes, in ICryptoCallback callback);
/**
* Opens setup using default parameters
*
*/
oneway void setup(boolean asciiArmor, boolean newKeyring, String newKeyringUserId);
} }

View File

@ -74,7 +74,7 @@ public class CryptoProviderDemoActivity extends Activity {
@Override @Override
public void onSuccess(final byte[] outputBytes, CryptoSignatureResult signatureResult) public void onSuccess(final byte[] outputBytes, CryptoSignatureResult signatureResult)
throws RemoteException { throws RemoteException {
Log.d(Constants.TAG, "onEncryptSignSuccess"); Log.d(Constants.TAG, "encryptCallback");
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
@ -92,12 +92,12 @@ public class CryptoProviderDemoActivity extends Activity {
}; };
final ICryptoCallback.Stub decryptCallback = new ICryptoCallback.Stub() { final ICryptoCallback.Stub decryptAndVerifyCallback = new ICryptoCallback.Stub() {
@Override @Override
public void onSuccess(final byte[] outputBytes, final CryptoSignatureResult signatureResult) public void onSuccess(final byte[] outputBytes, final CryptoSignatureResult signatureResult)
throws RemoteException { throws RemoteException {
Log.d(Constants.TAG, "onDecryptVerifySuccess"); Log.d(Constants.TAG, "decryptAndVerifyCallback");
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
@ -136,7 +136,7 @@ public class CryptoProviderDemoActivity extends Activity {
try { try {
mCryptoServiceConnection.getService().encrypt(inputBytes, mCryptoServiceConnection.getService().encrypt(inputBytes,
mEncryptUserIds.getText().toString().split(","), encryptCallback); mEncryptUserIds.getText().toString().split(","), true, encryptCallback);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(Constants.TAG, "CryptoProviderDemo", e); Log.e(Constants.TAG, "CryptoProviderDemo", e);
} }
@ -146,7 +146,7 @@ public class CryptoProviderDemoActivity extends Activity {
byte[] inputBytes = mMessage.getText().toString().getBytes(); byte[] inputBytes = mMessage.getText().toString().getBytes();
try { try {
mCryptoServiceConnection.getService().sign(inputBytes, encryptCallback); mCryptoServiceConnection.getService().sign(inputBytes, true, encryptCallback);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(Constants.TAG, "CryptoProviderDemo", e); Log.e(Constants.TAG, "CryptoProviderDemo", e);
} }
@ -157,17 +157,18 @@ public class CryptoProviderDemoActivity extends Activity {
try { try {
mCryptoServiceConnection.getService().encryptAndSign(inputBytes, mCryptoServiceConnection.getService().encryptAndSign(inputBytes,
mEncryptUserIds.getText().toString().split(","), encryptCallback); mEncryptUserIds.getText().toString().split(","), true, encryptCallback);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(Constants.TAG, "CryptoProviderDemo", e); Log.e(Constants.TAG, "CryptoProviderDemo", e);
} }
} }
public void decryptOnClick(View view) { public void decryptAndVerifyOnClick(View view) {
byte[] inputBytes = mCiphertext.getText().toString().getBytes(); byte[] inputBytes = mCiphertext.getText().toString().getBytes();
try { try {
mCryptoServiceConnection.getService().decryptAndVerify(inputBytes, decryptCallback); mCryptoServiceConnection.getService().decryptAndVerify(inputBytes,
decryptAndVerifyCallback);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(Constants.TAG, "CryptoProviderDemo", e); Log.e(Constants.TAG, "CryptoProviderDemo", e);
} }

View File

@ -82,15 +82,41 @@
android:id="@+id/api_app_settings_advanced" android:id="@+id/api_app_settings_advanced"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="vertical"
android:visibility="invisible" > android:visibility="invisible" >
<CheckBox <TextView
android:id="@+id/api_app_ascii_armor"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:text="@string/label_encryptionAlgorithm"
android:text="@string/label_asciiArmour" /> android:textAppearance="?android:attr/textAppearanceMedium" />
<Spinner
android:id="@+id/api_app_settings_encryption_algorithm"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/label_hashAlgorithm"
android:textAppearance="?android:attr/textAppearanceMedium" />
<Spinner
android:id="@+id/api_app_settings_hash_algorithm"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/label_messageCompression"
android:textAppearance="?android:attr/textAppearanceMedium" />
<Spinner
android:id="@+id/api_app_settings_compression"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

View File

@ -34,7 +34,7 @@ interface ICryptoService {
* @param callback * @param callback
* Callback where to return results * Callback where to return results
*/ */
oneway void encrypt(in byte[] inputBytes, in String[] encryptionUserIds, in ICryptoCallback callback); oneway void encrypt(in byte[] inputBytes, in String[] encryptionUserIds, in boolean asciiArmor, in ICryptoCallback callback);
/** /**
* Sign * Sign
@ -44,7 +44,7 @@ interface ICryptoService {
* @param callback * @param callback
* Callback where to return results * Callback where to return results
*/ */
oneway void sign(in byte[] inputBytes, in ICryptoCallback callback); oneway void sign(in byte[] inputBytes, in boolean asciiArmor, in ICryptoCallback callback);
/** /**
* Encrypt and sign * Encrypt and sign
@ -58,7 +58,7 @@ interface ICryptoService {
* @param callback * @param callback
* Callback where to return results * Callback where to return results
*/ */
oneway void encryptAndSign(in byte[] inputBytes, in String[] encryptionUserIds, in ICryptoCallback callback); oneway void encryptAndSign(in byte[] inputBytes, in String[] encryptionUserIds, in boolean asciiArmor, in ICryptoCallback callback);
/** /**
* Decrypts and verifies given input bytes. If no signature is present this method * Decrypts and verifies given input bytes. If no signature is present this method

View File

@ -21,6 +21,7 @@ import java.io.File;
import java.security.Security; import java.security.Security;
import org.spongycastle.jce.provider.BouncyCastleProvider; import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.PRNGFixes; import org.sufficientlysecure.keychain.util.PRNGFixes;
import android.app.Application; import android.app.Application;
@ -30,7 +31,7 @@ public class KeychainApplication extends Application {
static { static {
// Define Java Security Provider to be Bouncy Castle // Define Java Security Provider to be Bouncy Castle
Security.insertProviderAt(new BouncyCastleProvider(), 1); Security.insertProviderAt(new BouncyCastleProvider(), 1);
} }
@Override @Override
@ -39,6 +40,7 @@ public class KeychainApplication extends Application {
// apply RNG fixes // apply RNG fixes
PRNGFixes.apply(); PRNGFixes.apply();
Log.d(Constants.TAG, "PRNG Fixes applied!");
// Create APG directory on sdcard if not existing // Create APG directory on sdcard if not existing
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {

View File

@ -17,6 +17,30 @@
package org.sufficientlysecure.keychain.helper; package org.sufficientlysecure.keychain.helper;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.regex.Pattern;
import org.spongycastle.bcpg.ArmoredInputStream; import org.spongycastle.bcpg.ArmoredInputStream;
import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.bcpg.ArmoredOutputStream;
import org.spongycastle.bcpg.BCPGOutputStream; import org.spongycastle.bcpg.BCPGOutputStream;
@ -45,7 +69,6 @@ import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPPublicKey; 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.PGPPublicKeyRingCollection;
import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignature;
@ -75,17 +98,17 @@ import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactory
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.util.HkpKeyServer; import org.sufficientlysecure.keychain.util.HkpKeyServer;
import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.KeyServer.AddKeyException;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.PositionAwareInputStream; import org.sufficientlysecure.keychain.util.PositionAwareInputStream;
import org.sufficientlysecure.keychain.util.Primes; import org.sufficientlysecure.keychain.util.Primes;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
import org.sufficientlysecure.keychain.util.KeyServer.AddKeyException;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.R;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
@ -93,31 +116,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.regex.Pattern;
/** /**
* TODO: * TODO:
* *

View File

@ -56,7 +56,6 @@ public class KeychainContract {
interface ApiAppsColumns { interface ApiAppsColumns {
String PACKAGE_NAME = "package_name"; String PACKAGE_NAME = "package_name";
String KEY_ID = "key_id"; // not a database id String KEY_ID = "key_id"; // not a database id
String ASCII_ARMOR = "ascii_armor";
String ENCRYPTION_ALGORITHM = "encryption_algorithm"; String ENCRYPTION_ALGORITHM = "encryption_algorithm";
String HASH_ALORITHM = "hash_algorithm"; String HASH_ALORITHM = "hash_algorithm";
String COMPRESSION = "compression"; String COMPRESSION = "compression";

View File

@ -64,14 +64,11 @@ public class KeychainDatabase extends SQLiteOpenHelper {
+ UserIdsColumns.KEY_RING_ROW_ID + ") REFERENCES " + Tables.KEY_RINGS + "(" + UserIdsColumns.KEY_RING_ROW_ID + ") REFERENCES " + Tables.KEY_RINGS + "("
+ BaseColumns._ID + ") ON DELETE CASCADE)"; + BaseColumns._ID + ") ON DELETE CASCADE)";
private static final String CREATE_API_APPS = "CREATE TABLE IF NOT EXISTS " private static final String CREATE_API_APPS = "CREATE TABLE IF NOT EXISTS " + Tables.API_APPS
+ Tables.API_APPS + " (" + BaseColumns._ID + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ " INTEGER PRIMARY KEY AUTOINCREMENT, " + ApiAppsColumns.PACKAGE_NAME + ApiAppsColumns.PACKAGE_NAME + " TEXT UNIQUE, " + ApiAppsColumns.KEY_ID + " INT64, "
+ " TEXT UNIQUE, " + ApiAppsColumns.KEY_ID + " INT64, " + ApiAppsColumns.ENCRYPTION_ALGORITHM + " INTEGER, " + ApiAppsColumns.HASH_ALORITHM
+ ApiAppsColumns.ASCII_ARMOR + " INTEGER, " + " INTEGER, " + ApiAppsColumns.COMPRESSION + " INTEGER)";
+ ApiAppsColumns.ENCRYPTION_ALGORITHM + " INTEGER, "
+ ApiAppsColumns.HASH_ALORITHM + " INTEGER, "
+ ApiAppsColumns.COMPRESSION + " INTEGER)";
KeychainDatabase(Context context) { KeychainDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION); super(context, DATABASE_NAME, null, DATABASE_VERSION);

View File

@ -745,7 +745,6 @@ public class ProviderHelper {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(ApiApps.PACKAGE_NAME, appSettings.getPackageName()); values.put(ApiApps.PACKAGE_NAME, appSettings.getPackageName());
values.put(ApiApps.KEY_ID, appSettings.getKeyId()); values.put(ApiApps.KEY_ID, appSettings.getKeyId());
values.put(ApiApps.ASCII_ARMOR, appSettings.isAsciiArmor());
values.put(ApiApps.COMPRESSION, appSettings.getCompression()); values.put(ApiApps.COMPRESSION, appSettings.getCompression());
values.put(ApiApps.ENCRYPTION_ALGORITHM, appSettings.getEncryptionAlgorithm()); values.put(ApiApps.ENCRYPTION_ALGORITHM, appSettings.getEncryptionAlgorithm());
values.put(ApiApps.HASH_ALORITHM, appSettings.getHashAlgorithm()); values.put(ApiApps.HASH_ALORITHM, appSettings.getHashAlgorithm());
@ -775,8 +774,6 @@ public class ProviderHelper {
settings.setPackageName(cur.getString(cur settings.setPackageName(cur.getString(cur
.getColumnIndex(KeychainContract.ApiApps.PACKAGE_NAME))); .getColumnIndex(KeychainContract.ApiApps.PACKAGE_NAME)));
settings.setKeyId(cur.getLong(cur.getColumnIndex(KeychainContract.ApiApps.KEY_ID))); settings.setKeyId(cur.getLong(cur.getColumnIndex(KeychainContract.ApiApps.KEY_ID)));
settings.setAsciiArmor(cur.getInt(cur
.getColumnIndexOrThrow(KeychainContract.ApiApps.ASCII_ARMOR)) == 1);
settings.setCompression(cur.getInt(cur settings.setCompression(cur.getInt(cur
.getColumnIndexOrThrow(KeychainContract.ApiApps.COMPRESSION))); .getColumnIndexOrThrow(KeychainContract.ApiApps.COMPRESSION)));
settings.setHashAlgorithm(cur.getInt(cur settings.setHashAlgorithm(cur.getInt(cur

View File

@ -24,7 +24,6 @@ import org.sufficientlysecure.keychain.Id;
public class AppSettings { public class AppSettings {
private String packageName; private String packageName;
private long keyId = Id.key.none; private long keyId = Id.key.none;
private boolean asciiArmor;
private int encryptionAlgorithm; private int encryptionAlgorithm;
private int hashAlgorithm; private int hashAlgorithm;
private int compression; private int compression;
@ -37,10 +36,9 @@ public class AppSettings {
super(); super();
this.packageName = packageName; this.packageName = packageName;
// defaults: // defaults:
this.asciiArmor = true; this.encryptionAlgorithm = PGPEncryptedData.AES_128;
this.encryptionAlgorithm = PGPEncryptedData.AES_128; // AES-128 this.hashAlgorithm = HashAlgorithmTags.SHA256;
this.hashAlgorithm = HashAlgorithmTags.SHA512; // SHA-512 this.compression = Id.choice.compression.zlib;
this.compression = Id.choice.compression.zlib; // zlib
} }
public String getPackageName() { public String getPackageName() {
@ -59,14 +57,6 @@ public class AppSettings {
this.keyId = scretKeyId; this.keyId = scretKeyId;
} }
public boolean isAsciiArmor() {
return asciiArmor;
}
public void setAsciiArmor(boolean asciiArmor) {
this.asciiArmor = asciiArmor;
}
public int getEncryptionAlgorithm() { public int getEncryptionAlgorithm() {
return encryptionAlgorithm; return encryptionAlgorithm;
} }

View File

@ -17,6 +17,10 @@
package org.sufficientlysecure.keychain.remote_api; 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.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
@ -25,6 +29,7 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.PgpHelper; import org.sufficientlysecure.keychain.helper.PgpHelper;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.SelectSecretKeyActivity; import org.sufficientlysecure.keychain.ui.SelectSecretKeyActivity;
import org.sufficientlysecure.keychain.util.KeyValueSpinnerAdapter;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import android.app.Activity; import android.app.Activity;
@ -41,12 +46,12 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.animation.AlphaAnimation; import android.view.animation.AlphaAnimation;
import android.view.animation.Animation; import android.view.animation.Animation;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Button; import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
public class AppSettingsFragment extends Fragment { public class AppSettingsFragment extends Fragment {
@ -62,7 +67,13 @@ public class AppSettingsFragment extends Fragment {
private TextView mKeyUserId; private TextView mKeyUserId;
private TextView mKeyUserIdRest; private TextView mKeyUserIdRest;
private Button mSelectKeyButton; private Button mSelectKeyButton;
private CheckBox mAsciiArmorCheckBox; private Spinner mEncryptionAlgorithm;
private Spinner mHashAlgorithm;
private Spinner mCompression;
KeyValueSpinnerAdapter encryptionAdapter;
KeyValueSpinnerAdapter hashAdapter;
KeyValueSpinnerAdapter compressionAdapter;
public AppSettings getAppSettings() { public AppSettings getAppSettings() {
return appSettings; return appSettings;
@ -72,7 +83,10 @@ public class AppSettingsFragment extends Fragment {
this.appSettings = appSettings; this.appSettings = appSettings;
setPackage(appSettings.getPackageName()); setPackage(appSettings.getPackageName());
updateSelectedKeyView(appSettings.getKeyId()); 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); mKeyUserId = (TextView) view.findViewById(R.id.api_app_settings_user_id);
mKeyUserIdRest = (TextView) view.findViewById(R.id.api_app_settings_user_id_rest); mKeyUserIdRest = (TextView) view.findViewById(R.id.api_app_settings_user_id_rest);
mSelectKeyButton = (Button) view.findViewById(R.id.api_app_settings_select_key_button); 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() { 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); final Animation visibleAnimation = new AlphaAnimation(0.0f, 1.0f);
visibleAnimation.setDuration(250); visibleAnimation.setDuration(250);
final Animation invisibleAnimation = new AlphaAnimation(1.0f, 0.0f); final Animation invisibleAnimation = new AlphaAnimation(1.0f, 0.0f);

View File

@ -24,6 +24,7 @@ import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import org.openintents.crypto.CryptoError; import org.openintents.crypto.CryptoError;
import org.openintents.crypto.CryptoSignatureResult; import org.openintents.crypto.CryptoSignatureResult;
@ -233,7 +234,8 @@ public class CryptoService extends Service {
}; };
private synchronized void encryptAndSignSafe(byte[] inputBytes, String[] encryptionUserIds, 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 { try {
// build InputData and write into OutputStream // build InputData and write into OutputStream
InputStream inputStream = new ByteArrayInputStream(inputBytes); InputStream inputStream = new ByteArrayInputStream(inputBytes);
@ -252,13 +254,13 @@ public class CryptoService extends Service {
return; return;
} }
PgpMain.encryptAndSign(mContext, null, inputData, outputStream, PgpMain.encryptAndSign(mContext, null, inputData, outputStream, asciiArmor,
appSettings.isAsciiArmor(), appSettings.getCompression(), keyIds, null, appSettings.getCompression(), keyIds, null,
appSettings.getEncryptionAlgorithm(), appSettings.getKeyId(), appSettings.getEncryptionAlgorithm(), appSettings.getKeyId(),
appSettings.getHashAlgorithm(), true, passphrase); appSettings.getHashAlgorithm(), true, passphrase);
} else { } else {
PgpMain.encryptAndSign(mContext, null, inputData, outputStream, PgpMain.encryptAndSign(mContext, null, inputData, outputStream, asciiArmor,
appSettings.isAsciiArmor(), appSettings.getCompression(), keyIds, null, appSettings.getCompression(), keyIds, null,
appSettings.getEncryptionAlgorithm(), Id.key.none, appSettings.getEncryptionAlgorithm(), Id.key.none,
appSettings.getHashAlgorithm(), true, null); appSettings.getHashAlgorithm(), true, null);
} }
@ -280,6 +282,7 @@ public class CryptoService extends Service {
} }
} }
// TODO: asciiArmor?!
private void signSafe(byte[] inputBytes, ICryptoCallback callback, AppSettings appSettings) private void signSafe(byte[] inputBytes, ICryptoCallback callback, AppSettings appSettings)
throws RemoteException { throws RemoteException {
try { try {
@ -327,19 +330,50 @@ public class CryptoService extends Service {
InputStream inputStream = new ByteArrayInputStream(inputBytes); InputStream inputStream = new ByteArrayInputStream(inputBytes);
long inputLength = inputBytes.length; long inputLength = inputBytes.length;
InputData inputData = new InputData(inputStream, inputLength); InputData inputData = new InputData(inputStream, inputLength);
Log.d(Constants.TAG, "in: " + new String(inputBytes));
OutputStream outputStream = new ByteArrayOutputStream(); 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 // TODO: This allows to decrypt messages with ALL secret keys, not only the one for the
// app, Fix this? // app, Fix this?
long secretKeyId = PgpMain.getDecryptionKeyId(mContext, inputStream); // long secretKeyId = PgpMain.getDecryptionKeyId(mContext, inputStream);
if (secretKeyId == Id.key.none) { // if (secretKeyId == Id.key.none) {
throw new PgpMain.PgpGeneralException(getString(R.string.error_noSecretKeyFound)); // 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); Log.d(Constants.TAG, "secretKeyId " + secretKeyId);
@ -350,17 +384,15 @@ public class CryptoService extends Service {
return; return;
} }
// if (signedOnly) { Bundle outputBundle;
// resultData = PgpMain.verifyText(this, this, inputData, outStream, if (signedOnly) {
// lookupUnknownKey); // TODO: download missing keys from keyserver?
// } else { outputBundle = PgpMain.verifyText(this, null, inputData, outputStream, false);
// resultData = PgpMain.decryptAndVerify(this, this, inputData, outStream, } else {
// PassphraseCacheService.getCachedPassphrase(this, secretKeyId), // TODO: assume symmetric: callback to enter symmetric pass
// assumeSymmetricEncryption); outputBundle = PgpMain.decryptAndVerify(this, null, inputData, outputStream,
// } passphrase, false);
}
Bundle outputBundle = PgpMain.decryptAndVerify(mContext, null, inputData, outputStream,
passphrase, false);
outputStream.close(); outputStream.close();
@ -377,8 +409,11 @@ public class CryptoService extends Service {
boolean signatureUnknown = outputBundle boolean signatureUnknown = outputBundle
.getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN); .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN);
CryptoSignatureResult sigResult = new CryptoSignatureResult(signatureUserId, signature, CryptoSignatureResult sigResult = null;
signatureSuccess, signatureUnknown); if (signature) {
sigResult = new CryptoSignatureResult(signatureUserId, signature, signatureSuccess,
signatureUnknown);
}
// return over handler on client side // return over handler on client side
callback.onSuccess(outputBytes, sigResult); callback.onSuccess(outputBytes, sigResult);
@ -397,7 +432,7 @@ public class CryptoService extends Service {
@Override @Override
public void encrypt(final byte[] inputBytes, final String[] encryptionUserIds, 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(); final AppSettings settings = getAppSettings();
@ -406,7 +441,8 @@ public class CryptoService extends Service {
@Override @Override
public void run() { public void run() {
try { try {
encryptAndSignSafe(inputBytes, encryptionUserIds, callback, settings, false); encryptAndSignSafe(inputBytes, encryptionUserIds, asciiArmor, callback,
settings, false);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(Constants.TAG, "CryptoService", e); Log.e(Constants.TAG, "CryptoService", e);
} }
@ -418,7 +454,7 @@ public class CryptoService extends Service {
@Override @Override
public void encryptAndSign(final byte[] inputBytes, final String[] encryptionUserIds, 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(); final AppSettings settings = getAppSettings();
@ -427,7 +463,8 @@ public class CryptoService extends Service {
@Override @Override
public void run() { public void run() {
try { try {
encryptAndSignSafe(inputBytes, encryptionUserIds, callback, settings, true); encryptAndSignSafe(inputBytes, encryptionUserIds, asciiArmor, callback,
settings, true);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.e(Constants.TAG, "CryptoService", e); Log.e(Constants.TAG, "CryptoService", e);
} }
@ -438,7 +475,7 @@ public class CryptoService extends Service {
} }
@Override @Override
public void sign(final byte[] inputBytes, final ICryptoCallback callback) public void sign(final byte[] inputBytes, boolean asciiArmor, final ICryptoCallback callback)
throws RemoteException { throws RemoteException {
final AppSettings settings = getAppSettings(); final AppSettings settings = getAppSettings();

View File

@ -0,0 +1,101 @@
/*
* Copyright (C) 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.util;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import android.content.Context;
import android.widget.ArrayAdapter;
public class KeyValueSpinnerAdapter extends ArrayAdapter<String> {
private final HashMap<Integer, String> mData;
private final int[] mKeys;
private final String[] mValues;
static <K, V extends Comparable<? super V>> SortedSet<Map.Entry<K, V>> entriesSortedByValues(
Map<K, V> map) {
SortedSet<Map.Entry<K, V>> sortedEntries = new TreeSet<Map.Entry<K, V>>(
new Comparator<Map.Entry<K, V>>() {
@Override
public int compare(Map.Entry<K, V> e1, Map.Entry<K, V> e2) {
return e1.getValue().compareTo(e2.getValue());
}
});
sortedEntries.addAll(map.entrySet());
return sortedEntries;
}
public KeyValueSpinnerAdapter(Context context, HashMap<Integer, String> objects) {
// To make the drop down a simple text box
super(context, android.R.layout.simple_spinner_item);
mData = objects;
// To make the drop down view a radio button list
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
SortedSet<Map.Entry<Integer, String>> sorted = entriesSortedByValues(objects);
// Assign hash keys with a position so that we can present and retrieve them
int i = 0;
mKeys = new int[mData.size()];
mValues = new String[mData.size()];
for (Map.Entry<Integer, String> entry : sorted) {
mKeys[i] = entry.getKey();
mValues[i] = entry.getValue();
i++;
}
}
public int getCount() {
return mData.size();
}
/**
* Returns the value
*/
@Override
public String getItem(int position) {
// return the value based on the position. This is displayed in the list.
return mValues[position];
}
/**
* Returns item key
*/
public long getItemId(int position) {
// Return an id to represent the item.
return mKeys[position];
}
/**
* Find position from key
*/
public int getPosition(long itemId) {
for (int i = 0; i < mKeys.length; i++) {
if ((int) itemId == mKeys[i]) {
return i;
}
}
return -1;
}
}