summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/src/main/java/app/passwordstore/data/crypto/CryptoRepository.kt7
-rw-r--r--crypto-common/src/main/kotlin/app/passwordstore/crypto/CryptoHandler.kt4
-rw-r--r--crypto-common/src/main/kotlin/app/passwordstore/crypto/CryptoOptions.kt8
-rw-r--r--crypto-pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPDecryptOptions.kt21
-rw-r--r--crypto-pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPEncryptOptions.kt35
-rw-r--r--crypto-pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandler.kt5
-rw-r--r--crypto-pgpainless/src/test/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandlerTest.kt4
7 files changed, 81 insertions, 3 deletions
diff --git a/app/src/main/java/app/passwordstore/data/crypto/CryptoRepository.kt b/app/src/main/java/app/passwordstore/data/crypto/CryptoRepository.kt
index b673e94c..233dedef 100644
--- a/app/src/main/java/app/passwordstore/data/crypto/CryptoRepository.kt
+++ b/app/src/main/java/app/passwordstore/data/crypto/CryptoRepository.kt
@@ -6,6 +6,8 @@
package app.passwordstore.data.crypto
import app.passwordstore.crypto.GpgIdentifier
+import app.passwordstore.crypto.PGPDecryptOptions
+import app.passwordstore.crypto.PGPEncryptOptions
import app.passwordstore.crypto.PGPKeyManager
import app.passwordstore.crypto.PGPainlessCryptoHandler
import app.passwordstore.crypto.errors.CryptoHandlerException
@@ -42,8 +44,9 @@ constructor(
message: ByteArrayInputStream,
out: ByteArrayOutputStream,
): Result<Unit, CryptoHandlerException> {
+ val decryptionOptions = PGPDecryptOptions.Builder().build()
val keys = pgpKeyManager.getAllKeys().unwrap()
- return pgpCryptoHandler.decrypt(keys, password, message, out)
+ return pgpCryptoHandler.decrypt(keys, password, message, out, decryptionOptions)
}
private suspend fun encryptPgp(
@@ -51,11 +54,13 @@ constructor(
content: ByteArrayInputStream,
out: ByteArrayOutputStream,
): Result<Unit, CryptoHandlerException> {
+ val encryptionOptions = PGPEncryptOptions.Builder().build()
val keys = identities.map { id -> pgpKeyManager.getKeyById(id) }.getAll()
return pgpCryptoHandler.encrypt(
keys,
content,
out,
+ encryptionOptions,
)
}
}
diff --git a/crypto-common/src/main/kotlin/app/passwordstore/crypto/CryptoHandler.kt b/crypto-common/src/main/kotlin/app/passwordstore/crypto/CryptoHandler.kt
index ea42af6d..898cf058 100644
--- a/crypto-common/src/main/kotlin/app/passwordstore/crypto/CryptoHandler.kt
+++ b/crypto-common/src/main/kotlin/app/passwordstore/crypto/CryptoHandler.kt
@@ -11,7 +11,7 @@ import java.io.InputStream
import java.io.OutputStream
/** Generic interface to implement cryptographic operations on top of. */
-public interface CryptoHandler<Key> {
+public interface CryptoHandler<Key, EncOpts : CryptoOptions, DecryptOpts : CryptoOptions> {
/**
* Decrypt the given [ciphertextStream] using a set of potential [keys] and [passphrase], and
@@ -24,6 +24,7 @@ public interface CryptoHandler<Key> {
passphrase: String,
ciphertextStream: InputStream,
outputStream: OutputStream,
+ options: DecryptOpts,
): Result<Unit, CryptoHandlerException>
/**
@@ -35,6 +36,7 @@ public interface CryptoHandler<Key> {
keys: List<Key>,
plaintextStream: InputStream,
outputStream: OutputStream,
+ options: EncOpts,
): Result<Unit, CryptoHandlerException>
/** Given a [fileName], return whether this instance can handle it. */
diff --git a/crypto-common/src/main/kotlin/app/passwordstore/crypto/CryptoOptions.kt b/crypto-common/src/main/kotlin/app/passwordstore/crypto/CryptoOptions.kt
new file mode 100644
index 00000000..1e60cdba
--- /dev/null
+++ b/crypto-common/src/main/kotlin/app/passwordstore/crypto/CryptoOptions.kt
@@ -0,0 +1,8 @@
+package app.passwordstore.crypto
+
+/** Defines the contract for a grab-bag of options for individual cryptographic operations. */
+public interface CryptoOptions {
+
+ /** Returns a [Boolean] indicating if the [option] is enabled for this operation. */
+ public fun isOptionEnabled(option: String): Boolean
+}
diff --git a/crypto-pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPDecryptOptions.kt b/crypto-pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPDecryptOptions.kt
new file mode 100644
index 00000000..15ce92f0
--- /dev/null
+++ b/crypto-pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPDecryptOptions.kt
@@ -0,0 +1,21 @@
+package app.passwordstore.crypto
+
+/** [CryptoOptions] implementation for PGPainless decrypt operations. */
+public class PGPDecryptOptions
+private constructor(
+ private val values: Map<String, Boolean>,
+) : CryptoOptions {
+
+ override fun isOptionEnabled(option: String): Boolean {
+ return values.getOrDefault(option, false)
+ }
+
+ /** Implementation of a builder pattern for [PGPDecryptOptions]. */
+ public class Builder {
+
+ /** Build the final [PGPDecryptOptions] object. */
+ public fun build(): PGPDecryptOptions {
+ return PGPDecryptOptions(emptyMap())
+ }
+ }
+}
diff --git a/crypto-pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPEncryptOptions.kt b/crypto-pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPEncryptOptions.kt
new file mode 100644
index 00000000..90de6b51
--- /dev/null
+++ b/crypto-pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPEncryptOptions.kt
@@ -0,0 +1,35 @@
+package app.passwordstore.crypto
+
+/** [CryptoOptions] implementation for PGPainless encrypt operations. */
+public class PGPEncryptOptions
+private constructor(
+ private val values: Map<String, Boolean>,
+) : CryptoOptions {
+
+ internal companion object {
+ const val ASCII_ARMOR = "ASCII_ARMOR"
+ }
+
+ override fun isOptionEnabled(option: String): Boolean {
+ return values.getOrDefault(option, false)
+ }
+
+ /** Implementation of a builder pattern for [PGPEncryptOptions]. */
+ public class Builder {
+ private val optionsMap = mutableMapOf<String, Boolean>()
+
+ /**
+ * Toggle whether the encryption operation output will be ASCII armored or in OpenPGP's binary
+ * format.
+ */
+ public fun withAsciiArmor(enabled: Boolean): Builder {
+ optionsMap[ASCII_ARMOR] = enabled
+ return this
+ }
+
+ /** Build the final [PGPEncryptOptions] object. */
+ public fun build(): PGPEncryptOptions {
+ return PGPEncryptOptions(optionsMap)
+ }
+ }
+}
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 faa94dff..91c17004 100644
--- a/crypto-pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandler.kt
+++ b/crypto-pgpainless/src/main/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandler.kt
@@ -27,13 +27,15 @@ import org.pgpainless.exception.WrongPassphraseException
import org.pgpainless.key.protection.SecretKeyRingProtector
import org.pgpainless.util.Passphrase
-public class PGPainlessCryptoHandler @Inject constructor() : CryptoHandler<PGPKey> {
+public class PGPainlessCryptoHandler @Inject constructor() :
+ CryptoHandler<PGPKey, PGPEncryptOptions, PGPDecryptOptions> {
public override fun decrypt(
keys: List<PGPKey>,
passphrase: String,
ciphertextStream: InputStream,
outputStream: OutputStream,
+ options: PGPDecryptOptions,
): Result<Unit, CryptoHandlerException> =
runCatching {
if (keys.isEmpty()) throw NoKeysProvided("No keys provided for encryption")
@@ -63,6 +65,7 @@ public class PGPainlessCryptoHandler @Inject constructor() : CryptoHandler<PGPKe
keys: List<PGPKey>,
plaintextStream: InputStream,
outputStream: OutputStream,
+ options: PGPEncryptOptions,
): Result<Unit, CryptoHandlerException> =
runCatching {
if (keys.isEmpty()) throw NoKeysProvided("No keys provided for encryption")
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 80c8dc7c..386ca72b 100644
--- a/crypto-pgpainless/src/test/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandlerTest.kt
+++ b/crypto-pgpainless/src/test/kotlin/app/passwordstore/crypto/PGPainlessCryptoHandlerTest.kt
@@ -41,6 +41,7 @@ class PGPainlessCryptoHandlerTest {
encryptionKey.keySet,
CryptoConstants.PLAIN_TEXT.byteInputStream(Charsets.UTF_8),
ciphertextStream,
+ PGPEncryptOptions.Builder().build(),
)
assertIs<Ok<Unit>>(encryptRes)
val plaintextStream = ByteArrayOutputStream()
@@ -50,6 +51,7 @@ class PGPainlessCryptoHandlerTest {
CryptoConstants.KEY_PASSPHRASE,
ciphertextStream.toByteArray().inputStream(),
plaintextStream,
+ PGPDecryptOptions.Builder().build(),
)
assertIs<Ok<Unit>>(decryptRes)
assertEquals(CryptoConstants.PLAIN_TEXT, plaintextStream.toString(Charsets.UTF_8))
@@ -63,6 +65,7 @@ class PGPainlessCryptoHandlerTest {
encryptionKey.keySet,
CryptoConstants.PLAIN_TEXT.byteInputStream(Charsets.UTF_8),
ciphertextStream,
+ PGPEncryptOptions.Builder().build(),
)
assertIs<Ok<Unit>>(encryptRes)
val plaintextStream = ByteArrayOutputStream()
@@ -72,6 +75,7 @@ class PGPainlessCryptoHandlerTest {
"very incorrect passphrase",
ciphertextStream.toByteArray().inputStream(),
plaintextStream,
+ PGPDecryptOptions.Builder().build(),
)
assertIs<Err<Throwable>>(result)
assertIs<IncorrectPassphraseException>(result.getError())