xs_openssl.h 5.8 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_rsa_genkey(int bits);
  10. xs_str *xs_rsa_sign(const char *secret, const char *mem, int size);
  11. int xs_rsa_verify(const char *pubkey, const char *mem, int size, const char *b64sig);
  12. xs_str *xs_evp_sign(const char *secret, const char *mem, int size);
  13. int xs_evp_verify(const char *pubkey, const char *mem, int size, const char *b64sig);
  14. #ifdef XS_IMPLEMENTATION
  15. #include "openssl/rsa.h"
  16. #include "openssl/pem.h"
  17. #include "openssl/evp.h"
  18. xs_str *_xs_digest(const xs_val *input, int size, const char *digest, int as_hex)
  19. /* generic function for generating and encoding digests */
  20. {
  21. const EVP_MD *md;
  22. if ((md = EVP_get_digestbyname(digest)) == NULL)
  23. return NULL;
  24. unsigned char output[1024];
  25. unsigned int out_size;
  26. EVP_MD_CTX *mdctx;
  27. mdctx = EVP_MD_CTX_new();
  28. EVP_DigestInit_ex(mdctx, md, NULL);
  29. EVP_DigestUpdate(mdctx, input, size);
  30. EVP_DigestFinal_ex(mdctx, output, &out_size);
  31. EVP_MD_CTX_free(mdctx);
  32. return as_hex ? xs_hex_enc ((char *)output, out_size) :
  33. xs_base64_enc((char *)output, out_size);
  34. }
  35. xs_dict *xs_rsa_genkey(int bits)
  36. /* generates an RSA keypair */
  37. {
  38. BIGNUM *bne;
  39. RSA *rsa;
  40. xs_dict *keypair = NULL;
  41. if ((bne = BN_new()) != NULL) {
  42. if (BN_set_word(bne, RSA_F4) == 1) {
  43. if ((rsa = RSA_new()) != NULL) {
  44. if (RSA_generate_key_ex(rsa, bits, bne, NULL) == 1) {
  45. BIO *bs = BIO_new(BIO_s_mem());
  46. BIO *bp = BIO_new(BIO_s_mem());
  47. BUF_MEM *sptr;
  48. BUF_MEM *pptr;
  49. PEM_write_bio_RSAPrivateKey(bs, rsa, NULL, NULL, 0, 0, NULL);
  50. BIO_get_mem_ptr(bs, &sptr);
  51. PEM_write_bio_RSA_PUBKEY(bp, rsa);
  52. BIO_get_mem_ptr(bp, &pptr);
  53. keypair = xs_dict_new();
  54. keypair = xs_dict_append(keypair, "secret", sptr->data);
  55. keypair = xs_dict_append(keypair, "public", pptr->data);
  56. BIO_free(bs);
  57. BIO_free(bp);
  58. }
  59. }
  60. }
  61. }
  62. return keypair;
  63. }
  64. xs_str *xs_rsa_sign(const char *secret, const char *mem, int size)
  65. /* signs a memory block (secret is in PEM format) */
  66. {
  67. xs_str *signature = NULL;
  68. BIO *b;
  69. RSA *rsa;
  70. unsigned char *sig;
  71. unsigned int sig_len;
  72. /* un-PEM the key */
  73. b = BIO_new_mem_buf(secret, strlen(secret));
  74. rsa = PEM_read_bio_RSAPrivateKey(b, NULL, NULL, NULL);
  75. /* alloc space */
  76. sig = xs_realloc(NULL, RSA_size(rsa));
  77. if (RSA_sign(NID_sha256, (unsigned char *)mem, size, sig, &sig_len, rsa) == 1)
  78. signature = xs_base64_enc((char *)sig, sig_len);
  79. BIO_free(b);
  80. RSA_free(rsa);
  81. xs_free(sig);
  82. return signature;
  83. }
  84. int xs_rsa_verify(const char *pubkey, const char *mem, int size, const char *b64sig)
  85. /* verifies a base64 block, returns non-zero on ok */
  86. {
  87. int r = 0;
  88. BIO *b;
  89. RSA *rsa;
  90. /* un-PEM the key */
  91. b = BIO_new_mem_buf(pubkey, strlen(pubkey));
  92. rsa = PEM_read_bio_RSA_PUBKEY(b, NULL, NULL, NULL);
  93. if (rsa != NULL) {
  94. xs *sig = NULL;
  95. int s_size;
  96. /* de-base64 */
  97. sig = xs_base64_dec(b64sig, &s_size);
  98. if (sig != NULL)
  99. r = RSA_verify(NID_sha256, (unsigned char *)mem, size,
  100. (unsigned char *)sig, s_size, rsa);
  101. }
  102. BIO_free(b);
  103. RSA_free(rsa);
  104. return r;
  105. }
  106. xs_str *xs_evp_sign(const char *secret, const char *mem, int size)
  107. /* signs a memory block (secret is in PEM format) */
  108. {
  109. xs_str *signature = NULL;
  110. BIO *b;
  111. unsigned char *sig;
  112. unsigned int sig_len;
  113. EVP_PKEY *pkey;
  114. EVP_MD_CTX *mdctx;
  115. const EVP_MD *md;
  116. /* un-PEM the key */
  117. b = BIO_new_mem_buf(secret, strlen(secret));
  118. pkey = PEM_read_bio_PrivateKey(b, NULL, NULL, NULL);
  119. /* I've learnt all these magical incantations by watching
  120. the Python module code and the OpenSSL manual pages */
  121. /* Well, "learnt" may be an overstatement */
  122. md = EVP_get_digestbyname("sha256");
  123. mdctx = EVP_MD_CTX_new();
  124. sig_len = EVP_PKEY_size(pkey);
  125. sig = xs_realloc(NULL, sig_len);
  126. EVP_SignInit(mdctx, md);
  127. EVP_SignUpdate(mdctx, mem, size);
  128. if (EVP_SignFinal(mdctx, sig, &sig_len, pkey) == 1)
  129. signature = xs_base64_enc((char *)sig, sig_len);
  130. EVP_MD_CTX_free(mdctx);
  131. EVP_PKEY_free(pkey);
  132. BIO_free(b);
  133. xs_free(sig);
  134. return signature;
  135. }
  136. int xs_evp_verify(const char *pubkey, const char *mem, int size, const char *b64sig)
  137. /* verifies a base64 block, returns non-zero on ok */
  138. {
  139. int r = 0;
  140. BIO *b;
  141. EVP_PKEY *pkey;
  142. EVP_MD_CTX *mdctx;
  143. const EVP_MD *md;
  144. /* un-PEM the key */
  145. b = BIO_new_mem_buf(pubkey, strlen(pubkey));
  146. pkey = PEM_read_bio_PUBKEY(b, NULL, NULL, NULL);
  147. md = EVP_get_digestbyname("sha256");
  148. mdctx = EVP_MD_CTX_new();
  149. if (pkey != NULL) {
  150. xs *sig = NULL;
  151. int s_size;
  152. /* de-base64 */
  153. sig = xs_base64_dec(b64sig, &s_size);
  154. if (sig != NULL) {
  155. EVP_VerifyInit(mdctx, md);
  156. EVP_VerifyUpdate(mdctx, mem, size);
  157. r = EVP_VerifyFinal(mdctx, (unsigned char *)sig, s_size, pkey);
  158. }
  159. }
  160. EVP_MD_CTX_free(mdctx);
  161. EVP_PKEY_free(pkey);
  162. BIO_free(b);
  163. return r;
  164. }
  165. #endif /* XS_IMPLEMENTATION */
  166. #endif /* _XS_OPENSSL_H */