Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.flowcrypt.email.R
import com.flowcrypt.email.TestConstants
import com.flowcrypt.email.database.entity.KeyEntity
import com.flowcrypt.email.junit.annotations.DependsOnMailServer
import com.flowcrypt.email.junit.annotations.NotReadyForCI
import com.flowcrypt.email.matchers.CustomMatchers.Companion.withRecyclerViewItemCount
import com.flowcrypt.email.rules.AddPrivateKeyToDatabaseRule
import com.flowcrypt.email.rules.ClearAppSettingsRule
Expand Down Expand Up @@ -58,6 +59,7 @@ class BackupKeysFragmentSingleKeyPassphraseInRamTest : BaseBackupKeysFragmentTes

@Test
@DependsOnMailServer
@NotReadyForCI
fun testNeedPassphraseEmailOptionSingleFingerprint() {
onView(withId(R.id.btBackup))
.check(matches(isDisplayed()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import com.flowcrypt.email.extensions.org.bouncycastle.openpgp.armor
import com.flowcrypt.email.extensions.org.bouncycastle.openpgp.toPgpKeyDetails
import com.flowcrypt.email.extensions.org.owasp.html.allowAttributesOnElementsExt
import com.flowcrypt.email.security.pgp.PgpArmor.ARMOR_HEADER_DICT
import org.bouncycastle.bcpg.ArmoredInputStream
import org.bouncycastle.bcpg.PacketTags
import org.bouncycastle.openpgp.PGPDataValidationException
import org.bouncycastle.openpgp.PGPException
Expand All @@ -54,6 +53,7 @@ import org.pgpainless.key.info.KeyRingInfo
import org.pgpainless.key.protection.UnprotectedKeysProtector
import org.pgpainless.util.Passphrase
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.InputStream
import java.nio.charset.StandardCharsets
import java.util.Locale
Expand Down Expand Up @@ -202,9 +202,8 @@ object PgpMsg {
)
}

val input = data.inputStream()
val chunk = data.copyOfRange(0, data.size.coerceAtMost(50)).toString(StandardCharsets.US_ASCII)
var input = data.inputStream() as InputStream

if (chunk.contains(ARMOR_HEADER_DICT[MsgBlock.Type.SIGNED_MSG]!!.begin)) {
val msg: PgpArmor.CleartextSignedMessage
try {
Expand All @@ -227,9 +226,6 @@ object PgpMsg {
return DecryptionResult.withCleartext(msg.content, msg.signature)
}

val isArmored = chunk.contains(ARMOR_HEADER_DICT[MsgBlock.Type.ENCRYPTED_MSG]!!.begin)
if (isArmored) input = ArmoredInputStream(input)

val keyList: List<PGPSecretKeyRing>
try {
keyList = keys.map {
Expand All @@ -252,20 +248,26 @@ object PgpMsg {
)
}

val exception: Exception?
try {
val consumerOptions = ConsumerOptions()
.addDecryptionKeys(PGPSecretKeyRingCollection(keyList), UnprotectedKeysProtector())
pgpPublicKeyRingCollection?.let { consumerOptions.addVerificationCerts(it) }

val decryptionStream = PGPainless.decryptAndOrVerify()
.onInputStream(input)
.withOptions(consumerOptions)

val output = ByteArrayOutputStream()
decryptionStream.use { it.copyTo(output) }

val streamResult = decryptionStream.result
return DecryptionResult.withDecrypted(output, streamResult.fileName)
try {
decryptionStream.use { it.copyTo(output) }
} catch (ex: IOException) {
val message = ex.message
if (message != null && message.contains("crc check not found")) {
decryptionStream.close()
} else {
throw ex
}
}
return DecryptionResult.withDecrypted(output, decryptionStream.result.fileName)
} catch (ex: MessageNotIntegrityProtectedException) {
return DecryptionResult.withError(
type = PgpDecrypt.DecryptionErrorType.NO_MDC,
Expand Down Expand Up @@ -294,10 +296,28 @@ object PgpMsg {
message = "There is no suitable decryption key"
)
}
// other PGP error, fallback to default error return in the bottom
exception = ex
} catch (ex: Exception) {
if (
ex is IOException &&
ex.message?.contains("crc check failed in armored message") == true
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does PGPainless return exception as IOException? it would be better to have a predefined exception here. For now, it looks a little ugly

) {
return DecryptionResult.withError(
type = PgpDecrypt.DecryptionErrorType.FORMAT,
message = "Armor CRC check failed"
)
} else {
exception = ex
}
}
var message = "Decryption failed"
if (exception != null) {
message = "$message: ${exception.javaClass.canonicalName}: ${exception.message}"
}
return DecryptionResult.withError(
type = PgpDecrypt.DecryptionErrorType.OTHER,
message = "Decryption failed"
message = message
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class PgpMsgTest {
val quoted: Boolean? = null,
val charset: String = "UTF-8"
) {
val armored: String = loadResourceAsString("messages/$key.txt")
val armored: String by lazy { loadResourceAsString("messages/$key.txt") }
}

companion object {
Expand Down Expand Up @@ -112,7 +112,12 @@ class PgpMsgTest {
TestUtil.decodeString("=E3=82=BE=E3=81=97=E9=80=B8=E7=8F=BE=E9=A3=B2", "UTF-8")
),
charset = "ISO-2022-JP",
)
),

MessageInfo(
key = "decrypt - issue 1347 - wrong checksum",
content = listOf("")
),
)

private fun findMessage(key: String): MessageInfo {
Expand Down Expand Up @@ -172,15 +177,15 @@ class PgpMsgTest {
assertTrue("Bad MDC not detected", r.error!!.type == PgpDecrypt.DecryptionErrorType.BAD_MDC)
}

// TODO: Should there be any error?
// https://github.com/FlowCrypt/flowcrypt-android/issues/1214
@Test
fun decryptionTest3() {
val r = processMessage(
"decrypt - [everdesk] message encrypted for sub but claims encryptedFor-primary,sub"
)
assertTrue("Message not returned", r.content != null)
assertTrue("Error returned", r.error == null)
// TODO: Should there be any error?
// https://github.com/FlowCrypt/flowcrypt-android/issues/1214
}

@Test
Expand All @@ -194,6 +199,14 @@ class PgpMsgTest {
assertTrue("Error returned", r.error == null)
}

@Test
// @Ignore("BC ArmoredInputStream issue")
fun wrongArmorChecksumTest() {
val r = processMessage("decrypt - issue 1347 - wrong checksum")
assertTrue("Error not returned", r.error != null)
assertEquals(PgpDecrypt.DecryptionErrorType.FORMAT, r.error!!.type)
}

@Test
fun wrongPassphraseTest() {
val messageInfo = findMessage("decrypt - without a subject")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
-----BEGIN PGP MESSAGE-----
Version: FlowCrypt 5.0.4 Gmail Encryption flowcrypt.com
Comment: Seamlessly send, receive and search encrypted email

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
=FdCC
-----END PGP MESSAGE-----