aboutsummaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'crypto')
-rw-r--r--crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/KeyUtils.kt7
-rw-r--r--crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/KeyUtilsTest.kt19
2 files changed, 25 insertions, 1 deletions
diff --git a/crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/KeyUtils.kt b/crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/KeyUtils.kt
index f85fe92c..311e9049 100644
--- a/crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/KeyUtils.kt
+++ b/crypto/pgpainless/src/main/kotlin/app/passwordstore/crypto/KeyUtils.kt
@@ -10,6 +10,7 @@ import app.passwordstore.crypto.PGPIdentifier.UserId
import com.github.michaelbull.result.get
import com.github.michaelbull.result.runCatching
import org.bouncycastle.openpgp.PGPKeyRing
+import org.bouncycastle.openpgp.PGPSecretKeyRing
import org.pgpainless.PGPainless
import org.pgpainless.key.parsing.KeyRingReader
@@ -35,9 +36,13 @@ public object KeyUtils {
*/
public fun tryGetEmail(key: PGPKey): UserId? {
val keyRing = tryParseKeyring(key) ?: return null
- return UserId(keyRing.publicKey.userIDs.next())
+ // A key may carry no user ID at all: next() threw NoSuchElementException there.
+ return keyRing.publicKey.userIDs.asSequence().firstOrNull()?.let(::UserId)
}
+ /** True when [key] parses as a secret key ring, the only kind that can decrypt. */
+ public fun isSecretKey(key: PGPKey): Boolean = tryParseKeyring(key) is PGPSecretKeyRing
+
/**
* Tests if the given [key] can be used for encryption, which is a bare minimum necessity for the
* app.
diff --git a/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/KeyUtilsTest.kt b/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/KeyUtilsTest.kt
index e6e3d7d1..3281c334 100644
--- a/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/KeyUtilsTest.kt
+++ b/crypto/pgpainless/src/test/kotlin/app/passwordstore/crypto/KeyUtilsTest.kt
@@ -6,14 +6,18 @@
package app.passwordstore.crypto
import app.passwordstore.crypto.KeyUtils.isKeyUsable
+import app.passwordstore.crypto.KeyUtils.isSecretKey
+import app.passwordstore.crypto.KeyUtils.tryGetEmail
import app.passwordstore.crypto.KeyUtils.tryGetId
import app.passwordstore.crypto.KeyUtils.tryParseKeyring
import app.passwordstore.crypto.TestUtils.AllKeys
import app.passwordstore.crypto.TestUtils.getArmoredSecretKeyWithMultipleIdentities
import kotlin.test.Test
import kotlin.test.assertEquals
+import kotlin.test.assertFalse
import kotlin.test.assertIs
import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
import org.bouncycastle.openpgp.PGPSecretKeyRing
class KeyUtilsTest {
@@ -37,4 +41,19 @@ class KeyUtilsTest {
assertEquals(isUsable, isKeyUsable(key), "${allKeys.name} failed expectation:")
}
}
+
+ @Test
+ fun secretKeysAreTold() {
+ assertTrue(isSecretKey(PGPKey(AllKeys.ARMORED_SEC.keyMaterial)))
+ assertTrue(isSecretKey(PGPKey(AllKeys.GNUPG_OCB_SEC.keyMaterial)))
+ assertFalse(isSecretKey(PGPKey(AllKeys.ARMORED_PUB.keyMaterial)))
+ assertFalse(isSecretKey(PGPKey("not a key".encodeToByteArray())))
+ }
+
+ @Test
+ fun firstUserIdIsReturned() {
+ val key = PGPKey(getArmoredSecretKeyWithMultipleIdentities())
+ assertNotNull(tryGetEmail(key))
+ assertEquals(null, tryGetEmail(PGPKey("not a key".encodeToByteArray())))
+ }
}