001// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org> 002// 003// SPDX-License-Identifier: Apache-2.0 004 005package org.pgpainless.key.generation; 006 007import java.security.InvalidAlgorithmParameterException; 008import java.security.NoSuchAlgorithmException; 009import javax.annotation.Nonnull; 010 011import org.bouncycastle.openpgp.PGPException; 012import org.bouncycastle.openpgp.PGPSecretKeyRing; 013import org.pgpainless.PGPainless; 014import org.pgpainless.algorithm.KeyFlag; 015import org.pgpainless.key.generation.type.KeyType; 016import org.pgpainless.key.generation.type.eddsa.EdDSACurve; 017import org.pgpainless.key.generation.type.rsa.RsaLength; 018import org.pgpainless.key.generation.type.xdh.XDHSpec; 019import org.pgpainless.key.util.UserId; 020import org.pgpainless.util.Passphrase; 021 022public final class KeyRingTemplates { 023 024 public KeyRingTemplates() { 025 026 } 027 028 /** 029 * Creates a simple, unencrypted RSA KeyPair of length {@code length} with user-id {@code userId}. 030 * The KeyPair consists of a single RSA master key which is used for signing, encryption and certification. 031 * 032 * @param userId user id. 033 * @param length length in bits. 034 * 035 * @return {@link PGPSecretKeyRing} containing the KeyPair. 036 */ 037 public PGPSecretKeyRing simpleRsaKeyRing(@Nonnull UserId userId, @Nonnull RsaLength length) 038 throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { 039 return simpleRsaKeyRing(userId.toString(), length); 040 } 041 042 /** 043 * Creates a simple, unencrypted RSA KeyPair of length {@code length} with user-id {@code userId}. 044 * The KeyPair consists of a single RSA master key which is used for signing, encryption and certification. 045 * 046 * @param userId user id. 047 * @param length length in bits. 048 * 049 * @return {@link PGPSecretKeyRing} containing the KeyPair. 050 */ 051 public PGPSecretKeyRing simpleRsaKeyRing(@Nonnull String userId, @Nonnull RsaLength length) 052 throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { 053 return simpleRsaKeyRing(userId, length, null); 054 } 055 056 /** 057 * Creates a simple RSA KeyPair of length {@code length} with user-id {@code userId}. 058 * The KeyPair consists of a single RSA master key which is used for signing, encryption and certification. 059 * 060 * @param userId user id. 061 * @param length length in bits. 062 * @param password Password of the key. Can be null for unencrypted keys. 063 * 064 * @return {@link PGPSecretKeyRing} containing the KeyPair. 065 */ 066 public PGPSecretKeyRing simpleRsaKeyRing(@Nonnull UserId userId, @Nonnull RsaLength length, String password) 067 throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { 068 return simpleRsaKeyRing(userId.toString(), length, password); 069 } 070 071 /** 072 * Creates a simple RSA KeyPair of length {@code length} with user-id {@code userId}. 073 * The KeyPair consists of a single RSA master key which is used for signing, encryption and certification. 074 * 075 * @param userId user id. 076 * @param length length in bits. 077 * @param password Password of the key. Can be null for unencrypted keys. 078 * 079 * @return {@link PGPSecretKeyRing} containing the KeyPair. 080 */ 081 public PGPSecretKeyRing simpleRsaKeyRing(@Nonnull String userId, @Nonnull RsaLength length, String password) 082 throws PGPException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { 083 KeyRingBuilder builder = PGPainless.buildKeyRing() 084 .setPrimaryKey(KeySpec.getBuilder(KeyType.RSA(length), KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA, KeyFlag.ENCRYPT_COMMS)) 085 .addUserId(userId); 086 087 if (!isNullOrEmpty(password)) { 088 builder.setPassphrase(Passphrase.fromPassword(password)); 089 } 090 return builder.build(); 091 } 092 093 /** 094 * Creates a key ring consisting of an ed25519 EdDSA primary key and a curve25519 XDH subkey. 095 * The EdDSA primary key is used for signing messages and certifying the sub key. 096 * The XDH subkey is used for encryption and decryption of messages. 097 * 098 * @param userId user-id 099 * 100 * @return {@link PGPSecretKeyRing} containing the key pairs. 101 */ 102 public PGPSecretKeyRing simpleEcKeyRing(@Nonnull UserId userId) 103 throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { 104 return simpleEcKeyRing(userId.toString()); 105 } 106 107 /** 108 * Creates a key ring consisting of an ed25519 EdDSA primary key and a curve25519 XDH subkey. 109 * The EdDSA primary key is used for signing messages and certifying the sub key. 110 * The XDH subkey is used for encryption and decryption of messages. 111 * 112 * @param userId user-id 113 * 114 * @return {@link PGPSecretKeyRing} containing the key pairs. 115 */ 116 public PGPSecretKeyRing simpleEcKeyRing(@Nonnull String userId) 117 throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { 118 return simpleEcKeyRing(userId, null); 119 } 120 121 /** 122 * Creates a key ring consisting of an ed25519 EdDSA primary key and a curve25519 XDH subkey. 123 * The EdDSA primary key is used for signing messages and certifying the sub key. 124 * The XDH subkey is used for encryption and decryption of messages. 125 * 126 * @param userId user-id 127 * @param password Password of the private key. Can be null for an unencrypted key. 128 * 129 * @return {@link PGPSecretKeyRing} containing the key pairs. 130 */ 131 public PGPSecretKeyRing simpleEcKeyRing(@Nonnull UserId userId, String password) 132 throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { 133 return simpleEcKeyRing(userId.toString(), password); 134 } 135 136 /** 137 * Creates a key ring consisting of an ed25519 EdDSA primary key and a X25519 XDH subkey. 138 * The EdDSA primary key is used for signing messages and certifying the sub key. 139 * The XDH subkey is used for encryption and decryption of messages. 140 * 141 * @param userId user-id 142 * @param password Password of the private key. Can be null for an unencrypted key. 143 * 144 * @return {@link PGPSecretKeyRing} containing the key pairs. 145 */ 146 public PGPSecretKeyRing simpleEcKeyRing(@Nonnull String userId, String password) 147 throws PGPException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { 148 KeyRingBuilder builder = PGPainless.buildKeyRing() 149 .setPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) 150 .addSubkey(KeySpec.getBuilder(KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS)) 151 .addUserId(userId); 152 153 if (!isNullOrEmpty(password)) { 154 builder.setPassphrase(Passphrase.fromPassword(password)); 155 } 156 return builder.build(); 157 } 158 159 /** 160 * Generate a modern PGP key ring consisting of an ed25519 EdDSA primary key which is used to certify 161 * an X25519 XDH encryption subkey and an ed25519 EdDSA signing key. 162 * 163 * @param userId primary user id 164 * @param password passphrase or null if the key should be unprotected. 165 * @return key ring 166 */ 167 public PGPSecretKeyRing modernKeyRing(String userId, String password) 168 throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException { 169 KeyRingBuilder builder = PGPainless.buildKeyRing() 170 .setPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.CERTIFY_OTHER)) 171 .addSubkey(KeySpec.getBuilder(KeyType.XDH(XDHSpec._X25519), KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS)) 172 .addSubkey(KeySpec.getBuilder(KeyType.EDDSA(EdDSACurve._Ed25519), KeyFlag.SIGN_DATA)) 173 .addUserId(userId); 174 if (!isNullOrEmpty(password)) { 175 builder.setPassphrase(Passphrase.fromPassword(password)); 176 } 177 return builder.build(); 178 } 179 180 private static boolean isNullOrEmpty(String password) { 181 return password == null || password.trim().isEmpty(); 182 } 183 184}