crypto.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. #include <stdio.h>
  2. #include <string>
  3. #include <memory>
  4. using std::unique_ptr;
  5. #include <openssl/err.h>
  6. #include <openssl/bn.h>
  7. #include <openssl/rsa.h>
  8. #include <openssl/evp.h>
  9. #include <openssl/pem.h>
  10. //using BN_ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
  11. //using RSA_ptr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
  12. EVP_CIPHER_CTX *ctx;
  13. RSA* rsa;
  14. BIGNUM* bn;
  15. //RSA_ptr rsa_signing_keypair; //(RSA_new(), ::RSA_free);
  16. //BN_ptr rsa_bignum;
  17. // assumes that the digest is at least of length 256/8 bytes.
  18. uint32_t generate_sha256_hash(const unsigned char *message, size_t message_len, unsigned char *digest)
  19. {
  20. EVP_MD_CTX *mdctx; unsigned int digest_len;
  21. if((mdctx = EVP_MD_CTX_create()) == NULL)
  22. {
  23. printf("EVP_MD_CTX_create returned NULL - could not create context\n"); fflush(stdout); return 0x1;
  24. }
  25. if(EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL) != 1)
  26. {
  27. printf("EVP_DigestInit_ex returned 0 - could not initialize hash with SHA256\n"); fflush(stdout); return 0x2;
  28. }
  29. if(EVP_DigestUpdate(mdctx, message, message_len) != 1)
  30. {
  31. printf("EVP_DigestUpdate returned 0 - could not compute SHA256 hash\n"); fflush(stdout); return 0x3;
  32. }
  33. if(1 != EVP_DigestFinal_ex(mdctx, digest, &digest_len))
  34. {
  35. printf("EVP_DigestFinal_ex returned 0 - could not finalize SHA256 hash\n"); fflush(stdout); return 0x4;
  36. }
  37. if(digest_len != 32)
  38. {
  39. printf("EVP_DigestFinal_ex returned a digest length of 0x%x instead of 0x20\n", digest_len); fflush(stdout); return 0x5;
  40. }
  41. EVP_MD_CTX_destroy(mdctx);
  42. return 0;
  43. }
  44. //private:
  45. // RSA_ptr rsa(RSA_new(), ::RSA_free);
  46. // BN_ptr bn(BN_new(), ::BN_free);
  47. uint32_t generate_rsa_keypair(FILE* fp, std::string& priv_key_str, std::string& pub_key_str) //, uint8_t* hash)
  48. {
  49. int rc;
  50. rsa=RSA_new();
  51. bn=BN_new();
  52. rc = BN_set_word(bn, 3);
  53. if(rc != 1)
  54. return 0x1;
  55. rc = RSA_generate_key_ex(rsa, 3072, bn, NULL);
  56. if(rc != 1)
  57. return 0x2;
  58. printf("Generated key\n"); fflush(stdout);
  59. /* int pub_key_der_encoded_len, priv_key_der_encoded_len;
  60. unsigned char *pub_key_der, priv_key_der;
  61. pub_key_der = NULL;
  62. pub_key_der_encoded_len = i2d_RSAPublicKey(rsa.get(), (unsigned char**) &pub_key_der);
  63. if (pub_key_der_encoded_len < 0)
  64. return 0x3;
  65. priv_key_der = NULL;
  66. priv_key_der_encoded_len = i2d_RSAPrivateKey(rsa.get(), (unsigned char**) &priv_key_der);
  67. if (priv_key_der_encoded_len < 0)
  68. return 0x4;
  69. printf("Done\n"); fflush(stdout);
  70. // priv_key_str=std::string(priv_key_der, priv_key_der_encoded_len); //, priv_key_der);
  71. // pub_key_str=std::string(pub_key_der, pub_key_der_encoded_len);
  72. */
  73. // BIO* bio_rsa;
  74. // rc = PEM_write_RSA_PUBKEY(fp, rsa);
  75. rc= PEM_write_RSAPrivateKey(fp, rsa, NULL, NULL, 0, NULL, NULL);
  76. if(rc != 1)
  77. return 0x3;
  78. fflush(fp);
  79. // bio_rsa = BIO_new_file("apache_signature_keypair.pem", "w+");
  80. // rc = PEM_write_bio_RSAPublicKey(bio_rsa, rsa.get());
  81. // if(rc != 1)
  82. // return 0x3;
  83. // BIO_flush(bio_rsa); free(bio_rsa);
  84. return 0;
  85. }
  86. uint32_t generate_rsa_keypair_hash(uint8_t* hash)
  87. {
  88. uint32_t return_internal;
  89. const BIGNUM* n_internal_bigendian_struct;
  90. RSA_get0_key(rsa, &n_internal_bigendian_struct, NULL, NULL);
  91. BIGNUM* n_bigendian_struct = BN_dup(n_internal_bigendian_struct);
  92. uint32_t count;
  93. int n_bignum_length=BN_num_bytes(n_bigendian_struct);
  94. unsigned char *n_bigendian = (unsigned char*) malloc(n_bignum_length);
  95. int length_bignum_le = BN_bn2bin(n_bigendian_struct, n_bigendian);
  96. unsigned char* n_littleendian = (unsigned char*) malloc(length_bignum_le);
  97. for(count=0; count<length_bignum_le; count++)
  98. n_littleendian[count] = n_bigendian[length_bignum_le-count-1];
  99. free(n_bigendian);
  100. // unsigned char hash[32];
  101. return_internal=generate_sha256_hash(n_littleendian, length_bignum_le, hash);
  102. free(n_littleendian);
  103. if(return_internal != 0)
  104. { return return_internal ; }// TODO: Memory leak here.
  105. for(count=0;count<32; count++)
  106. printf("%x", hash[count]);
  107. printf("\n");
  108. fflush(stdout);
  109. return return_internal;
  110. // return 0; //length_bignum_le;
  111. }
  112. void crypto_cleanup()
  113. {
  114. RSA_free(rsa);
  115. BN_free(bn);
  116. EVP_CIPHER_CTX_free(ctx);
  117. }
  118. // Code adapted from here: https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption
  119. int aes_cipher(int enc, unsigned char *key, unsigned char *iv, unsigned char* plaintext, int plaintext_len, unsigned char *ciphertext, int* op_ciphertext_len, unsigned char* tag)
  120. {
  121. int len;
  122. int ciphertext_len;
  123. int reset_return;
  124. if(ctx == NULL)
  125. {
  126. /* Create and initialise the context */
  127. if(!(ctx = EVP_CIPHER_CTX_new())) { ERR_print_errors_fp(stderr); fflush(stderr);return 0x1; }
  128. }
  129. /* Initialise the encryption operation. */
  130. if(1 != EVP_CipherInit_ex(ctx, EVP_aes_128_gcm(), NULL, key, iv, enc))
  131. {
  132. reset_return = EVP_CIPHER_CTX_reset(ctx);
  133. ERR_print_errors_fp(stderr);
  134. if(reset_return != 1)
  135. return 0xf2;
  136. return 0x2;
  137. }
  138. /* Provide the message to be encrypted, and obtain the encrypted output.
  139. * EVP_EncryptUpdate can be called multiple times if necessary
  140. */
  141. if(1 != EVP_CipherUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
  142. {
  143. reset_return = EVP_CIPHER_CTX_reset(ctx);
  144. ERR_print_errors_fp(stderr);
  145. if(1 != reset_return)
  146. return 0xF3;
  147. return 0x3;
  148. }
  149. ciphertext_len = len;
  150. if(enc == 0)
  151. {
  152. if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
  153. {
  154. reset_return = EVP_CIPHER_CTX_reset(ctx);
  155. ERR_print_errors_fp(stderr); fflush(stderr);
  156. if(1 != reset_return)
  157. return 0xF5;
  158. return 0x5;
  159. }
  160. }
  161. /* Finalise the encryption. Normally ciphertext bytes may be written at
  162. * this stage, but this does not occur in GCM mode
  163. */
  164. // TODO: ^^^ Why the heck does it not occur in GCM mode ?
  165. if(1 != EVP_CipherFinal_ex(ctx, ciphertext + len, &len))
  166. {
  167. reset_return = EVP_CIPHER_CTX_reset(ctx);
  168. ERR_print_errors_fp(stderr); fflush(stderr);
  169. if(1 != reset_return)
  170. return 0xF4;
  171. return 0x4;
  172. }
  173. ciphertext_len += len;
  174. /* Get the tag */
  175. if(enc == 1)
  176. {
  177. if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
  178. {
  179. reset_return = EVP_CIPHER_CTX_reset(ctx);
  180. ERR_print_errors_fp(stderr); fflush(stderr);
  181. if(1 != reset_return)
  182. return 0xF5;
  183. return 0x5;
  184. }
  185. }
  186. /* Clean up */
  187. if(1 != EVP_CIPHER_CTX_reset(ctx))
  188. {
  189. ERR_print_errors_fp(stderr); fflush(stderr);
  190. return 0xF0;
  191. }
  192. *op_ciphertext_len=ciphertext_len;
  193. return 0;
  194. }