diff --git a/OpenPGP-Keychain-API-Demo/res/layout/crypto_provider_demo.xml b/OpenPGP-Keychain-API-Demo/res/layout/crypto_provider_demo.xml index 47a8b6520..0579aa643 100644 --- a/OpenPGP-Keychain-API-Demo/res/layout/crypto_provider_demo.xml +++ b/OpenPGP-Keychain-API-Demo/res/layout/crypto_provider_demo.xml @@ -78,7 +78,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" - android:onClick="decryptOnClick" + android:onClick="decryptAndVerifyOnClick" android:text="Decrypt" /> diff --git a/OpenPGP-Keychain-API-Demo/src/org/openintents/crypto/ICryptoService.aidl b/OpenPGP-Keychain-API-Demo/src/org/openintents/crypto/ICryptoService.aidl index b74ab642c..45a80dfd3 100644 --- a/OpenPGP-Keychain-API-Demo/src/org/openintents/crypto/ICryptoService.aidl +++ b/OpenPGP-Keychain-API-Demo/src/org/openintents/crypto/ICryptoService.aidl @@ -34,7 +34,7 @@ interface ICryptoService { * @param callback * 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 @@ -44,7 +44,7 @@ interface ICryptoService { * @param callback * 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 @@ -58,7 +58,7 @@ interface ICryptoService { * @param callback * 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 @@ -71,10 +71,4 @@ interface ICryptoService { */ oneway void decryptAndVerify(in byte[] inputBytes, in ICryptoCallback callback); - /** - * Opens setup using default parameters - * - */ - oneway void setup(boolean asciiArmor, boolean newKeyring, String newKeyringUserId); - } \ No newline at end of file diff --git a/OpenPGP-Keychain-API-Demo/src/org/sufficientlysecure/keychain/demo/CryptoProviderDemoActivity.java b/OpenPGP-Keychain-API-Demo/src/org/sufficientlysecure/keychain/demo/CryptoProviderDemoActivity.java index db84a1742..f60db04b2 100644 --- a/OpenPGP-Keychain-API-Demo/src/org/sufficientlysecure/keychain/demo/CryptoProviderDemoActivity.java +++ b/OpenPGP-Keychain-API-Demo/src/org/sufficientlysecure/keychain/demo/CryptoProviderDemoActivity.java @@ -74,7 +74,7 @@ public class CryptoProviderDemoActivity extends Activity { @Override public void onSuccess(final byte[] outputBytes, CryptoSignatureResult signatureResult) throws RemoteException { - Log.d(Constants.TAG, "onEncryptSignSuccess"); + Log.d(Constants.TAG, "encryptCallback"); 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 public void onSuccess(final byte[] outputBytes, final CryptoSignatureResult signatureResult) throws RemoteException { - Log.d(Constants.TAG, "onDecryptVerifySuccess"); + Log.d(Constants.TAG, "decryptAndVerifyCallback"); runOnUiThread(new Runnable() { @@ -136,7 +136,7 @@ public class CryptoProviderDemoActivity extends Activity { try { mCryptoServiceConnection.getService().encrypt(inputBytes, - mEncryptUserIds.getText().toString().split(","), encryptCallback); + mEncryptUserIds.getText().toString().split(","), true, encryptCallback); } catch (RemoteException e) { Log.e(Constants.TAG, "CryptoProviderDemo", e); } @@ -146,7 +146,7 @@ public class CryptoProviderDemoActivity extends Activity { byte[] inputBytes = mMessage.getText().toString().getBytes(); try { - mCryptoServiceConnection.getService().sign(inputBytes, encryptCallback); + mCryptoServiceConnection.getService().sign(inputBytes, true, encryptCallback); } catch (RemoteException e) { Log.e(Constants.TAG, "CryptoProviderDemo", e); } @@ -157,17 +157,18 @@ public class CryptoProviderDemoActivity extends Activity { try { mCryptoServiceConnection.getService().encryptAndSign(inputBytes, - mEncryptUserIds.getText().toString().split(","), encryptCallback); + mEncryptUserIds.getText().toString().split(","), true, encryptCallback); } catch (RemoteException e) { Log.e(Constants.TAG, "CryptoProviderDemo", e); } } - public void decryptOnClick(View view) { + public void decryptAndVerifyOnClick(View view) { byte[] inputBytes = mCiphertext.getText().toString().getBytes(); try { - mCryptoServiceConnection.getService().decryptAndVerify(inputBytes, decryptCallback); + mCryptoServiceConnection.getService().decryptAndVerify(inputBytes, + decryptAndVerifyCallback); } catch (RemoteException e) { Log.e(Constants.TAG, "CryptoProviderDemo", e); } diff --git a/OpenPGP-Keychain/res/layout/api_app_settings_fragment.xml b/OpenPGP-Keychain/res/layout/api_app_settings_fragment.xml index 307da3efb..45dd11252 100644 --- a/OpenPGP-Keychain/res/layout/api_app_settings_fragment.xml +++ b/OpenPGP-Keychain/res/layout/api_app_settings_fragment.xml @@ -82,15 +82,41 @@ android:id="@+id/api_app_settings_advanced" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:orientation="horizontal" + android:orientation="vertical" android:visibility="invisible" > - + android:text="@string/label_encryptionAlgorithm" + android:textAppearance="?android:attr/textAppearanceMedium" /> + + + + + + + + + + \ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/openintents/crypto/ICryptoService.aidl b/OpenPGP-Keychain/src/org/openintents/crypto/ICryptoService.aidl index 555a71cd6..45a80dfd3 100644 --- a/OpenPGP-Keychain/src/org/openintents/crypto/ICryptoService.aidl +++ b/OpenPGP-Keychain/src/org/openintents/crypto/ICryptoService.aidl @@ -34,7 +34,7 @@ interface ICryptoService { * @param callback * 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 @@ -44,7 +44,7 @@ interface ICryptoService { * @param callback * 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 @@ -58,7 +58,7 @@ interface ICryptoService { * @param callback * 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 diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/KeychainApplication.java index 7f06ccc04..654eca5b8 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/KeychainApplication.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/KeychainApplication.java @@ -21,6 +21,7 @@ import java.io.File; import java.security.Security; import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.PRNGFixes; import android.app.Application; @@ -30,15 +31,16 @@ public class KeychainApplication extends Application { static { // Define Java Security Provider to be Bouncy Castle - Security.insertProviderAt(new BouncyCastleProvider(), 1); + Security.insertProviderAt(new BouncyCastleProvider(), 1); } @Override public void onCreate() { super.onCreate(); - + // apply RNG fixes PRNGFixes.apply(); + Log.d(Constants.TAG, "PRNG Fixes applied!"); // Create APG directory on sdcard if not existing if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/PgpMain.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/PgpMain.java index 76fc880a0..71466ff22 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/PgpMain.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/PgpMain.java @@ -17,6 +17,30 @@ 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.ArmoredOutputStream; import org.spongycastle.bcpg.BCPGOutputStream; @@ -45,7 +69,6 @@ import org.spongycastle.openpgp.PGPPrivateKey; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKeyEncryptedData; import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPPublicKeyRingCollection; import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; 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.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; +import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.util.HkpKeyServer; 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.PositionAwareInputStream; import org.sufficientlysecure.keychain.util.Primes; 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.pm.PackageInfo; @@ -93,31 +116,6 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; 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: * diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainContract.java index 9207cb596..82dcfe15f 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -56,7 +56,6 @@ public class KeychainContract { interface ApiAppsColumns { String PACKAGE_NAME = "package_name"; String KEY_ID = "key_id"; // not a database id - String ASCII_ARMOR = "ascii_armor"; String ENCRYPTION_ALGORITHM = "encryption_algorithm"; String HASH_ALORITHM = "hash_algorithm"; String COMPRESSION = "compression"; diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainDatabase.java index be640df57..0f962967d 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainDatabase.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainDatabase.java @@ -64,14 +64,11 @@ public class KeychainDatabase extends SQLiteOpenHelper { + UserIdsColumns.KEY_RING_ROW_ID + ") REFERENCES " + Tables.KEY_RINGS + "(" + BaseColumns._ID + ") ON DELETE CASCADE)"; - private static final String CREATE_API_APPS = "CREATE TABLE IF NOT EXISTS " - + Tables.API_APPS + " (" + BaseColumns._ID - + " INTEGER PRIMARY KEY AUTOINCREMENT, " + ApiAppsColumns.PACKAGE_NAME - + " TEXT UNIQUE, " + ApiAppsColumns.KEY_ID + " INT64, " - + ApiAppsColumns.ASCII_ARMOR + " INTEGER, " - + ApiAppsColumns.ENCRYPTION_ALGORITHM + " INTEGER, " - + ApiAppsColumns.HASH_ALORITHM + " INTEGER, " - + ApiAppsColumns.COMPRESSION + " INTEGER)"; + private static final String CREATE_API_APPS = "CREATE TABLE IF NOT EXISTS " + Tables.API_APPS + + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + ApiAppsColumns.PACKAGE_NAME + " TEXT UNIQUE, " + ApiAppsColumns.KEY_ID + " INT64, " + + ApiAppsColumns.ENCRYPTION_ALGORITHM + " INTEGER, " + ApiAppsColumns.HASH_ALORITHM + + " INTEGER, " + ApiAppsColumns.COMPRESSION + " INTEGER)"; KeychainDatabase(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 13f4e085c..7f7e81e8c 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -745,7 +745,6 @@ public class ProviderHelper { ContentValues values = new ContentValues(); values.put(ApiApps.PACKAGE_NAME, appSettings.getPackageName()); values.put(ApiApps.KEY_ID, appSettings.getKeyId()); - values.put(ApiApps.ASCII_ARMOR, appSettings.isAsciiArmor()); values.put(ApiApps.COMPRESSION, appSettings.getCompression()); values.put(ApiApps.ENCRYPTION_ALGORITHM, appSettings.getEncryptionAlgorithm()); values.put(ApiApps.HASH_ALORITHM, appSettings.getHashAlgorithm()); @@ -775,8 +774,6 @@ public class ProviderHelper { settings.setPackageName(cur.getString(cur .getColumnIndex(KeychainContract.ApiApps.PACKAGE_NAME))); 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 .getColumnIndexOrThrow(KeychainContract.ApiApps.COMPRESSION))); settings.setHashAlgorithm(cur.getInt(cur diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/AppSettings.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/AppSettings.java index 98f48ff59..eb2527455 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/AppSettings.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/AppSettings.java @@ -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; } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/AppSettingsFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/AppSettingsFragment.java index 8cef63ca3..a29b63e97 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/AppSettingsFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/AppSettingsFragment.java @@ -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 encryptionMap = new HashMap(); + 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 hashMap = new HashMap(); + 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 compressionMap = new HashMap(); + 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); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoService.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoService.java index e33314ea6..defacb448 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoService.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/remote_api/CryptoService.java @@ -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(); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/util/KeyValueSpinnerAdapter.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/util/KeyValueSpinnerAdapter.java new file mode 100644 index 000000000..e8905062c --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/util/KeyValueSpinnerAdapter.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2013 Dominik Schürmann + * + * 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 . + */ + +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 { + private final HashMap mData; + private final int[] mKeys; + private final String[] mValues; + + static > SortedSet> entriesSortedByValues( + Map map) { + SortedSet> sortedEntries = new TreeSet>( + new Comparator>() { + @Override + public int compare(Map.Entry e1, Map.Entry e2) { + return e1.getValue().compareTo(e2.getValue()); + } + }); + sortedEntries.addAll(map.entrySet()); + return sortedEntries; + } + + public KeyValueSpinnerAdapter(Context context, HashMap 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> 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 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; + } +} \ No newline at end of file