1 /*- 2 * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 /* 11 * Example showing how to generate an RSA key pair. 12 * 13 * When generating an RSA key, you must specify the number of bits in the key. A 14 * reasonable value would be 4096. Avoid using values below 2048. These values 15 * are reasonable as of 2022. 16 */ 17 18 #include <string.h> 19 #include <stdio.h> 20 #include <openssl/err.h> 21 #include <openssl/evp.h> 22 #include <openssl/rsa.h> 23 #include <openssl/core_names.h> 24 #include <openssl/pem.h> 25 26 /* A property query used for selecting algorithm implementations. */ 27 static const char *propq = NULL; 28 29 /* 30 * Generates an RSA public-private key pair and returns it. 31 * The number of bits is specified by the bits argument. 32 * 33 * This uses the long way of generating an RSA key. 34 */ 35 static EVP_PKEY *generate_rsa_key_long(OSSL_LIB_CTX *libctx, unsigned int bits) 36 { 37 EVP_PKEY_CTX *genctx = NULL; 38 EVP_PKEY *pkey = NULL; 39 unsigned int primes = 2; 40 41 /* Create context using RSA algorithm. "RSA-PSS" could also be used here. */ 42 genctx = EVP_PKEY_CTX_new_from_name(libctx, "RSA", propq); 43 if (genctx == NULL) { 44 fprintf(stderr, "EVP_PKEY_CTX_new_from_name() failed\n"); 45 goto cleanup; 46 } 47 48 /* Initialize context for key generation purposes. */ 49 if (EVP_PKEY_keygen_init(genctx) <= 0) { 50 fprintf(stderr, "EVP_PKEY_keygen_init() failed\n"); 51 goto cleanup; 52 } 53 54 /* 55 * Here we set the number of bits to use in the RSA key. 56 * See comment at top of file for information on appropriate values. 57 */ 58 if (EVP_PKEY_CTX_set_rsa_keygen_bits(genctx, bits) <= 0) { 59 fprintf(stderr, "EVP_PKEY_CTX_set_rsa_keygen_bits() failed\n"); 60 goto cleanup; 61 } 62 63 /* 64 * It is possible to create an RSA key using more than two primes. 65 * Do not do this unless you know why you need this. 66 * You ordinarily do not need to specify this, as the default is two. 67 * 68 * Both of these parameters can also be set via EVP_PKEY_CTX_set_params, but 69 * these functions provide a more concise way to do so. 70 */ 71 if (EVP_PKEY_CTX_set_rsa_keygen_primes(genctx, primes) <= 0) { 72 fprintf(stderr, "EVP_PKEY_CTX_set_rsa_keygen_primes() failed\n"); 73 goto cleanup; 74 } 75 76 /* 77 * Generating an RSA key with a number of bits large enough to be secure for 78 * modern applications can take a fairly substantial amount of time (e.g. 79 * one second). If you require fast key generation, consider using an EC key 80 * instead. 81 * 82 * If you require progress information during the key generation process, 83 * you can set a progress callback using EVP_PKEY_set_cb; see the example in 84 * EVP_PKEY_generate(3). 85 */ 86 fprintf(stderr, "Generating RSA key, this may take some time...\n"); 87 if (EVP_PKEY_generate(genctx, &pkey) <= 0) { 88 fprintf(stderr, "EVP_PKEY_generate() failed\n"); 89 goto cleanup; 90 } 91 92 /* pkey is now set to an object representing the generated key pair. */ 93 94 cleanup: 95 EVP_PKEY_CTX_free(genctx); 96 return pkey; 97 } 98 99 /* 100 * Generates an RSA public-private key pair and returns it. 101 * The number of bits is specified by the bits argument. 102 * 103 * This uses a more concise way of generating an RSA key, which is suitable for 104 * simple cases. It is used if -s is passed on the command line, otherwise the 105 * long method above is used. The ability to choose between these two methods is 106 * shown here only for demonstration; the results are equivalent. 107 */ 108 static EVP_PKEY *generate_rsa_key_short(OSSL_LIB_CTX *libctx, unsigned int bits) 109 { 110 EVP_PKEY *pkey = NULL; 111 112 fprintf(stderr, "Generating RSA key, this may take some time...\n"); 113 pkey = EVP_PKEY_Q_keygen(libctx, propq, "RSA", (size_t)bits); 114 115 if (pkey == NULL) 116 fprintf(stderr, "EVP_PKEY_Q_keygen() failed\n"); 117 118 return pkey; 119 } 120 121 /* 122 * Prints information on an EVP_PKEY object representing an RSA key pair. 123 */ 124 static int dump_key(const EVP_PKEY *pkey) 125 { 126 int rv = 0; 127 int bits = 0; 128 BIGNUM *n = NULL, *e = NULL, *d = NULL, *p = NULL, *q = NULL; 129 130 /* 131 * Retrieve value of n. This value is not secret and forms part of the 132 * public key. 133 * 134 * Calling EVP_PKEY_get_bn_param with a NULL BIGNUM pointer causes 135 * a new BIGNUM to be allocated, so these must be freed subsequently. 136 */ 137 if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &n) == 0) { 138 fprintf(stderr, "Failed to retrieve n\n"); 139 goto cleanup; 140 } 141 142 /* 143 * Retrieve value of e. This value is not secret and forms part of the 144 * public key. It is typically 65537 and need not be changed. 145 */ 146 if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &e) == 0) { 147 fprintf(stderr, "Failed to retrieve e\n"); 148 goto cleanup; 149 } 150 151 /* 152 * Retrieve value of d. This value is secret and forms part of the private 153 * key. It must not be published. 154 */ 155 if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_D, &d) == 0) { 156 fprintf(stderr, "Failed to retrieve d\n"); 157 goto cleanup; 158 } 159 160 /* 161 * Retrieve value of the first prime factor, commonly known as p. This value 162 * is secret and forms part of the private key. It must not be published. 163 */ 164 if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, &p) == 0) { 165 fprintf(stderr, "Failed to retrieve p\n"); 166 goto cleanup; 167 } 168 169 /* 170 * Retrieve value of the second prime factor, commonly known as q. This value 171 * is secret and forms part of the private key. It must not be published. 172 * 173 * If you are creating an RSA key with more than two primes for special 174 * applications, you can retrieve these primes with 175 * OSSL_PKEY_PARAM_RSA_FACTOR3, etc. 176 */ 177 if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, &q) == 0) { 178 fprintf(stderr, "Failed to retrieve q\n"); 179 goto cleanup; 180 } 181 182 /* 183 * We can also retrieve the key size in bits for informational purposes. 184 */ 185 if (EVP_PKEY_get_int_param(pkey, OSSL_PKEY_PARAM_BITS, &bits) == 0) { 186 fprintf(stderr, "Failed to retrieve bits\n"); 187 goto cleanup; 188 } 189 190 /* Output hexadecimal representations of the BIGNUM objects. */ 191 fprintf(stdout, "\nNumber of bits: %d\n\n", bits); 192 fprintf(stderr, "Public values:\n"); 193 fprintf(stdout, " n = 0x"); 194 BN_print_fp(stdout, n); 195 fprintf(stdout, "\n"); 196 197 fprintf(stdout, " e = 0x"); 198 BN_print_fp(stdout, e); 199 fprintf(stdout, "\n\n"); 200 201 fprintf(stdout, "Private values:\n"); 202 fprintf(stdout, " d = 0x"); 203 BN_print_fp(stdout, d); 204 fprintf(stdout, "\n"); 205 206 fprintf(stdout, " p = 0x"); 207 BN_print_fp(stdout, p); 208 fprintf(stdout, "\n"); 209 210 fprintf(stdout, " q = 0x"); 211 BN_print_fp(stdout, q); 212 fprintf(stdout, "\n\n"); 213 214 /* Output a PEM encoding of the public key. */ 215 if (PEM_write_PUBKEY(stdout, pkey) == 0) { 216 fprintf(stderr, "Failed to output PEM-encoded public key\n"); 217 goto cleanup; 218 } 219 220 /* 221 * Output a PEM encoding of the private key. Please note that this output is 222 * not encrypted. You may wish to use the arguments to specify encryption of 223 * the key if you are storing it on disk. See PEM_write_PrivateKey(3). 224 */ 225 if (PEM_write_PrivateKey(stdout, pkey, NULL, NULL, 0, NULL, NULL) == 0) { 226 fprintf(stderr, "Failed to output PEM-encoded private key\n"); 227 goto cleanup; 228 } 229 230 rv = 1; 231 cleanup: 232 BN_free(n); /* not secret */ 233 BN_free(e); /* not secret */ 234 BN_clear_free(d); /* secret - scrub before freeing */ 235 BN_clear_free(p); /* secret - scrub before freeing */ 236 BN_clear_free(q); /* secret - scrub before freeing */ 237 return rv; 238 } 239 240 int main(int argc, char **argv) 241 { 242 int rv = 1; 243 OSSL_LIB_CTX *libctx = NULL; 244 EVP_PKEY *pkey = NULL; 245 unsigned int bits = 4096; 246 int bits_i, use_short = 0; 247 248 /* usage: [-s] [<bits>] */ 249 if (argc > 1 && strcmp(argv[1], "-s") == 0) { 250 --argc; 251 ++argv; 252 use_short = 1; 253 } 254 255 if (argc > 1) { 256 bits_i = atoi(argv[1]); 257 if (bits < 512) { 258 fprintf(stderr, "Invalid RSA key size\n"); 259 return 1; 260 } 261 262 bits = (unsigned int)bits_i; 263 } 264 265 /* Avoid using key sizes less than 2048 bits; see comment at top of file. */ 266 if (bits < 2048) 267 fprintf(stderr, "Warning: very weak key size\n\n"); 268 269 /* Generate RSA key. */ 270 if (use_short) 271 pkey = generate_rsa_key_short(libctx, bits); 272 else 273 pkey = generate_rsa_key_long(libctx, bits); 274 275 if (pkey == NULL) 276 goto cleanup; 277 278 /* Dump the integers comprising the key. */ 279 if (dump_key(pkey) == 0) { 280 fprintf(stderr, "Failed to dump key\n"); 281 goto cleanup; 282 } 283 284 rv = 0; 285 cleanup: 286 EVP_PKEY_free(pkey); 287 OSSL_LIB_CTX_free(libctx); 288 return rv; 289 } 290