diff options
author | Harsh Shandilya <me@msfjarvis.dev> | 2022-01-09 16:19:52 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-09 16:19:52 +0530 |
commit | 799f1393e49955d05f68b81af26d6cfaf9beadfd (patch) | |
tree | e1da29f5c1b3807016bea5f2f1d7046e92529e53 /crypto-pgpainless/src/main/kotlin | |
parent | ccb33af854132f1b35b71393ff68d24850de6960 (diff) |
Make CryptoHandler use Key as the abstraction layer (#1651)
Diffstat (limited to 'crypto-pgpainless/src/main/kotlin')
3 files changed, 64 insertions, 50 deletions
diff --git a/crypto-pgpainless/src/main/kotlin/dev/msfjarvis/aps/crypto/KeyUtils.kt b/crypto-pgpainless/src/main/kotlin/dev/msfjarvis/aps/crypto/KeyUtils.kt new file mode 100644 index 00000000..e7a3c387 --- /dev/null +++ b/crypto-pgpainless/src/main/kotlin/dev/msfjarvis/aps/crypto/KeyUtils.kt @@ -0,0 +1,54 @@ +/* + * Copyright © 2014-2022 The Android Password Store Authors. All Rights Reserved. + * SPDX-License-Identifier: GPL-3.0-only + */ + +package dev.msfjarvis.aps.crypto + +import com.github.michaelbull.result.get +import com.github.michaelbull.result.runCatching +import java.util.Locale +import org.bouncycastle.openpgp.PGPKeyRing +import org.pgpainless.PGPainless + +/** Utility methods to deal with PGP [Key]s. */ +public object KeyUtils { + /** + * Attempts to parse a [PGPKeyRing] from a given [key]. The key is first tried as a secret key and + * then as a public one before the method gives up and returns null. + */ + public fun tryParseKeyring(key: Key): PGPKeyRing? { + val secKeyRing = runCatching { PGPainless.readKeyRing().secretKeyRing(key.contents) }.get() + if (secKeyRing != null) { + return secKeyRing + } + val pubKeyRing = runCatching { PGPainless.readKeyRing().publicKeyRing(key.contents) }.get() + if (pubKeyRing != null) { + return pubKeyRing + } + return null + } + + /** Parses a [PGPKeyRing] from the given [key] and returns its hex-formatted key ID. */ + public fun tryGetId(key: Key): String? { + val keyRing = tryParseKeyring(key) ?: return null + return convertKeyIdToHex(keyRing.publicKey.keyID) + } + + /** Convert a [Long] key ID to a formatted string. */ + private fun convertKeyIdToHex(keyId: Long): String { + return "0x" + convertKeyIdToHex32bit(keyId shr 32) + convertKeyIdToHex32bit(keyId) + } + + /** + * Converts [keyId] to an unsigned [Long] then uses [java.lang.Long.toHexString] to convert it to + * a lowercase hex ID. + */ + private fun convertKeyIdToHex32bit(keyId: Long): String { + var hexString = java.lang.Long.toHexString(keyId and 0xffffffffL).lowercase(Locale.ENGLISH) + while (hexString.length < 8) { + hexString = "0$hexString" + } + return hexString + } +} diff --git a/crypto-pgpainless/src/main/kotlin/dev/msfjarvis/aps/crypto/PGPKeyManager.kt b/crypto-pgpainless/src/main/kotlin/dev/msfjarvis/aps/crypto/PGPKeyManager.kt index f1c53721..2053ecd7 100644 --- a/crypto-pgpainless/src/main/kotlin/dev/msfjarvis/aps/crypto/PGPKeyManager.kt +++ b/crypto-pgpainless/src/main/kotlin/dev/msfjarvis/aps/crypto/PGPKeyManager.kt @@ -8,15 +8,13 @@ package dev.msfjarvis.aps.crypto import androidx.annotation.VisibleForTesting import com.github.michaelbull.result.Result -import com.github.michaelbull.result.get import com.github.michaelbull.result.runCatching +import dev.msfjarvis.aps.crypto.KeyUtils.tryGetId +import dev.msfjarvis.aps.crypto.KeyUtils.tryParseKeyring import java.io.File -import java.util.Locale import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.withContext -import org.bouncycastle.openpgp.PGPKeyRing -import org.pgpainless.PGPainless import org.pgpainless.util.selection.userid.SelectUserId public class PGPKeyManager @@ -118,45 +116,6 @@ constructor( return keyDir.exists() || keyDir.mkdirs() } - /** - * Attempts to parse a [PGPKeyRing] from a given [key]. The key is first tried as a secret key and - * then as a public one before the method gives up and returns null. - */ - private fun tryParseKeyring(key: Key): PGPKeyRing? { - val secKeyRing = runCatching { PGPainless.readKeyRing().secretKeyRing(key.contents) }.get() - if (secKeyRing != null) { - return secKeyRing - } - val pubKeyRing = runCatching { PGPainless.readKeyRing().publicKeyRing(key.contents) }.get() - if (pubKeyRing != null) { - return pubKeyRing - } - return null - } - - /** Parses a [PGPKeyRing] from the given [key] and returns its hex-formatted key ID. */ - private fun tryGetId(key: Key): String? { - val keyRing = tryParseKeyring(key) ?: return null - return convertKeyIdToHex(keyRing.publicKey.keyID) - } - - /** Convert a [Long] key ID to a formatted string. */ - private fun convertKeyIdToHex(keyId: Long): String { - return "0x" + convertKeyIdToHex32bit(keyId shr 32) + convertKeyIdToHex32bit(keyId) - } - - /** - * Converts [keyId] to an unsigned [Long] then uses [java.lang.Long.toHexString] to convert it to - * a lowercase hex ID. - */ - private fun convertKeyIdToHex32bit(keyId: Long): String { - var hexString = java.lang.Long.toHexString(keyId and 0xffffffffL).lowercase(Locale.ENGLISH) - while (hexString.length < 8) { - hexString = "0$hexString" - } - return hexString - } - public companion object { @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) diff --git a/crypto-pgpainless/src/main/kotlin/dev/msfjarvis/aps/crypto/PGPainlessCryptoHandler.kt b/crypto-pgpainless/src/main/kotlin/dev/msfjarvis/aps/crypto/PGPainlessCryptoHandler.kt index 3276b995..427cd555 100644 --- a/crypto-pgpainless/src/main/kotlin/dev/msfjarvis/aps/crypto/PGPainlessCryptoHandler.kt +++ b/crypto-pgpainless/src/main/kotlin/dev/msfjarvis/aps/crypto/PGPainlessCryptoHandler.kt @@ -21,34 +21,35 @@ import org.pgpainless.util.Passphrase public class PGPainlessCryptoHandler @Inject constructor() : CryptoHandler { public override fun decrypt( - privateKey: String, - password: String, + privateKey: Key, + passphrase: String, ciphertextStream: InputStream, outputStream: OutputStream, ) { - val pgpSecretKeyRing = PGPainless.readKeyRing().secretKeyRing(privateKey) + val pgpSecretKeyRing = PGPainless.readKeyRing().secretKeyRing(privateKey.contents) val keyringCollection = PGPSecretKeyRingCollection(listOf(pgpSecretKeyRing)) val protector = PasswordBasedSecretKeyRingProtector.forKey( pgpSecretKeyRing, - Passphrase.fromPassword(password) + Passphrase.fromPassword(passphrase) ) PGPainless.decryptAndOrVerify() .onInputStream(ciphertextStream) .withOptions( ConsumerOptions() .addDecryptionKeys(keyringCollection, protector) - .addDecryptionPassphrase(Passphrase.fromPassword(password)) + .addDecryptionPassphrase(Passphrase.fromPassword(passphrase)) ) .use { decryptionStream -> decryptionStream.copyTo(outputStream) } } public override fun encrypt( - pubKeys: List<String>, + keys: List<Key>, plaintextStream: InputStream, outputStream: OutputStream, ) { - val pubKeysStream = ByteArrayInputStream(pubKeys.joinToString("\n").toByteArray()) + val armoredKeys = keys.map { key -> key.contents.decodeToString() } + val pubKeysStream = ByteArrayInputStream(armoredKeys.joinToString("\n").toByteArray()) val publicKeyRingCollection = pubKeysStream.use { ArmoredInputStream(it).use { armoredInputStream -> |