diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/KeyFlag.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/KeyFlag.java index 5b1f74e6..be12f41e 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/KeyFlag.java +++ b/pgpainless-core/src/main/java/org/pgpainless/algorithm/KeyFlag.java @@ -51,7 +51,15 @@ public enum KeyFlag { return flags; } + public static int toBitmask(KeyFlag... flags) { + int mask = 0; + for (KeyFlag f : flags) { + mask |= f.getFlag(); + } + return mask; + } + public static boolean hasKeyFlag(int mask, KeyFlag flag) { - return (mask & flag.getFlag()) == 0; + return (mask & flag.getFlag()) == flag.getFlag(); } } diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java index 8d05cc84..1c87b910 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java @@ -75,7 +75,8 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { */ public PGPKeyRing simpleRsaKeyRing(@Nonnull String userId, @Nonnull RsaLength length) throws PGPException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { - return withMasterKey( + return this + .withMasterKey( KeySpec.getBuilder(RSA_GENERAL.withLength(length)) .withDefaultKeyFlags() .withDefaultAlgorithms()) @@ -98,7 +99,8 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { */ public PGPKeyRing simpleEcKeyRing(@Nonnull String userId) throws PGPException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { - return withSubKey( + return this + .withSubKey( KeySpec.getBuilder(ECDH.fromCurve(EllipticCurve._P256)) .withKeyFlags(KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS) .withDefaultAlgorithms()) @@ -119,16 +121,21 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { @Override public WithPrimaryUserId withMasterKey(@Nonnull KeySpec spec) { - if (canCertifyOthers(spec)) { - throw new IllegalArgumentException("Certification Key MUST have KeyFlag CERTIFY_OTHER"); - } + verifyMasterKeyCanCertify(spec); KeyRingBuilder.this.keySpecs.add(0, spec); return new WithPrimaryUserIdImpl(); } + private void verifyMasterKeyCanCertify(KeySpec spec) { + if (!canCertifyOthers(spec)) { + throw new IllegalArgumentException("Certification Key MUST have KeyFlag CERTIFY_OTHER"); + } + } + private boolean canCertifyOthers(KeySpec keySpec) { - return KeyFlag.hasKeyFlag(keySpec.getSubpackets().getKeyFlags(), KeyFlag.CERTIFY_OTHER); + int flags = keySpec.getSubpackets().getKeyFlags(); + return KeyFlag.hasKeyFlag(flags, KeyFlag.CERTIFY_OTHER); } class WithPrimaryUserIdImpl implements WithPrimaryUserId { @@ -189,14 +196,18 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { return new PGPKeyRing(publicKeys, secretKeys); } - private PGPKeyRingGenerator buildRingGenerator(PGPKeyPair certKey, PGPContentSignerBuilder signer, PGPSignatureSubpacketVector hashedSubPackets) throws PGPException { + private PGPKeyRingGenerator buildRingGenerator(PGPKeyPair certKey, + PGPContentSignerBuilder signer, + PGPSignatureSubpacketVector hashedSubPackets) + throws PGPException { return new PGPKeyRingGenerator( - PGPSignature.POSITIVE_CERTIFICATION, certKey, - userId, digestCalculator, - hashedSubPackets, null, signer, secretKeyEncryptor); + PGPSignature.POSITIVE_CERTIFICATION, certKey, + userId, digestCalculator, + hashedSubPackets, null, signer, secretKeyEncryptor); } - private void addSubKeys(PGPKeyRingGenerator ringGenerator) throws NoSuchAlgorithmException, PGPException, InvalidAlgorithmParameterException { + private void addSubKeys(PGPKeyRingGenerator ringGenerator) + throws NoSuchAlgorithmException, PGPException, InvalidAlgorithmParameterException { for (KeySpec subKeySpec : keySpecs) { PGPKeyPair subKey = generateKeyPair(subKeySpec); if (subKeySpec.isInheritedSubPackets()) { @@ -209,8 +220,8 @@ public class KeyRingBuilder implements KeyRingBuilderInterface { private PGPContentSignerBuilder buildContentSigner(PGPKeyPair certKey) { return new JcaPGPContentSignerBuilder( - certKey.getPublicKey().getAlgorithm(), HashAlgorithm.SHA512.getAlgorithmId()) - .setProvider(ProviderFactory.getProvider()); + certKey.getPublicKey().getAlgorithm(), HashAlgorithm.SHA512.getAlgorithmId()) + .setProvider(ProviderFactory.getProvider()); } private PBESecretKeyEncryptor buildSecretKeyEncryptor() { diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilder.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilder.java index da79fc9b..fe67ade8 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilder.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilder.java @@ -38,11 +38,7 @@ public class KeySpecBuilder implements KeySpecBuilderInterface { @Override public WithDetailedConfiguration withKeyFlags(@Nonnull KeyFlag... flags) { - int val = 0; - for (KeyFlag f : flags) { - val |= f.getFlag(); - } - this.hashedSubPackets.setKeyFlags(false, val); + this.hashedSubPackets.setKeyFlags(false, KeyFlag.toBitmask(flags)); return new WithDetailedConfigurationImpl(); } diff --git a/pgpainless-core/src/test/java/org/pgpainless/key/KeyFlagTest.java b/pgpainless-core/src/test/java/org/pgpainless/key/KeyFlagTest.java new file mode 100644 index 00000000..0a8b1ac0 --- /dev/null +++ b/pgpainless-core/src/test/java/org/pgpainless/key/KeyFlagTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2020 Paul Schaub. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.pgpainless.key; + +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; + +import java.util.Arrays; + +import org.junit.Test; +import org.pgpainless.algorithm.KeyFlag; + +public class KeyFlagTest { + + @Test + public void hasKeyFlagTest() { + int mask = KeyFlag.toBitmask(KeyFlag.AUTHENTICATION, KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA); + assertEquals(0x23, mask); + assertEquals(Arrays.asList(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA, KeyFlag.AUTHENTICATION), + KeyFlag.fromBitmask(mask)); + + assertTrue(KeyFlag.hasKeyFlag(mask, KeyFlag.CERTIFY_OTHER)); + assertTrue(KeyFlag.hasKeyFlag(mask, KeyFlag.AUTHENTICATION)); + assertTrue(KeyFlag.hasKeyFlag(mask, KeyFlag.SIGN_DATA)); + + assertFalse(KeyFlag.hasKeyFlag(mask, KeyFlag.ENCRYPT_STORAGE)); + assertFalse(KeyFlag.hasKeyFlag(mask, KeyFlag.SHARED)); + } +}