diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 0bc9cdb8a..57b93be51 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -169,7 +169,6 @@ dependencies { implementation(libs.bundles.filemojicompat) - implementation(libs.bouncycastle) implementation(libs.unified.push) implementation(libs.bundles.xmldiff) diff --git a/app/lint-baseline.xml b/app/lint-baseline.xml index 4c604aefa..57f0081e0 100644 --- a/app/lint-baseline.xml +++ b/app/lint-baseline.xml @@ -1,19 +1,5 @@ - - - - - - - - - + @@ -184,7 +170,7 @@ errorLine2=" ^"> @@ -195,7 +181,7 @@ errorLine2=" ^"> @@ -217,7 +203,7 @@ errorLine2=" ^"> @@ -228,7 +214,7 @@ errorLine2=" ^"> @@ -239,7 +225,7 @@ errorLine2=" ^"> @@ -250,7 +236,7 @@ errorLine2=" ^"> @@ -261,7 +247,7 @@ errorLine2=" ^"> @@ -272,7 +258,7 @@ errorLine2=" ^"> @@ -283,7 +269,7 @@ errorLine2=" ^"> @@ -294,7 +280,7 @@ errorLine2=" ^"> @@ -305,7 +291,7 @@ errorLine2=" ^"> @@ -316,7 +302,7 @@ errorLine2=" ^"> @@ -327,7 +313,7 @@ errorLine2=" ^"> @@ -338,7 +324,7 @@ errorLine2=" ^"> @@ -349,7 +335,7 @@ errorLine2=" ^"> @@ -360,7 +346,7 @@ errorLine2=" ^"> @@ -371,7 +357,7 @@ errorLine2=" ^"> @@ -382,7 +368,7 @@ errorLine2=" ^"> @@ -393,7 +379,7 @@ errorLine2=" ^"> @@ -404,7 +390,7 @@ errorLine2=" ^"> @@ -415,7 +401,7 @@ errorLine2=" ^"> @@ -426,7 +412,7 @@ errorLine2=" ^"> @@ -437,7 +423,7 @@ errorLine2=" ^"> @@ -448,7 +434,7 @@ errorLine2=" ^"> @@ -459,7 +445,7 @@ errorLine2=" ^"> @@ -470,7 +456,7 @@ errorLine2=" ^"> @@ -569,7 +555,7 @@ errorLine2=" ^"> @@ -580,7 +566,7 @@ errorLine2=" ^"> @@ -591,7 +577,7 @@ errorLine2=" ^"> @@ -602,7 +588,7 @@ errorLine2=" ^"> @@ -613,7 +599,7 @@ errorLine2=" ^"> @@ -624,7 +610,7 @@ errorLine2=" ^"> @@ -635,7 +621,7 @@ errorLine2=" ^"> @@ -646,7 +632,7 @@ errorLine2=" ^"> @@ -657,7 +643,7 @@ errorLine2=" ^"> @@ -668,7 +654,7 @@ errorLine2=" ^"> @@ -679,7 +665,7 @@ errorLine2=" ^"> @@ -690,7 +676,7 @@ errorLine2=" ^"> @@ -701,7 +687,7 @@ errorLine2=" ^"> @@ -712,7 +698,7 @@ errorLine2=" ^"> @@ -745,7 +731,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -910,7 +896,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -1119,7 +1105,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -1130,7 +1116,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -1262,7 +1248,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -1273,7 +1259,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -1284,7 +1270,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index bfae18a3e..0a86f904d 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -73,10 +73,6 @@ -keepattributes SourceFile,LineNumberTable -renamesourcefileattribute SourceFile -# Bouncy Castle -- Keep EC --keep class org.bouncycastle.jcajce.provider.asymmetric.EC$* { *; } --keep class org.bouncycastle.jcajce.provider.asymmetric.ec.KeyPairGeneratorSpi$EC - # remove all logging from production apk -assumenosideeffects class android.util.Log { public static *** getStackTraceString(...); diff --git a/app/src/main/java/app/pachli/util/CryptoUtil.kt b/app/src/main/java/app/pachli/util/CryptoUtil.kt index a179fb59e..e59283c7b 100644 --- a/app/src/main/java/app/pachli/util/CryptoUtil.kt +++ b/app/src/main/java/app/pachli/util/CryptoUtil.kt @@ -19,22 +19,14 @@ package app.pachli.util import android.util.Base64 import java.security.KeyPairGenerator import java.security.SecureRandom -import java.security.Security -import org.bouncycastle.jce.ECNamedCurveTable -import org.bouncycastle.jce.interfaces.ECPrivateKey -import org.bouncycastle.jce.interfaces.ECPublicKey -import org.bouncycastle.jce.provider.BouncyCastleProvider +import java.security.interfaces.ECPublicKey +import java.security.spec.ECGenParameterSpec object CryptoUtil { const val CURVE_PRIME256_V1 = "prime256v1" private const val BASE64_FLAGS = Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP - init { - Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME) - Security.addProvider(BouncyCastleProvider()) - } - private fun secureRandomBytes(len: Int): ByteArray { val ret = ByteArray(len) SecureRandom.getInstance("SHA1PRNG").nextBytes(ret) @@ -48,14 +40,54 @@ object CryptoUtil { data class EncodedKeyPair(val pubkey: String, val privKey: String) fun generateECKeyPair(curve: String): EncodedKeyPair { - val spec = ECNamedCurveTable.getParameterSpec(curve) - val gen = KeyPairGenerator.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME) + val spec = ECGenParameterSpec(curve) + val gen = KeyPairGenerator.getInstance("EC") gen.initialize(spec) val keyPair = gen.genKeyPair() val pubKey = keyPair.public as ECPublicKey - val privKey = keyPair.private as ECPrivateKey - val encodedPubKey = Base64.encodeToString(pubKey.q.getEncoded(false), BASE64_FLAGS) - val encodedPrivKey = Base64.encodeToString(privKey.d.toByteArray(), BASE64_FLAGS) + val privKey = keyPair.private + val encodedPubKey = Base64.encodeToString(encodeP256Dh(pubKey), BASE64_FLAGS) + val encodedPrivKey = Base64.encodeToString(privKey.encoded, BASE64_FLAGS) return EncodedKeyPair(encodedPubKey, encodedPrivKey) } + + /** + * Encodes the public key point P in X9.62 uncompressed format. + * + * This is section "2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion" from + * https://www.secg.org/sec1-v2.pdf + */ + // Code originally from https://github.com/tateisu/SubwayTooter/blob/main/base/src/main/java/jp/juggler/crypt/CryptUtils.kt + // under the Apache 2.0 license + private fun encodeP256Dh(key: ECPublicKey): ByteArray = key.run { + val bitsInByte = 8 + val fieldSizeBytes = (params.order.bitLength() + bitsInByte - 1) / bitsInByte + return ByteArray(1 + 2 * fieldSizeBytes).also { dst -> + var offset = 0 + dst[offset++] = 0x04 // 0x04 designates uncompressed format + w.affineX.toByteArray().let { x -> + when { + x.size <= fieldSizeBytes -> + System.arraycopy(x, 0, dst, offset + fieldSizeBytes - x.size, x.size) + + x.size == fieldSizeBytes + 1 && x[0].toInt() == 0 -> + System.arraycopy(x, 1, dst, offset, fieldSizeBytes) + + else -> error("x value is too large") + } + } + offset += fieldSizeBytes + w.affineY.toByteArray().let { y -> + when { + y.size <= fieldSizeBytes -> + System.arraycopy(y, 0, dst, offset + fieldSizeBytes - y.size, y.size) + + y.size == fieldSizeBytes + 1 && y[0].toInt() == 0 -> + System.arraycopy(y, 1, dst, offset, fieldSizeBytes) + + else -> error("y value is too large") + } + } + } + } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d5c98c39b..94c20f0c0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,7 +31,6 @@ app-update = "2.1.0" apollographql = "3.8.5" auto-service = "1.1.1" auto-service-ksp = "1.2.0" -bouncycastle = "1.70" conscrypt = "2.5.3" coroutines = "1.9.0" coroutines-play-services = "1.9.0" @@ -162,7 +161,6 @@ app-update-ktx = { module = "com.google.android.play:app-update-ktx", version.re apollo-runtime = { module = "com.apollographql.apollo3:apollo-runtime", version.ref = "apollographql" } auto-service-annotations = { module = "com.google.auto.service:auto-service-annotations", version.ref = "auto-service"} auto-service-ksp = { module = "dev.zacsweers.autoservice:auto-service-ksp", version.ref = "auto-service-ksp"} -bouncycastle = { module = "org.bouncycastle:bcprov-jdk15on", version.ref = "bouncycastle" } conscrypt-android = { module = "org.conscrypt:conscrypt-android", version.ref = "conscrypt" } desugar_jdk_libs = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugar_jdk_libs" } diffx = { module = "org.pageseeder.diffx:pso-diffx", version.ref = "diffx" } diff --git a/licenses/libraries/subway_tooter.json b/licenses/libraries/subway_tooter.json new file mode 100644 index 000000000..f6dd973d0 --- /dev/null +++ b/licenses/libraries/subway_tooter.json @@ -0,0 +1,16 @@ +{ + "uniqueId": "com.github.tateisu/SubwayTooter", + "developers": [ + { + "name": "tateisu@mastodon.juggler.jp", + "organisationUrl": "https://github.com/tateisu/SubwayTooter" + } + ], + "artifactVersion": "f20f9fee8e", + "description": "X9.62 point encoding", + "name": "SubwayTooter code", + "licenses": [ + "Apache_2_0" + ], + "website": "https://subwaytooter.hatenadiary.jp/" +}