diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/KeyRingBuilder.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/KeyRingBuilder.kt index aacfcceb..ba043f05 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/KeyRingBuilder.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/KeyRingBuilder.kt @@ -45,6 +45,9 @@ class KeyRingBuilder : KeyRingBuilderInterface { } override fun addUserId(userId: CharSequence): KeyRingBuilder = apply { + require(!userId.contains("\n") && !userId.contains("\r")) { + "User-ID cannot contain newlines and/or carriage returns." + } userIds[userId.toString()] = null } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.kt index 5480442d..b012c216 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.kt @@ -569,10 +569,11 @@ class SecretKeyRingEditor( } private fun sanitizeUserId(userId: CharSequence): CharSequence = - // I'm not sure, what kind of sanitization is needed. - // Newlines are allowed, they just need to be escaped when emitted in an ASCII armor header - // Trailing/Leading whitespace is also fine. - userId.toString() + userId.toString().also { + require(!it.contains("\n") && !it.contains("\r")) { + "UserId cannot contain newlines and/or carriage returns." + } + } private fun callbackFromRevocationAttributes(attributes: RevocationAttributes?) = object : RevocationSignatureSubpackets.Callback { diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/util/ArmorUtils.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/util/ArmorUtils.kt index b6e802b2..b5d5b839 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/util/ArmorUtils.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/util/ArmorUtils.kt @@ -247,8 +247,7 @@ class ArmorUtils { .add(OpenPgpFingerprint.of(publicKey).prettyPrint()) // Primary / First User ID (primary ?: first)?.let { - headerMap.getOrPut(HEADER_COMMENT) { mutableSetOf() } - .add(it.replace("\n", "\\n").replace("\r", "\\r")) + headerMap.getOrPut(HEADER_COMMENT) { mutableSetOf() }.add(it) } // X-1 further identities when (userIds.size) { diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/util/Passphrase.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/util/Passphrase.kt index bd25f2b9..395198ed 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/util/Passphrase.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/util/Passphrase.kt @@ -11,9 +11,14 @@ import org.bouncycastle.util.Arrays * * @param chars may be null for empty passwords. */ -class Passphrase(private val chars: CharArray?) { +class Passphrase(chars: CharArray?) { private val lock = Any() private var valid = true + private val chars: CharArray? + + init { + this.chars = chars;//trimWhitespace(chars) + } /** * Return a copy of the underlying char array. A return value of null represents an empty @@ -62,11 +67,6 @@ class Passphrase(private val chars: CharArray?) { override fun hashCode(): Int = getChars()?.let { String(it) }.hashCode() - /** - * Return a copy of this [Passphrase], but with whitespace characters trimmed off. - * - * @return copy with trimmed whitespace - */ fun withTrimmedWhitespace(): Passphrase = Passphrase(trimWhitespace(chars)) companion object { diff --git a/pgpainless-sop/src/test/java/org/pgpainless/sop/GenerateKeyTest.java b/pgpainless-sop/src/test/java/org/pgpainless/sop/GenerateKeyTest.java index 521cdfe0..ca6df790 100644 --- a/pgpainless-sop/src/test/java/org/pgpainless/sop/GenerateKeyTest.java +++ b/pgpainless-sop/src/test/java/org/pgpainless/sop/GenerateKeyTest.java @@ -100,14 +100,4 @@ public class GenerateKeyTest { assertThrows(SOPGPException.UnsupportedProfile.class, () -> sop.generateKey().profile("invalid")); } - - @Test - public void generateKeyWithNewlinesInUserId() throws IOException { - byte[] keyBytes = sop.generateKey() - .userId("Foo\n\nBar") - .generate() - .getBytes(); - - assertTrue(new String(keyBytes).contains("Foo\\n\\nBar")); - } }