001// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org> 002// 003// SPDX-License-Identifier: Apache-2.0 004 005package sop.cli.picocli.commands; 006 007import java.io.File; 008import java.io.FileInputStream; 009import java.io.FileNotFoundException; 010import java.io.IOException; 011import java.util.ArrayList; 012import java.util.List; 013 014import picocli.CommandLine; 015import sop.Ready; 016import sop.cli.picocli.SopCLI; 017import sop.enums.EncryptAs; 018import sop.exception.SOPGPException; 019import sop.operation.Encrypt; 020 021@CommandLine.Command(name = "encrypt", 022 description = "Encrypt a message from standard input", 023 exitCodeOnInvalidInput = 37) 024public class EncryptCmd implements Runnable { 025 026 @CommandLine.Option(names = "--no-armor", 027 description = "ASCII armor the output", 028 negatable = true) 029 boolean armor = true; 030 031 @CommandLine.Option(names = {"--as"}, 032 description = "Type of the input data. Defaults to 'binary'", 033 paramLabel = "{binary|text|mime}") 034 EncryptAs type; 035 036 @CommandLine.Option(names = "--with-password", 037 description = "Encrypt the message with a password", 038 paramLabel = "PASSWORD") 039 List<String> withPassword = new ArrayList<>(); 040 041 @CommandLine.Option(names = "--sign-with", 042 description = "Sign the output with a private key", 043 paramLabel = "KEY") 044 List<File> signWith = new ArrayList<>(); 045 046 @CommandLine.Parameters(description = "Certificates the message gets encrypted to", 047 index = "0..*", 048 paramLabel = "CERTS") 049 List<File> certs = new ArrayList<>(); 050 051 @Override 052 public void run() { 053 Encrypt encrypt = SopCLI.getSop().encrypt(); 054 if (type != null) { 055 try { 056 encrypt.mode(type); 057 } catch (SOPGPException.UnsupportedOption unsupportedOption) { 058 throw new SOPGPException.UnsupportedOption("Unsupported option '--as'.", unsupportedOption); 059 } 060 } 061 062 if (withPassword.isEmpty() && certs.isEmpty()) { 063 throw new SOPGPException.MissingArg("At least one password or cert file required for encryption."); 064 } 065 066 for (String password : withPassword) { 067 try { 068 encrypt.withPassword(password); 069 } catch (SOPGPException.UnsupportedOption unsupportedOption) { 070 throw new SOPGPException.UnsupportedOption("Unsupported option '--with-password'.", unsupportedOption); 071 } 072 } 073 074 for (File keyFile : signWith) { 075 try (FileInputStream keyIn = new FileInputStream(keyFile)) { 076 encrypt.signWith(keyIn); 077 } catch (FileNotFoundException e) { 078 throw new SOPGPException.MissingInput("Key file " + keyFile.getAbsolutePath() + " not found.", e); 079 } catch (IOException e) { 080 throw new RuntimeException(e); 081 } catch (SOPGPException.KeyIsProtected keyIsProtected) { 082 throw new SOPGPException.KeyIsProtected("Key from " + keyFile.getAbsolutePath() + " is password protected.", keyIsProtected); 083 } catch (SOPGPException.UnsupportedAsymmetricAlgo unsupportedAsymmetricAlgo) { 084 throw new SOPGPException.UnsupportedAsymmetricAlgo("Key from " + keyFile.getAbsolutePath() + " has unsupported asymmetric algorithm.", unsupportedAsymmetricAlgo); 085 } catch (SOPGPException.CertCannotSign certCannotSign) { 086 throw new RuntimeException("Key from " + keyFile.getAbsolutePath() + " cannot sign.", certCannotSign); 087 } catch (SOPGPException.BadData badData) { 088 throw new SOPGPException.BadData("Key file " + keyFile.getAbsolutePath() + " does not contain a valid OpenPGP private key.", badData); 089 } 090 } 091 092 for (File certFile : certs) { 093 try (FileInputStream certIn = new FileInputStream(certFile)) { 094 encrypt.withCert(certIn); 095 } catch (FileNotFoundException e) { 096 throw new SOPGPException.MissingInput("Certificate file " + certFile.getAbsolutePath() + " not found.", e); 097 } catch (IOException e) { 098 throw new RuntimeException(e); 099 } catch (SOPGPException.UnsupportedAsymmetricAlgo unsupportedAsymmetricAlgo) { 100 throw new SOPGPException.UnsupportedAsymmetricAlgo("Certificate from " + certFile.getAbsolutePath() + " has unsupported asymmetric algorithm.", unsupportedAsymmetricAlgo); 101 } catch (SOPGPException.CertCannotEncrypt certCannotEncrypt) { 102 throw new SOPGPException.CertCannotEncrypt("Certificate from " + certFile.getAbsolutePath() + " is not capable of encryption.", certCannotEncrypt); 103 } catch (SOPGPException.BadData badData) { 104 throw new SOPGPException.BadData("Certificate file " + certFile.getAbsolutePath() + " does not contain a valid OpenPGP certificate.", badData); 105 } 106 } 107 108 if (!armor) { 109 encrypt.noArmor(); 110 } 111 112 try { 113 Ready ready = encrypt.plaintext(System.in); 114 ready.writeTo(System.out); 115 } catch (IOException e) { 116 throw new RuntimeException(e); 117 } 118 } 119}