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