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