diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index ed14512f5..f844acb0d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -533,6 +533,7 @@ public abstract class OperationResult implements Parcelable { MSG_CR_ERROR_FLAGS_DSA (LogLevel.ERROR, R.string.msg_cr_error_flags_dsa), MSG_CR_ERROR_FLAGS_ELGAMAL (LogLevel.ERROR, R.string.msg_cr_error_flags_elgamal), MSG_CR_ERROR_FLAGS_ECDSA (LogLevel.ERROR, R.string.msg_cr_error_flags_ecdsa), + MSG_CR_ERROR_FLAGS_EDDSA (LogLevel.ERROR, R.string.msg_cr_error_flags_eddsa), MSG_CR_ERROR_FLAGS_ECDH (LogLevel.ERROR, R.string.msg_cr_error_flags_ecdh), // secret key modify diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java index e32c97e2f..e8c776ef8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -209,6 +209,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { mPrivateKey = mSecretKey.extractPrivateKey(keyDecryptor); mPrivateKeyState = PRIVATE_KEY_STATE_UNLOCKED; } catch (PGPException e) { + Log.e(Constants.TAG, "Error extracting private key!", e); return false; } if (mPrivateKey == null) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 27ba4638c..e45e07c8e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -45,6 +45,7 @@ import org.bouncycastle.bcpg.S2K; import org.bouncycastle.bcpg.sig.Features; import org.bouncycastle.bcpg.sig.KeyFlags; import org.bouncycastle.bcpg.sig.RevocationReasonTags; +import org.bouncycastle.jcajce.provider.asymmetric.eddsa.spec.EdDSAGenParameterSpec; import org.bouncycastle.jce.spec.ElGamalParameterSpec; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPKeyFlags; @@ -174,7 +175,7 @@ public class PgpKeyOperation { log.add(LogType.MSG_CR_ERROR_NO_CURVE, indent); return null; } - } else { + } else if (add.getAlgorithm() != Algorithm.EDDSA) { if (add.getKeySize() == null) { log.add(LogType.MSG_CR_ERROR_NO_KEYSIZE, indent); return null; @@ -241,6 +242,21 @@ public class PgpKeyOperation { break; } + case EDDSA: { + if ((add.getFlags() & (PGPKeyFlags.CAN_ENCRYPT_COMMS | PGPKeyFlags.CAN_ENCRYPT_STORAGE)) > 0) { + log.add(LogType.MSG_CR_ERROR_FLAGS_ECDSA, indent); + return null; + } + progress(R.string.progress_generating_eddsa, 30); + EdDSAGenParameterSpec edParamSpec = + new EdDSAGenParameterSpec("ed25519"); + keyGen = KeyPairGenerator.getInstance("EdDSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME); + keyGen.initialize(edParamSpec, new SecureRandom()); + + algorithm = PGPPublicKey.EDDSA; + break; + } + case ECDH: { // make sure there are no sign or certify flags set if ((add.getFlags() & (PGPKeyFlags.CAN_SIGN | PGPKeyFlags.CAN_CERTIFY)) > 0) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java index 892207938..dc887bbef 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSecurityConstants.java @@ -174,6 +174,9 @@ public class PgpSecurityConstants { } return null; } + case PublicKeyAlgorithmTags.EDDSA: { + return null; + } // ELGAMAL_GENERAL: deprecated in RFC 4880, use ELGAMAL_ENCRYPT // DIFFIE_HELLMAN: unsure // TODO specialize all cases! diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index 907fa6996..acdbb93fc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -250,6 +250,7 @@ public class UncachedKeyRing { PublicKeyAlgorithmTags.ECDSA, // 19 PublicKeyAlgorithmTags.ELGAMAL_GENERAL, // 20 // PublicKeyAlgorithmTags.DIFFIE_HELLMAN, // 21 + PublicKeyAlgorithmTags.EDDSA, // 22 }; /** "Canonicalizes" a public key, removing inconsistencies in the process. diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java index 4093ce6f7..77ce0dc90 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java @@ -223,7 +223,8 @@ public class UncachedPublicKey { public boolean isEC() { return getAlgorithm() == PGPPublicKey.ECDH - || getAlgorithm() == PGPPublicKey.ECDSA; + || getAlgorithm() == PGPPublicKey.ECDSA + || getAlgorithm() == PGPPublicKey.EDDSA; } public byte[] getFingerprint() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java index 06909127a..6d67fd5c1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -290,7 +290,7 @@ public abstract class SaveKeyringParcel implements Parcelable { // All supported algorithms public enum Algorithm { - RSA, DSA, ELGAMAL, ECDSA, ECDH + RSA, DSA, ELGAMAL, ECDSA, ECDH, EDDSA } // All curves defined in the standard diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java index bf1b2f378..d307482b0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java @@ -62,7 +62,7 @@ public class AddSubkeyDialogFragment extends DialogFragment { } public enum SupportedKeyType { - RSA_2048, RSA_3072, RSA_4096, ECC_P256, ECC_P521 + RSA_2048, RSA_3072, RSA_4096, ECC_P256, ECC_P521, EDDSA } private static final String ARG_WILL_BE_MASTER_KEY = "will_be_master_key"; @@ -158,6 +158,8 @@ public class AddSubkeyDialogFragment extends DialogFragment { R.string.ecc_p256), getResources().getString(R.string.ecc_p256_description_html))); choices.add(new Choice<>(SupportedKeyType.ECC_P521, getResources().getString( R.string.ecc_p521), getResources().getString(R.string.ecc_p521_description_html))); + choices.add(new Choice<>(SupportedKeyType.EDDSA, getResources().getString( + R.string.ecc_eddsa), getResources().getString(R.string.ecc_eddsa_description_html))); TwoLineArrayAdapter adapter = new TwoLineArrayAdapter(context, android.R.layout.simple_spinner_item, choices); mKeyTypeSpinner.setAdapter(adapter); @@ -198,6 +200,9 @@ public class AddSubkeyDialogFragment extends DialogFragment { if (mWillBeMasterKey) { mUsageEncrypt.setEnabled(false); } + } else if (keyType == SupportedKeyType.EDDSA) { + mUsageSignAndEncrypt.setEnabled(false); + mUsageEncrypt.setEnabled(false); } else { // need to enable if previously disabled for ECC masterkey mUsageEncrypt.setEnabled(true); @@ -275,6 +280,9 @@ public class AddSubkeyDialogFragment extends DialogFragment { } break; } + case EDDSA: { + algorithm = Algorithm.EDDSA; + } } // set flags diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java index 85f721a90..b830c6cd9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java @@ -110,6 +110,10 @@ public class KeyFormattingUtils { return "ECDH (" + oidName + ")"; } + case PublicKeyAlgorithmTags.EDDSA: { + return "EdDSA"; + } + default: { if (context != null) { algorithmStr = context.getResources().getString(R.string.unknown); diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 4f1fb4ea9..32c660cbf 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -315,6 +315,8 @@ "very tiny file size, considered secure until 2040 <br/> <u>experimental and not supported by all implementations</u>" "ECC P-521" "tiny file size, considered secure until 2040+ <br/> <u>experimental and not supported by all implementations</u>" + "ECC EdDSA" + "tiny file size, considered secure until 2040+ <br/> <u>experimental and not supported by all implementations</u>" "None (subkey binding only)" "Sign" "Encrypt" @@ -452,6 +454,7 @@ "generating new DSA key…" "generating new ElGamal key…" "generating new ECDSA key…" + "generating new EdDSA key…" "generating new ECDH key…" "modifying keyring…" @@ -1084,6 +1087,7 @@ "Bad key flags selected, DSA cannot be used for encryption!" "Bad key flags selected, ElGamal cannot be used for signing!" "Bad key flags selected, ECDSA cannot be used for encryption!" + "Bad key flags selected, EdDSA cannot be used for encryption!" "Bad key flags selected, ECDH cannot be used for signing!" diff --git a/extern/bouncycastle b/extern/bouncycastle index 2f4b5a448..1c44d1e9f 160000 --- a/extern/bouncycastle +++ b/extern/bouncycastle @@ -1 +1 @@ -Subproject commit 2f4b5a448c051ad980a437d7efbf4402b593f929 +Subproject commit 1c44d1e9f5fd52dd515552ae000e44be5ee9f4a4