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