diff options
author | Harsh Shandilya <me@msfjarvis.dev> | 2024-04-14 22:50:59 +0530 |
---|---|---|
committer | Harsh Shandilya <me@msfjarvis.dev> | 2024-04-14 23:19:31 +0530 |
commit | 87738477be87afb639509f5ebdf5da979ba0bd04 (patch) | |
tree | d2575904de2bd37e23463d8f9831161b38be790b /crypto | |
parent | 312f92d21a5b8925496d5015357c257dace3a028 (diff) |
fix: special-case AEAD failure
Fixes #2974
Fixes #2963
Fixes #2921
Fixes #2924
Fixes #2653
Fixes #2461
Fixes #2586
Fixes #2179
Diffstat (limited to 'crypto')
5 files changed, 36 insertions, 1 deletions
diff --git a/crypto/common/src/main/kotlin/app/passwordstore/crypto/errors/CryptoException.kt b/crypto/common/src/main/kotlin/app/passwordstore/crypto/errors/CryptoException.kt index eb64541e..c2d3ca4d 100644 --- a/crypto/common/src/main/kotlin/app/passwordstore/crypto/errors/CryptoException.kt +++ b/crypto/common/src/main/kotlin/app/passwordstore/crypto/errors/CryptoException.kt @@ -41,8 +41,13 @@ public sealed class CryptoHandlerException(message: String? = null, cause: Throw /** The passphrase provided for decryption was incorrect. */ public class IncorrectPassphraseException(cause: Throwable) : CryptoHandlerException(null, cause) +/** The encrypted material is using an incompatible variant of PGP's AEAD standard. */ +public class NonStandardAEAD(cause: Throwable) : + CryptoHandlerException("GnuPG's AEAD implementation is non-standard and unsupported", cause) + /** No keys were passed to the encrypt/decrypt operation. */ public data object NoKeysProvidedException : CryptoHandlerException(null, null) /** An unexpected error that cannot be mapped to a known type. */ -public class UnknownError(cause: Throwable) : CryptoHandlerException(null, cause) +public class UnknownError(cause: Throwable, message: String? = null) : + CryptoHandlerException(message, cause) diff --git a/crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandler.kt b/crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandler.kt index a7087acf..92fbfa64 100644 --- a/crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandler.kt +++ b/crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandler.kt @@ -8,6 +8,7 @@ package app.passwordstore.crypto import app.passwordstore.crypto.errors.CryptoHandlerException import app.passwordstore.crypto.errors.IncorrectPassphraseException import app.passwordstore.crypto.errors.NoKeysProvidedException +import app.passwordstore.crypto.errors.NonStandardAEAD import app.passwordstore.crypto.errors.UnknownError import com.github.michaelbull.result.Result import com.github.michaelbull.result.mapError @@ -24,6 +25,7 @@ import org.pgpainless.PGPainless import org.pgpainless.decryption_verification.ConsumerOptions import org.pgpainless.encryption_signing.EncryptionOptions import org.pgpainless.encryption_signing.ProducerOptions +import org.pgpainless.exception.MessageNotIntegrityProtectedException import org.pgpainless.exception.WrongPassphraseException import org.pgpainless.key.protection.SecretKeyRingProtector import org.pgpainless.util.Passphrase @@ -75,6 +77,13 @@ public class PGPainlessCryptoHandler @Inject constructor() : when (error) { is WrongPassphraseException -> IncorrectPassphraseException(error) is CryptoHandlerException -> error + is MessageNotIntegrityProtectedException -> { + if (error.message?.contains("Symmetrically Encrypted Data") == true) { + NonStandardAEAD(error) + } else { + UnknownError(error) + } + } else -> UnknownError(error) } } diff --git a/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandlerTest.kt b/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandlerTest.kt index 4ec4b7fa..5de2bf4f 100644 --- a/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandlerTest.kt +++ b/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandlerTest.kt @@ -9,6 +9,7 @@ package app.passwordstore.crypto import app.passwordstore.crypto.CryptoConstants.KEY_PASSPHRASE import app.passwordstore.crypto.CryptoConstants.PLAIN_TEXT import app.passwordstore.crypto.errors.IncorrectPassphraseException +import app.passwordstore.crypto.errors.NonStandardAEAD import com.github.michaelbull.result.getError import com.google.testing.junit.testparameterinjector.TestParameter import com.google.testing.junit.testparameterinjector.TestParameterInjector @@ -138,6 +139,23 @@ class PGPainlessCryptoHandlerTest { } @Test + fun aeadEncryptedMaterialIsSurfacedProperly() { + val secKey = PGPKey(TestUtils.getAEADSecretKey()) + val plaintextStream = ByteArrayOutputStream() + val ciphertextStream = TestUtils.getAEADEncryptedFile().inputStream() + val res = + cryptoHandler.decrypt( + listOf(secKey), + "Password", + ciphertextStream, + plaintextStream, + PGPDecryptOptions.Builder().build(), + ) + assertTrue(res.isErr) + assertIs<NonStandardAEAD>(res.error, message = "${res.error.cause}") + } + + @Test fun canHandleFiltersFormats() { assertFalse { cryptoHandler.canHandle("example.com") } assertTrue { cryptoHandler.canHandle("example.com.gpg") } diff --git a/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/TestUtils.kt b/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/TestUtils.kt index 90b98ac9..56c8c1d8 100644 --- a/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/TestUtils.kt +++ b/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/TestUtils.kt @@ -21,6 +21,9 @@ object TestUtils { fun getAEADSecretKey() = this::class.java.classLoader.getResource("aead_sec").readBytes() + fun getAEADEncryptedFile() = + this::class.java.classLoader.getResource("aead_encrypted_file").readBytes() + enum class AllKeys(val keyMaterial: ByteArray) { ARMORED_SEC(getArmoredSecretKey()), ARMORED_PUB(getArmoredPublicKey()), diff --git a/crypto/pgpainless/src/test/resources/aead_encrypted_file b/crypto/pgpainless/src/test/resources/aead_encrypted_file Binary files differnew file mode 100644 index 00000000..d8547bdb --- /dev/null +++ b/crypto/pgpainless/src/test/resources/aead_encrypted_file |