Skip to content
This repository has been archived by the owner on Oct 15, 2024. It is now read-only.

Switch new PGP backend to use PGPainless #1522

Merged
merged 12 commits into from
Oct 23, 2021
Merged
62 changes: 0 additions & 62 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,65 +51,3 @@ jobs:
with:
name: Test report
path: app/build/reports

instrumentation-tests:
runs-on: macos-11
steps:
- name: Checkout repository
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
with:
fetch-depth: 0

- name: Check if relevant files have changed
uses: actions/github-script@a3e7071a34d7e1f219a8a4de9a5e0a34d1ee1293
id: service-changed
with:
result-encoding: string
script: |
const script = require('.github/check-changed-files.js')
return await script({github, context})

- uses: actions/cache@c64c572235d810460d0d6876e9c705ad5002b353
if: ${{ steps.service-changed.outputs.result == 'true' }}
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-23

- uses: actions/setup-java@d202f5dbf7256730fb690ec59f6381650114feb2
if: ${{ steps.service-changed.outputs.result == 'true' }}
with:
java-version: '11'

- name: Copy CI gradle.properties
if: ${{ steps.service-changed.outputs.result == 'true' }}
run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties

- name: Create AVD and generate snapshot for caching
uses: reactivecircus/android-emulator-runner@5de26e4bd23bf523e8a4b7f077df8bfb8e52b50e
if: ${{ steps.avd-cache.outputs.cache-hit != 'true' }}
with:
api-level: 23
force-avd-creation: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: false
script: echo "Generated AVD snapshot for caching"

- name: Run screenshot tests
uses: reactivecircus/android-emulator-runner@5de26e4bd23bf523e8a4b7f077df8bfb8e52b50e
if: ${{ steps.service-changed.outputs.result == 'true' }}
with:
api-level: 23
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
script: ./gradlew connectedCheck -PslimTests

- name: (Fail-only) upload test report
if: failure()
uses: actions/upload-artifact@27121b0bdffd731efa15d66772be8dc71245d074
with:
name: Test report
path: app/build/reports
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ dependencies {
implementation(libs.androidx.annotation)
coreLibraryDesugaring(libs.android.desugarJdkLibs)
implementation(projects.autofillParser)
implementation(projects.cryptoPgp)
implementation(projects.cryptoPgpainless)
implementation(projects.formatCommon)
implementation(projects.openpgpKtx)
implementation(libs.androidx.activity.ktx)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dagger.multibindings.IntoSet
import dev.msfjarvis.aps.data.crypto.CryptoHandler
import dev.msfjarvis.aps.data.crypto.GopenpgpCryptoHandler
import dev.msfjarvis.aps.crypto.CryptoHandler
import dev.msfjarvis.aps.crypto.PGPainlessCryptoHandler

/**
* This module adds all [CryptoHandler] implementations into a Set which makes it easier to build
Expand All @@ -23,7 +23,7 @@ object CryptoHandlerModule {
@Provides
@IntoSet
fun providePgpCryptoHandler(): CryptoHandler {
return GopenpgpCryptoHandler()
return PGPainlessCryptoHandler()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import dev.msfjarvis.aps.util.autofill.AutofillPreferences
import dev.msfjarvis.aps.util.autofill.AutofillResponseBuilder
import dev.msfjarvis.aps.util.autofill.DirectoryStructure
import dev.msfjarvis.aps.util.extensions.asLog
import java.io.ByteArrayOutputStream
import java.io.File
import javax.inject.Inject
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -130,11 +131,14 @@ class AutofillDecryptActivityV2 : AppCompatActivity() {
runCatching {
val crypto = cryptos.first { it.canHandle(file.absolutePath) }
withContext(Dispatchers.IO) {
val outputStream = ByteArrayOutputStream()
crypto.decrypt(
DecryptActivityV2.PRIV_KEY,
DecryptActivityV2.PASS.toByteArray(charset = Charsets.UTF_8),
encryptedInput.readBytes()
DecryptActivityV2.PASS,
encryptedInput,
outputStream,
)
outputStream
}
}
.onFailure { e ->
Expand All @@ -143,7 +147,7 @@ class AutofillDecryptActivityV2 : AppCompatActivity() {
}
.onSuccess { result ->
return runCatching {
val entry = passwordEntryFactory.create(lifecycleScope, result)
val entry = passwordEntryFactory.create(lifecycleScope, result.toByteArray())
AutofillPreferences.credentialsFromStoreEntry(this, file, entry, directoryStructure)
}
.getOrElse { e ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import dev.msfjarvis.aps.injection.password.PasswordEntryFactory
import dev.msfjarvis.aps.ui.adapters.FieldItemAdapter
import dev.msfjarvis.aps.util.extensions.unsafeLazy
import dev.msfjarvis.aps.util.extensions.viewBinding
import java.io.ByteArrayOutputStream
import java.io.File
import javax.inject.Inject
import kotlin.time.Duration
Expand Down Expand Up @@ -126,19 +127,22 @@ class DecryptActivityV2 : BasePgpActivity() {
private fun decrypt() {
lifecycleScope.launch {
// TODO(msfjarvis): native methods are fallible, add error handling once out of testing
val message = withContext(Dispatchers.IO) { File(fullPath).readBytes() }
val message = withContext(Dispatchers.IO) { File(fullPath).inputStream() }
val result =
withContext(Dispatchers.IO) {
val crypto = cryptos.first { it.canHandle(fullPath) }
val outputStream = ByteArrayOutputStream()
crypto.decrypt(
PRIV_KEY,
PASS.toByteArray(charset = Charsets.UTF_8),
PASS,
message,
outputStream,
)
outputStream
}
startAutoDismissTimer()

val entry = passwordEntryFactory.create(lifecycleScope, result)
val entry = passwordEntryFactory.create(lifecycleScope, result.toByteArray())
passwordEntry = entry
invalidateOptionsMenu()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import dev.msfjarvis.aps.util.extensions.snackbar
import dev.msfjarvis.aps.util.extensions.unsafeLazy
import dev.msfjarvis.aps.util.extensions.viewBinding
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.IOException
import javax.inject.Inject
Expand Down Expand Up @@ -319,7 +320,15 @@ class PasswordCreationActivityV2 : BasePgpActivity() {
runCatching {
val crypto = cryptos.first { it.canHandle(path) }
val result =
withContext(Dispatchers.IO) { crypto.encrypt(PUB_KEY, content.encodeToByteArray()) }
withContext(Dispatchers.IO) {
val outputStream = ByteArrayOutputStream()
crypto.encrypt(
listOf(PUB_KEY),
content.byteInputStream(),
outputStream,
)
outputStream
}
val file = File(path)
// If we're not editing, this file should not already exist!
// Additionally, if we were editing and the incoming and outgoing
Expand All @@ -336,7 +345,7 @@ class PasswordCreationActivityV2 : BasePgpActivity() {
return@runCatching
}

withContext(Dispatchers.IO) { file.outputStream().use { it.write(result) } }
withContext(Dispatchers.IO) { file.writeBytes(result.toByteArray()) }

// associate the new password name with the last name's timestamp in
// history
Expand Down
44 changes: 22 additions & 22 deletions crypto-common/api/crypto-common.api
Original file line number Diff line number Diff line change
@@ -1,63 +1,63 @@
public abstract class dev/msfjarvis/aps/data/crypto/CryptoException : java/lang/Exception {
public abstract class dev/msfjarvis/aps/crypto/CryptoException : java/lang/Exception {
public synthetic fun <init> (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public abstract interface class dev/msfjarvis/aps/data/crypto/CryptoHandler {
public abstract interface class dev/msfjarvis/aps/crypto/CryptoHandler {
public abstract fun canHandle (Ljava/lang/String;)Z
public abstract fun decrypt (Ljava/lang/String;[B[B)[B
public abstract fun encrypt (Ljava/lang/String;[B)[B
public abstract fun decrypt (Ljava/lang/String;Ljava/lang/String;Ljava/io/InputStream;Ljava/io/OutputStream;)V
public abstract fun encrypt (Ljava/util/List;Ljava/io/InputStream;Ljava/io/OutputStream;)V
}

public abstract interface class dev/msfjarvis/aps/data/crypto/KeyManager {
public abstract fun addKey (Ldev/msfjarvis/aps/data/crypto/KeyPair;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract interface class dev/msfjarvis/aps/crypto/KeyManager {
public abstract fun addKey (Ldev/msfjarvis/aps/crypto/KeyPair;ZLkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun canHandle (Ljava/lang/String;)Z
public abstract fun getAllKeys (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun getKeyById (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun removeKey (Ldev/msfjarvis/aps/data/crypto/KeyPair;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun removeKey (Ldev/msfjarvis/aps/crypto/KeyPair;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}

public final class dev/msfjarvis/aps/data/crypto/KeyManager$DefaultImpls {
public static synthetic fun addKey$default (Ldev/msfjarvis/aps/data/crypto/KeyManager;Ldev/msfjarvis/aps/data/crypto/KeyPair;ZLkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
public final class dev/msfjarvis/aps/crypto/KeyManager$DefaultImpls {
public static synthetic fun addKey$default (Ldev/msfjarvis/aps/crypto/KeyManager;Ldev/msfjarvis/aps/crypto/KeyPair;ZLkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
}

public abstract class dev/msfjarvis/aps/data/crypto/KeyManagerException : dev/msfjarvis/aps/data/crypto/CryptoException {
public abstract class dev/msfjarvis/aps/crypto/KeyManagerException : dev/msfjarvis/aps/crypto/CryptoException {
public synthetic fun <init> (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class dev/msfjarvis/aps/data/crypto/KeyManagerException$KeyAlreadyExistsException : dev/msfjarvis/aps/data/crypto/KeyManagerException {
public final class dev/msfjarvis/aps/crypto/KeyManagerException$KeyAlreadyExistsException : dev/msfjarvis/aps/crypto/KeyManagerException {
public fun <init> (Ljava/lang/String;)V
}

public final class dev/msfjarvis/aps/data/crypto/KeyManagerException$KeyDeletionFailedException : dev/msfjarvis/aps/data/crypto/KeyManagerException {
public static final field INSTANCE Ldev/msfjarvis/aps/data/crypto/KeyManagerException$KeyDeletionFailedException;
public final class dev/msfjarvis/aps/crypto/KeyManagerException$KeyDeletionFailedException : dev/msfjarvis/aps/crypto/KeyManagerException {
public static final field INSTANCE Ldev/msfjarvis/aps/crypto/KeyManagerException$KeyDeletionFailedException;
}

public final class dev/msfjarvis/aps/data/crypto/KeyManagerException$KeyDirectoryUnavailableException : dev/msfjarvis/aps/data/crypto/KeyManagerException {
public static final field INSTANCE Ldev/msfjarvis/aps/data/crypto/KeyManagerException$KeyDirectoryUnavailableException;
public final class dev/msfjarvis/aps/crypto/KeyManagerException$KeyDirectoryUnavailableException : dev/msfjarvis/aps/crypto/KeyManagerException {
public static final field INSTANCE Ldev/msfjarvis/aps/crypto/KeyManagerException$KeyDirectoryUnavailableException;
}

public final class dev/msfjarvis/aps/data/crypto/KeyManagerException$KeyNotFoundException : dev/msfjarvis/aps/data/crypto/KeyManagerException {
public final class dev/msfjarvis/aps/crypto/KeyManagerException$KeyNotFoundException : dev/msfjarvis/aps/crypto/KeyManagerException {
public fun <init> (Ljava/lang/String;)V
}

public final class dev/msfjarvis/aps/data/crypto/KeyManagerException$NoKeysAvailableException : dev/msfjarvis/aps/data/crypto/KeyManagerException {
public static final field INSTANCE Ldev/msfjarvis/aps/data/crypto/KeyManagerException$NoKeysAvailableException;
public final class dev/msfjarvis/aps/crypto/KeyManagerException$NoKeysAvailableException : dev/msfjarvis/aps/crypto/KeyManagerException {
public static final field INSTANCE Ldev/msfjarvis/aps/crypto/KeyManagerException$NoKeysAvailableException;
}

public abstract interface class dev/msfjarvis/aps/data/crypto/KeyPair {
public abstract interface class dev/msfjarvis/aps/crypto/KeyPair {
public abstract fun getKeyId ()Ljava/lang/String;
public abstract fun getPrivateKey ()[B
public abstract fun getPublicKey ()[B
}

public abstract class dev/msfjarvis/aps/data/crypto/KeyPairException : dev/msfjarvis/aps/data/crypto/CryptoException {
public abstract class dev/msfjarvis/aps/crypto/KeyPairException : dev/msfjarvis/aps/crypto/CryptoException {
public synthetic fun <init> (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
}

public final class dev/msfjarvis/aps/data/crypto/KeyPairException$PrivateKeyUnavailableException : dev/msfjarvis/aps/data/crypto/KeyPairException {
public static final field INSTANCE Ldev/msfjarvis/aps/data/crypto/KeyPairException$PrivateKeyUnavailableException;
public final class dev/msfjarvis/aps/crypto/KeyPairException$PrivateKeyUnavailableException : dev/msfjarvis/aps/crypto/KeyPairException {
public static final field INSTANCE Ldev/msfjarvis/aps/crypto/KeyPairException$PrivateKeyUnavailableException;
}

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.msfjarvis.aps.data.crypto
package dev.msfjarvis.aps.crypto

public sealed class CryptoException(message: String? = null) : Exception(message)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/

package dev.msfjarvis.aps.crypto

import java.io.InputStream
import java.io.OutputStream

/** Generic interface to implement cryptographic operations on top of. */
public interface CryptoHandler {

/**
* Decrypt the given [ciphertextStream] using a [privateKey] and [password], and writes the
* resultant plaintext to [outputStream].
*/
public fun decrypt(
privateKey: String,
password: String,
ciphertextStream: InputStream,
outputStream: OutputStream,
)

/**
* Encrypt the given [plaintextStream] to the provided [pubKeys], and writes the encrypted
* ciphertext to [outputStream].
*/
public fun encrypt(
pubKeys: List<String>,
plaintextStream: InputStream,
outputStream: OutputStream,
)

/** Given a [fileName], return whether this instance can handle it. */
public fun canHandle(fileName: String): Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: GPL-3.0-only
*/

package dev.msfjarvis.aps.data.crypto
package dev.msfjarvis.aps.crypto

import com.github.michaelbull.result.Result

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: GPL-3.0-only
*/

package dev.msfjarvis.aps.data.crypto
package dev.msfjarvis.aps.crypto

/** Defines expectations for a keypair used in public key cryptography. */
public interface KeyPair {
Expand Down

This file was deleted.

25 changes: 0 additions & 25 deletions crypto-pgp/api/crypto-pgp.api

This file was deleted.

Loading