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

Commit 8076f44

Browse files
committed
wip: decrypt files using key imported during onboarding
Signed-off-by: Aditya Wasan <adityawasan55@gmail.com>
1 parent 32ce8f0 commit 8076f44

File tree

5 files changed

+49
-9
lines changed

5 files changed

+49
-9
lines changed

app/src/main/java/dev/msfjarvis/aps/ui/crypto/GopenpgpDecryptActivity.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import android.os.Bundle
1010
import android.view.Menu
1111
import android.view.MenuItem
1212
import androidx.lifecycle.lifecycleScope
13+
import com.github.michaelbull.result.unwrap
1314
import dagger.hilt.android.AndroidEntryPoint
1415
import dev.msfjarvis.aps.R
16+
import dev.msfjarvis.aps.data.crypto.AndroidKeyManager
1517
import dev.msfjarvis.aps.data.crypto.GopenpgpCryptoHandler
1618
import dev.msfjarvis.aps.data.passfile.PasswordEntry
1719
import dev.msfjarvis.aps.data.password.FieldItem
@@ -36,6 +38,7 @@ class GopenpgpDecryptActivity : BasePgpActivity() {
3638
private val binding by viewBinding(DecryptLayoutBinding::inflate)
3739
@Inject lateinit var passwordEntryFactory: PasswordEntryFactory
3840
@Inject lateinit var gopenpgpCrypto: GopenpgpCryptoHandler
41+
@Inject lateinit var gpgKeyManager: AndroidKeyManager
3942
private val relativeParentPath by unsafeLazy { getParentPath(fullPath, repoPath) }
4043

4144
private var passwordEntry: PasswordEntry? = null
@@ -125,12 +128,13 @@ class GopenpgpDecryptActivity : BasePgpActivity() {
125128
private fun decrypt() =
126129
lifecycleScope.launch {
127130
// TODO(msfjarvis): native methods are fallible, add error handling once out of testing
128-
val message = withContext(Dispatchers.IO) { File(fullPath).readBytes() }
131+
val message = withContext(Dispatchers.IO) { File(fullPath).readText() }
129132
val result =
130133
withContext(Dispatchers.IO) {
131-
gopenpgpCrypto.decrypt(
132-
PRIV_KEY,
133-
PASS.toByteArray(charset = Charsets.UTF_8),
134+
// TODO(aditya): Use .gpg-id to get the key id
135+
gopenpgpCrypto.decryptFromKeyId(
136+
"b950ae2813841585",
137+
"12345678".toByteArray(charset = Charsets.UTF_8),
134138
message,
135139
)
136140
}

app/src/main/java/dev/msfjarvis/aps/ui/onboarding/fragments/GopenpgpKeySelectionFragment.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import androidx.activity.result.contract.ActivityResultContracts
1212
import androidx.core.content.edit
1313
import androidx.fragment.app.Fragment
1414
import androidx.fragment.app.viewModels
15+
import androidx.lifecycle.lifecycleScope
16+
import com.github.ajalt.timberkt.d
1517
import com.github.michaelbull.result.onFailure
1618
import com.github.michaelbull.result.onSuccess
1719
import dagger.hilt.android.AndroidEntryPoint
@@ -24,6 +26,7 @@ import dev.msfjarvis.aps.util.extensions.sharedPrefs
2426
import dev.msfjarvis.aps.util.extensions.unsafeLazy
2527
import dev.msfjarvis.aps.util.extensions.viewBinding
2628
import dev.msfjarvis.aps.util.settings.PreferenceKeys
29+
import kotlinx.coroutines.flow.launchIn
2730
import kotlinx.coroutines.flow.onEach
2831

2932
@AndroidEntryPoint
@@ -32,14 +35,12 @@ class GopenpgpKeySelectionFragment : Fragment(R.layout.fragment_key_selection) {
3235
private val settings by unsafeLazy { requireActivity().applicationContext.sharedPrefs }
3336
private val binding by viewBinding(FragmentKeySelectionBinding::bind)
3437
private val viewModel: KeySelectionViewModel by viewModels()
35-
3638
private val gpgKeySelectAction = registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
3739
if (uri == null) {
3840
// TODO: Use string resources here
3941
showError("No files chosen")
4042
return@registerForActivityResult
4143
}
42-
4344
val fis = requireContext().contentResolver.openInputStream(uri)
4445
if (fis == null) {
4546
showError("Error resolving content uri")
@@ -55,15 +56,18 @@ class GopenpgpKeySelectionFragment : Fragment(R.layout.fragment_key_selection) {
5556
gpgKeySelectAction.launch("*/*")
5657
}
5758

59+
// TODO: Use new flowWithLifecycle APIs
5860
viewModel.importKeyStatus.onEach { result ->
5961
result.onSuccess {
62+
d { "Key imported successfully" }
6063
settings.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, true) }
6164
requireActivity().commitChange(getString(R.string.git_commit_gpg_id, getString(R.string.app_name)))
6265
finish()
6366
}.onFailure {
67+
d(it)
6468
showError(it.message!!)
6569
}
66-
}
70+
}.launchIn(viewLifecycleOwner.lifecycleScope)
6771
}
6872

6973
private fun showError(message: String) {

app/src/main/java/dev/msfjarvis/aps/ui/onboarding/viewmodel/KeySelectionViewModel.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package dev.msfjarvis.aps.ui.onboarding.viewmodel
22

3+
import android.util.Log
34
import androidx.lifecycle.ViewModel
45
import androidx.lifecycle.viewModelScope
56
import com.github.michaelbull.result.Err
@@ -60,7 +61,9 @@ class KeySelectionViewModel @Inject constructor(private val keyManager: KeyManag
6061

6162
private suspend fun createGpgIdFile(): Result<Unit, Throwable> = withContext(Dispatchers.IO) {
6263
return@withContext keyManager.listKeyIds().map { keys ->
64+
Log.d("CreateIdFile", "$keys")
6365
val idFile = File(PasswordRepository.getRepositoryDirectory(), ".gpg-id")
66+
idFile.createNewFile()
6467
idFile.writeText((keys + "").joinToString("\n"))
6568
}
6669
}

crypto-pgp/src/main/kotlin/dev/msfjarvis/aps/data/crypto/AndroidKeyManager.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package dev.msfjarvis.aps.data.crypto
22

3+
import android.util.Log
34
import com.github.michaelbull.result.Err
45
import com.github.michaelbull.result.Result
56
import com.github.michaelbull.result.runCatching
7+
import com.proton.Gopenpgp.crypto.Crypto
8+
import com.proton.Gopenpgp.crypto.GopenPGP
69
import com.proton.Gopenpgp.crypto.Key
710
import java.io.File
811
import kotlinx.coroutines.CoroutineDispatcher
@@ -17,14 +20,16 @@ public class AndroidKeyManager(
1720
private val keyDir = File(filesDirPath, KeyDir)
1821

1922
override suspend fun addKey(stringKey: String): Result<String, Throwable> = withContext(dispatcher) {
20-
return@withContext addKey(Key(stringKey))
23+
return@withContext addKey(Crypto.newKeyFromArmored(stringKey))
2124
}
2225

2326
override suspend fun addKey(key: Key): Result<String, Throwable> = withContext(dispatcher) {
2427
if (!keyDirExists()) return@withContext Err<Throwable>(IllegalStateException("Key directory does not exist"))
2528

2629
return@withContext runCatching {
2730
val keyFile = File(keyDir, "${key.hexKeyID}.key")
31+
if (keyFile.exists()) keyFile.delete()
32+
2833
keyFile.writeText(key.armor())
2934

3035
key.hexKeyID

crypto-pgp/src/main/kotlin/dev/msfjarvis/aps/data/crypto/GopenpgpCryptoHandler.kt

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@
55

66
package dev.msfjarvis.aps.data.crypto
77

8+
import com.github.michaelbull.result.unwrap
89
import com.proton.Gopenpgp.crypto.Crypto
10+
import com.proton.Gopenpgp.crypto.Key
911
import com.proton.Gopenpgp.helper.Helper
1012
import javax.inject.Inject
1113

1214
/** Gopenpgp backed implementation of [CryptoHandler]. */
13-
public class GopenpgpCryptoHandler @Inject constructor() : CryptoHandler {
15+
public class GopenpgpCryptoHandler @Inject constructor(
16+
private val gpgKeyManager: AndroidKeyManager
17+
) : CryptoHandler {
1418

1519
/**
1620
* Decrypt the given [ciphertext] using the given PGP [privateKey] and corresponding [passphrase].
@@ -34,4 +38,24 @@ public class GopenpgpCryptoHandler @Inject constructor() : CryptoHandler {
3438
plaintext,
3539
)
3640
}
41+
42+
43+
/**
44+
* TODO: Find a better place for this method
45+
* Utility method to decrypt the given [ciphertext] using the given PGP key [id] and corresponding [passphrase].
46+
*/
47+
public suspend fun decryptFromKeyId(
48+
id: String,
49+
passphrase: ByteArray,
50+
ciphertext: String,
51+
): ByteArray {
52+
// TODO(aditya): Handle error cases
53+
val key = gpgKeyManager.findKeyById(id).unwrap()
54+
val message = Crypto.newPGPMessageFromArmored(ciphertext)
55+
return Helper.decryptMessageArmored(
56+
key.armor(),
57+
passphrase,
58+
message.armored,
59+
).toByteArray()
60+
}
3761
}

0 commit comments

Comments
 (0)