mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-12-10 06:11:08 +01:00
Prevent decryption of messages using SED instead of SEIP packets and create dedicated exceptions for MDC related errors
This commit is contained in:
parent
eb47e5caa3
commit
6ee8a9416f
9 changed files with 237 additions and 25 deletions
|
|
@ -55,6 +55,7 @@ import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
|
|||
import org.pgpainless.algorithm.CompressionAlgorithm;
|
||||
import org.pgpainless.algorithm.StreamEncoding;
|
||||
import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
||||
import org.pgpainless.exception.MessageNotIntegrityProtectedException;
|
||||
import org.pgpainless.implementation.ImplementationFactory;
|
||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||
|
|
@ -201,8 +202,11 @@ public final class DecryptionStreamFactory {
|
|||
while (encryptedDataIterator.hasNext()) {
|
||||
PGPEncryptedData encryptedData = encryptedDataIterator.next();
|
||||
|
||||
if (encryptedData instanceof PGPPBEEncryptedData) {
|
||||
if (!encryptedData.isIntegrityProtected()) {
|
||||
throw new MessageNotIntegrityProtectedException();
|
||||
}
|
||||
|
||||
if (encryptedData instanceof PGPPBEEncryptedData) {
|
||||
PGPPBEEncryptedData pbeEncryptedData = (PGPPBEEncryptedData) encryptedData;
|
||||
if (decryptionPassphrase != null) {
|
||||
PBEDataDecryptorFactory passphraseDecryptor = ImplementationFactory.getInstance()
|
||||
|
|
@ -213,7 +217,6 @@ public final class DecryptionStreamFactory {
|
|||
throw new PGPException("Data is not encrypted.");
|
||||
}
|
||||
resultBuilder.setSymmetricKeyAlgorithm(symmetricKeyAlgorithm);
|
||||
resultBuilder.setIntegrityProtected(pbeEncryptedData.isIntegrityProtected());
|
||||
|
||||
try {
|
||||
return pbeEncryptedData.getDataStream(passphraseDecryptor);
|
||||
|
|
@ -278,8 +281,6 @@ public final class DecryptionStreamFactory {
|
|||
LOGGER.log(LEVEL, "Message is encrypted using " + symmetricKeyAlgorithm);
|
||||
resultBuilder.setSymmetricKeyAlgorithm(symmetricKeyAlgorithm);
|
||||
|
||||
resultBuilder.setIntegrityProtected(encryptedSessionKey.isIntegrityProtected());
|
||||
|
||||
if (encryptedSessionKey.isIntegrityProtected()) {
|
||||
IntegrityProtectedInputStream integrityProtected =
|
||||
new IntegrityProtectedInputStream(encryptedSessionKey.getDataStream(dataDecryptor), encryptedSessionKey);
|
||||
|
|
|
|||
|
|
@ -41,14 +41,12 @@ public class OpenPgpMetadata {
|
|||
private final List<DetachedSignature> detachedSignatures;
|
||||
private final SymmetricKeyAlgorithm symmetricKeyAlgorithm;
|
||||
private final CompressionAlgorithm compressionAlgorithm;
|
||||
private final boolean integrityProtected;
|
||||
private final FileInfo fileInfo;
|
||||
|
||||
public OpenPgpMetadata(Set<Long> recipientKeyIds,
|
||||
OpenPgpV4Fingerprint decryptionFingerprint,
|
||||
SymmetricKeyAlgorithm symmetricKeyAlgorithm,
|
||||
CompressionAlgorithm algorithm,
|
||||
boolean integrityProtected,
|
||||
List<OnePassSignature> onePassSignatures,
|
||||
List<DetachedSignature> detachedSignatures,
|
||||
FileInfo fileInfo) {
|
||||
|
|
@ -57,7 +55,6 @@ public class OpenPgpMetadata {
|
|||
this.decryptionFingerprint = decryptionFingerprint;
|
||||
this.symmetricKeyAlgorithm = symmetricKeyAlgorithm;
|
||||
this.compressionAlgorithm = algorithm;
|
||||
this.integrityProtected = integrityProtected;
|
||||
this.detachedSignatures = Collections.unmodifiableList(detachedSignatures);
|
||||
this.onePassSignatures = Collections.unmodifiableList(onePassSignatures);
|
||||
this.fileInfo = fileInfo;
|
||||
|
|
@ -83,10 +80,6 @@ public class OpenPgpMetadata {
|
|||
return compressionAlgorithm;
|
||||
}
|
||||
|
||||
public boolean isIntegrityProtected() {
|
||||
return integrityProtected;
|
||||
}
|
||||
|
||||
public Set<PGPSignature> getSignatures() {
|
||||
Set<PGPSignature> signatures = new HashSet<>();
|
||||
for (DetachedSignature detachedSignature : detachedSignatures) {
|
||||
|
|
@ -245,7 +238,6 @@ public class OpenPgpMetadata {
|
|||
private final List<OnePassSignature> onePassSignatures = new ArrayList<>();
|
||||
private SymmetricKeyAlgorithm symmetricKeyAlgorithm = SymmetricKeyAlgorithm.NULL;
|
||||
private CompressionAlgorithm compressionAlgorithm = CompressionAlgorithm.UNCOMPRESSED;
|
||||
private boolean integrityProtected = false;
|
||||
private FileInfo fileInfo;
|
||||
|
||||
public Builder addRecipientKeyId(Long keyId) {
|
||||
|
|
@ -272,11 +264,6 @@ public class OpenPgpMetadata {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder setIntegrityProtected(boolean integrityProtected) {
|
||||
this.integrityProtected = integrityProtected;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void addDetachedSignature(DetachedSignature signature) {
|
||||
this.detachedSignatures.add(signature);
|
||||
}
|
||||
|
|
@ -292,7 +279,7 @@ public class OpenPgpMetadata {
|
|||
|
||||
public OpenPgpMetadata build() {
|
||||
return new OpenPgpMetadata(recipientFingerprints, decryptionFingerprint,
|
||||
symmetricKeyAlgorithm, compressionAlgorithm, integrityProtected,
|
||||
symmetricKeyAlgorithm, compressionAlgorithm,
|
||||
onePassSignatures, detachedSignatures, fileInfo);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
package org.pgpainless.exception;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
|
||||
public class MessageNotIntegrityProtectedException extends PGPException {
|
||||
|
||||
public MessageNotIntegrityProtectedException() {
|
||||
super("Message is encrypted using a 'Symmetrically Encrypted Data' (SED) packet, which enables certain types of attacks. " +
|
||||
"A 'Symmetrically Encrypted Integrity Protected' (SEIP) packet should be used instead.");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
package org.pgpainless.exception;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Exception that gets thrown when the verification of a modification detection code failed.
|
||||
*/
|
||||
public class ModificationDetectionException extends IOException {
|
||||
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ import java.io.InputStream;
|
|||
|
||||
import org.bouncycastle.openpgp.PGPEncryptedData;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.pgpainless.exception.ModificationDetectionException;
|
||||
|
||||
public class IntegrityProtectedInputStream extends InputStream {
|
||||
|
||||
|
|
@ -41,10 +42,10 @@ public class IntegrityProtectedInputStream extends InputStream {
|
|||
if (encryptedData.isIntegrityProtected()) {
|
||||
try {
|
||||
if (!encryptedData.verify()) {
|
||||
throw new PGPException("Modification Detection failed.");
|
||||
throw new ModificationDetectionException();
|
||||
}
|
||||
} catch (PGPException e) {
|
||||
throw new IOException(e);
|
||||
throw new IOException("Failed to verify integrity protection", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue