From dd458e7da707f2d655d5a563971a7f52e05d879c Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Mon, 16 Jul 2018 17:16:16 +0200 Subject: [PATCH] Apply sub key fix to generated keys --- .../key/generation/KeyRingBuilder.java | 5 +++++ .../pgpainless/pgpainless/util/BCUtil.java | 16 ++++++++++++++ .../pgpainless/util/KeyRingSubKeyFix.java | 22 +++++++++++++------ .../pgpainless/KeyRingSubKeyFixTest.java | 22 +++++-------------- 4 files changed, 41 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/pgpainless/pgpainless/key/generation/KeyRingBuilder.java b/src/main/java/org/pgpainless/pgpainless/key/generation/KeyRingBuilder.java index 85f1e914..abd726b2 100644 --- a/src/main/java/org/pgpainless/pgpainless/key/generation/KeyRingBuilder.java +++ b/src/main/java/org/pgpainless/pgpainless/key/generation/KeyRingBuilder.java @@ -52,6 +52,7 @@ import org.pgpainless.pgpainless.key.generation.type.KeyType; import org.pgpainless.pgpainless.key.generation.type.RSA_GENERAL; import org.pgpainless.pgpainless.key.generation.type.curve.EllipticCurve; import org.pgpainless.pgpainless.key.generation.type.length.RsaLength; +import org.pgpainless.pgpainless.util.KeyRingSubKeyFix; import org.pgpainless.pgpainless.util.Passphrase; public class KeyRingBuilder implements KeyRingBuilderInterface { @@ -210,6 +211,10 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { PGPPublicKeyRing publicKeys = ringGenerator.generatePublicKeyRing(); PGPSecretKeyRing secretKeys = ringGenerator.generateSecretKeyRing(); + + // TODO: Remove once BC 1.61 is released + secretKeys = KeyRingSubKeyFix.repairSubkeyPackets(secretKeys, null, null); + return new PGPKeyRing(publicKeys, secretKeys); } diff --git a/src/main/java/org/pgpainless/pgpainless/util/BCUtil.java b/src/main/java/org/pgpainless/pgpainless/util/BCUtil.java index 38d317b1..395d0809 100644 --- a/src/main/java/org/pgpainless/pgpainless/util/BCUtil.java +++ b/src/main/java/org/pgpainless/pgpainless/util/BCUtil.java @@ -37,6 +37,7 @@ import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; import org.bouncycastle.openpgp.PGPUtil; +import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; import org.bouncycastle.util.io.Streams; import org.pgpainless.pgpainless.algorithm.KeyFlag; import org.pgpainless.pgpainless.key.selection.key.PublicKeySelectionStrategy; @@ -61,6 +62,21 @@ public class BCUtil { return new PGPSecretKeyRingCollection(Arrays.asList(rings)); } + public static PGPPublicKeyRing publicKeyRingFromSecretKeyRing(PGPSecretKeyRing secretKeys) + throws PGPException, IOException { + PGPSecretKeyRing fixedSecretKeys = KeyRingSubKeyFix.repairSubkeyPackets(secretKeys, null, null); + + ByteArrayOutputStream buffer = new ByteArrayOutputStream(512); + for (PGPSecretKey secretKey : fixedSecretKeys) { + PGPPublicKey publicKey = secretKey.getPublicKey(); + if (publicKey != null) { + publicKey.encode(buffer, false); + } + } + + return new PGPPublicKeyRing(buffer.toByteArray(), new BcKeyFingerprintCalculator()); + } + /* PGPXxxKeyRingCollection -> PGPXxxKeyRing */ diff --git a/src/main/java/org/pgpainless/pgpainless/util/KeyRingSubKeyFix.java b/src/main/java/org/pgpainless/pgpainless/util/KeyRingSubKeyFix.java index 0230ccfe..08b42619 100644 --- a/src/main/java/org/pgpainless/pgpainless/util/KeyRingSubKeyFix.java +++ b/src/main/java/org/pgpainless/pgpainless/util/KeyRingSubKeyFix.java @@ -60,17 +60,24 @@ public class KeyRingSubKeyFix { PBESecretKeyDecryptor decryptor, PBESecretKeyEncryptor encryptor) throws PGPException { - List _secretKeys = new ArrayList<>(); - Iterator secretKeyIterator = secretKeys.iterator(); - _secretKeys.add(secretKeyIterator.next()); PGPDigestCalculator calculator = new BcPGPDigestCalculatorProvider().get(HashAlgorithmTags.SHA1); + List _secretKeys = new ArrayList<>(); + Iterator secretKeyIterator = secretKeys.iterator(); try { while (secretKeyIterator.hasNext()) { - PGPSecretKey subKey = secretKeyIterator.next(); - PGPPublicKey pubSubKey = subKey.getPublicKey(); + PGPSecretKey key = secretKeyIterator.next(); + + if (key.isMasterKey()) { + LOGGER.log(Level.INFO, Long.toHexString(key.getKeyID()) + " is master key. Skip."); + _secretKeys.add(key); + continue; + } + + PGPSecretKey secSubKey = key; + PGPPublicKey pubSubKey = secSubKey.getPublicKey(); // check for public key packet type @@ -80,15 +87,16 @@ public class KeyRingSubKeyFix { if (keyPacket instanceof PublicSubkeyPacket) { // Sub key is already sub key + _secretKeys.add(secSubKey); continue; } // Sub key is normal key -> fix - LOGGER.log(Level.INFO, "Subkey " + Long.toHexString(subKey.getKeyID()) + " does not have a subkey key packet. Convert it..."); + LOGGER.log(Level.INFO, "Subkey " + Long.toHexString(secSubKey.getKeyID()) + " does not have a subkey key packet. Convert it..."); keyPacket = new PublicSubkeyPacket(pubSubKey.getAlgorithm(), pubSubKey.getCreationTime(), keyPacket.getKey()); publicPk.set(pubSubKey, keyPacket); - PGPPrivateKey privateKey = subKey.extractPrivateKey(decryptor); + PGPPrivateKey privateKey = secSubKey.extractPrivateKey(decryptor); PGPSecretKey secretKey = new PGPSecretKey(privateKey, pubSubKey, calculator, false, encryptor); _secretKeys.add(secretKey); diff --git a/src/test/java/org/pgpainless/pgpainless/KeyRingSubKeyFixTest.java b/src/test/java/org/pgpainless/pgpainless/KeyRingSubKeyFixTest.java index beb1688a..eda961cc 100644 --- a/src/test/java/org/pgpainless/pgpainless/KeyRingSubKeyFixTest.java +++ b/src/test/java/org/pgpainless/pgpainless/KeyRingSubKeyFixTest.java @@ -17,7 +17,6 @@ package org.pgpainless.pgpainless; import static junit.framework.TestCase.assertTrue; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; @@ -27,13 +26,11 @@ import java.util.Arrays; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; import org.junit.Test; import org.pgpainless.pgpainless.key.collection.PGPKeyRing; +import org.pgpainless.pgpainless.util.BCUtil; import org.pgpainless.pgpainless.util.KeyRingSubKeyFix; public class KeyRingSubKeyFixTest { @@ -51,20 +48,11 @@ public class KeyRingSubKeyFixTest { PGPPublicKeyRing publicKeys = ring.getPublicKeys(); PGPSecretKeyRing fixed = KeyRingSubKeyFix.repairSubkeyPackets(secretKeys, null, null); - PGPPublicKeyRing fixedPub = publicKeyRing(fixed); + + assertTrue(Arrays.equals(secretKeys.getEncoded(), fixed.getEncoded())); + + PGPPublicKeyRing fixedPub = BCUtil.publicKeyRingFromSecretKeyRing(fixed); assertTrue(Arrays.equals(publicKeys.getEncoded(), fixedPub.getEncoded())); } - - private PGPPublicKeyRing publicKeyRing(PGPSecretKeyRing secretKeys) throws IOException { - ByteArrayOutputStream buffer = new ByteArrayOutputStream(2048); - for (PGPSecretKey s : secretKeys) { - PGPPublicKey p = s.getPublicKey(); - if (p != null) { - p.encode(buffer); - } - } - - return new PGPPublicKeyRing(buffer.toByteArray(), new BcKeyFingerprintCalculator()); - } }