Path: blob/main/crypto/openssl/demos/encrypt/rsa_encrypt.c
34879 views
/*-1* Copyright 2021 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89/*10* An example that uses EVP_PKEY_encrypt and EVP_PKEY_decrypt methods11* to encrypt and decrypt data using an RSA keypair.12* RSA encryption produces different encrypted output each time it is run,13* hence this is not a known answer test.14*/1516#include <stdio.h>17#include <stdlib.h>18#include <openssl/err.h>19#include <openssl/evp.h>20#include <openssl/decoder.h>21#include <openssl/core_names.h>22#include "rsa_encrypt.h"2324/* Input data to encrypt */25static const unsigned char msg[] =26"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";3031/*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*/35static EVP_PKEY *get_key(OSSL_LIB_CTX *libctx, const char *propq, int public)36{37OSSL_DECODER_CTX *dctx = NULL;38EVP_PKEY *pkey = NULL;39int selection;40const unsigned char *data;41size_t data_len;4243if (public) {44selection = EVP_PKEY_PUBLIC_KEY;45data = pub_key_der;46data_len = sizeof(pub_key_der);47} else {48selection = EVP_PKEY_KEYPAIR;49data = priv_key_der;50data_len = sizeof(priv_key_der);51}52dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", NULL, "RSA",53selection, libctx, propq);54(void)OSSL_DECODER_from_data(dctx, &data, &data_len);55OSSL_DECODER_CTX_free(dctx);56return pkey;57}5859/* Set optional parameters for RSA OAEP Padding */60static void set_optional_params(OSSL_PARAM *p, const char *propq)61{62static unsigned char label[] = "label";6364/* "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,66OSSL_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,69label, 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 the75* OAEP digest then it needs to be specified here.76*/77if (propq != NULL)78*p++ = OSSL_PARAM_construct_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST_PROPS,79(char *)propq, 0);8081/*82* OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST and83* OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS can also be optionally added84* here if the MGF1 digest differs from the OAEP digest.85*/8687*p = OSSL_PARAM_construct_end();88}8990/*91* The length of the input data that can be encrypted is limited by the92* RSA key length minus some additional bytes that depends on the padding mode.93*94*/95static int do_encrypt(OSSL_LIB_CTX *libctx,96const unsigned char *in, size_t in_len,97unsigned char **out, size_t *out_len)98{99int ret = 0, public = 1;100size_t buf_len = 0;101unsigned char *buf = NULL;102const char *propq = NULL;103EVP_PKEY_CTX *ctx = NULL;104EVP_PKEY *pub_key = NULL;105OSSL_PARAM params[5];106107/* Get public key */108pub_key = get_key(libctx, propq, public);109if (pub_key == NULL) {110fprintf(stderr, "Get public key failed.\n");111goto cleanup;112}113ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pub_key, propq);114if (ctx == NULL) {115fprintf(stderr, "EVP_PKEY_CTX_new_from_pkey() failed.\n");116goto cleanup;117}118set_optional_params(params, propq);119/* If no optional parameters are required then NULL can be passed */120if (EVP_PKEY_encrypt_init_ex(ctx, params) <= 0) {121fprintf(stderr, "EVP_PKEY_encrypt_init_ex() failed.\n");122goto cleanup;123}124/* Calculate the size required to hold the encrypted data */125if (EVP_PKEY_encrypt(ctx, NULL, &buf_len, in, in_len) <= 0) {126fprintf(stderr, "EVP_PKEY_encrypt() failed.\n");127goto cleanup;128}129buf = OPENSSL_zalloc(buf_len);130if (buf == NULL) {131fprintf(stderr, "Malloc failed.\n");132goto cleanup;133}134if (EVP_PKEY_encrypt(ctx, buf, &buf_len, in, in_len) <= 0) {135fprintf(stderr, "EVP_PKEY_encrypt() failed.\n");136goto cleanup;137}138*out_len = buf_len;139*out = buf;140fprintf(stdout, "Encrypted:\n");141BIO_dump_indent_fp(stdout, buf, buf_len, 2);142fprintf(stdout, "\n");143ret = 1;144145cleanup:146if (!ret)147OPENSSL_free(buf);148EVP_PKEY_free(pub_key);149EVP_PKEY_CTX_free(ctx);150return ret;151}152153static int do_decrypt(OSSL_LIB_CTX *libctx, const unsigned char *in, size_t in_len,154unsigned char **out, size_t *out_len)155{156int ret = 0, public = 0;157size_t buf_len = 0;158unsigned char *buf = NULL;159const char *propq = NULL;160EVP_PKEY_CTX *ctx = NULL;161EVP_PKEY *priv_key = NULL;162OSSL_PARAM params[5];163164/* Get private key */165priv_key = get_key(libctx, propq, public);166if (priv_key == NULL) {167fprintf(stderr, "Get private key failed.\n");168goto cleanup;169}170ctx = EVP_PKEY_CTX_new_from_pkey(libctx, priv_key, propq);171if (ctx == NULL) {172fprintf(stderr, "EVP_PKEY_CTX_new_from_pkey() failed.\n");173goto cleanup;174}175176/* The parameters used for encryption must also be used for decryption */177set_optional_params(params, propq);178/* If no optional parameters are required then NULL can be passed */179if (EVP_PKEY_decrypt_init_ex(ctx, params) <= 0) {180fprintf(stderr, "EVP_PKEY_decrypt_init_ex() failed.\n");181goto cleanup;182}183/* Calculate the size required to hold the decrypted data */184if (EVP_PKEY_decrypt(ctx, NULL, &buf_len, in, in_len) <= 0) {185fprintf(stderr, "EVP_PKEY_decrypt() failed.\n");186goto cleanup;187}188buf = OPENSSL_zalloc(buf_len);189if (buf == NULL) {190fprintf(stderr, "Malloc failed.\n");191goto cleanup;192}193if (EVP_PKEY_decrypt(ctx, buf, &buf_len, in, in_len) <= 0) {194fprintf(stderr, "EVP_PKEY_decrypt() failed.\n");195goto cleanup;196}197*out_len = buf_len;198*out = buf;199fprintf(stdout, "Decrypted:\n");200BIO_dump_indent_fp(stdout, buf, buf_len, 2);201fprintf(stdout, "\n");202ret = 1;203204cleanup:205if (!ret)206OPENSSL_free(buf);207EVP_PKEY_free(priv_key);208EVP_PKEY_CTX_free(ctx);209return ret;210}211212int main(void)213{214int ret = EXIT_FAILURE;215size_t msg_len = sizeof(msg) - 1;216size_t encrypted_len = 0, decrypted_len = 0;217unsigned char *encrypted = NULL, *decrypted = NULL;218OSSL_LIB_CTX *libctx = NULL;219220if (!do_encrypt(libctx, msg, msg_len, &encrypted, &encrypted_len)) {221fprintf(stderr, "encryption failed.\n");222goto cleanup;223}224if (!do_decrypt(libctx, encrypted, encrypted_len,225&decrypted, &decrypted_len)) {226fprintf(stderr, "decryption failed.\n");227goto cleanup;228}229if (CRYPTO_memcmp(msg, decrypted, decrypted_len) != 0) {230fprintf(stderr, "Decrypted data does not match expected value\n");231goto cleanup;232}233ret = EXIT_SUCCESS;234235cleanup:236OPENSSL_free(decrypted);237OPENSSL_free(encrypted);238OSSL_LIB_CTX_free(libctx);239if (ret != EXIT_SUCCESS)240ERR_print_errors_fp(stderr);241return ret;242}243244245