Home | History | Annotate | Line # | Download | only in encrypt
      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