rsa_encrypt.c 7.7 KB

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