From fc0c084a621eb67e07cc4c4d65ecc9f841b78cc9 Mon Sep 17 00:00:00 2001 From: gogowitczak Date: Mon, 7 Apr 2014 16:31:38 +0200 Subject: [PATCH] Added possibility to enter custom key length. Added key length limitations, according to issue #102 and SpongyCastle specification. --- .../ui/dialog/CreateKeyDialogFragment.java | 148 +++++++++++++++--- .../src/main/res/layout/create_key_dialog.xml | 18 +++ OpenKeychain/src/main/res/values/arrays.xml | 2 + OpenKeychain/src/main/res/values/strings.xml | 3 + 4 files changed, 149 insertions(+), 22 deletions(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java index ad558a81e..2b8e19f86 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java @@ -23,11 +23,15 @@ import android.content.DialogInterface; import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentActivity; +import android.text.Editable; +import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.EditText; import android.widget.Spinner; +import android.widget.TextView; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.util.Choice; @@ -45,6 +49,10 @@ public class CreateKeyDialogFragment extends DialogFragment { private int mNewKeySize; private Choice mNewKeyAlgorithmChoice; private OnAlgorithmSelectedListener mAlgorithmSelectedListener; + private Spinner mAlgorithmSpinner; + private Spinner mKeySizeSpinner; + private TextView mCustomKeyTextView; + private EditText mCustomKeyEditText; public void setOnAlgorithmSelectedListener(OnAlgorithmSelectedListener listener) { mAlgorithmSelectedListener = listener; @@ -77,7 +85,7 @@ public class CreateKeyDialogFragment extends DialogFragment { boolean wouldBeMasterKey = (childCount == 0); - final Spinner algorithm = (Spinner) view.findViewById(R.id.create_key_algorithm); + mAlgorithmSpinner = (Spinner) view.findViewById(R.id.create_key_algorithm); ArrayList choices = new ArrayList(); choices.add(new Choice(Id.choice.algorithm.dsa, getResources().getString( R.string.dsa))); @@ -92,38 +100,53 @@ public class CreateKeyDialogFragment extends DialogFragment { ArrayAdapter adapter = new ArrayAdapter(context, android.R.layout.simple_spinner_item, choices); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - algorithm.setAdapter(adapter); + mAlgorithmSpinner.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); + mAlgorithmSpinner.setSelection(i); break; } } - final Spinner keySize = (Spinner) view.findViewById(R.id.create_key_size); + mKeySizeSpinner = (Spinner) view.findViewById(R.id.create_key_size); ArrayAdapter 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 + mKeySizeSpinner.setAdapter(keySizeAdapter); + mKeySizeSpinner.setSelection(3); // Default to 4096 for the key length + + mCustomKeyTextView = (TextView) view.findViewById(R.id.custom_key_size_label); + mCustomKeyEditText = (EditText) view.findViewById(R.id.custom_key_size_input); + + final AdapterView.OnItemSelectedListener customKeySelectedLisener = new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + final String selectedItemString = (String) parent.getSelectedItem(); + final String customLengthString = getResources().getString(R.string.key_size_custom); + final boolean customSelected = customLengthString.equals(selectedItemString); + final int visibility = customSelected ? View.VISIBLE : View.GONE; + mCustomKeyEditText.setVisibility(visibility); + mCustomKeyTextView.setVisibility(visibility); + } + + @Override + public void onNothingSelected(AdapterView parent) { + } + }; + dialog.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface di, int id) { di.dismiss(); - try { - final String selectedItem = (String) keySize.getSelectedItem(); - mNewKeySize = Integer.parseInt(selectedItem); - } catch (NumberFormatException e) { - mNewKeySize = 0; - } - - mNewKeyAlgorithmChoice = (Choice) algorithm.getSelectedItem(); + mNewKeyAlgorithmChoice = (Choice) mAlgorithmSpinner.getSelectedItem(); + mNewKeySize = getProperKeyLength(mNewKeyAlgorithmChoice.getId(), getSelectedKeyLength()); mAlgorithmSelectedListener.onAlgorithmSelected(mNewKeyAlgorithmChoice, mNewKeySize); } - }); + } + ); dialog.setCancelable(true); dialog.setNegativeButton(android.R.string.cancel, @@ -138,11 +161,9 @@ public class CreateKeyDialogFragment extends DialogFragment { final AdapterView.OnItemSelectedListener weakRsaListener = new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { - final Choice selectedAlgorithm = (Choice) algorithm.getSelectedItem(); - final int selectedKeySize = Integer.parseInt((String) keySize.getSelectedItem()); - final boolean isWeakRsa = (selectedAlgorithm.getId() == Id.choice.algorithm.rsa && - selectedKeySize <= 1024); - alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(!isWeakRsa); + if (mKeySizeSpinner == parent) + customKeySelectedLisener.onItemSelected(parent, view, position, id); + setOkButtonAvailability(alertDialog); } @Override @@ -150,10 +171,93 @@ public class CreateKeyDialogFragment extends DialogFragment { } }; - keySize.setOnItemSelectedListener(weakRsaListener); - algorithm.setOnItemSelectedListener(weakRsaListener); + mCustomKeyEditText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable s) { + setOkButtonAvailability(alertDialog); + } + }); + + mKeySizeSpinner.setOnItemSelectedListener(weakRsaListener); + mAlgorithmSpinner.setOnItemSelectedListener(weakRsaListener); return alertDialog; } + private int getSelectedKeyLength() { + final String selectedItemString = (String) mKeySizeSpinner.getSelectedItem(); + final String customLengthString = getResources().getString(R.string.key_size_custom); + final boolean customSelected = customLengthString.equals(selectedItemString); + String keyLengthString = customSelected ? mCustomKeyEditText.getText().toString() : selectedItemString; + int keySize = 0; + try { + keySize = Integer.parseInt(keyLengthString); + } catch (NumberFormatException e) { + keySize = 0; + } + return keySize; + } + + /** + *

RSA

+ *

for RSA algorithm, key length must be greater than 1024 (according to + * #102). Possibility to generate keys bigger + * than 8192 bits is currently disabled, because it's almost impossible to generate them on a mobile device (check + * RSA key length plot and + * Cryptographic Key Length Recommendation). Also, key length must be a + * multiplicity of 8.

+ *

ElGamal

+ *

For ElGamal algorithm, supported key lengths are 1536, 2048, 3072, 4096 or 8192 bits.

+ *

DSA

+ *

For DSA algorithm key length must be between 512 and 1024. Also, it must me dividable by 64.

+ * + * @return correct key length, according to SpongyCastle specification. Returns -1, if key length is + * inappropriate. + */ + private int getProperKeyLength(int algorithmId, int currentKeyLength) { + final int[] elGamalSupportedLengths = {1536, 2048, 3072, 4096, 8192}; + int properKeyLength = -1; + switch (algorithmId) { + case Id.choice.algorithm.rsa: + if (currentKeyLength > 1024 && currentKeyLength <= 8192) { + properKeyLength = currentKeyLength + ((8 - (currentKeyLength % 8)) % 8); + } + break; + case Id.choice.algorithm.elgamal: + int[] elGammalKeyDiff = new int[elGamalSupportedLengths.length]; + for (int i = 0; i < elGamalSupportedLengths.length; i++) + elGammalKeyDiff[i] = Math.abs(elGamalSupportedLengths[i] - currentKeyLength); + int minimalValue = Integer.MAX_VALUE; + int minimalIndex = -1; + for (int i = 0; i < elGammalKeyDiff.length; i++) + if (elGammalKeyDiff[i] <= minimalValue) { + minimalValue = elGammalKeyDiff[i]; + minimalIndex = i; + } + properKeyLength = elGamalSupportedLengths[minimalIndex]; + break; + case Id.choice.algorithm.dsa: + if (currentKeyLength >= 512 && currentKeyLength <= 1024) { + properKeyLength = currentKeyLength + ((64 - (currentKeyLength % 64)) % 64); + } + break; + } + return properKeyLength; + } + + private void setOkButtonAvailability(AlertDialog alertDialog) { + final Choice selectedAlgorithm = (Choice) mAlgorithmSpinner.getSelectedItem(); + final int selectedKeySize = getSelectedKeyLength(); //Integer.parseInt((String) mKeySizeSpinner.getSelectedItem()); + final int properKeyLength = getProperKeyLength(selectedAlgorithm.getId(), selectedKeySize); + alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(properKeyLength > 0); + } + } diff --git a/OpenKeychain/src/main/res/layout/create_key_dialog.xml b/OpenKeychain/src/main/res/layout/create_key_dialog.xml index 57a1b865f..da884ceb5 100644 --- a/OpenKeychain/src/main/res/layout/create_key_dialog.xml +++ b/OpenKeychain/src/main/res/layout/create_key_dialog.xml @@ -56,6 +56,24 @@ android:gravity="right" android:padding="4dp" /> + + + + + \ No newline at end of file diff --git a/OpenKeychain/src/main/res/values/arrays.xml b/OpenKeychain/src/main/res/values/arrays.xml index c84c2648d..b16973f90 100644 --- a/OpenKeychain/src/main/res/values/arrays.xml +++ b/OpenKeychain/src/main/res/values/arrays.xml @@ -34,6 +34,8 @@ @string/key_size_1024 @string/key_size_2048 @string/key_size_4096 + @string/key_size_8192 + @string/key_size_custom @string/menu_import_from_key_server diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 6c6d05103..c1d62fd52 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -378,6 +378,9 @@ 1024 2048 4096 + 8192 + Custom key size + Type custom key length (in bits): fast