Path: blob/main/crypto/openssl/demos/encrypt/rsa_encrypt.c
107175 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[] = "To be, or not to be, that is the question,\n"26"Whether tis nobler in the minde to suffer\n"27"The slings and arrowes of outragious fortune,\n"28"Or to take Armes again in a sea of troubles";2930/*31* For do_encrypt(), load an RSA public key from pub_key_der[].32* For do_decrypt(), load an RSA private key from priv_key_der[].33*/34static EVP_PKEY *get_key(OSSL_LIB_CTX *libctx, const char *propq, int public)35{36OSSL_DECODER_CTX *dctx = NULL;37EVP_PKEY *pkey = NULL;38int selection;39const unsigned char *data;40size_t data_len;4142if (public) {43selection = EVP_PKEY_PUBLIC_KEY;44data = pub_key_der;45data_len = sizeof(pub_key_der);46} else {47selection = EVP_PKEY_KEYPAIR;48data = priv_key_der;49data_len = sizeof(priv_key_der);50}51dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", NULL, "RSA",52selection, libctx, propq);53(void)OSSL_DECODER_from_data(dctx, &data, &data_len);54OSSL_DECODER_CTX_free(dctx);55return pkey;56}5758/* Set optional parameters for RSA OAEP Padding */59static void set_optional_params(OSSL_PARAM *p, const char *propq)60{61static unsigned char label[] = "label";6263/* "pkcs1" is used by default if the padding mode is not set */64*p++ = OSSL_PARAM_construct_utf8_string(OSSL_ASYM_CIPHER_PARAM_PAD_MODE,65OSSL_PKEY_RSA_PAD_MODE_OAEP, 0);66/* No oaep_label is used if this is not set */67*p++ = OSSL_PARAM_construct_octet_string(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL,68label, sizeof(label));69/* "SHA1" is used if this is not set */70*p++ = OSSL_PARAM_construct_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST,71"SHA256", 0);72/*73* If a non default property query needs to be specified when fetching the74* OAEP digest then it needs to be specified here.75*/76if (propq != NULL)77*p++ = OSSL_PARAM_construct_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST_PROPS,78(char *)propq, 0);7980/*81* OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST and82* OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS can also be optionally added83* here if the MGF1 digest differs from the OAEP digest.84*/8586*p = OSSL_PARAM_construct_end();87}8889/*90* The length of the input data that can be encrypted is limited by the91* RSA key length minus some additional bytes that depends on the padding mode.92*93*/94static int do_encrypt(OSSL_LIB_CTX *libctx,95const unsigned char *in, size_t in_len,96unsigned char **out, size_t *out_len)97{98int ret = 0, public = 1;99size_t buf_len = 0;100unsigned char *buf = NULL;101const char *propq = NULL;102EVP_PKEY_CTX *ctx = NULL;103EVP_PKEY *pub_key = NULL;104OSSL_PARAM params[5];105106/* Get public key */107pub_key = get_key(libctx, propq, public);108if (pub_key == NULL) {109fprintf(stderr, "Get public key failed.\n");110goto cleanup;111}112ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pub_key, propq);113if (ctx == NULL) {114fprintf(stderr, "EVP_PKEY_CTX_new_from_pkey() failed.\n");115goto cleanup;116}117set_optional_params(params, propq);118/* If no optional parameters are required then NULL can be passed */119if (EVP_PKEY_encrypt_init_ex(ctx, params) <= 0) {120fprintf(stderr, "EVP_PKEY_encrypt_init_ex() failed.\n");121goto cleanup;122}123/* Calculate the size required to hold the encrypted data */124if (EVP_PKEY_encrypt(ctx, NULL, &buf_len, in, in_len) <= 0) {125fprintf(stderr, "EVP_PKEY_encrypt() failed.\n");126goto cleanup;127}128buf = OPENSSL_zalloc(buf_len);129if (buf == NULL) {130fprintf(stderr, "Malloc failed.\n");131goto cleanup;132}133if (EVP_PKEY_encrypt(ctx, buf, &buf_len, in, in_len) <= 0) {134fprintf(stderr, "EVP_PKEY_encrypt() failed.\n");135goto cleanup;136}137*out_len = buf_len;138*out = buf;139fprintf(stdout, "Encrypted:\n");140BIO_dump_indent_fp(stdout, buf, buf_len, 2);141fprintf(stdout, "\n");142ret = 1;143144cleanup:145if (!ret)146OPENSSL_free(buf);147EVP_PKEY_free(pub_key);148EVP_PKEY_CTX_free(ctx);149return ret;150}151152static int do_decrypt(OSSL_LIB_CTX *libctx, const unsigned char *in, size_t in_len,153unsigned char **out, size_t *out_len)154{155int ret = 0, public = 0;156size_t buf_len = 0;157unsigned char *buf = NULL;158const char *propq = NULL;159EVP_PKEY_CTX *ctx = NULL;160EVP_PKEY *priv_key = NULL;161OSSL_PARAM params[5];162163/* Get private key */164priv_key = get_key(libctx, propq, public);165if (priv_key == NULL) {166fprintf(stderr, "Get private key failed.\n");167goto cleanup;168}169ctx = EVP_PKEY_CTX_new_from_pkey(libctx, priv_key, propq);170if (ctx == NULL) {171fprintf(stderr, "EVP_PKEY_CTX_new_from_pkey() failed.\n");172goto cleanup;173}174175/* The parameters used for encryption must also be used for decryption */176set_optional_params(params, propq);177/* If no optional parameters are required then NULL can be passed */178if (EVP_PKEY_decrypt_init_ex(ctx, params) <= 0) {179fprintf(stderr, "EVP_PKEY_decrypt_init_ex() failed.\n");180goto cleanup;181}182/* Calculate the size required to hold the decrypted data */183if (EVP_PKEY_decrypt(ctx, NULL, &buf_len, in, in_len) <= 0) {184fprintf(stderr, "EVP_PKEY_decrypt() failed.\n");185goto cleanup;186}187buf = OPENSSL_zalloc(buf_len);188if (buf == NULL) {189fprintf(stderr, "Malloc failed.\n");190goto cleanup;191}192if (EVP_PKEY_decrypt(ctx, buf, &buf_len, in, in_len) <= 0) {193fprintf(stderr, "EVP_PKEY_decrypt() failed.\n");194goto cleanup;195}196*out_len = buf_len;197*out = buf;198fprintf(stdout, "Decrypted:\n");199BIO_dump_indent_fp(stdout, buf, buf_len, 2);200fprintf(stdout, "\n");201ret = 1;202203cleanup:204if (!ret)205OPENSSL_free(buf);206EVP_PKEY_free(priv_key);207EVP_PKEY_CTX_free(ctx);208return ret;209}210211int main(void)212{213int ret = EXIT_FAILURE;214size_t msg_len = sizeof(msg) - 1;215size_t encrypted_len = 0, decrypted_len = 0;216unsigned char *encrypted = NULL, *decrypted = NULL;217OSSL_LIB_CTX *libctx = NULL;218219if (!do_encrypt(libctx, msg, msg_len, &encrypted, &encrypted_len)) {220fprintf(stderr, "encryption failed.\n");221goto cleanup;222}223if (!do_decrypt(libctx, encrypted, encrypted_len,224&decrypted, &decrypted_len)) {225fprintf(stderr, "decryption failed.\n");226goto cleanup;227}228if (CRYPTO_memcmp(msg, decrypted, decrypted_len) != 0) {229fprintf(stderr, "Decrypted data does not match expected value\n");230goto cleanup;231}232ret = EXIT_SUCCESS;233234cleanup:235OPENSSL_free(decrypted);236OPENSSL_free(encrypted);237OSSL_LIB_CTX_free(libctx);238if (ret != EXIT_SUCCESS)239ERR_print_errors_fp(stderr);240return ret;241}242243244