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