diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/GenerateOpenPgpKey.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/GenerateOpenPgpKey.kt index 726ff644..ea899c2b 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/GenerateOpenPgpKey.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/GenerateOpenPgpKey.kt @@ -4,8 +4,10 @@ package org.pgpainless.key.generation -import org.bouncycastle.bcpg.attr.ImageAttribute +import java.io.IOException +import java.io.InputStream import java.util.* +import org.bouncycastle.bcpg.attr.ImageAttribute import org.bouncycastle.openpgp.PGPSecretKey import org.bouncycastle.openpgp.PGPSecretKeyRing import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector @@ -19,8 +21,6 @@ import org.pgpainless.key.generation.type.KeyType import org.pgpainless.key.protection.SecretKeyRingProtector import org.pgpainless.policy.Policy import org.pgpainless.signature.subpackets.SelfSignatureSubpackets -import java.io.File -import java.io.IOException /** * OpenPGP key builder. This implementation supersedes the old [KeyRingBuilder]. @@ -41,16 +41,14 @@ open class GenerateOpenPgpKey( protected val preferences: AlgorithmSuite ) { - /** - * Make sure, that the chosen [KeyType] is allowed. - */ + /** Make sure, that the chosen [KeyType] is allowed. */ open fun sanitizePublicKeyAlgorithms(keyType: KeyType, policy: Policy) { verifyAlgorithmComplianceWithPolicy(keyType, policy) } /** - * Make sure, that the chosen [KeyType] complies to the given [Policy] by comparing it to the - * [Policy.PublicKeyAlgorithmPolicy]. + * Make sure, that the chosen [KeyType] complies to the given [Policy] by comparing it to + * the [Policy.PublicKeyAlgorithmPolicy]. * * @throws IllegalArgumentException if [keyType] fails to be accepted by [policy] */ @@ -73,7 +71,8 @@ open class GenerateOpenPgpKey( fun buildV4Key( keyType: KeyType, flags: List? = listOf(KeyFlag.CERTIFY_OTHER) - ): V4GenerateOpenPgpKey = V4GenerateOpenPgpKey(keyType, flags, policy, referenceTime, preferences) + ): V4GenerateOpenPgpKey = + V4GenerateOpenPgpKey(keyType, flags, policy, referenceTime, preferences) /** * Builder for version 4 OpenPGP keys. @@ -146,24 +145,22 @@ open class GenerateOpenPgpKey( } /** - * Add the contents of a JPEG file as image attribute to the key. + * Add the contents of a JPEG input stream as image attribute to the key. * - * @param jpegFile file containing a JPEG image - * @param subpacketsCallback callback to modify the user-attribute binding signature subpackets. + * @param jpegInputStream input stream containing a JPEG image + * @param subpacketsCallback callback to modify the user-attribute binding signature + * subpackets. * @return this */ @Throws(IOException::class) fun addJpegImage( - jpegFile: File, + jpegInputStream: InputStream, subpacketsCallback: SelfSignatureSubpackets.Callback = SelfSignatureSubpackets.nop() ) = apply { - jpegFile.inputStream() - .let { Streams.readAll(it) } - .let { - PGPUserAttributeSubpacketVectorGenerator().apply { - setImageAttribute(ImageAttribute.JPEG, it) - }.generate() - }.let { addUserAttribute(it, subpacketsCallback) } + PGPUserAttributeSubpacketVectorGenerator() + .apply { setImageAttribute(ImageAttribute.JPEG, Streams.readAll(jpegInputStream)) } + .generate() + .let { addUserAttribute(it, subpacketsCallback) } } /** diff --git a/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/GenerateOpenPgpKeyTest.kt b/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/GenerateOpenPgpKeyTest.kt index 978924c4..20cf8ba2 100644 --- a/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/GenerateOpenPgpKeyTest.kt +++ b/pgpainless-core/src/test/kotlin/org/pgpainless/key/generation/GenerateOpenPgpKeyTest.kt @@ -1,9 +1,15 @@ +// SPDX-FileCopyrightText: 2024 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + package org.pgpainless.key.generation import org.bouncycastle.bcpg.attr.ImageAttribute import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVectorGenerator +import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows +import org.opentest4j.TestAbortedException import org.pgpainless.PGPainless import org.pgpainless.algorithm.KeyFlag import org.pgpainless.algorithm.PublicKeyAlgorithm @@ -14,6 +20,7 @@ import org.pgpainless.key.generation.type.xdh.XDHSpec import org.pgpainless.key.protection.SecretKeyRingProtector import org.pgpainless.policy.Policy import org.pgpainless.util.DateUtil +import java.io.InputStream class GenerateOpenPgpKeyTest { @@ -27,7 +34,8 @@ class GenerateOpenPgpKeyTest { .addUserAttribute( PGPUserAttributeSubpacketVectorGenerator() .apply { setImageAttribute(ImageAttribute.JPEG, byteArrayOf()) } - .generate()) + .generate(), + ) .addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519)) .addSigningSubkey(KeyType.EDDSA(EdDSACurve._Ed25519)) .build(SecretKeyRingProtector.unprotectedKeys()) @@ -59,7 +67,8 @@ class GenerateOpenPgpKeyTest { val policy = Policy( publicKeyAlgorithmPolicy = - Policy.PublicKeyAlgorithmPolicy(mapOf(PublicKeyAlgorithm.RSA_GENERAL to 4096))) + Policy.PublicKeyAlgorithmPolicy(mapOf(PublicKeyAlgorithm.RSA_GENERAL to 4096)), + ) val builder = GenerateOpenPgpKey(policy) assertThrows { @@ -74,8 +83,17 @@ class GenerateOpenPgpKeyTest { @Test fun testKeyGenerationWithJPEGAttribute() { - GenerateOpenPgpKey(Policy.getInstance()) + val key = GenerateOpenPgpKey(Policy.getInstance()) .buildV4Key(KeyType.EDDSA(EdDSACurve._Ed25519)) - .addJpegImage() + .addJpegImage(requireResource("suzanne.jpg")) + .build() + + assertTrue(key.publicKey.userAttributes.hasNext()) + } + + private fun requireResource(resourceName: String): InputStream { + return javaClass.classLoader.getResourceAsStream(resourceName) + ?: throw TestAbortedException( + "Cannot read resource $resourceName: InputStream is null.") } } diff --git a/pgpainless-core/src/test/resources/suzanne.jpg b/pgpainless-core/src/test/resources/suzanne.jpg new file mode 100644 index 00000000..c343ef09 Binary files /dev/null and b/pgpainless-core/src/test/resources/suzanne.jpg differ