// SPDX-FileCopyrightText: 2023 Paul Schaub // // SPDX-License-Identifier: Apache-2.0 package org.pgpainless.key.generation import org.bouncycastle.openpgp.PGPSecretKeyRing import org.pgpainless.PGPainless.Companion.buildKeyRing import org.pgpainless.algorithm.KeyFlag import org.pgpainless.key.generation.KeySpec.Companion.getBuilder import org.pgpainless.key.generation.type.KeyType import org.pgpainless.key.generation.type.eddsa_legacy.EdDSALegacyCurve import org.pgpainless.key.generation.type.rsa.RsaLength import org.pgpainless.key.generation.type.xdh_legacy.XDHLegacySpec import org.pgpainless.util.Passphrase class KeyRingTemplates { /** * Generate an RSA OpenPGP key consisting of an RSA primary key used for certification, a * dedicated RSA subkey used for signing and a third RSA subkey used for encryption. * * @param userId userId or null * @param length length of the RSA keys * @param passphrase passphrase to encrypt the key with. Can be empty for an unencrytped key. * @return key */ @JvmOverloads fun rsaKeyRing( userId: CharSequence?, length: RsaLength, passphrase: Passphrase = Passphrase.emptyPassphrase() ): PGPSecretKeyRing = buildKeyRing() .apply { setPrimaryKey(getBuilder(KeyType.RSA(length), KeyFlag.CERTIFY_OTHER)) addSubkey(getBuilder(KeyType.RSA(length), KeyFlag.SIGN_DATA)) addSubkey( getBuilder(KeyType.RSA(length), KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE)) setPassphrase(passphrase) if (userId != null) { addUserId(userId) } } .build() /** * Generate an RSA OpenPGP key consisting of an RSA primary key used for certification, a * dedicated RSA subkey used for signing and a third RSA subkey used for encryption. * * @param userId userId or null * @param length length of the RSA keys * @param password passphrase to encrypt the key with. Can be null or blank for unencrypted * keys. * @return key */ fun rsaKeyRing(userId: CharSequence?, length: RsaLength, password: String?): PGPSecretKeyRing = password.let { if (it.isNullOrBlank()) { rsaKeyRing(userId, length, Passphrase.emptyPassphrase()) } else { rsaKeyRing(userId, length, Passphrase.fromPassword(it)) } } /** * Creates a simple RSA KeyPair of length {@code length} with user-id {@code userId}. The * KeyPair consists of a single RSA master key which is used for signing, encryption and * certification. * * @param userId user id. * @param length length in bits. * @param password Password of the key. Can be empty for unencrypted keys. * @return {@link PGPSecretKeyRing} containing the KeyPair. */ @JvmOverloads fun simpleRsaKeyRing( userId: CharSequence?, length: RsaLength, passphrase: Passphrase = Passphrase.emptyPassphrase() ): PGPSecretKeyRing = buildKeyRing() .apply { setPrimaryKey( getBuilder( KeyType.RSA(length), KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA, KeyFlag.ENCRYPT_COMMS)) setPassphrase(passphrase) if (userId != null) { addUserId(userId.toString()) } } .build() /** * Creates a simple RSA KeyPair of length {@code length} with user-id {@code userId}. The * KeyPair consists of a single RSA master key which is used for signing, encryption and * certification. * * @param userId user id. * @param length length in bits. * @param password Password of the key. Can be null or blank for unencrypted keys. * @return {@link PGPSecretKeyRing} containing the KeyPair. */ fun simpleRsaKeyRing(userId: CharSequence?, length: RsaLength, password: String?) = password.let { if (it.isNullOrBlank()) { simpleRsaKeyRing(userId, length, Passphrase.emptyPassphrase()) } else { simpleRsaKeyRing(userId, length, Passphrase.fromPassword(it)) } } /** * Creates a key ring consisting of an ed25519 EdDSA primary key and a X25519 XDH subkey. The * EdDSA primary key is used for signing messages and certifying the sub key. The XDH subkey is * used for encryption and decryption of messages. * * @param userId user-id * @param passphrase Password of the private key. Can be empty for an unencrypted key. * @return {@link PGPSecretKeyRing} containing the key pairs. */ @JvmOverloads fun simpleEcKeyRing( userId: CharSequence?, passphrase: Passphrase = Passphrase.emptyPassphrase() ): PGPSecretKeyRing = buildKeyRing() .apply { setPrimaryKey( getBuilder( KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) addSubkey( getBuilder( KeyType.XDH_LEGACY(XDHLegacySpec._X25519), KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS)) setPassphrase(passphrase) if (userId != null) { addUserId(userId.toString()) } } .build() /** * Creates a key ring consisting of an ed25519 EdDSA primary key and a X25519 XDH subkey. The * EdDSA primary key is used for signing messages and certifying the sub key. The XDH subkey is * used for encryption and decryption of messages. * * @param userId user-id * @param passphrase Password of the private key. Can be null or blank for an unencrypted key. * @return {@link PGPSecretKeyRing} containing the key pairs. */ fun simpleEcKeyRing(userId: CharSequence?, password: String?): PGPSecretKeyRing = password.let { if (it.isNullOrBlank()) { simpleEcKeyRing(userId, Passphrase.emptyPassphrase()) } else { simpleEcKeyRing(userId, Passphrase.fromPassword(it)) } } /** * Generate a modern PGP key ring consisting of an ed25519 EdDSA primary key which is used to * certify an X25519 XDH encryption subkey and an ed25519 EdDSA signing key. * * @param userId primary user id * @param passphrase passphrase for the private key. Can be empty for an unencrypted key. * @return key ring */ @JvmOverloads fun modernKeyRing( userId: CharSequence?, passphrase: Passphrase = Passphrase.emptyPassphrase() ): PGPSecretKeyRing = buildKeyRing() .apply { setPrimaryKey( getBuilder( KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.CERTIFY_OTHER)) addSubkey( getBuilder( KeyType.XDH_LEGACY(XDHLegacySpec._X25519), KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE)) addSubkey( getBuilder(KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.SIGN_DATA)) setPassphrase(passphrase) if (userId != null) { addUserId(userId) } } .build() /** * Generate a modern PGP key ring consisting of an ed25519 EdDSA primary key which is used to * certify an X25519 XDH encryption subkey and an ed25519 EdDSA signing key. * * @param userId primary user id * @param password passphrase for the private key. Can be null or blank for an unencrypted key. * @return key ring */ fun modernKeyRing(userId: CharSequence?, password: String?): PGPSecretKeyRing = password.let { if (it.isNullOrBlank()) { modernKeyRing(userId, Passphrase.emptyPassphrase()) } else { modernKeyRing(userId, Passphrase.fromPassword(it)) } } }