1 /*- 2 * Copyright 2021 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 * An example that uses EVP_PKEY_encrypt and EVP_PKEY_decrypt methods 12 * to encrypt and decrypt data using an RSA keypair. 13 * RSA encryption produces different encrypted output each time it is run, 14 * hence this is not a known answer test. 15 */ 16 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <openssl/err.h> 20 #include <openssl/evp.h> 21 #include <openssl/decoder.h> 22 #include <openssl/core_names.h> 23 #include "rsa_encrypt.h" 24 25 /* Input data to encrypt */ 26 static const unsigned char msg[] = "To be, or not to be, that is the question,\n" 27 "Whether tis nobler in the minde to suffer\n" 28 "The slings and arrowes of outragious fortune,\n" 29 "Or to take Armes again in a sea of troubles"; 30 31 /* 32 * For do_encrypt(), load an RSA public key from pub_key_der[]. 33 * For do_decrypt(), load an RSA private key from priv_key_der[]. 34 */ 35 static EVP_PKEY *get_key(OSSL_LIB_CTX *libctx, const char *propq, int public) 36 { 37 OSSL_DECODER_CTX *dctx = NULL; 38 EVP_PKEY *pkey = NULL; 39 int selection; 40 const unsigned char *data; 41 size_t data_len; 42 43 if (public) { 44 selection = EVP_PKEY_PUBLIC_KEY; 45 data = pub_key_der; 46 data_len = sizeof(pub_key_der); 47 } else { 48 selection = EVP_PKEY_KEYPAIR; 49 data = priv_key_der; 50 data_len = sizeof(priv_key_der); 51 } 52 dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", NULL, "RSA", 53 selection, libctx, propq); 54 (void)OSSL_DECODER_from_data(dctx, &data, &data_len); 55 OSSL_DECODER_CTX_free(dctx); 56 return pkey; 57 } 58 59 /* Set optional parameters for RSA OAEP Padding */ 60 static void set_optional_params(OSSL_PARAM *p, const char *propq) 61 { 62 static unsigned char label[] = "label"; 63 64 /* "pkcs1" is used by default if the padding mode is not set */ 65 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, 66 OSSL_PKEY_RSA_PAD_MODE_OAEP, 0); 67 /* No oaep_label is used if this is not set */ 68 *p++ = OSSL_PARAM_construct_octet_string(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, 69 label, sizeof(label)); 70 /* "SHA1" is used if this is not set */ 71 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST, 72 "SHA256", 0); 73 /* 74 * If a non default property query needs to be specified when fetching the 75 * OAEP digest then it needs to be specified here. 76 */ 77 if (propq != NULL) 78 *p++ = OSSL_PARAM_construct_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST_PROPS, 79 (char *)propq, 0); 80 81 /* 82 * OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST and 83 * OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS can also be optionally added 84 * here if the MGF1 digest differs from the OAEP digest. 85 */ 86 87 *p = OSSL_PARAM_construct_end(); 88 } 89 90 /* 91 * The length of the input data that can be encrypted is limited by the 92 * RSA key length minus some additional bytes that depends on the padding mode. 93 * 94 */ 95 static int do_encrypt(OSSL_LIB_CTX *libctx, 96 const unsigned char *in, size_t in_len, 97 unsigned char **out, size_t *out_len) 98 { 99 int ret = 0, public = 1; 100 size_t buf_len = 0; 101 unsigned char *buf = NULL; 102 const char *propq = NULL; 103 EVP_PKEY_CTX *ctx = NULL; 104 EVP_PKEY *pub_key = NULL; 105 OSSL_PARAM params[5]; 106 107 /* Get public key */ 108 pub_key = get_key(libctx, propq, public); 109 if (pub_key == NULL) { 110 fprintf(stderr, "Get public key failed.\n"); 111 goto cleanup; 112 } 113 ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pub_key, propq); 114 if (ctx == NULL) { 115 fprintf(stderr, "EVP_PKEY_CTX_new_from_pkey() failed.\n"); 116 goto cleanup; 117 } 118 set_optional_params(params, propq); 119 /* If no optional parameters are required then NULL can be passed */ 120 if (EVP_PKEY_encrypt_init_ex(ctx, params) <= 0) { 121 fprintf(stderr, "EVP_PKEY_encrypt_init_ex() failed.\n"); 122 goto cleanup; 123 } 124 /* Calculate the size required to hold the encrypted data */ 125 if (EVP_PKEY_encrypt(ctx, NULL, &buf_len, in, in_len) <= 0) { 126 fprintf(stderr, "EVP_PKEY_encrypt() failed.\n"); 127 goto cleanup; 128 } 129 buf = OPENSSL_zalloc(buf_len); 130 if (buf == NULL) { 131 fprintf(stderr, "Malloc failed.\n"); 132 goto cleanup; 133 } 134 if (EVP_PKEY_encrypt(ctx, buf, &buf_len, in, in_len) <= 0) { 135 fprintf(stderr, "EVP_PKEY_encrypt() failed.\n"); 136 goto cleanup; 137 } 138 *out_len = buf_len; 139 *out = buf; 140 fprintf(stdout, "Encrypted:\n"); 141 BIO_dump_indent_fp(stdout, buf, buf_len, 2); 142 fprintf(stdout, "\n"); 143 ret = 1; 144 145 cleanup: 146 if (!ret) 147 OPENSSL_free(buf); 148 EVP_PKEY_free(pub_key); 149 EVP_PKEY_CTX_free(ctx); 150 return ret; 151 } 152 153 static int do_decrypt(OSSL_LIB_CTX *libctx, const unsigned char *in, size_t in_len, 154 unsigned char **out, size_t *out_len) 155 { 156 int ret = 0, public = 0; 157 size_t buf_len = 0; 158 unsigned char *buf = NULL; 159 const char *propq = NULL; 160 EVP_PKEY_CTX *ctx = NULL; 161 EVP_PKEY *priv_key = NULL; 162 OSSL_PARAM params[5]; 163 164 /* Get private key */ 165 priv_key = get_key(libctx, propq, public); 166 if (priv_key == NULL) { 167 fprintf(stderr, "Get private key failed.\n"); 168 goto cleanup; 169 } 170 ctx = EVP_PKEY_CTX_new_from_pkey(libctx, priv_key, propq); 171 if (ctx == NULL) { 172 fprintf(stderr, "EVP_PKEY_CTX_new_from_pkey() failed.\n"); 173 goto cleanup; 174 } 175 176 /* The parameters used for encryption must also be used for decryption */ 177 set_optional_params(params, propq); 178 /* If no optional parameters are required then NULL can be passed */ 179 if (EVP_PKEY_decrypt_init_ex(ctx, params) <= 0) { 180 fprintf(stderr, "EVP_PKEY_decrypt_init_ex() failed.\n"); 181 goto cleanup; 182 } 183 /* Calculate the size required to hold the decrypted data */ 184 if (EVP_PKEY_decrypt(ctx, NULL, &buf_len, in, in_len) <= 0) { 185 fprintf(stderr, "EVP_PKEY_decrypt() failed.\n"); 186 goto cleanup; 187 } 188 buf = OPENSSL_zalloc(buf_len); 189 if (buf == NULL) { 190 fprintf(stderr, "Malloc failed.\n"); 191 goto cleanup; 192 } 193 if (EVP_PKEY_decrypt(ctx, buf, &buf_len, in, in_len) <= 0) { 194 fprintf(stderr, "EVP_PKEY_decrypt() failed.\n"); 195 goto cleanup; 196 } 197 *out_len = buf_len; 198 *out = buf; 199 fprintf(stdout, "Decrypted:\n"); 200 BIO_dump_indent_fp(stdout, buf, buf_len, 2); 201 fprintf(stdout, "\n"); 202 ret = 1; 203 204 cleanup: 205 if (!ret) 206 OPENSSL_free(buf); 207 EVP_PKEY_free(priv_key); 208 EVP_PKEY_CTX_free(ctx); 209 return ret; 210 } 211 212 int main(void) 213 { 214 int ret = EXIT_FAILURE; 215 size_t msg_len = sizeof(msg) - 1; 216 size_t encrypted_len = 0, decrypted_len = 0; 217 unsigned char *encrypted = NULL, *decrypted = NULL; 218 OSSL_LIB_CTX *libctx = NULL; 219 220 if (!do_encrypt(libctx, msg, msg_len, &encrypted, &encrypted_len)) { 221 fprintf(stderr, "encryption failed.\n"); 222 goto cleanup; 223 } 224 if (!do_decrypt(libctx, encrypted, encrypted_len, 225 &decrypted, &decrypted_len)) { 226 fprintf(stderr, "decryption failed.\n"); 227 goto cleanup; 228 } 229 if (CRYPTO_memcmp(msg, decrypted, decrypted_len) != 0) { 230 fprintf(stderr, "Decrypted data does not match expected value\n"); 231 goto cleanup; 232 } 233 ret = EXIT_SUCCESS; 234 235 cleanup: 236 OPENSSL_free(decrypted); 237 OPENSSL_free(encrypted); 238 OSSL_LIB_CTX_free(libctx); 239 if (ret != EXIT_SUCCESS) 240 ERR_print_errors_fp(stderr); 241 return ret; 242 } 243