summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-11-02 10:09:49 +0100
committerDanilo M. <danix@danix.xyz>2026-11-02 10:09:49 +0100
commit1c4d04c2089f719e8344f6c4f5cd8488c2320e9f (patch)
treeb4d3f432f7ebf558af01186601745e0402e135e4
parent9b8a56cb859f45845a620d7de344079e6a91d7c9 (diff)
downloadHardenedPass-1c4d04c2089f719e8344f6c4f5cd8488c2320e9f.tar.gz
HardenedPass-1c4d04c2089f719e8344f6c4f5cd8488c2320e9f.zip
build(deps): update Bouncy Castle to 1.86 and PGPainless to 1.7.8
Bouncy Castle 1.78.1 is affected by GHSA-574f-3g2m-x479, GHSA-9pwp-9qqc-pr26, GHSA-c3fc-8qff-9hwx and GHSA-qp49-qgx5-5m26, all fixed by 1.85. PGPainless 1.7.8 is the newest 1.x release. A root resolution rule keeps every Bouncy Castle module on the catalog version; before, bcpg 1.77 shipped next to bcprov 1.78.1. The new stack decrypts the OCB (LibrePGP) packets GnuPG 2.3+ emits by default, which the old one rejected as "non-standard AEAD". Drop the NonStandardAEAD error, its bottom sheet and strings, and replace the mislabelled aead_* fixtures (SHA-1 self-signed keys plus a message encrypted to an unrelated key) with a real GnuPG 2.5 key and OCB message that the tests now decrypt. The new fixture is a throwaway test key, so it is allowlisted in .gitleaksignore by fingerprint. Fix KeyUtils.isKeyUsable, which compared a Boolean to null and so accepted every key that parsed, including keys with no encryption subkey. A signing-only key fixture now covers the rejection path. Also: migrate the removed SelectUserId.firstMatch and deprecated addDecryptionPassphrase APIs, keep one copy of the Bouncy Castle META-INF/LICENSE.md in the APK, and move the existing InvalidPackage lint baseline entries to the bcpkix 1.86 jar. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
-rw-r--r--.gitleaksignore2
-rw-r--r--app/build.gradle.kts6
-rw-r--r--app/lint-baseline.xml4
-rw-r--r--app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt21
-rw-r--r--app/src/main/res/values-de/strings.xml2
-rw-r--r--app/src/main/res/values-gl/strings.xml2
-rw-r--r--app/src/main/res/values-pl-rPL/strings.xml2
-rw-r--r--app/src/main/res/values-pt-rBR/strings.xml2
-rw-r--r--app/src/main/res/values/strings.xml2
-rw-r--r--build.gradle.kts10
-rw-r--r--crypto/common/src/main/kotlin/app/passwordstore/crypto/errors/CryptoException.kt6
-rw-r--r--crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/KeyUtils.kt2
-rw-r--r--crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPKeyManager.kt4
-rw-r--r--crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandler.kt11
-rw-r--r--crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/KeyUtilsTest.kt2
-rw-r--r--crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/PGPKeyManagerTest.kt2
-rw-r--r--crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandlerTest.kt11
-rw-r--r--crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/TestUtils.kt15
-rw-r--r--crypto/pgpainless/src/test/resources/aead_encrypted_filebin354 -> 0 bytes
-rw-r--r--crypto/pgpainless/src/test/resources/aead_pub51
-rw-r--r--crypto/pgpainless/src/test/resources/aead_sec107
-rw-r--r--crypto/pgpainless/src/test/resources/gnupg_ocb_encrypted_file2
-rw-r--r--crypto/pgpainless/src/test/resources/gnupg_ocb_sec18
-rw-r--r--crypto/pgpainless/src/test/resources/sign_only_pub10
-rw-r--r--gradle/libs.versions.toml4
25 files changed, 74 insertions, 224 deletions
diff --git a/.gitleaksignore b/.gitleaksignore
new file mode 100644
index 00000000..70d1130e
--- /dev/null
+++ b/.gitleaksignore
@@ -0,0 +1,2 @@
+# Throwaway OpenPGP test key (passphrase "Password") used to decrypt a GnuPG OCB fixture.
+crypto/pgpainless/src/test/resources/gnupg_ocb_sec:private-key:1
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 90294283..206a3972 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -28,7 +28,11 @@ android {
androidResources { generateLocaleConfig = true }
- packaging { resources.excludes.add("META-INF/versions/**") }
+ packaging {
+ resources.excludes.add("META-INF/versions/**")
+ // Every Bouncy Castle jar ships the same license file; keep one copy in the APK.
+ resources.pickFirsts.add("META-INF/LICENSE.md")
+ }
}
dependencies {
diff --git a/app/lint-baseline.xml b/app/lint-baseline.xml
index a8a3f662..8feed974 100644
--- a/app/lint-baseline.xml
+++ b/app/lint-baseline.xml
@@ -5,14 +5,14 @@
id="InvalidPackage"
message="Invalid package reference in library; not included in Android: `javax.naming.directory`. Referenced from `org.bouncycastle.cert.dane.fetcher.JndiDANEFetcherFactory`.">
<location
- file="$GRADLE_USER_HOME/caches/modules-2/files-2.1/org.bouncycastle/bcpkix-jdk18on/1.78.1/17b3541f736df97465f87d9f5b5dfa4991b37bb3/bcpkix-jdk18on-1.78.1.jar"/>
+ file="$GRADLE_USER_HOME/caches/modules-2/files-2.1/org.bouncycastle/bcpkix-jdk18on/1.86/fb5ea65959db10fe5d61148bb2b77f6e231455b1/bcpkix-jdk18on-1.86.jar"/>
</issue>
<issue
id="InvalidPackage"
message="Invalid package reference in library; not included in Android: `javax.naming`. Referenced from `org.bouncycastle.cert.dane.fetcher.JndiDANEFetcherFactory.1`.">
<location
- file="$GRADLE_USER_HOME/caches/modules-2/files-2.1/org.bouncycastle/bcpkix-jdk18on/1.78.1/17b3541f736df97465f87d9f5b5dfa4991b37bb3/bcpkix-jdk18on-1.78.1.jar"/>
+ file="$GRADLE_USER_HOME/caches/modules-2/files-2.1/org.bouncycastle/bcpkix-jdk18on/1.86/fb5ea65959db10fe5d61148bb2b77f6e231455b1/bcpkix-jdk18on-1.86.jar"/>
</issue>
<issue
diff --git a/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt b/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt
index 0d7f8dfb..8b2109bf 100644
--- a/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt
+++ b/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt
@@ -15,13 +15,11 @@ import androidx.lifecycle.lifecycleScope
import app.passwordstore.Application.Companion.screenWasOff
import app.passwordstore.R
import app.passwordstore.crypto.PGPIdentifier
-import app.passwordstore.crypto.errors.NonStandardAEAD
import app.passwordstore.data.crypto.PGPPassphraseCache
import app.passwordstore.data.passfile.PasswordEntry
import app.passwordstore.data.password.FieldItem
import app.passwordstore.databinding.DecryptLayoutBinding
import app.passwordstore.ui.adapters.FieldItemAdapter
-import app.passwordstore.ui.dialogs.BasicBottomSheet
import app.passwordstore.util.auth.BiometricAuthenticator
import app.passwordstore.util.auth.BiometricAuthenticator.Result as BiometricResult
import app.passwordstore.util.extensions.getString
@@ -255,24 +253,7 @@ class DecryptActivity : BasePGPActivity() {
onSuccess()
} else {
logcat(ERROR) { result.error.stackTraceToString() }
- when (result.error) {
- is NonStandardAEAD -> {
- BasicBottomSheet.Builder(this)
- .setTitle(getString(R.string.aead_detect_title))
- .setMessage(getString(R.string.aead_detect_message, result.error.message))
- .setPositiveButtonClickListener(getString(R.string.dialog_ok)) {
- setResult(RESULT_CANCELED)
- finish()
- }
- .setOnDismissListener {
- setResult(RESULT_CANCELED)
- finish()
- }
- .build()
- .show(supportFragmentManager, "AEAD_INFO_SHEET")
- }
- else -> decrypt(isError = true, authResult = authResult)
- }
+ decrypt(isError = true, authResult = authResult)
}
}
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 03576885..f577bd64 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -344,6 +344,4 @@
<string name="no_keys_imported_dialog_title">Keine Schlüssel importiert</string>
<string name="no_keys_imported_dialog_message">Es wurden noch keine PGP-Schlüssel in die App importiert. Wählen Sie eine Schlüsseldatei über die Schaltfläche \"Importieren\" aus.</string>
<string name="biometric_prompt_title_gpg_passphrase_cache">Freischalten des Passphrase-Zwischenspeichers</string>
- <string name="aead_detect_title">AEAD-Verschlüsselung festgestellt</string>
- <string name="aead_detect_message">%1$s, siehe https://passwordstore.app/fix-aead für weiterführende Informationen.</string>
</resources>
diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml
index 791a6385..7d886c40 100644
--- a/app/src/main/res/values-gl/strings.xml
+++ b/app/src/main/res/values-gl/strings.xml
@@ -346,6 +346,4 @@ a app desde unha fonte de confianza, como a Play Store, Amazon Appstore, F-Droid
<string name="no_keys_imported_dialog_title">Non se importaron chaves</string>
<string name="no_keys_imported_dialog_message">Aínda non hai chaves PGP importadas na app, preme no botón inferior para seleccionar un ficheiro de chave</string>
<string name="biometric_prompt_title_gpg_passphrase_cache">Desbloquear cache da frase de paso</string>
- <string name="aead_detect_title">Detectada cifraxe AEAD</string>
- <string name="aead_detect_message">%1$s, le https://passwordstore.app/fix-aead para ter máis información</string>
</resources>
diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml
index 3907a0e5..f85577c5 100644
--- a/app/src/main/res/values-pl-rPL/strings.xml
+++ b/app/src/main/res/values-pl-rPL/strings.xml
@@ -330,6 +330,4 @@
<string name="activity_label_pgp_key_manager">Menedżer kluczy PGP</string>
<string name="pgp_key_manager_delete_confirmation_dialog_title">Usunąć klucz?</string>
<string name="git_utils_reset_remote_branch_title">Nazwa zdalnej gałęzi</string>
- <string name="aead_detect_title">Wykryto szyfrowanie AEAD</string>
- <string name="aead_detect_message">%1$s, zobacz https://passwordstore.app/fix-aead aby uzyskać więcej informacji</string>
</resources>
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index 6f4b9ed9..0ba3d6eb 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -344,6 +344,4 @@
<string name="no_keys_imported_dialog_title">Nenhuma chave importada</string>
<string name="no_keys_imported_dialog_message">Não há chaves PGP importadas no aplicativo ainda, pressione o botão abaixo para escolher um arquivo de chave</string>
<string name="biometric_prompt_title_gpg_passphrase_cache">Desbloquear cache da senha</string>
- <string name="aead_detect_title">Criptografia AEAD detectada</string>
- <string name="aead_detect_message">%1$s, consulte https://passwordstore.app/fix-aead para obter mais informações</string>
</resources>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e03e5319..b3f3e71c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -384,7 +384,5 @@
<string name="no_keys_imported_dialog_title">No keys imported</string>
<string name="no_keys_imported_dialog_message">There are no PGP keys imported in the app yet, press the button below to pick a key file</string>
<string name="biometric_prompt_title_gpg_passphrase_cache">Unlock passphrase cache</string>
- <string name="aead_detect_title">AEAD encryption detected</string>
- <string name="aead_detect_message">%1$s, see https://passwordstore.app/fix-aead for more information</string>
<string name="clear_cached_password_on_screen_off">Clear cached password on screen-off</string>
</resources>
diff --git a/build.gradle.kts b/build.gradle.kts
index a0957b1b..150e3566 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -8,3 +8,13 @@ plugins {
id("com.github.android-password-store.spotless")
id("com.github.android-password-store.versions")
}
+
+// Keep every Bouncy Castle module (bcprov, bcpg, bcpkix, bcutil) on one version. They are
+// pulled in by PGPainless and sshj at different versions, and mixing them is unsupported.
+subprojects {
+ configurations.configureEach {
+ resolutionStrategy.eachDependency {
+ if (requested.group == "org.bouncycastle") useVersion(libs.versions.bouncycastle.get())
+ }
+ }
+}
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 c847889f..af6145d0 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
@@ -29,7 +29,7 @@ public data object InvalidKeyException :
/** Key failed the [app.passwordstore.crypto.KeyUtils.isKeyUsable] test. */
public data object UnusableKeyException :
- KeyManagerException("Given key is not usable for encryption - is it using AEAD?")
+ KeyManagerException("Given key is not usable for encryption")
/** No key matching `keyId` could be found. */
public class KeyNotFoundException(keyId: String) :
@@ -46,10 +46,6 @@ 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)
diff --git a/crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/KeyUtils.kt b/crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/KeyUtils.kt
index 939fed43..f85fe92c 100644
--- a/crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/KeyUtils.kt
+++ b/crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/KeyUtils.kt
@@ -47,6 +47,6 @@ public object KeyUtils {
val keyRing = tryParseKeyring(key) ?: return false
PGPainless.inspectKeyRing(keyRing).isUsableForEncryption
}
- .get() != null
+ .get() == true
}
}
diff --git a/crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPKeyManager.kt b/crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPKeyManager.kt
index ca411fa3..6f852af4 100644
--- a/crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPKeyManager.kt
+++ b/crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPKeyManager.kt
@@ -110,7 +110,9 @@ constructor(filesDir: String, private val dispatcher: CoroutineDispatcher) :
val userIdMatch =
keys
.map { key -> key to tryParseKeyring(key) }
- .firstOrNull { (_, keyRing) -> selector.firstMatch(keyRing) != null }
+ .firstOrNull { (_, keyRing) ->
+ keyRing?.publicKey?.userIDs?.asSequence()?.any(selector) == true
+ }
userIdMatch?.first
}
}
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 4a800129..a284ee0d 100644
--- a/crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandler.kt
+++ b/crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandler.kt
@@ -8,7 +8,6 @@ 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.mapBoth
@@ -26,7 +25,6 @@ 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
@@ -63,7 +61,7 @@ public class PGPainlessCryptoHandler @Inject constructor() :
.withOptions(
ConsumerOptions()
.addDecryptionKeys(keyringCollection, protector)
- .addDecryptionPassphrase(Passphrase.fromPassword(passphrase))
+ .addMessagePassphrase(Passphrase.fromPassword(passphrase))
)
decryptionStream.use { Streams.pipeAll(it, outputStream) }
return@runCatching
@@ -72,13 +70,6 @@ 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/KeyUtilsTest.kt b/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/KeyUtilsTest.kt
index 4aa83f5f..e6e3d7d1 100644
--- a/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/KeyUtilsTest.kt
+++ b/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/KeyUtilsTest.kt
@@ -31,7 +31,7 @@ class KeyUtilsTest {
@Test
fun isKeyUsable() {
- val params = AllKeys.entries.map { it to (it != AllKeys.AEAD_PUB && it != AllKeys.AEAD_SEC) }
+ val params = AllKeys.entries.map { it to (it != AllKeys.SIGN_ONLY_PUB) }
params.forEach { (allKeys, isUsable) ->
val key = PGPKey(allKeys.keyMaterial)
assertEquals(isUsable, isKeyUsable(key), "${allKeys.name} failed expectation:")
diff --git a/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/PGPKeyManagerTest.kt b/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/PGPKeyManagerTest.kt
index 7603cfe2..0525c28a 100644
--- a/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/PGPKeyManagerTest.kt
+++ b/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/PGPKeyManagerTest.kt
@@ -76,7 +76,7 @@ class PGPKeyManagerTest {
@Test
fun addKeyWithUnusableKey() =
runTest(dispatcher) {
- val error = keyManager.addKey(PGPKey(TestUtils.getAEADSecretKey())).unwrapError()
+ val error = keyManager.addKey(PGPKey(TestUtils.getSignOnlyPublicKey())).unwrapError()
assertEquals(UnusableKeyException, 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 42677337..2bfffd61 100644
--- a/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandlerTest.kt
+++ b/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandlerTest.kt
@@ -9,7 +9,6 @@ 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
@@ -139,10 +138,10 @@ class PGPainlessCryptoHandlerTest {
}
@Test
- fun aeadEncryptedMaterialIsSurfacedProperly() {
- val secKey = PGPKey(TestUtils.getAEADSecretKey())
+ fun decryptsGnuPGOcbEncryptedMaterial() {
+ val secKey = PGPKey(TestUtils.getGnuPGOcbSecretKey())
val plaintextStream = ByteArrayOutputStream()
- val ciphertextStream = TestUtils.getAEADEncryptedFile().inputStream()
+ val ciphertextStream = TestUtils.getGnuPGOcbEncryptedFile().inputStream()
val res =
cryptoHandler.decrypt(
listOf(secKey),
@@ -151,8 +150,8 @@ class PGPainlessCryptoHandlerTest {
plaintextStream,
PGPDecryptOptions.Builder().build(),
)
- assertTrue(res.isErr)
- assertIs<NonStandardAEAD>(res.error, message = "${res.error.cause}")
+ assertTrue(res.isOk, "${res.component2()?.cause}")
+ assertEquals("hunter2", plaintextStream.toString(Charsets.UTF_8).trim())
}
@Test
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 7170b558..001fdafd 100644
--- a/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/TestUtils.kt
+++ b/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/TestUtils.kt
@@ -17,19 +17,22 @@ object TestUtils {
fun getArmoredPublicKeyWithMultipleIdentities() =
this::class.java.classLoader.getResource("public_key_multiple_identities").readBytes()
- fun getAEADPublicKey() = this::class.java.classLoader.getResource("aead_pub").readBytes()
+ /** A secret key generated by GnuPG 2.5 with default settings, passphrase "Password". */
+ fun getGnuPGOcbSecretKey() = this::class.java.classLoader.getResource("gnupg_ocb_sec").readBytes()
- fun getAEADSecretKey() = this::class.java.classLoader.getResource("aead_sec").readBytes()
+ /** "hunter2" encrypted to [getGnuPGOcbSecretKey] by GnuPG using its OCB (LibrePGP) packet. */
+ fun getGnuPGOcbEncryptedFile() =
+ this::class.java.classLoader.getResource("gnupg_ocb_encrypted_file").readBytes()
- fun getAEADEncryptedFile() =
- this::class.java.classLoader.getResource("aead_encrypted_file").readBytes()
+ /** A public key with no encryption-capable subkey. */
+ fun getSignOnlyPublicKey() = this::class.java.classLoader.getResource("sign_only_pub").readBytes()
enum class AllKeys(val keyMaterial: ByteArray) {
ARMORED_SEC(getArmoredSecretKey()),
ARMORED_PUB(getArmoredPublicKey()),
MULTIPLE_IDENTITIES_SEC(getArmoredSecretKeyWithMultipleIdentities()),
MULTIPLE_IDENTITIES_PUB(getArmoredPublicKeyWithMultipleIdentities()),
- AEAD_SEC(getAEADSecretKey()),
- AEAD_PUB(getAEADPublicKey()),
+ GNUPG_OCB_SEC(getGnuPGOcbSecretKey()),
+ SIGN_ONLY_PUB(getSignOnlyPublicKey()),
}
}
diff --git a/crypto/pgpainless/src/test/resources/aead_encrypted_file b/crypto/pgpainless/src/test/resources/aead_encrypted_file
deleted file mode 100644
index d8547bdb..00000000
--- a/crypto/pgpainless/src/test/resources/aead_encrypted_file
+++ /dev/null
Binary files differ
diff --git a/crypto/pgpainless/src/test/resources/aead_pub b/crypto/pgpainless/src/test/resources/aead_pub
deleted file mode 100644
index f6ae1e82..00000000
--- a/crypto/pgpainless/src/test/resources/aead_pub
+++ /dev/null
@@ -1,51 +0,0 @@
------BEGIN PGP PUBLIC KEY BLOCK-----
-
-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
-=lwhh
------END PGP PUBLIC KEY BLOCK-----
diff --git a/crypto/pgpainless/src/test/resources/aead_sec b/crypto/pgpainless/src/test/resources/aead_sec
deleted file mode 100644
index 8e13ac0e..00000000
--- a/crypto/pgpainless/src/test/resources/aead_sec
+++ /dev/null
@@ -1,107 +0,0 @@
------BEGIN PGP PRIVATE KEY BLOCK-----
-
-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
-iHcmZE4pREmRPz9CinzsQXCm5yqJkucSfXtqn4c=
-=m5E4
------END PGP PRIVATE KEY BLOCK-----
diff --git a/crypto/pgpainless/src/test/resources/gnupg_ocb_encrypted_file b/crypto/pgpainless/src/test/resources/gnupg_ocb_encrypted_file
new file mode 100644
index 00000000..f4d5c043
--- /dev/null
+++ b/crypto/pgpainless/src/test/resources/gnupg_ocb_encrypted_file
@@ -0,0 +1,2 @@
+„^)•%XɘÝ@ëg¹(VÑ„ìÓî º¡söòo�´—h:]Bì-,�.´%0h¢_?8»FuƒÕà R¸a32wK^šÙß2
+Hù”EâhSÅ1KJØá KŒqÔM ¢åÙ!¾ �–¯H|¢:Ž£Dš(úo§e80rãâ7ÎõãŽÒcDüæ'�97­§?@( Wìó�~eÉA:®[2Ì-¨§(þ\¡ \ No newline at end of file
diff --git a/crypto/pgpainless/src/test/resources/gnupg_ocb_sec b/crypto/pgpainless/src/test/resources/gnupg_ocb_sec
new file mode 100644
index 00000000..e91d7df0
--- /dev/null
+++ b/crypto/pgpainless/src/test/resources/gnupg_ocb_sec
@@ -0,0 +1,18 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+lIYEauhQJRYJKwYBBAHaRw8BAQdAbpP/vX+rAng4A46YUZ1NMURKSkvNS0UPOZPy
+1D7avk3+BwMC9e5bxxzpzc//2zvQ0TdwE4lqi5Lbjm4LAKe3NL4qOCcuZUWk5voy
+4df6LLKRPFDVTBq/7JbIBvaOOBr8M/wjOgo6/vqnGj4XInt5975buLQfSm9obiBE
+b2UgPGpvaG4uZG9lQGV4YW1wbGUuY29tPoivBBMWCgBXFiEEetBjyKz3tBaENPNJ
+WngbP50zuXoFAmroUCUbFIAAAAAABAAObWFudTIsMi41KzEuMTIsMiwyAhsDBQsJ
+CAcCAiICBhUKCQgLAgQWAgMBAh4HAheAAAoJEFp4Gz+dM7l6DRoBAMJc0lnEHFtb
+x9bX2q3ZjuWZMRFFvCEtBXKzi/8VobvsAQD4m5c2Wl0+QCHl3Fa/JUcnbB4g8xvJ
+6qXk86fu8fTND5yLBGroUCUSCisGAQQBl1UBBQEBB0DLn1Rbk8SIqgwix4FwHkSe
+QAPixLvJYLWkS7ZddD9hUwMBCAf+BwMC+dAO/JFwC+//mzU4/YsJbF+N3cSUMJ3U
+fclSmRfaOcWbFBjSzWG2CSVQJqJkgkamYBKIJY8Iw7hF4Fj67vBi5/tJYCzk2Sn7
+M1c45TTwpoiUBBgWCgA8FiEEetBjyKz3tBaENPNJWngbP50zuXoFAmroUCUbFIAA
+AAAABAAObWFudTIsMi41KzEuMTIsMiwyAhsMAAoJEFp4Gz+dM7l6UNcA/R4HA0XJ
+1EQB2Vv2IR6zLe+vOHKK8j9LCBWmXv8eMhFrAQC11yEWH7SuXKedxRkTsVS4V6dO
+/stzkZYyq7lRWmNFCg==
+=eelL
+-----END PGP PRIVATE KEY BLOCK-----
diff --git a/crypto/pgpainless/src/test/resources/sign_only_pub b/crypto/pgpainless/src/test/resources/sign_only_pub
new file mode 100644
index 00000000..bb9715af
--- /dev/null
+++ b/crypto/pgpainless/src/test/resources/sign_only_pub
@@ -0,0 +1,10 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mDMEauhQoBYJKwYBBAHaRw8BAQdAnDvmcpRwRiGMDwuTMaz2bN2Giz966jSfLmYw
+V1nSC460IVNpZ24gT25seSA8c2lnbi5vbmx5QGV4YW1wbGUuY29tPoivBBMWCgBX
+FiEEt2karFi4tC6Y6DdBZBOuDsoW6SIFAmroUKAbFIAAAAAABAAObWFudTIsMi41
+KzEuMTIsMiwyAhsDBQsJCAcCAiICBhUKCQgLAgQWAgMBAh4HAheAAAoJEGQTrg7K
+Fuki9jYBALsBVZDDFsQ69KielwC/S7VOMkrauc56Y8MX2rq1J7NSAP9lLzL25+16
+qiHjATR19RC8Ha3Dt5iTFeDiIN1WsgyGCQ==
+=uU24
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 6bf58a62..6150bb65 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,7 +1,7 @@
[versions]
agp = "8.7.0"
androidxActivity = "1.9.2"
-bouncycastle = "1.78.1"
+bouncycastle = "1.86"
coroutines = "1.9.0"
flowbinding = "1.2.0"
hilt = "2.52"
@@ -88,7 +88,7 @@ thirdparty-logcat = "com.squareup.logcat:logcat:0.1"
thirdparty-modernAndroidPrefs = "de.maxr1998:modernandroidpreferences:2.4.0-beta2"
thirdparty-nonfree-googlePlayAuthApiPhone = "com.google.android.gms:play-services-auth-api-phone:18.1.0"
thirdparty-nonfree-sentry = "io.sentry:sentry-android:7.15.0"
-thirdparty-pgpainless = "org.pgpainless:pgpainless-core:1.6.7"
+thirdparty-pgpainless = "org.pgpainless:pgpainless-core:1.7.8"
thirdparty-slack-lints = "com.slack.lint:slack-lint-checks:0.8.0"
thirdparty-slf4j-api = { module = "org.slf4j:slf4j-api", version = { strictly = "[1.7, 1.8[", prefer = "1.7.36" } }
thirdparty-sshj = "com.hierynomus:sshj:0.39.0"