001// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org> 002// 003// SPDX-License-Identifier: Apache-2.0 004 005package org.pgpainless.encryption_signing; 006 007import java.util.Collections; 008import java.util.Date; 009import java.util.HashSet; 010import java.util.Set; 011import javax.annotation.Nonnull; 012 013import org.bouncycastle.openpgp.PGPLiteralData; 014import org.bouncycastle.openpgp.PGPSignature; 015import org.pgpainless.algorithm.CompressionAlgorithm; 016import org.pgpainless.algorithm.StreamEncoding; 017import org.pgpainless.algorithm.SymmetricKeyAlgorithm; 018import org.pgpainless.key.SubkeyIdentifier; 019import org.pgpainless.util.MultiMap; 020 021public final class EncryptionResult { 022 023 private final SymmetricKeyAlgorithm encryptionAlgorithm; 024 private final CompressionAlgorithm compressionAlgorithm; 025 026 private final MultiMap<SubkeyIdentifier, PGPSignature> detachedSignatures; 027 private final Set<SubkeyIdentifier> recipients; 028 private final String fileName; 029 private final Date modificationDate; 030 private final StreamEncoding fileEncoding; 031 032 private EncryptionResult(SymmetricKeyAlgorithm encryptionAlgorithm, 033 CompressionAlgorithm compressionAlgorithm, 034 MultiMap<SubkeyIdentifier, PGPSignature> detachedSignatures, 035 Set<SubkeyIdentifier> recipients, 036 String fileName, 037 Date modificationDate, 038 StreamEncoding encoding) { 039 this.encryptionAlgorithm = encryptionAlgorithm; 040 this.compressionAlgorithm = compressionAlgorithm; 041 this.detachedSignatures = detachedSignatures; 042 this.recipients = Collections.unmodifiableSet(recipients); 043 this.fileName = fileName; 044 this.modificationDate = modificationDate; 045 this.fileEncoding = encoding; 046 } 047 048 /** 049 * Return the symmetric encryption algorithm used to encrypt the message. 050 * @return symmetric encryption algorithm 051 * 052 * @deprecated use {@link #getEncryptionAlgorithm()} instead. 053 */ 054 @Deprecated 055 public SymmetricKeyAlgorithm getSymmetricKeyAlgorithm() { 056 return getEncryptionAlgorithm(); 057 } 058 059 /** 060 * Return the symmetric encryption algorithm used to encrypt the message. 061 * 062 * @return symmetric encryption algorithm 063 * */ 064 public SymmetricKeyAlgorithm getEncryptionAlgorithm() { 065 return encryptionAlgorithm; 066 } 067 068 /** 069 * Return the compression algorithm that was used to compress the message before encryption/signing. 070 * 071 * @return compression algorithm 072 */ 073 public CompressionAlgorithm getCompressionAlgorithm() { 074 return compressionAlgorithm; 075 } 076 077 /** 078 * Return a {@link MultiMap} of key identifiers and detached signatures that were generated for the message. 079 * Each key of the map represents a signing key, which has one or more detached signatures associated with it. 080 * 081 * @return detached signatures 082 */ 083 public MultiMap<SubkeyIdentifier, PGPSignature> getDetachedSignatures() { 084 return detachedSignatures; 085 } 086 087 /** 088 * Return the set of recipient encryption keys. 089 * 090 * @return recipients 091 */ 092 public Set<SubkeyIdentifier> getRecipients() { 093 return recipients; 094 } 095 096 /** 097 * Return the file name of the encrypted/signed data. 098 * 099 * @return filename 100 */ 101 public String getFileName() { 102 return fileName; 103 } 104 105 /** 106 * Return the modification date of the encrypted/signed file. 107 * 108 * @return modification date 109 */ 110 public Date getModificationDate() { 111 return modificationDate; 112 } 113 114 /** 115 * Return the encoding format of the encrypted/signed data. 116 * 117 * @return encoding format 118 */ 119 public StreamEncoding getFileEncoding() { 120 return fileEncoding; 121 } 122 123 /** 124 * Return true, if the message is marked as for-your-eyes-only. 125 * This is typically done by setting the filename "_CONSOLE". 126 * 127 * @return is message for your eyes only? 128 */ 129 public boolean isForYourEyesOnly() { 130 return PGPLiteralData.CONSOLE.equals(getFileName()); 131 } 132 133 /** 134 * Create a builder for the encryption result class. 135 * 136 * @return builder 137 */ 138 public static Builder builder() { 139 return new Builder(); 140 } 141 142 public static class Builder { 143 144 private SymmetricKeyAlgorithm encryptionAlgorithm; 145 private CompressionAlgorithm compressionAlgorithm; 146 147 private final MultiMap<SubkeyIdentifier, PGPSignature> detachedSignatures = new MultiMap<>(); 148 private final Set<SubkeyIdentifier> recipients = new HashSet<>(); 149 private String fileName = ""; 150 private Date modificationDate = new Date(0L); // NOW 151 private StreamEncoding encoding = StreamEncoding.BINARY; 152 153 public Builder setEncryptionAlgorithm(SymmetricKeyAlgorithm encryptionAlgorithm) { 154 this.encryptionAlgorithm = encryptionAlgorithm; 155 return this; 156 } 157 158 public Builder setCompressionAlgorithm(CompressionAlgorithm compressionAlgorithm) { 159 this.compressionAlgorithm = compressionAlgorithm; 160 return this; 161 } 162 163 public Builder addRecipient(SubkeyIdentifier recipient) { 164 this.recipients.add(recipient); 165 return this; 166 } 167 168 public Builder addDetachedSignature(SubkeyIdentifier signingSubkeyIdentifier, PGPSignature detachedSignature) { 169 this.detachedSignatures.put(signingSubkeyIdentifier, detachedSignature); 170 return this; 171 } 172 173 public Builder setFileName(@Nonnull String fileName) { 174 this.fileName = fileName; 175 return this; 176 } 177 178 public Builder setModificationDate(@Nonnull Date modificationDate) { 179 this.modificationDate = modificationDate; 180 return this; 181 } 182 183 public Builder setFileEncoding(StreamEncoding fileEncoding) { 184 this.encoding = fileEncoding; 185 return this; 186 } 187 188 public EncryptionResult build() { 189 if (encryptionAlgorithm == null) { 190 throw new IllegalStateException("Encryption algorithm not set."); 191 } 192 if (compressionAlgorithm == null) { 193 throw new IllegalStateException("Compression algorithm not set."); 194 } 195 196 return new EncryptionResult(encryptionAlgorithm, compressionAlgorithm, detachedSignatures, recipients, 197 fileName, modificationDate, encoding); 198 } 199 } 200}