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