001// SPDX-FileCopyrightText: 2018 Paul Schaub <vanitasvitae@fsfe.org>
002//
003// SPDX-License-Identifier: Apache-2.0
004
005package org.pgpainless.key.generation;
006
007import java.util.Arrays;
008import java.util.LinkedHashSet;
009import java.util.Set;
010import javax.annotation.Nonnull;
011
012import org.pgpainless.PGPainless;
013import org.pgpainless.algorithm.AlgorithmSuite;
014import org.pgpainless.algorithm.CompressionAlgorithm;
015import org.pgpainless.algorithm.Feature;
016import org.pgpainless.algorithm.HashAlgorithm;
017import org.pgpainless.algorithm.KeyFlag;
018import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
019import org.pgpainless.key.generation.type.KeyType;
020import org.pgpainless.signature.subpackets.SelfSignatureSubpackets;
021import org.pgpainless.signature.subpackets.SignatureSubpackets;
022import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
023import org.pgpainless.util.CollectionUtils;
024
025public class KeySpecBuilder implements KeySpecBuilderInterface {
026
027    private final KeyType type;
028    private final KeyFlag[] keyFlags;
029    private final SelfSignatureSubpackets hashedSubpackets = new SignatureSubpackets();
030    private final AlgorithmSuite algorithmSuite = PGPainless.getPolicy().getKeyGenerationAlgorithmSuite();
031    private Set<CompressionAlgorithm> preferredCompressionAlgorithms = algorithmSuite.getCompressionAlgorithms();
032    private Set<HashAlgorithm> preferredHashAlgorithms = algorithmSuite.getHashAlgorithms();
033    private Set<SymmetricKeyAlgorithm> preferredSymmetricAlgorithms = algorithmSuite.getSymmetricKeyAlgorithms();
034
035    KeySpecBuilder(@Nonnull KeyType type, KeyFlag flag, KeyFlag... flags) {
036        if (flag == null) {
037            throw new IllegalArgumentException("Key MUST carry at least one key flag");
038        }
039        if (flags == null) {
040            throw new IllegalArgumentException("List of additional flags MUST NOT be null.");
041        }
042        flags = CollectionUtils.concat(flag, flags);
043        SignatureSubpacketsUtil.assureKeyCanCarryFlags(type, flags);
044        this.type = type;
045        this.keyFlags = flags;
046    }
047
048    @Override
049    public KeySpecBuilder overridePreferredCompressionAlgorithms(
050            @Nonnull CompressionAlgorithm... compressionAlgorithms) {
051        this.preferredCompressionAlgorithms = new LinkedHashSet<>(Arrays.asList(compressionAlgorithms));
052        return this;
053    }
054
055    @Override
056    public KeySpecBuilder overridePreferredHashAlgorithms(
057            @Nonnull HashAlgorithm... preferredHashAlgorithms) {
058        this.preferredHashAlgorithms = new LinkedHashSet<>(Arrays.asList(preferredHashAlgorithms));
059        return this;
060    }
061
062    @Override
063    public KeySpecBuilder overridePreferredSymmetricKeyAlgorithms(
064            @Nonnull SymmetricKeyAlgorithm... preferredSymmetricKeyAlgorithms) {
065        this.preferredSymmetricAlgorithms = new LinkedHashSet<>(Arrays.asList(preferredSymmetricKeyAlgorithms));
066        return this;
067    }
068
069
070    @Override
071    public KeySpec build() {
072        this.hashedSubpackets.setKeyFlags(keyFlags);
073        this.hashedSubpackets.setPreferredCompressionAlgorithms(preferredCompressionAlgorithms);
074        this.hashedSubpackets.setPreferredHashAlgorithms(preferredHashAlgorithms);
075        this.hashedSubpackets.setPreferredSymmetricKeyAlgorithms(preferredSymmetricAlgorithms);
076        this.hashedSubpackets.setFeatures(Feature.MODIFICATION_DETECTION);
077
078        return new KeySpec(type, (SignatureSubpackets) hashedSubpackets, false);
079    }
080}