2018-06-13 17:26:48 +02:00
/ *
* Copyright 2018 Paul Schaub .
*
* Licensed under the Apache License , Version 2 . 0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
2018-07-18 18:23:06 +02:00
package org.pgpainless.decryption_verification ;
2018-06-06 18:46:41 +02:00
2021-06-15 17:35:58 +02:00
import java.io.BufferedInputStream ;
2021-07-15 16:55:13 +02:00
import java.io.EOFException ;
2018-06-06 18:46:41 +02:00
import java.io.IOException ;
import java.io.InputStream ;
2021-09-02 18:01:06 +02:00
import java.util.ArrayList ;
2018-06-06 18:46:41 +02:00
import java.util.Iterator ;
2020-08-24 14:55:06 +02:00
import java.util.List ;
2021-08-23 00:47:26 +02:00
import java.util.Set ;
2020-12-27 01:56:18 +01:00
import javax.annotation.Nonnull ;
2018-06-06 18:46:41 +02:00
2021-07-27 15:09:59 +02:00
import org.bouncycastle.bcpg.ArmoredInputStream ;
2018-06-06 18:46:41 +02:00
import org.bouncycastle.openpgp.PGPCompressedData ;
2020-12-26 19:04:27 +01:00
import org.bouncycastle.openpgp.PGPEncryptedData ;
2018-06-06 18:46:41 +02:00
import org.bouncycastle.openpgp.PGPEncryptedDataList ;
import org.bouncycastle.openpgp.PGPException ;
import org.bouncycastle.openpgp.PGPLiteralData ;
import org.bouncycastle.openpgp.PGPObjectFactory ;
import org.bouncycastle.openpgp.PGPOnePassSignature ;
import org.bouncycastle.openpgp.PGPOnePassSignatureList ;
2020-12-26 19:04:27 +01:00
import org.bouncycastle.openpgp.PGPPBEEncryptedData ;
2018-06-06 18:46:41 +02:00
import org.bouncycastle.openpgp.PGPPrivateKey ;
import org.bouncycastle.openpgp.PGPPublicKey ;
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData ;
import org.bouncycastle.openpgp.PGPPublicKeyRing ;
import org.bouncycastle.openpgp.PGPSecretKey ;
2021-01-09 16:16:17 +01:00
import org.bouncycastle.openpgp.PGPSecretKeyRing ;
2020-08-24 14:55:06 +02:00
import org.bouncycastle.openpgp.PGPSignature ;
2021-09-02 18:01:06 +02:00
import org.bouncycastle.openpgp.PGPSignatureList ;
2018-06-06 18:46:41 +02:00
import org.bouncycastle.openpgp.PGPUtil ;
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator ;
2020-12-26 19:04:27 +01:00
import org.bouncycastle.openpgp.operator.PBEDataDecryptorFactory ;
2018-06-06 18:46:41 +02:00
import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilderProvider ;
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory ;
2021-05-17 13:47:46 +02:00
import org.pgpainless.PGPainless ;
2018-07-18 18:23:06 +02:00
import org.pgpainless.algorithm.CompressionAlgorithm ;
2021-06-15 17:08:40 +02:00
import org.pgpainless.algorithm.EncryptionPurpose ;
2021-04-25 00:28:48 +02:00
import org.pgpainless.algorithm.StreamEncoding ;
2018-07-18 18:23:06 +02:00
import org.pgpainless.algorithm.SymmetricKeyAlgorithm ;
2021-04-27 12:27:25 +02:00
import org.pgpainless.exception.MessageNotIntegrityProtectedException ;
2021-05-28 23:20:25 +02:00
import org.pgpainless.exception.MissingDecryptionMethodException ;
2021-06-15 17:35:58 +02:00
import org.pgpainless.exception.MissingLiteralDataException ;
2021-05-17 13:47:46 +02:00
import org.pgpainless.exception.UnacceptableAlgorithmException ;
2021-08-29 13:35:27 +02:00
import org.pgpainless.exception.WrongConsumingMethodException ;
2020-12-27 01:56:18 +01:00
import org.pgpainless.implementation.ImplementationFactory ;
2021-04-26 13:38:12 +02:00
import org.pgpainless.key.SubkeyIdentifier ;
2021-06-15 17:08:40 +02:00
import org.pgpainless.key.info.KeyRingInfo ;
2021-09-15 16:33:03 +02:00
import org.pgpainless.key.protection.SecretKeyRingProtector ;
2021-05-14 13:18:34 +02:00
import org.pgpainless.key.protection.UnlockSecretKey ;
2021-10-03 13:47:20 +02:00
import org.pgpainless.signature.DetachedSignatureCheck ;
2021-09-02 18:01:06 +02:00
import org.pgpainless.signature.OnePassSignatureCheck ;
2021-07-31 22:24:39 +02:00
import org.pgpainless.signature.SignatureUtils ;
2021-07-27 15:09:59 +02:00
import org.pgpainless.util.CRCingArmoredInputStreamWrapper ;
2021-10-01 15:04:37 +02:00
import org.pgpainless.util.PGPUtilWrapper ;
2020-12-26 19:04:27 +01:00
import org.pgpainless.util.Passphrase ;
2021-09-15 16:33:03 +02:00
import org.pgpainless.util.Tuple ;
2021-08-23 13:29:57 +02:00
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
2018-06-06 18:46:41 +02:00
2018-07-02 21:40:59 +02:00
public final class DecryptionStreamFactory {
2018-06-06 18:46:41 +02:00
2021-08-23 13:29:57 +02:00
private static final Logger LOGGER = LoggerFactory . getLogger ( DecryptionStreamFactory . class ) ;
2021-02-19 21:37:54 +01:00
private static final int MAX_RECURSION_DEPTH = 16 ;
2018-06-19 17:14:37 +02:00
2021-06-15 17:08:40 +02:00
private final ConsumerOptions options ;
2018-07-23 16:23:23 +02:00
private final OpenPgpMetadata . Builder resultBuilder = OpenPgpMetadata . getBuilder ( ) ;
2021-09-02 18:01:06 +02:00
private final List < OnePassSignatureCheck > onePassSignatureChecks = new ArrayList < > ( ) ;
2021-10-03 13:47:20 +02:00
private final List < DetachedSignatureCheck > detachedSignatureChecks = new ArrayList < > ( ) ;
2021-09-02 18:01:06 +02:00
2021-07-15 16:55:13 +02:00
private static final PGPContentVerifierBuilderProvider verifierBuilderProvider =
ImplementationFactory . getInstance ( ) . getPGPContentVerifierBuilderProvider ( ) ;
private static final KeyFingerPrintCalculator keyFingerprintCalculator =
ImplementationFactory . getInstance ( ) . getKeyFingerprintCalculator ( ) ;
2021-09-06 15:14:13 +02:00
private IntegrityProtectedInputStream integrityProtectedEncryptedInputStream ;
2018-06-06 18:46:41 +02:00
2021-09-02 18:01:06 +02:00
2021-09-06 17:15:17 +02:00
public static DecryptionStream create ( @Nonnull InputStream inputStream ,
@Nonnull ConsumerOptions options )
throws PGPException , IOException {
DecryptionStreamFactory factory = new DecryptionStreamFactory ( options ) ;
return factory . parseOpenPGPDataAndCreateDecryptionStream ( inputStream ) ;
}
2021-06-15 17:08:40 +02:00
public DecryptionStreamFactory ( ConsumerOptions options ) {
this . options = options ;
2021-08-23 00:47:26 +02:00
initializeDetachedSignatures ( options . getDetachedSignatures ( ) ) ;
}
2021-07-27 15:09:59 +02:00
2021-08-23 00:47:26 +02:00
private void initializeDetachedSignatures ( Set < PGPSignature > signatures ) {
for ( PGPSignature signature : signatures ) {
2021-07-31 22:24:39 +02:00
long issuerKeyId = SignatureUtils . determineIssuerKeyId ( signature ) ;
PGPPublicKeyRing signingKeyRing = findSignatureVerificationKeyRing ( issuerKeyId ) ;
2021-07-27 15:09:59 +02:00
if ( signingKeyRing = = null ) {
continue ;
}
2021-07-31 22:24:39 +02:00
PGPPublicKey signingKey = signingKeyRing . getPublicKey ( issuerKeyId ) ;
2021-07-27 15:09:59 +02:00
SubkeyIdentifier signingKeyIdentifier = new SubkeyIdentifier ( signingKeyRing , signingKey . getKeyID ( ) ) ;
try {
2021-09-02 18:01:06 +02:00
signature . init ( verifierBuilderProvider , signingKey ) ;
2021-10-03 13:47:20 +02:00
DetachedSignatureCheck detachedSignature = new DetachedSignatureCheck ( signature , signingKeyRing , signingKeyIdentifier ) ;
2021-09-02 18:01:06 +02:00
detachedSignatureChecks . add ( detachedSignature ) ;
2021-07-27 15:09:59 +02:00
} catch ( PGPException e ) {
2021-08-23 13:29:57 +02:00
LOGGER . warn ( " Cannot verify detached signature made by {}. Reason: {} " , signingKeyIdentifier , e . getMessage ( ) , e ) ;
2021-07-27 15:09:59 +02:00
}
}
2018-06-06 18:46:41 +02:00
}
2021-09-06 17:15:17 +02:00
private DecryptionStream parseOpenPGPDataAndCreateDecryptionStream ( InputStream inputStream ) throws IOException , PGPException {
2021-10-01 15:04:37 +02:00
// Make sure we handle armored and non-armored data properly
2021-06-15 17:35:58 +02:00
BufferedInputStream bufferedIn = new BufferedInputStream ( inputStream ) ;
2021-10-01 15:04:37 +02:00
InputStream decoderStream = PGPUtilWrapper . getDecoderStream ( bufferedIn ) ;
2021-06-15 17:08:40 +02:00
2021-07-27 15:09:59 +02:00
decoderStream = CRCingArmoredInputStreamWrapper . possiblyWrap ( decoderStream ) ;
2021-06-15 17:08:40 +02:00
2021-08-29 13:35:27 +02:00
if ( decoderStream instanceof ArmoredInputStream ) {
ArmoredInputStream armor = ( ArmoredInputStream ) decoderStream ;
if ( armor . isClearText ( ) ) {
throw new WrongConsumingMethodException ( " Message appears to be using the Cleartext Signature Framework. " +
" Use PGPainless.verifyCleartextSignedMessage() to verify this message instead. " ) ;
}
}
2021-06-15 17:08:40 +02:00
PGPObjectFactory objectFactory = new PGPObjectFactory (
2021-07-27 15:09:59 +02:00
decoderStream , keyFingerprintCalculator ) ;
2021-06-15 17:08:40 +02:00
2021-06-15 17:35:58 +02:00
try {
// Parse OpenPGP message
2021-09-06 17:15:17 +02:00
inputStream = processPGPPackets ( objectFactory , 1 ) ;
2021-07-15 16:55:13 +02:00
} catch ( EOFException e ) {
throw e ;
2021-09-02 18:01:06 +02:00
} catch ( MissingLiteralDataException e ) {
2021-07-15 16:55:13 +02:00
// Not an OpenPGP message.
// Reset the buffered stream to parse the message as arbitrary binary data
2021-06-15 17:35:58 +02:00
// to allow for detached signature verification.
2021-08-25 12:39:31 +02:00
LOGGER . debug ( " The message appears to not be an OpenPGP message. This is probably data signed with detached signatures? " ) ;
2021-06-15 17:35:58 +02:00
bufferedIn . reset ( ) ;
2021-09-02 18:01:06 +02:00
inputStream = wrapInVerifySignatureStream ( bufferedIn ) ;
2021-07-15 16:55:13 +02:00
} catch ( IOException e ) {
2021-10-01 15:21:42 +02:00
if ( e . getMessage ( ) . contains ( " invalid armor " ) | | e . getMessage ( ) . contains ( " invalid header encountered " ) ) {
2021-07-15 16:55:13 +02:00
// We falsely assumed the data to be armored.
2021-08-25 12:39:31 +02:00
LOGGER . debug ( " The message is apparently not armored. " ) ;
2021-07-15 16:55:13 +02:00
bufferedIn . reset ( ) ;
2021-09-02 18:01:06 +02:00
inputStream = wrapInVerifySignatureStream ( bufferedIn ) ;
2021-07-15 16:55:13 +02:00
} else {
throw e ;
}
2021-06-15 17:35:58 +02:00
}
2021-09-02 18:01:06 +02:00
return new DecryptionStream ( inputStream , resultBuilder , integrityProtectedEncryptedInputStream ,
2021-07-27 15:09:59 +02:00
( decoderStream instanceof ArmoredInputStream ) ? decoderStream : null ) ;
2018-06-06 18:46:41 +02:00
}
2021-09-02 18:01:06 +02:00
private InputStream wrapInVerifySignatureStream ( InputStream bufferedIn ) {
return new SignatureInputStream . VerifySignatures (
bufferedIn , onePassSignatureChecks ,
detachedSignatureChecks , options ,
resultBuilder ) ;
}
2021-02-19 21:37:54 +01:00
private InputStream processPGPPackets ( @Nonnull PGPObjectFactory objectFactory , int depth ) throws IOException , PGPException {
if ( depth > = MAX_RECURSION_DEPTH ) {
throw new PGPException ( " Maximum recursion depth of packages exceeded. " ) ;
}
2020-01-10 17:12:13 +01:00
Object nextPgpObject ;
while ( ( nextPgpObject = objectFactory . nextObject ( ) ) ! = null ) {
if ( nextPgpObject instanceof PGPEncryptedDataList ) {
2021-02-19 21:37:54 +01:00
return processPGPEncryptedDataList ( ( PGPEncryptedDataList ) nextPgpObject , depth ) ;
2018-06-06 18:46:41 +02:00
}
2020-01-10 17:12:13 +01:00
if ( nextPgpObject instanceof PGPCompressedData ) {
2021-02-19 21:37:54 +01:00
return processPGPCompressedData ( ( PGPCompressedData ) nextPgpObject , depth ) ;
2018-06-06 18:46:41 +02:00
}
2020-01-10 17:12:13 +01:00
if ( nextPgpObject instanceof PGPOnePassSignatureList ) {
2021-02-19 21:37:54 +01:00
return processOnePassSignatureList ( objectFactory , ( PGPOnePassSignatureList ) nextPgpObject , depth ) ;
2018-06-06 18:46:41 +02:00
}
2020-01-10 17:12:13 +01:00
if ( nextPgpObject instanceof PGPLiteralData ) {
2021-08-23 13:29:57 +02:00
return processPGPLiteralData ( objectFactory , ( PGPLiteralData ) nextPgpObject , depth ) ;
2020-01-10 17:12:13 +01:00
}
}
2018-06-06 18:46:41 +02:00
2021-06-15 17:35:58 +02:00
throw new MissingLiteralDataException ( " No Literal Data Packet found " ) ;
2020-01-10 17:12:13 +01:00
}
2018-06-06 18:46:41 +02:00
2021-02-19 21:37:54 +01:00
private InputStream processPGPEncryptedDataList ( PGPEncryptedDataList pgpEncryptedDataList , int depth )
2020-01-10 17:12:13 +01:00
throws PGPException , IOException {
2021-08-23 13:29:57 +02:00
LOGGER . debug ( " Depth {}: Encountered PGPEncryptedDataList " , depth ) ;
2021-09-06 17:15:17 +02:00
InputStream decryptedDataStream = decryptSessionKey ( pgpEncryptedDataList ) ;
2021-07-15 16:55:13 +02:00
InputStream decodedDataStream = PGPUtil . getDecoderStream ( decryptedDataStream ) ;
PGPObjectFactory factory = new PGPObjectFactory ( decodedDataStream , keyFingerprintCalculator ) ;
return processPGPPackets ( factory , + + depth ) ;
2020-01-10 17:12:13 +01:00
}
2018-06-06 18:46:41 +02:00
2021-02-19 21:37:54 +01:00
private InputStream processPGPCompressedData ( PGPCompressedData pgpCompressedData , int depth )
2020-01-10 17:12:13 +01:00
throws PGPException , IOException {
CompressionAlgorithm compressionAlgorithm = CompressionAlgorithm . fromId ( pgpCompressedData . getAlgorithm ( ) ) ;
2021-08-23 13:29:57 +02:00
LOGGER . debug ( " Depth {}: Encountered PGPCompressedData: {} " , depth , compressionAlgorithm ) ;
2020-01-10 17:12:13 +01:00
resultBuilder . setCompressionAlgorithm ( compressionAlgorithm ) ;
2021-07-15 16:55:13 +02:00
InputStream inflatedDataStream = pgpCompressedData . getDataStream ( ) ;
InputStream decodedDataStream = PGPUtil . getDecoderStream ( inflatedDataStream ) ;
PGPObjectFactory objectFactory = new PGPObjectFactory ( decodedDataStream , keyFingerprintCalculator ) ;
2020-01-10 17:12:13 +01:00
2021-02-19 21:37:54 +01:00
return processPGPPackets ( objectFactory , + + depth ) ;
2020-01-10 17:12:13 +01:00
}
2021-02-19 21:37:54 +01:00
private InputStream processOnePassSignatureList ( @Nonnull PGPObjectFactory objectFactory , PGPOnePassSignatureList onePassSignatures , int depth )
2020-01-10 17:12:13 +01:00
throws PGPException , IOException {
2021-08-23 13:29:57 +02:00
LOGGER . debug ( " Depth {}: Encountered PGPOnePassSignatureList of size {} " , depth , onePassSignatures . size ( ) ) ;
2020-01-10 17:12:13 +01:00
initOnePassSignatures ( onePassSignatures ) ;
2021-02-19 21:37:54 +01:00
return processPGPPackets ( objectFactory , + + depth ) ;
2020-01-10 17:12:13 +01:00
}
2021-09-02 18:01:06 +02:00
private InputStream processPGPLiteralData ( @Nonnull PGPObjectFactory objectFactory , PGPLiteralData pgpLiteralData , int depth ) throws IOException {
2021-08-23 13:29:57 +02:00
LOGGER . debug ( " Depth {}: Found PGPLiteralData " , depth ) ;
2020-01-10 17:12:13 +01:00
InputStream literalDataInputStream = pgpLiteralData . getInputStream ( ) ;
2021-07-15 16:55:13 +02:00
resultBuilder . setFileName ( pgpLiteralData . getFileName ( ) )
. setModificationDate ( pgpLiteralData . getModificationTime ( ) )
. setFileEncoding ( StreamEncoding . fromCode ( pgpLiteralData . getFormat ( ) ) ) ;
2020-01-10 17:12:13 +01:00
2021-09-02 18:01:06 +02:00
if ( onePassSignatureChecks . isEmpty ( ) ) {
2021-08-23 13:29:57 +02:00
LOGGER . debug ( " No OnePassSignatures found -> We are done " ) ;
2020-01-10 17:12:13 +01:00
return literalDataInputStream ;
2018-06-06 18:46:41 +02:00
}
2021-10-03 14:12:26 +02:00
// Parse signatures from message
2021-09-02 18:01:06 +02:00
PGPSignatureList signatures = parseSignatures ( objectFactory ) ;
List < PGPSignature > signatureList = SignatureUtils . toList ( signatures ) ;
2021-10-03 14:12:26 +02:00
// Set signatures as comparison sigs in OPS checks
2021-09-02 18:01:06 +02:00
for ( int i = 0 ; i < onePassSignatureChecks . size ( ) ; i + + ) {
2021-10-03 14:12:26 +02:00
int reversedIndex = onePassSignatureChecks . size ( ) - i - 1 ;
onePassSignatureChecks . get ( i ) . setSignature ( signatureList . get ( reversedIndex ) ) ;
2021-09-02 18:01:06 +02:00
}
return new SignatureInputStream . VerifySignatures ( literalDataInputStream ,
onePassSignatureChecks , detachedSignatureChecks , options , resultBuilder ) {
} ;
}
private PGPSignatureList parseSignatures ( PGPObjectFactory objectFactory ) throws IOException {
PGPSignatureList signatureList = null ;
Object pgpObject = objectFactory . nextObject ( ) ;
while ( pgpObject ! = null & & signatureList = = null ) {
if ( pgpObject instanceof PGPSignatureList ) {
signatureList = ( PGPSignatureList ) pgpObject ;
} else {
pgpObject = objectFactory . nextObject ( ) ;
}
}
if ( signatureList = = null | | signatureList . isEmpty ( ) ) {
throw new IOException ( " Verification failed - No Signatures found " ) ;
}
return signatureList ;
2018-06-06 18:46:41 +02:00
}
2021-09-06 17:15:17 +02:00
private InputStream decryptSessionKey ( @Nonnull PGPEncryptedDataList encryptedDataList )
2018-06-06 18:46:41 +02:00
throws PGPException {
2020-12-26 19:04:27 +01:00
Iterator < PGPEncryptedData > encryptedDataIterator = encryptedDataList . getEncryptedDataObjects ( ) ;
2020-01-10 17:12:13 +01:00
if ( ! encryptedDataIterator . hasNext ( ) ) {
2018-06-19 17:14:37 +02:00
throw new PGPException ( " Decryption failed - EncryptedDataList has no items " ) ;
2018-06-06 18:46:41 +02:00
}
PGPPrivateKey decryptionKey = null ;
PGPPublicKeyEncryptedData encryptedSessionKey = null ;
2021-09-15 16:33:03 +02:00
List < PGPPBEEncryptedData > passphraseProtected = new ArrayList < > ( ) ;
List < PGPPublicKeyEncryptedData > publicKeyProtected = new ArrayList < > ( ) ;
List < Tuple < SubkeyIdentifier , PGPPublicKeyEncryptedData > > postponedDueToMissingPassphrase = new ArrayList < > ( ) ;
// Sort PKESK and SKESK packets
2020-01-10 17:12:13 +01:00
while ( encryptedDataIterator . hasNext ( ) ) {
2020-12-26 19:04:27 +01:00
PGPEncryptedData encryptedData = encryptedDataIterator . next ( ) ;
2021-10-01 13:54:51 +02:00
if ( ! encryptedData . isIntegrityProtected ( ) & & ! options . isIgnoreMDCErrors ( ) ) {
2021-04-27 12:27:25 +02:00
throw new MessageNotIntegrityProtectedException ( ) ;
}
2021-06-15 17:08:40 +02:00
2021-09-15 16:33:03 +02:00
// SKESK
2021-04-27 12:27:25 +02:00
if ( encryptedData instanceof PGPPBEEncryptedData ) {
2021-09-15 16:33:03 +02:00
passphraseProtected . add ( ( PGPPBEEncryptedData ) encryptedData ) ;
}
// PKESK
else if ( encryptedData instanceof PGPPublicKeyEncryptedData ) {
publicKeyProtected . add ( ( PGPPublicKeyEncryptedData ) encryptedData ) ;
}
}
// Try decryption with passphrases first
for ( PGPPBEEncryptedData pbeEncryptedData : passphraseProtected ) {
for ( Passphrase passphrase : options . getDecryptionPassphrases ( ) ) {
PBEDataDecryptorFactory passphraseDecryptor = ImplementationFactory . getInstance ( )
. getPBEDataDecryptorFactory ( passphrase ) ;
try {
InputStream decryptedDataStream = pbeEncryptedData . getDataStream ( passphraseDecryptor ) ;
SymmetricKeyAlgorithm symmetricKeyAlgorithm = SymmetricKeyAlgorithm . fromId (
pbeEncryptedData . getSymmetricAlgorithm ( passphraseDecryptor ) ) ;
throwIfAlgorithmIsRejected ( symmetricKeyAlgorithm ) ;
resultBuilder . setSymmetricKeyAlgorithm ( symmetricKeyAlgorithm ) ;
2021-10-01 13:54:51 +02:00
integrityProtectedEncryptedInputStream = new IntegrityProtectedInputStream ( decryptedDataStream , pbeEncryptedData , options ) ;
2021-09-15 16:33:03 +02:00
return integrityProtectedEncryptedInputStream ;
} catch ( PGPException e ) {
LOGGER . debug ( " Probable passphrase mismatch, skip PBE encrypted data block " , e ) ;
2020-12-26 19:04:27 +01:00
}
2021-05-14 13:18:34 +02:00
}
2021-09-15 16:33:03 +02:00
}
2021-06-15 17:08:40 +02:00
2021-09-15 16:33:03 +02:00
// Then try decryption with public key encryption
for ( PGPPublicKeyEncryptedData publicKeyEncryptedData : publicKeyProtected ) {
PGPPrivateKey privateKey = null ;
if ( options . getDecryptionKeys ( ) . isEmpty ( ) ) {
break ;
}
2021-06-15 17:08:40 +02:00
2021-09-15 16:33:03 +02:00
long keyId = publicKeyEncryptedData . getKeyID ( ) ;
// Wildcard KeyID
if ( keyId = = 0L ) {
LOGGER . debug ( " Hidden recipient detected. Try to decrypt with all available secret keys. " ) ;
for ( PGPSecretKeyRing secretKeys : options . getDecryptionKeys ( ) ) {
if ( privateKey ! = null ) {
break ;
}
KeyRingInfo info = new KeyRingInfo ( secretKeys ) ;
List < PGPPublicKey > encryptionSubkeys = info . getEncryptionSubkeys ( EncryptionPurpose . STORAGE_AND_COMMUNICATIONS ) ;
for ( PGPPublicKey pubkey : encryptionSubkeys ) {
PGPSecretKey secretKey = secretKeys . getSecretKey ( pubkey . getKeyID ( ) ) ;
// Skip missing secret key
if ( secretKey = = null ) {
continue ;
2021-01-09 16:16:17 +01:00
}
2021-09-15 16:33:03 +02:00
privateKey = tryPublicKeyDecryption ( secretKeys , secretKey , publicKeyEncryptedData , postponedDueToMissingPassphrase , true ) ;
2020-12-26 19:04:27 +01:00
}
}
2018-06-06 18:46:41 +02:00
}
2021-09-15 16:33:03 +02:00
// Non-wildcard key-id
else {
LOGGER . debug ( " PGPEncryptedData is encrypted for key {} " , Long . toHexString ( keyId ) ) ;
resultBuilder . addRecipientKeyId ( keyId ) ;
PGPSecretKeyRing secretKeys = findDecryptionKeyRing ( keyId ) ;
if ( secretKeys = = null ) {
LOGGER . debug ( " Missing certificate of {}. Skip. " , Long . toHexString ( keyId ) ) ;
continue ;
}
PGPSecretKey secretKey = secretKeys . getSecretKey ( keyId ) ;
privateKey = tryPublicKeyDecryption ( secretKeys , secretKey , publicKeyEncryptedData , postponedDueToMissingPassphrase , true ) ;
}
if ( privateKey = = null ) {
continue ;
}
decryptionKey = privateKey ;
encryptedSessionKey = publicKeyEncryptedData ;
}
// Try postponed keys with missing passphrases (will cause missing passphrase callbacks to fire)
if ( encryptedSessionKey = = null ) {
for ( Tuple < SubkeyIdentifier , PGPPublicKeyEncryptedData > missingPassphrases : postponedDueToMissingPassphrase ) {
SubkeyIdentifier keyId = missingPassphrases . getA ( ) ;
PGPPublicKeyEncryptedData publicKeyEncryptedData = missingPassphrases . getB ( ) ;
PGPSecretKeyRing secretKeys = findDecryptionKeyRing ( keyId . getKeyId ( ) ) ;
PGPSecretKey secretKey = secretKeys . getSecretKey ( keyId . getSubkeyId ( ) ) ;
PGPPrivateKey privateKey = tryPublicKeyDecryption ( secretKeys , secretKey , publicKeyEncryptedData , postponedDueToMissingPassphrase , false ) ;
if ( privateKey = = null ) {
continue ;
}
decryptionKey = privateKey ;
encryptedSessionKey = publicKeyEncryptedData ;
break ;
}
2018-06-06 18:46:41 +02:00
}
2021-09-15 16:33:03 +02:00
2021-06-15 17:08:40 +02:00
return decryptWith ( encryptedSessionKey , decryptionKey ) ;
}
2018-06-06 18:46:41 +02:00
2021-09-15 16:33:03 +02:00
/ * *
* Try decryption of the provided public - key - encrypted - data using the given secret key .
* If the secret key is encrypted and the secret key protector does not have a passphrase available and the boolean
* postponeIfMissingPassphrase is true , data decryption is postponed by pushing a tuple of the encrypted data decryption key
* identifier to the postponed list .
*
* This method only returns a non - null private key , if the private key is able to decrypt the message successfully .
*
* @param secretKeys secret key ring
* @param secretKey secret key
* @param publicKeyEncryptedData encrypted data which is tried to decrypt using the secret key
* @param postponed list of postponed decryptions due to missing secret key passphrases
* @param postponeIfMissingPassphrase flag to specify whether missing secret key passphrases should result in postponed decryption
* @return private key if decryption is successful , null if decryption is unsuccessful or postponed
*
* @throws PGPException in case of an OpenPGP error
* /
private PGPPrivateKey tryPublicKeyDecryption (
PGPSecretKeyRing secretKeys ,
PGPSecretKey secretKey ,
PGPPublicKeyEncryptedData publicKeyEncryptedData ,
List < Tuple < SubkeyIdentifier , PGPPublicKeyEncryptedData > > postponed ,
boolean postponeIfMissingPassphrase ) throws PGPException {
SecretKeyRingProtector protector = options . getSecretKeyProtector ( secretKeys ) ;
if ( postponeIfMissingPassphrase & & ! protector . hasPassphraseFor ( secretKey . getKeyID ( ) ) ) {
// Postpone decryption with key with missing passphrase
SubkeyIdentifier identifier = new SubkeyIdentifier ( secretKeys , secretKey . getKeyID ( ) ) ;
postponed . add ( new Tuple < > ( identifier , publicKeyEncryptedData ) ) ;
return null ;
}
PGPPrivateKey privateKey = UnlockSecretKey . unlockSecretKey (
secretKey , protector . getDecryptor ( secretKey . getKeyID ( ) ) ) ;
// test if we have the right private key
PublicKeyDataDecryptorFactory decryptorFactory = ImplementationFactory . getInstance ( )
. getPublicKeyDataDecryptorFactory ( privateKey ) ;
try {
publicKeyEncryptedData . getSymmetricAlgorithm ( decryptorFactory ) ; // will only succeed if we have the right secret key
LOGGER . debug ( " Found correct decryption key {}. " , Long . toHexString ( secretKey . getKeyID ( ) ) ) ;
resultBuilder . setDecryptionKey ( new SubkeyIdentifier ( secretKeys , privateKey . getKeyID ( ) ) ) ;
return privateKey ;
} catch ( PGPException | ClassCastException e ) {
return null ;
}
}
2021-06-15 17:08:40 +02:00
private InputStream decryptWith ( PGPPublicKeyEncryptedData encryptedSessionKey , PGPPrivateKey decryptionKey )
throws PGPException {
2021-09-15 16:33:03 +02:00
if ( decryptionKey = = null | | encryptedSessionKey = = null ) {
2021-05-28 23:20:25 +02:00
throw new MissingDecryptionMethodException ( " Decryption failed - No suitable decryption key or passphrase found " ) ;
2018-06-06 18:46:41 +02:00
}
2021-02-17 21:04:05 +01:00
PublicKeyDataDecryptorFactory dataDecryptor = ImplementationFactory . getInstance ( )
2020-12-27 01:56:18 +01:00
. getPublicKeyDataDecryptorFactory ( decryptionKey ) ;
2020-12-26 19:04:27 +01:00
2018-06-19 17:14:37 +02:00
SymmetricKeyAlgorithm symmetricKeyAlgorithm = SymmetricKeyAlgorithm
2021-02-17 21:04:05 +01:00
. fromId ( encryptedSessionKey . getSymmetricAlgorithm ( dataDecryptor ) ) ;
2021-02-17 20:07:54 +01:00
if ( symmetricKeyAlgorithm = = SymmetricKeyAlgorithm . NULL ) {
2021-08-23 13:29:57 +02:00
LOGGER . debug ( " Message is unencrypted " ) ;
2021-05-17 13:47:46 +02:00
} else {
2021-08-23 13:29:57 +02:00
LOGGER . debug ( " Message is encrypted using {} " , symmetricKeyAlgorithm ) ;
2021-02-17 20:07:54 +01:00
}
2021-05-17 13:47:46 +02:00
throwIfAlgorithmIsRejected ( symmetricKeyAlgorithm ) ;
2018-06-19 17:14:37 +02:00
resultBuilder . setSymmetricKeyAlgorithm ( symmetricKeyAlgorithm ) ;
2021-10-01 13:54:51 +02:00
integrityProtectedEncryptedInputStream = new IntegrityProtectedInputStream ( encryptedSessionKey . getDataStream ( dataDecryptor ) , encryptedSessionKey , options ) ;
2021-09-06 15:14:13 +02:00
return integrityProtectedEncryptedInputStream ;
2021-05-17 13:47:46 +02:00
}
private void throwIfAlgorithmIsRejected ( SymmetricKeyAlgorithm algorithm ) throws UnacceptableAlgorithmException {
2021-09-13 19:20:19 +02:00
if ( ! PGPainless . getPolicy ( ) . getSymmetricKeyDecryptionAlgorithmPolicy ( ) . isAcceptable ( algorithm ) ) {
2021-05-17 13:47:46 +02:00
throw new UnacceptableAlgorithmException ( " Data is "
+ ( algorithm = = SymmetricKeyAlgorithm . NULL ? " unencrypted " : " encrypted with symmetric algorithm " + algorithm ) + " which is not acceptable as per PGPainless' policy. \ n " +
" To mark this algorithm as acceptable, use PGPainless.getPolicy().setSymmetricKeyDecryptionAlgorithmPolicy(). " ) ;
2021-02-17 21:04:05 +01:00
}
2018-06-06 18:46:41 +02:00
}
2018-07-31 20:09:16 +02:00
private void initOnePassSignatures ( @Nonnull PGPOnePassSignatureList onePassSignatureList ) throws PGPException {
2018-06-06 18:46:41 +02:00
Iterator < PGPOnePassSignature > iterator = onePassSignatureList . iterator ( ) ;
if ( ! iterator . hasNext ( ) ) {
2018-06-19 17:14:37 +02:00
throw new PGPException ( " Verification failed - No OnePassSignatures found " ) ;
2018-06-06 18:46:41 +02:00
}
2020-01-10 15:12:04 +01:00
processOnePassSignatures ( iterator ) ;
}
private void processOnePassSignatures ( Iterator < PGPOnePassSignature > signatures ) throws PGPException {
while ( signatures . hasNext ( ) ) {
PGPOnePassSignature signature = signatures . next ( ) ;
2020-01-10 17:12:13 +01:00
processOnePassSignature ( signature ) ;
}
}
2018-06-06 18:46:41 +02:00
2020-01-10 17:12:13 +01:00
private void processOnePassSignature ( PGPOnePassSignature signature ) throws PGPException {
final long keyId = signature . getKeyID ( ) ;
2018-07-02 20:46:27 +02:00
2021-09-02 18:01:06 +02:00
LOGGER . debug ( " Encountered OnePassSignature from {} " , Long . toHexString ( keyId ) ) ;
2018-07-02 20:46:27 +02:00
2020-01-10 17:12:13 +01:00
// Find public key
2021-04-26 13:38:12 +02:00
PGPPublicKeyRing verificationKeyRing = findSignatureVerificationKeyRing ( keyId ) ;
if ( verificationKeyRing = = null ) {
2021-08-23 13:29:57 +02:00
LOGGER . debug ( " Missing verification key from {} " , Long . toHexString ( keyId ) ) ;
2020-01-10 17:12:13 +01:00
return ;
}
2021-04-26 13:38:12 +02:00
PGPPublicKey verificationKey = verificationKeyRing . getPublicKey ( keyId ) ;
2018-07-02 20:46:27 +02:00
2020-01-10 17:12:13 +01:00
signature . init ( verifierBuilderProvider , verificationKey ) ;
2021-09-02 18:01:06 +02:00
OnePassSignatureCheck onePassSignature = new OnePassSignatureCheck ( signature , verificationKeyRing ) ;
onePassSignatureChecks . add ( onePassSignature ) ;
2020-01-10 17:12:13 +01:00
}
2018-07-02 20:46:27 +02:00
2021-06-15 17:08:40 +02:00
private PGPSecretKeyRing findDecryptionKeyRing ( long keyId ) {
for ( PGPSecretKeyRing key : options . getDecryptionKeys ( ) ) {
if ( key . getSecretKey ( keyId ) ! = null ) {
return key ;
}
}
return null ;
}
2021-04-26 13:38:12 +02:00
private PGPPublicKeyRing findSignatureVerificationKeyRing ( long keyId ) {
PGPPublicKeyRing verificationKeyRing = null ;
2021-06-15 17:08:40 +02:00
for ( PGPPublicKeyRing publicKeyRing : options . getCertificates ( ) ) {
2021-04-26 13:38:12 +02:00
PGPPublicKey verificationKey = publicKeyRing . getPublicKey ( keyId ) ;
2020-01-10 17:12:13 +01:00
if ( verificationKey ! = null ) {
2021-08-23 13:29:57 +02:00
LOGGER . debug ( " Found public key {} for signature verification " , Long . toHexString ( keyId ) ) ;
2021-04-26 13:38:12 +02:00
verificationKeyRing = publicKeyRing ;
2020-01-10 17:12:13 +01:00
break ;
2018-06-06 18:46:41 +02:00
}
2020-01-10 17:12:13 +01:00
}
2018-07-02 20:46:27 +02:00
2021-06-15 17:08:40 +02:00
if ( verificationKeyRing = = null & & options . getMissingCertificateCallback ( ) ! = null ) {
verificationKeyRing = options . getMissingCertificateCallback ( ) . onMissingPublicKeyEncountered ( keyId ) ;
2021-05-29 12:19:12 +02:00
}
2021-04-26 13:38:12 +02:00
return verificationKeyRing ;
2018-06-06 18:46:41 +02:00
}
}