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
107175 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[] = "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
244