From 3fb47716024700ccb29888ca2d1ea9d4f2d1cc9b Mon Sep 17 00:00:00 2001 From: David Hedberg Date: Sat, 20 Feb 2021 14:26:18 +0100 Subject: [PATCH 1/2] Activate ssh encoding of public keys for ed25519 --- .../keychain/pgp/SshPublicKey.java | 19 +++++++++---------- extern/bouncycastle | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SshPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SshPublicKey.java index f6b5224d5..407da6b14 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SshPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SshPublicKey.java @@ -19,11 +19,13 @@ package org.sufficientlysecure.keychain.pgp; import org.bouncycastle.bcpg.DSAPublicBCPGKey; import org.bouncycastle.bcpg.ECPublicBCPGKey; +import org.bouncycastle.bcpg.EdDSAPublicBCPGKey; import org.bouncycastle.bcpg.RSAPublicBCPGKey; import org.bouncycastle.openpgp.PGPPublicKey; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.ssh.key.SshDSAPublicKey; import org.sufficientlysecure.keychain.ssh.key.SshECDSAPublicKey; +import org.sufficientlysecure.keychain.ssh.key.SshEd25519PublicKey; import org.sufficientlysecure.keychain.ssh.key.SshRSAPublicKey; import org.sufficientlysecure.keychain.ssh.utils.SshUtils; @@ -46,9 +48,8 @@ public class SshPublicKey { return encodeRSAKey(key); case PGPPublicKey.ECDSA: return encodeECKey(key); - // TODO -// case PGPPublicKey.EDDSA: -// return encodeEdDSAKey(key); + case PGPPublicKey.EDDSA: + return encodeEdDSAKey(key); case PGPPublicKey.DSA: return encodeDSAKey(key); default: @@ -73,15 +74,13 @@ public class SshPublicKey { return sshECDSAPublicKey.getPublicKeyBlob(); } + private String encodeEdDSAKey(PGPPublicKey publicKey) { + EdDSAPublicBCPGKey publicBCPGKey = (EdDSAPublicBCPGKey) publicKey.getPublicKeyPacket().getKey(); + SshEd25519PublicKey pubkey = new SshEd25519PublicKey(publicBCPGKey.getEdDSAEncodedPoint()); -// private String encodeEdDSAKey(PGPPublicKey publicKey) { -// EdDSAPublicBCPGKey publicBCPGKey = (EdDSAPublicBCPGKey) publicKey.getPublicKeyPacket().getKey(); -// -// SshEd25519PublicKey pubkey = new SshEd25519PublicKey(publicBCPGKey.getEdDSAEncodedPoint()); -// -// return pubkey.getPublicKeyBlob(); -// } + return pubkey.getPublicKeyBlob(); + } private String encodeDSAKey(PGPPublicKey publicKey) { DSAPublicBCPGKey publicBCPGKey = (DSAPublicBCPGKey) publicKey.getPublicKeyPacket().getKey(); diff --git a/extern/bouncycastle b/extern/bouncycastle index 40bdff642..be424633c 160000 --- a/extern/bouncycastle +++ b/extern/bouncycastle @@ -1 +1 @@ -Subproject commit 40bdff6428fbe09f20f727abcb06ce5c62efb436 +Subproject commit be424633c3bfb942dd07f290dc4b7299034ac021 From 6d4f37b1546b0f525ba97496e6130c5f0cc4b11f Mon Sep 17 00:00:00 2001 From: David Hedberg Date: Sat, 20 Feb 2021 14:27:55 +0100 Subject: [PATCH 2/2] Don't hash the data to sign when using EDDSA --- .../NfcSyncPGPContentSignerBuilder.java | 58 +++++++++++++++++++ .../keychain/pgp/CanonicalizedSecretKey.java | 4 +- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/NfcSyncPGPContentSignerBuilder.java b/OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/NfcSyncPGPContentSignerBuilder.java index e38e70c21..95580d07a 100644 --- a/OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/NfcSyncPGPContentSignerBuilder.java +++ b/OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/NfcSyncPGPContentSignerBuilder.java @@ -7,12 +7,14 @@ package org.bouncycastle.openpgp.operator.jcajce; +import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPrivateKey; import org.bouncycastle.openpgp.operator.PGPContentSigner; import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder; import org.bouncycastle.openpgp.operator.PGPDigestCalculator; +import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.security.Provider; @@ -93,6 +95,10 @@ public class NfcSyncPGPContentSignerBuilder public PGPContentSigner build(final int signatureType, final long keyID) throws PGPException { + if (keyAlgorithm == PublicKeyAlgorithmTags.EDDSA) { + return buildEdDSASigner(signatureType, keyID); + } + final PGPDigestCalculator digestCalculator = digestCalculatorProviderBuilder.build().get(hashAlgorithm); return new PGPContentSigner() @@ -139,4 +145,56 @@ public class NfcSyncPGPContentSignerBuilder } }; } + + public PGPContentSigner buildEdDSASigner(final int signatureType, final long keyID) + throws PGPException + { + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + return new PGPContentSigner() + { + public int getType() + { + return signatureType; + } + + public int getHashAlgorithm() + { + return hashAlgorithm; + } + + public int getKeyAlgorithm() + { + return keyAlgorithm; + } + + public long getKeyID() + { + return keyID; + } + + public OutputStream getOutputStream() + { + return outputStream; + } + + public byte[] getSignature() { + byte[] rawData = outputStream.toByteArray(); + + ByteBuffer buf = ByteBuffer.wrap(rawData); + if (signedHashes.containsKey(buf)) { + return (byte[]) signedHashes.get(buf); + } + // catch this when signatureGenerator.generate() is executed and divert to card, + // when doing the operation again reuse creationTimestamp (this will be hashed) + throw new NfcInteractionNeeded(rawData, getHashAlgorithm()); + } + + public byte[] getDigest() + { + return outputStream.toByteArray(); + } + }; + + } } 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 697e5da7d..6ee583e8c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -255,7 +255,9 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { private PGPContentSignerBuilder getAuthenticationContentSignerBuilder(int hashAlgorithm, Map signedHashes) { - if (getAlgorithm() == PublicKeyAlgorithmTags.EDDSA) { + if ( + getAlgorithm() == PublicKeyAlgorithmTags.EDDSA + && mPrivateKeyState != PRIVATE_KEY_STATE_DIVERT_TO_CARD) { // content signer feeding the input directly into the signature engine, // since EdDSA hashes the input anyway return new EdDsaAuthenticationContentSignerBuilder(