1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-11-27 06:42:05 +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:
Paul Schaub 2021-04-27 12:27:25 +02:00
parent eb47e5caa3
commit 6ee8a9416f
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
9 changed files with 237 additions and 25 deletions

View file

@ -55,6 +55,7 @@ import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
import org.pgpainless.algorithm.CompressionAlgorithm; import org.pgpainless.algorithm.CompressionAlgorithm;
import org.pgpainless.algorithm.StreamEncoding; import org.pgpainless.algorithm.StreamEncoding;
import org.pgpainless.algorithm.SymmetricKeyAlgorithm; import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
import org.pgpainless.exception.MessageNotIntegrityProtectedException;
import org.pgpainless.implementation.ImplementationFactory; import org.pgpainless.implementation.ImplementationFactory;
import org.pgpainless.key.OpenPgpV4Fingerprint; import org.pgpainless.key.OpenPgpV4Fingerprint;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
@ -201,8 +202,11 @@ public final class DecryptionStreamFactory {
while (encryptedDataIterator.hasNext()) { while (encryptedDataIterator.hasNext()) {
PGPEncryptedData encryptedData = encryptedDataIterator.next(); PGPEncryptedData encryptedData = encryptedDataIterator.next();
if (encryptedData instanceof PGPPBEEncryptedData) { if (!encryptedData.isIntegrityProtected()) {
throw new MessageNotIntegrityProtectedException();
}
if (encryptedData instanceof PGPPBEEncryptedData) {
PGPPBEEncryptedData pbeEncryptedData = (PGPPBEEncryptedData) encryptedData; PGPPBEEncryptedData pbeEncryptedData = (PGPPBEEncryptedData) encryptedData;
if (decryptionPassphrase != null) { if (decryptionPassphrase != null) {
PBEDataDecryptorFactory passphraseDecryptor = ImplementationFactory.getInstance() PBEDataDecryptorFactory passphraseDecryptor = ImplementationFactory.getInstance()
@ -213,7 +217,6 @@ public final class DecryptionStreamFactory {
throw new PGPException("Data is not encrypted."); throw new PGPException("Data is not encrypted.");
} }
resultBuilder.setSymmetricKeyAlgorithm(symmetricKeyAlgorithm); resultBuilder.setSymmetricKeyAlgorithm(symmetricKeyAlgorithm);
resultBuilder.setIntegrityProtected(pbeEncryptedData.isIntegrityProtected());
try { try {
return pbeEncryptedData.getDataStream(passphraseDecryptor); return pbeEncryptedData.getDataStream(passphraseDecryptor);
@ -278,8 +281,6 @@ public final class DecryptionStreamFactory {
LOGGER.log(LEVEL, "Message is encrypted using " + symmetricKeyAlgorithm); LOGGER.log(LEVEL, "Message is encrypted using " + symmetricKeyAlgorithm);
resultBuilder.setSymmetricKeyAlgorithm(symmetricKeyAlgorithm); resultBuilder.setSymmetricKeyAlgorithm(symmetricKeyAlgorithm);
resultBuilder.setIntegrityProtected(encryptedSessionKey.isIntegrityProtected());
if (encryptedSessionKey.isIntegrityProtected()) { if (encryptedSessionKey.isIntegrityProtected()) {
IntegrityProtectedInputStream integrityProtected = IntegrityProtectedInputStream integrityProtected =
new IntegrityProtectedInputStream(encryptedSessionKey.getDataStream(dataDecryptor), encryptedSessionKey); new IntegrityProtectedInputStream(encryptedSessionKey.getDataStream(dataDecryptor), encryptedSessionKey);

View file

@ -41,14 +41,12 @@ public class OpenPgpMetadata {
private final List<DetachedSignature> detachedSignatures; private final List<DetachedSignature> detachedSignatures;
private final SymmetricKeyAlgorithm symmetricKeyAlgorithm; private final SymmetricKeyAlgorithm symmetricKeyAlgorithm;
private final CompressionAlgorithm compressionAlgorithm; private final CompressionAlgorithm compressionAlgorithm;
private final boolean integrityProtected;
private final FileInfo fileInfo; private final FileInfo fileInfo;
public OpenPgpMetadata(Set<Long> recipientKeyIds, public OpenPgpMetadata(Set<Long> recipientKeyIds,
OpenPgpV4Fingerprint decryptionFingerprint, OpenPgpV4Fingerprint decryptionFingerprint,
SymmetricKeyAlgorithm symmetricKeyAlgorithm, SymmetricKeyAlgorithm symmetricKeyAlgorithm,
CompressionAlgorithm algorithm, CompressionAlgorithm algorithm,
boolean integrityProtected,
List<OnePassSignature> onePassSignatures, List<OnePassSignature> onePassSignatures,
List<DetachedSignature> detachedSignatures, List<DetachedSignature> detachedSignatures,
FileInfo fileInfo) { FileInfo fileInfo) {
@ -57,7 +55,6 @@ public class OpenPgpMetadata {
this.decryptionFingerprint = decryptionFingerprint; this.decryptionFingerprint = decryptionFingerprint;
this.symmetricKeyAlgorithm = symmetricKeyAlgorithm; this.symmetricKeyAlgorithm = symmetricKeyAlgorithm;
this.compressionAlgorithm = algorithm; this.compressionAlgorithm = algorithm;
this.integrityProtected = integrityProtected;
this.detachedSignatures = Collections.unmodifiableList(detachedSignatures); this.detachedSignatures = Collections.unmodifiableList(detachedSignatures);
this.onePassSignatures = Collections.unmodifiableList(onePassSignatures); this.onePassSignatures = Collections.unmodifiableList(onePassSignatures);
this.fileInfo = fileInfo; this.fileInfo = fileInfo;
@ -83,10 +80,6 @@ public class OpenPgpMetadata {
return compressionAlgorithm; return compressionAlgorithm;
} }
public boolean isIntegrityProtected() {
return integrityProtected;
}
public Set<PGPSignature> getSignatures() { public Set<PGPSignature> getSignatures() {
Set<PGPSignature> signatures = new HashSet<>(); Set<PGPSignature> signatures = new HashSet<>();
for (DetachedSignature detachedSignature : detachedSignatures) { for (DetachedSignature detachedSignature : detachedSignatures) {
@ -245,7 +238,6 @@ public class OpenPgpMetadata {
private final List<OnePassSignature> onePassSignatures = new ArrayList<>(); private final List<OnePassSignature> onePassSignatures = new ArrayList<>();
private SymmetricKeyAlgorithm symmetricKeyAlgorithm = SymmetricKeyAlgorithm.NULL; private SymmetricKeyAlgorithm symmetricKeyAlgorithm = SymmetricKeyAlgorithm.NULL;
private CompressionAlgorithm compressionAlgorithm = CompressionAlgorithm.UNCOMPRESSED; private CompressionAlgorithm compressionAlgorithm = CompressionAlgorithm.UNCOMPRESSED;
private boolean integrityProtected = false;
private FileInfo fileInfo; private FileInfo fileInfo;
public Builder addRecipientKeyId(Long keyId) { public Builder addRecipientKeyId(Long keyId) {
@ -272,11 +264,6 @@ public class OpenPgpMetadata {
return this; return this;
} }
public Builder setIntegrityProtected(boolean integrityProtected) {
this.integrityProtected = integrityProtected;
return this;
}
public void addDetachedSignature(DetachedSignature signature) { public void addDetachedSignature(DetachedSignature signature) {
this.detachedSignatures.add(signature); this.detachedSignatures.add(signature);
} }
@ -292,7 +279,7 @@ public class OpenPgpMetadata {
public OpenPgpMetadata build() { public OpenPgpMetadata build() {
return new OpenPgpMetadata(recipientFingerprints, decryptionFingerprint, return new OpenPgpMetadata(recipientFingerprints, decryptionFingerprint,
symmetricKeyAlgorithm, compressionAlgorithm, integrityProtected, symmetricKeyAlgorithm, compressionAlgorithm,
onePassSignatures, detachedSignatures, fileInfo); onePassSignatures, detachedSignatures, fileInfo);
} }
} }

View file

@ -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.");
}
}

View file

@ -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 {
}

View file

@ -20,6 +20,7 @@ import java.io.InputStream;
import org.bouncycastle.openpgp.PGPEncryptedData; import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.pgpainless.exception.ModificationDetectionException;
public class IntegrityProtectedInputStream extends InputStream { public class IntegrityProtectedInputStream extends InputStream {
@ -41,10 +42,10 @@ public class IntegrityProtectedInputStream extends InputStream {
if (encryptedData.isIntegrityProtected()) { if (encryptedData.isIntegrityProtected()) {
try { try {
if (!encryptedData.verify()) { if (!encryptedData.verify()) {
throw new PGPException("Modification Detection failed."); throw new ModificationDetectionException();
} }
} catch (PGPException e) { } catch (PGPException e) {
throw new IOException(e); throw new IOException("Failed to verify integrity protection", e);
} }
} }
} }

View file

@ -78,7 +78,6 @@ public class DecryptAndVerifyMessageTest {
assertArrayEquals(expected, actual); assertArrayEquals(expected, actual);
assertTrue(metadata.isIntegrityProtected());
assertTrue(metadata.isEncrypted()); assertTrue(metadata.isEncrypted());
assertTrue(metadata.isSigned()); assertTrue(metadata.isSigned());
assertTrue(metadata.isVerified()); assertTrue(metadata.isVerified());

View file

@ -29,11 +29,15 @@ import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.util.io.Streams; import org.bouncycastle.util.io.Streams;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.exception.MessageNotIntegrityProtectedException;
import org.pgpainless.exception.ModificationDetectionException;
import org.pgpainless.implementation.ImplementationFactory; import org.pgpainless.implementation.ImplementationFactory;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.util.Passphrase;
public class ModificationDetectionTests { public class ModificationDetectionTests {
@ -120,6 +124,12 @@ public class ModificationDetectionTests {
"=miES\n" + "=miES\n" +
"-----END PGP PRIVATE KEY BLOCK-----\n"; "-----END PGP PRIVATE KEY BLOCK-----\n";
/**
* Messages containing a missing MDC shall fail to decrypt.
* @param implementationFactory
* @throws IOException
* @throws PGPException
*/
@ParameterizedTest @ParameterizedTest
@MethodSource("org.pgpainless.util.TestUtil#provideImplementationFactories") @MethodSource("org.pgpainless.util.TestUtil#provideImplementationFactories")
public void testMissingMDC(ImplementationFactory implementationFactory) throws IOException, PGPException { public void testMissingMDC(ImplementationFactory implementationFactory) throws IOException, PGPException {
@ -183,7 +193,7 @@ public class ModificationDetectionTests {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
Streams.pipeAll(decryptionStream, out); Streams.pipeAll(decryptionStream, out);
assertThrows(IOException.class, decryptionStream::close); assertThrows(ModificationDetectionException.class, decryptionStream::close);
} }
@ParameterizedTest @ParameterizedTest
@ -214,7 +224,172 @@ public class ModificationDetectionTests {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
Streams.pipeAll(decryptionStream, out); Streams.pipeAll(decryptionStream, out);
assertThrows(IOException.class, decryptionStream::close); assertThrows(ModificationDetectionException.class, decryptionStream::close);
}
@Test
public void decryptMessageWithSEDPacket() throws IOException, PGPException {
Passphrase passphrase = Passphrase.fromPassword("flowcrypt compatibility tests");
String key = "-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n" +
"Version: FlowCrypt 6.9.1 Gmail Encryption\r\n" +
"Comment: Seamlessly send and receive encrypted email\r\n" +
"\r\n" +
"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\r\n" +
"tiL0VgGWS0GVL1cZMUwhvvu8bxI=\r\n" +
"=2z30\r\n" +
"-----END PGP PRIVATE KEY BLOCK-----\r\n";
// longId = "ADAC279C95093207"
PGPSecretKeyRing secretKeyRing = PGPainless.readKeyRing().secretKeyRing(key);
String ciphertext = "-----BEGIN PGP MESSAGE-----\n" +
"Version: FlowCrypt 5.5.9 Gmail Encryption flowcrypt.com\n" +
"Comment: Seamlessly send, receive and search encrypted email\n" +
"\n" +
"wcFMA0taL/zmLZUBAQ/7Bwida5vvhXv5Zi+qJbG/QPst11jWfljDQlw1VLzF\n" +
"ou8ofoIEHpvoFgXegZUnoQXBmlHGD+XLs9jG/TV1mtE2RWq4hDtqiTQ6rEIa\n" +
"brN3Nx77Yr+4EN1aKI20aTLEPTIjVU2GH2i9DAmjHteBU3nkL9Z3yecB8Pn8\n" +
"EdhpCRY6cj2yrhJ5MPwmXrus9OFv39wA2DqYpqW5Be+KD8mipZ2CtJo5xtin\n" +
"aeEhpWSDsdg26rjx1nz4dA0NcFzZK2p/BPfPIFzRvmoXoWFigpUnwryEoCqX\n" +
"/tgmcrv7PqiYT5oziPmMuBc1lb7icI/Aq69uXz2z6+4MJHOlcTEFygV36J+1\n" +
"1opcjoX+JKJNn1nvHovBxuemcMwriJdmDj4Hmfo4zkd6ryUtGVrMVn8DbRp6\n" +
"TWB/0MSE8cmfuiA5DgzdGbrevdL6RxnQDmalTHJ5oxurFQVoLwpmbgd36C4Q\n" +
"xMfG1xEqFn5zvrCTGHg2OfS2cynal8CQDG0ZQCoWwdb0kT5D6bx7QKcuyy1/\n" +
"1TXKnp1NamD5Uhu1+XuxD7EbvDYUWYh3bkqgslsoX+OUl+ONdtMD5PswArd5\n" +
"KisD9UJuddJShL4clBUPoXeNrRxrU6HqjP5T4fapK684MeizicHIRpAww7fu\n" +
"Z8YtaySZ/hoOAKWsx0rV4grgJV7pryj4ARBRa1pLL9rBwUwDS1ov/OYtlQEB\n" +
"D/47fyD/6BvepqWmZXj7VLl2y63eE0b/6hf5K+Izv5A/+5l/EnjFx0rq+qeX\n" +
"6hftYZBUAbbBvKfxq9D5xsWg3tnhFv2sYIE3YpkCSzZpWJmahHwQOVNT0ASw\n" +
"gbO25OiTPlYPqfSkGYe0palbL+4T5dLOwVilmrZ2bQf/rLePwA4RQpWDPYio\n" +
"NDU0Xfi7TQcHQrZTpwFbVzNPXgCHnQkqF+s0v8RDJHnt9vVs2KEpi49V/YgN\n" +
"+gZnZOeADL0rbre/PrIck1YSjZLbrWtQVk4+sCf0TjvixJ7MNjA4NgdZPo0M\n" +
"Hke/9XBFie3NiZaW/cEIVZ7WnjB3IbhkmOMJd4LgdHKgmswJwCYm+XvpOI19\n" +
"FzU1vzZmfOA1nEJSuuCDNVUoKYIQA5UEYJrVJeGnVN5sU5jkdlX9xPtYceww\n" +
"YFmLisuf9Ev0HC7v27KwYQRDPNYRA8GeK/jY6aZdg+VccsnzEigdYL5Tm4JI\n" +
"Zrxp/G807bZvt0yZwWh0gpWOFgbVgrm4Hpji5ilDyulZSW+8nJxB5tDoPzL4\n" +
"j4w9malje0c60GWNtiyCPLURyN63C2q144UpQjSU5r66oP1yF2A97aXKbf4p\n" +
"qO7cSNWEOTpqJkJrNFVKQdWvXZ+mvW1PQFmkkwish2HiQIXmWb04uV1pI8hR\n" +
"6YWk2ox9aZiJ664MpncgyJ5uIMlzVfYrX+AZRtBW36RgCTprIv6l1M5NcHMy\n" +
"zEscTaSY/e+pM5HzQKSzX+zHLa5kk5L7veX+1G33saiqSJ/fK13+k7qDNZQD\n" +
"nbtaebfh2JS0Pdbub6FUFjPHR5PydU9ltuppGEeYrOe1SxwiZ6BZfIXO2/8M\n" +
"hA==\n" +
"=B/NE\n" +
"-----END PGP MESSAGE-----\n" +
"\n";
assertThrows(MessageNotIntegrityProtectedException.class, () -> PGPainless.decryptAndOrVerify()
.onInputStream(new ByteArrayInputStream(ciphertext.getBytes(StandardCharsets.UTF_8)))
.decryptWith(SecretKeyRingProtector.unlockAllKeysWith(passphrase, secretKeyRing), new PGPSecretKeyRingCollection(Collections.singleton(secretKeyRing)))
.doNotVerify()
.build());
} }
private PGPSecretKeyRingCollection getDecryptionKey() throws IOException, PGPException { private PGPSecretKeyRingCollection getDecryptionKey() throws IOException, PGPException {

View file

@ -195,7 +195,6 @@ public class EncryptDecryptTest {
assertArrayEquals(secretMessage, decryptedSecretMessage.toByteArray()); assertArrayEquals(secretMessage, decryptedSecretMessage.toByteArray());
OpenPgpMetadata result = decryptor.getResult(); OpenPgpMetadata result = decryptor.getResult();
assertTrue(result.containsVerifiedSignatureFrom(senderPub)); assertTrue(result.containsVerifiedSignatureFrom(senderPub));
assertTrue(result.isIntegrityProtected());
assertTrue(result.isSigned()); assertTrue(result.isSigned());
assertTrue(result.isEncrypted()); assertTrue(result.isEncrypted());
assertTrue(result.isVerified()); assertTrue(result.isVerified());

View file

@ -111,7 +111,6 @@ public class SigningTest {
assertTrue(metadata.isEncrypted()); assertTrue(metadata.isEncrypted());
assertTrue(metadata.isSigned()); assertTrue(metadata.isSigned());
assertTrue(metadata.isVerified()); assertTrue(metadata.isVerified());
assertTrue(metadata.isIntegrityProtected());
assertTrue(metadata.containsVerifiedSignatureFrom(KeyRingUtils.publicKeyRingFrom(cryptieKeys))); assertTrue(metadata.containsVerifiedSignatureFrom(KeyRingUtils.publicKeyRingFrom(cryptieKeys)));
assertFalse(metadata.containsVerifiedSignatureFrom(julietKeys)); assertFalse(metadata.containsVerifiedSignatureFrom(julietKeys));
} }