1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2025-09-09 10:19:39 +02:00

SOP generate-key: Implement additional profiles

This commit is contained in:
Paul Schaub 2025-05-30 14:21:43 +02:00
parent e45b551ab3
commit 0027a3ed24
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
3 changed files with 90 additions and 12 deletions

View file

@ -21,6 +21,8 @@ import org.pgpainless.key.generation.KeySpec;
import org.pgpainless.key.generation.type.KeyType; import org.pgpainless.key.generation.type.KeyType;
import org.pgpainless.key.generation.type.eddsa_legacy.EdDSALegacyCurve; import org.pgpainless.key.generation.type.eddsa_legacy.EdDSALegacyCurve;
import org.pgpainless.key.generation.type.xdh_legacy.XDHLegacySpec; import org.pgpainless.key.generation.type.xdh_legacy.XDHLegacySpec;
import org.pgpainless.sop.EncryptImpl;
import org.pgpainless.sop.GenerateKeyImpl;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sop.exception.SOPGPException; import sop.exception.SOPGPException;
@ -647,7 +649,7 @@ public class RoundTripEncryptDecryptCmdTest extends CLITest {
// Generate key // Generate key
File passwordFile = writeFile("password", "sw0rdf1sh"); File passwordFile = writeFile("password", "sw0rdf1sh");
File keyFile = pipeStdoutToFile("key.asc"); File keyFile = pipeStdoutToFile("key.asc");
assertSuccess(executeCommand("generate-key", "--profile=rfc4880", "--with-key-password", passwordFile.getAbsolutePath(), "Alice <alice@example.org>")); assertSuccess(executeCommand("generate-key", "--profile=" + GenerateKeyImpl.RFC4880_RSA4096_PROFILE.getName(), "--with-key-password", passwordFile.getAbsolutePath(), "Alice <alice@example.org>"));
File certFile = pipeStdoutToFile("cert.asc"); File certFile = pipeStdoutToFile("cert.asc");
pipeFileToStdin(keyFile); pipeFileToStdin(keyFile);
@ -659,7 +661,7 @@ public class RoundTripEncryptDecryptCmdTest extends CLITest {
// Encrypt // Encrypt
File ciphertextFile = pipeStdoutToFile("msg.asc"); File ciphertextFile = pipeStdoutToFile("msg.asc");
pipeFileToStdin(plaintextFile); pipeFileToStdin(plaintextFile);
assertSuccess(executeCommand("encrypt", "--profile=rfc4880", certFile.getAbsolutePath())); assertSuccess(executeCommand("encrypt", "--profile=" + EncryptImpl.RFC4880_PROFILE.getName(), certFile.getAbsolutePath()));
ByteArrayOutputStream decrypted = pipeStdoutToStream(); ByteArrayOutputStream decrypted = pipeStdoutToStream();
pipeFileToStdin(ciphertextFile); pipeFileToStdin(ciphertextFile);

View file

@ -19,6 +19,7 @@ import org.pgpainless.bouncycastle.extensions.encode
import org.pgpainless.key.generation.KeyRingBuilder import org.pgpainless.key.generation.KeyRingBuilder
import org.pgpainless.key.generation.KeySpec import org.pgpainless.key.generation.KeySpec
import org.pgpainless.key.generation.type.KeyType import org.pgpainless.key.generation.type.KeyType
import org.pgpainless.key.generation.type.ecc.EllipticCurve
import org.pgpainless.key.generation.type.eddsa_legacy.EdDSALegacyCurve import org.pgpainless.key.generation.type.eddsa_legacy.EdDSALegacyCurve
import org.pgpainless.key.generation.type.rsa.RsaLength import org.pgpainless.key.generation.type.rsa.RsaLength
import org.pgpainless.key.generation.type.xdh_legacy.XDHLegacySpec import org.pgpainless.key.generation.type.xdh_legacy.XDHLegacySpec
@ -34,17 +35,24 @@ class GenerateKeyImpl(private val api: PGPainless) : GenerateKey {
companion object { companion object {
@JvmField @JvmField
val CURVE25519_PROFILE = val CURVE25519_PROFILE =
Profile( Profile("draft-koch-eddsa-for-openpgp-00", "OpenPGP v4 keys over Curve25519")
"draft-koch-eddsa-for-openpgp-00", "Generate EdDSA / ECDH keys using Curve25519") @JvmField
@JvmField val RSA4096_PROFILE = Profile("rfc4880", "Generate 4096-bit RSA keys") val RFC4880_RSA4096_PROFILE = Profile("rfc4880-rsa4096", "OpenPGP v4 keys with RSA 4096")
@JvmField val RFC9580_PROFILE = Profile("rfc9580", "Generate OpenPGP v6 keys") @JvmField val RFC6637_NIST_P256_PROFILE = Profile("rfc6637-nist-p256")
@JvmField val RFC6637_NIST_P384_PROFILE = Profile("rfc6637-nist-p384")
@JvmField val RFC6637_NIST_P521_PROFILE = Profile("rfc6637-nist-p521")
@JvmField
val RFC9580_CURVE25519_PROFILE =
Profile("rfc9580-curve25519", "OpenPGP v6 keys over Curve25519")
@JvmField
val RFC9580_CURVE448_PROFILE = Profile("rfc9580-curve448", "OpenPGP v6 keys over Curve448")
@JvmField @JvmField
val SUPPORTED_PROFILES = val SUPPORTED_PROFILES =
listOf( listOf(
CURVE25519_PROFILE.withAliases("default", "compatibility"), CURVE25519_PROFILE.withAliases("default", "compatibility"),
RSA4096_PROFILE, RFC4880_RSA4096_PROFILE,
RFC9580_PROFILE.withAliases("performance", "security")) RFC9580_CURVE25519_PROFILE.withAliases("performance", "security"))
} }
private val userIds = mutableSetOf<String>() private val userIds = mutableSetOf<String>()
@ -116,7 +124,7 @@ class GenerateKeyImpl(private val api: PGPainless) : GenerateKey {
KeyFlag.ENCRYPT_STORAGE)) KeyFlag.ENCRYPT_STORAGE))
} }
} }
RSA4096_PROFILE.name -> { RFC4880_RSA4096_PROFILE.name -> {
api.buildKey(OpenPGPKeyVersion.v4) api.buildKey(OpenPGPKeyVersion.v4)
.setPrimaryKey( .setPrimaryKey(
KeySpec.getBuilder(KeyType.RSA(RsaLength._4096), KeyFlag.CERTIFY_OTHER)) KeySpec.getBuilder(KeyType.RSA(RsaLength._4096), KeyFlag.CERTIFY_OTHER))
@ -132,7 +140,61 @@ class GenerateKeyImpl(private val api: PGPainless) : GenerateKey {
} }
} }
} }
RFC9580_PROFILE.name -> { RFC6637_NIST_P256_PROFILE.name -> {
api.buildKey(OpenPGPKeyVersion.v4)
.setPrimaryKey(
KeySpec.getBuilder(
KeyType.ECDSA(EllipticCurve._P256), KeyFlag.CERTIFY_OTHER))
.addSubkey(
KeySpec.getBuilder(
KeyType.ECDSA(EllipticCurve._P256), KeyFlag.SIGN_DATA))
.apply {
if (!signingOnly) {
addSubkey(
KeySpec.getBuilder(
KeyType.ECDH(EllipticCurve._P256),
KeyFlag.ENCRYPT_COMMS,
KeyFlag.ENCRYPT_STORAGE))
}
}
}
RFC6637_NIST_P384_PROFILE.name -> {
api.buildKey(OpenPGPKeyVersion.v4)
.setPrimaryKey(
KeySpec.getBuilder(
KeyType.ECDSA(EllipticCurve._P384), KeyFlag.CERTIFY_OTHER))
.addSubkey(
KeySpec.getBuilder(
KeyType.ECDSA(EllipticCurve._P384), KeyFlag.SIGN_DATA))
.apply {
if (!signingOnly) {
addSubkey(
KeySpec.getBuilder(
KeyType.ECDH(EllipticCurve._P384),
KeyFlag.ENCRYPT_COMMS,
KeyFlag.ENCRYPT_STORAGE))
}
}
}
RFC6637_NIST_P521_PROFILE.name -> {
api.buildKey(OpenPGPKeyVersion.v4)
.setPrimaryKey(
KeySpec.getBuilder(
KeyType.ECDSA(EllipticCurve._P521), KeyFlag.CERTIFY_OTHER))
.addSubkey(
KeySpec.getBuilder(
KeyType.ECDSA(EllipticCurve._P521), KeyFlag.SIGN_DATA))
.apply {
if (!signingOnly) {
addSubkey(
KeySpec.getBuilder(
KeyType.ECDH(EllipticCurve._P521),
KeyFlag.ENCRYPT_COMMS,
KeyFlag.ENCRYPT_STORAGE))
}
}
}
RFC9580_CURVE25519_PROFILE.name -> {
api.buildKey(OpenPGPKeyVersion.v6) api.buildKey(OpenPGPKeyVersion.v6)
.setPrimaryKey(KeySpec.getBuilder(KeyType.Ed25519(), KeyFlag.CERTIFY_OTHER)) .setPrimaryKey(KeySpec.getBuilder(KeyType.Ed25519(), KeyFlag.CERTIFY_OTHER))
.addSubkey(KeySpec.getBuilder(KeyType.Ed25519(), KeyFlag.SIGN_DATA)) .addSubkey(KeySpec.getBuilder(KeyType.Ed25519(), KeyFlag.SIGN_DATA))
@ -146,6 +208,20 @@ class GenerateKeyImpl(private val api: PGPainless) : GenerateKey {
} }
} }
} }
RFC9580_CURVE448_PROFILE.name -> {
api.buildKey(OpenPGPKeyVersion.v6)
.setPrimaryKey(KeySpec.getBuilder(KeyType.Ed448(), KeyFlag.CERTIFY_OTHER))
.addSubkey(KeySpec.getBuilder(KeyType.Ed448(), KeyFlag.SIGN_DATA))
.apply {
if (!signingOnly) {
addSubkey(
KeySpec.getBuilder(
KeyType.X448(),
KeyFlag.ENCRYPT_COMMS,
KeyFlag.ENCRYPT_STORAGE))
}
}
}
else -> throw SOPGPException.UnsupportedProfile("generate-key", profile) else -> throw SOPGPException.UnsupportedProfile("generate-key", profile)
} }

View file

@ -568,7 +568,7 @@ public class EncryptDecryptRoundTripTest {
public void encryptWithSupportedProfileTest() throws IOException { public void encryptWithSupportedProfileTest() throws IOException {
byte[] key = sop.generateKey() byte[] key = sop.generateKey()
.profile("rfc4880") .profile(GenerateKeyImpl.RFC4880_RSA4096_PROFILE.getName())
.userId("Alice <alice@pgpainless.org>") .userId("Alice <alice@pgpainless.org>")
.generate() .generate()
.getBytes(); .getBytes();
@ -578,7 +578,7 @@ public class EncryptDecryptRoundTripTest {
.getBytes(); .getBytes();
byte[] encrypted = sop.encrypt() byte[] encrypted = sop.encrypt()
.profile("rfc4880") .profile(EncryptImpl.RFC4880_PROFILE.getName())
.withCert(cert) .withCert(cert)
.plaintext(message) .plaintext(message)
.toByteArrayAndResult() .toByteArrayAndResult()