xs_openssl.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /* copyright (c) 2022 - 2023 grunfink / MIT license */
  2. #ifndef _XS_OPENSSL_H
  3. #define _XS_OPENSSL_H
  4. xs_str *_xs_digest(const xs_val *input, int size, const char *digest, int as_hex);
  5. #define xs_md5_hex(input, size) _xs_digest(input, size, "md5", 1)
  6. #define xs_sha1_hex(input, size) _xs_digest(input, size, "sha1", 1)
  7. #define xs_sha256_hex(input, size) _xs_digest(input, size, "sha256", 1)
  8. #define xs_sha256_base64(input, size) _xs_digest(input, size, "sha256", 0)
  9. xs_dict *xs_evp_genkey(int bits);
  10. xs_str *xs_evp_sign(const char *secret, const char *mem, int size);
  11. int xs_evp_verify(const char *pubkey, const char *mem, int size, const char *b64sig);
  12. #ifdef XS_IMPLEMENTATION
  13. #include "openssl/rsa.h"
  14. #include "openssl/pem.h"
  15. #include "openssl/evp.h"
  16. #if 0
  17. xs_str *xs_base64_enc(const xs_val *data, int sz)
  18. /* encodes data to base64 */
  19. {
  20. BIO *mem, *b64;
  21. BUF_MEM *bptr;
  22. b64 = BIO_new(BIO_f_base64());
  23. mem = BIO_new(BIO_s_mem());
  24. b64 = BIO_push(b64, mem);
  25. BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
  26. BIO_write(b64, data, sz);
  27. BIO_flush(b64);
  28. BIO_get_mem_ptr(b64, &bptr);
  29. int n = bptr->length;
  30. xs_str *s = xs_realloc(NULL, _xs_blk_size(n + 1));
  31. memcpy(s, bptr->data, n);
  32. s[n] = '\0';
  33. BIO_free_all(b64);
  34. return s;
  35. }
  36. xs_val *xs_base64_dec(const xs_str *data, int *size)
  37. /* decodes data from base64 */
  38. {
  39. BIO *b64, *mem;
  40. *size = strlen(data);
  41. b64 = BIO_new(BIO_f_base64());
  42. mem = BIO_new_mem_buf(data, *size);
  43. b64 = BIO_push(b64, mem);
  44. BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
  45. /* alloc a very big buffer */
  46. xs_str *s = xs_realloc(NULL, *size);
  47. *size = BIO_read(b64, s, *size);
  48. /* adjust to current size */
  49. s = xs_realloc(s, _xs_blk_size(*size + 1));
  50. s[*size] = '\0';
  51. BIO_free_all(mem);
  52. return s;
  53. }
  54. #endif
  55. xs_str *_xs_digest(const xs_val *input, int size, const char *digest, int as_hex)
  56. /* generic function for generating and encoding digests */
  57. {
  58. const EVP_MD *md;
  59. if ((md = EVP_get_digestbyname(digest)) == NULL)
  60. return NULL;
  61. unsigned char output[1024];
  62. unsigned int out_size;
  63. EVP_MD_CTX *mdctx;
  64. mdctx = EVP_MD_CTX_new();
  65. EVP_DigestInit_ex(mdctx, md, NULL);
  66. EVP_DigestUpdate(mdctx, input, size);
  67. EVP_DigestFinal_ex(mdctx, output, &out_size);
  68. EVP_MD_CTX_free(mdctx);
  69. return as_hex ? xs_hex_enc ((char *)output, out_size) :
  70. xs_base64_enc((char *)output, out_size);
  71. }
  72. xs_dict *xs_evp_genkey(int bits)
  73. /* generates an RSA keypair using the EVP interface */
  74. {
  75. xs_dict *keypair = NULL;
  76. EVP_PKEY_CTX *ctx;
  77. EVP_PKEY *pkey = NULL;
  78. if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL)) == NULL)
  79. goto end;
  80. if (EVP_PKEY_keygen_init(ctx) <= 0 ||
  81. EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0 ||
  82. EVP_PKEY_keygen(ctx, &pkey) <= 0)
  83. goto end;
  84. BIO *bs = BIO_new(BIO_s_mem());
  85. BIO *bp = BIO_new(BIO_s_mem());
  86. BUF_MEM *sptr;
  87. BUF_MEM *pptr;
  88. PEM_write_bio_PrivateKey(bs, pkey, NULL, NULL, 0, 0, NULL);
  89. BIO_get_mem_ptr(bs, &sptr);
  90. PEM_write_bio_PUBKEY(bp, pkey);
  91. BIO_get_mem_ptr(bp, &pptr);
  92. keypair = xs_dict_new();
  93. keypair = xs_dict_append(keypair, "secret", sptr->data);
  94. keypair = xs_dict_append(keypair, "public", pptr->data);
  95. BIO_free(bs);
  96. BIO_free(bp);
  97. end:
  98. return keypair;
  99. }
  100. xs_str *xs_evp_sign(const char *secret, const char *mem, int size)
  101. /* signs a memory block (secret is in PEM format) */
  102. {
  103. xs_str *signature = NULL;
  104. BIO *b;
  105. unsigned char *sig;
  106. unsigned int sig_len;
  107. EVP_PKEY *pkey;
  108. EVP_MD_CTX *mdctx;
  109. const EVP_MD *md;
  110. /* un-PEM the key */
  111. b = BIO_new_mem_buf(secret, strlen(secret));
  112. pkey = PEM_read_bio_PrivateKey(b, NULL, NULL, NULL);
  113. /* I've learnt all these magical incantations by watching
  114. the Python module code and the OpenSSL manual pages */
  115. /* Well, "learnt" may be an overstatement */
  116. md = EVP_get_digestbyname("sha256");
  117. mdctx = EVP_MD_CTX_new();
  118. sig_len = EVP_PKEY_size(pkey);
  119. sig = xs_realloc(NULL, sig_len);
  120. EVP_SignInit(mdctx, md);
  121. EVP_SignUpdate(mdctx, mem, size);
  122. if (EVP_SignFinal(mdctx, sig, &sig_len, pkey) == 1)
  123. signature = xs_base64_enc((char *)sig, sig_len);
  124. EVP_MD_CTX_free(mdctx);
  125. EVP_PKEY_free(pkey);
  126. BIO_free(b);
  127. xs_free(sig);
  128. return signature;
  129. }
  130. int xs_evp_verify(const char *pubkey, const char *mem, int size, const char *b64sig)
  131. /* verifies a base64 block, returns non-zero on ok */
  132. {
  133. int r = 0;
  134. BIO *b;
  135. EVP_PKEY *pkey;
  136. EVP_MD_CTX *mdctx;
  137. const EVP_MD *md;
  138. /* un-PEM the key */
  139. b = BIO_new_mem_buf(pubkey, strlen(pubkey));
  140. pkey = PEM_read_bio_PUBKEY(b, NULL, NULL, NULL);
  141. md = EVP_get_digestbyname("sha256");
  142. mdctx = EVP_MD_CTX_new();
  143. if (pkey != NULL) {
  144. xs *sig = NULL;
  145. int s_size;
  146. /* de-base64 */
  147. sig = xs_base64_dec(b64sig, &s_size);
  148. if (sig != NULL) {
  149. EVP_VerifyInit(mdctx, md);
  150. EVP_VerifyUpdate(mdctx, mem, size);
  151. r = EVP_VerifyFinal(mdctx, (unsigned char *)sig, s_size, pkey);
  152. }
  153. }
  154. EVP_MD_CTX_free(mdctx);
  155. EVP_PKEY_free(pkey);
  156. BIO_free(b);
  157. return r;
  158. }
  159. #endif /* XS_IMPLEMENTATION */
  160. #endif /* _XS_OPENSSL_H */