001// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
002//
003// SPDX-License-Identifier: Apache-2.0
004
005package org.pgpainless.sop;
006
007import java.io.IOException;
008import java.io.OutputStream;
009import java.security.InvalidAlgorithmParameterException;
010import java.security.NoSuchAlgorithmException;
011import java.util.Iterator;
012import java.util.LinkedHashSet;
013import java.util.Set;
014
015import org.bouncycastle.bcpg.ArmoredOutputStream;
016import org.bouncycastle.openpgp.PGPException;
017import org.bouncycastle.openpgp.PGPSecretKeyRing;
018import org.pgpainless.PGPainless;
019import org.pgpainless.key.modification.secretkeyring.SecretKeyRingEditorInterface;
020import org.pgpainless.key.protection.SecretKeyRingProtector;
021import org.pgpainless.util.ArmorUtils;
022import sop.Ready;
023import sop.exception.SOPGPException;
024import sop.operation.GenerateKey;
025
026public class GenerateKeyImpl implements GenerateKey {
027
028    private boolean armor = true;
029    private final Set<String> userIds = new LinkedHashSet<>();
030
031    @Override
032    public GenerateKey noArmor() {
033        this.armor = false;
034        return this;
035    }
036
037    @Override
038    public GenerateKey userId(String userId) {
039        this.userIds.add(userId);
040        return this;
041    }
042
043    @Override
044    public Ready generate() throws SOPGPException.MissingArg, SOPGPException.UnsupportedAsymmetricAlgo {
045        Iterator<String> userIdIterator = userIds.iterator();
046        if (!userIdIterator.hasNext()) {
047            throw new SOPGPException.MissingArg("Missing user-id.");
048        }
049
050        PGPSecretKeyRing key;
051        try {
052             key = PGPainless.generateKeyRing()
053                    .modernKeyRing(userIdIterator.next(), null);
054
055            if (userIdIterator.hasNext()) {
056                SecretKeyRingEditorInterface editor = PGPainless.modifyKeyRing(key);
057
058                while (userIdIterator.hasNext()) {
059                    editor.addUserId(userIdIterator.next(), SecretKeyRingProtector.unprotectedKeys());
060                }
061
062                key = editor.done();
063            }
064
065            PGPSecretKeyRing finalKey = key;
066            return new Ready() {
067                @Override
068                public void writeTo(OutputStream outputStream) throws IOException {
069                    if (armor) {
070                        ArmoredOutputStream armoredOutputStream = ArmorUtils.toAsciiArmoredStream(finalKey, outputStream);
071                        finalKey.encode(armoredOutputStream);
072                        armoredOutputStream.close();
073                    } else {
074                        finalKey.encode(outputStream);
075                    }
076                }
077            };
078        } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException e) {
079            throw new SOPGPException.UnsupportedAsymmetricAlgo("Unsupported asymmetric algorithm.", e);
080        } catch (PGPException e) {
081            throw new RuntimeException(e);
082        }
083    }
084}