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

Commit d65fc88

Browse files
authored
Reimplement PGPainless encryption logic (#1955)
* crypto-pgpainless: reimplement encryption logic * crypto-pgpainless: add an explicit error type for empty keyset
1 parent 2ba3a08 commit d65fc88

File tree

2 files changed

+24
-12
lines changed

2 files changed

+24
-12
lines changed

crypto-common/src/main/kotlin/dev/msfjarvis/aps/crypto/errors/CryptoException.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,8 @@ public sealed class CryptoHandlerException(message: String? = null, cause: Throw
3737
/** The passphrase provided for decryption was incorrect. */
3838
public class IncorrectPassphraseException(cause: Throwable) : CryptoHandlerException(null, cause)
3939

40+
/** No keys were provided for encryption. */
41+
public class NoKeysProvided(message: String?) : CryptoHandlerException(message, null)
42+
4043
/** An unexpected error that cannot be mapped to a known type. */
4144
public class UnknownError(cause: Throwable) : CryptoHandlerException(null, cause)

crypto-pgpainless/src/main/kotlin/dev/msfjarvis/aps/crypto/PGPainlessCryptoHandler.kt

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ import com.github.michaelbull.result.mapError
1010
import com.github.michaelbull.result.runCatching
1111
import dev.msfjarvis.aps.crypto.errors.CryptoHandlerException
1212
import dev.msfjarvis.aps.crypto.errors.IncorrectPassphraseException
13+
import dev.msfjarvis.aps.crypto.errors.NoKeysProvided
1314
import dev.msfjarvis.aps.crypto.errors.UnknownError
1415
import java.io.ByteArrayInputStream
1516
import java.io.InputStream
1617
import java.io.OutputStream
1718
import javax.inject.Inject
18-
import org.bouncycastle.bcpg.ArmoredInputStream
1919
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection
2020
import org.pgpainless.PGPainless
2121
import org.pgpainless.decryption_verification.ConsumerOptions
@@ -64,24 +64,33 @@ public class PGPainlessCryptoHandler @Inject constructor() : CryptoHandler<PGPKe
6464
outputStream: OutputStream,
6565
): Result<Unit, CryptoHandlerException> =
6666
runCatching {
67+
if (keys.isEmpty()) throw NoKeysProvided("No keys provided for encryption")
6768
val armoredKeys = keys.map { key -> key.contents.decodeToString() }
6869
val pubKeysStream = ByteArrayInputStream(armoredKeys.joinToString("\n").toByteArray())
6970
val publicKeyRingCollection =
70-
pubKeysStream.use {
71-
ArmoredInputStream(it).use { armoredInputStream ->
72-
PGPainless.readKeyRing().publicKeyRingCollection(armoredInputStream)
73-
}
71+
pubKeysStream.use { PGPainless.readKeyRing().publicKeyRingCollection(pubKeysStream) }
72+
val encryptionOptions =
73+
EncryptionOptions.encryptCommunications()
74+
.addRecipients(publicKeyRingCollection.asIterable())
75+
val producerOptions = ProducerOptions.encrypt(encryptionOptions).setAsciiArmor(true)
76+
val encryptor =
77+
PGPainless.encryptAndOrSign().onOutputStream(outputStream).withOptions(producerOptions)
78+
plaintextStream.copyTo(encryptor)
79+
encryptor.close()
80+
val result = encryptor.result
81+
publicKeyRingCollection.keyRings.forEach { keyRing ->
82+
require(result.isEncryptedFor(keyRing)) {
83+
"Stream should be encrypted for ${keyRing.publicKey.keyID} but wasn't"
7484
}
75-
val encOpt =
76-
EncryptionOptions().apply { publicKeyRingCollection.forEach { addRecipient(it) } }
77-
val prodOpt = ProducerOptions.encrypt(encOpt).setAsciiArmor(true)
78-
PGPainless.encryptAndOrSign().onOutputStream(outputStream).withOptions(prodOpt).use {
79-
encryptionStream ->
80-
plaintextStream.copyTo(encryptionStream)
8185
}
8286
return@runCatching
8387
}
84-
.mapError { error -> UnknownError(error) }
88+
.mapError { error ->
89+
when (error) {
90+
is CryptoHandlerException -> error
91+
else -> UnknownError(error)
92+
}
93+
}
8594

8695
public override fun canHandle(fileName: String): Boolean {
8796
return fileName.split('.').lastOrNull() == "gpg"

0 commit comments

Comments
 (0)