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}