dh_util.cc 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /* dh_util.c
  2. *
  3. * Adapted from ZNC-fish
  4. */
  5. #include "src/libcrypto.h"
  6. #include "src/compat/compat.h"
  7. #include <bdlib/src/String.h>
  8. #include <bdlib/src/base64.h>
  9. #include "dh_util.h"
  10. static BIGNUM* b_prime = NULL;
  11. static BIGNUM* b_generator = NULL;
  12. void DH1080_init() {
  13. // ### new sophie-germain 1080bit prime number ###
  14. //const char *prime1080 = "++ECLiPSE+is+proud+to+present+latest+FiSH+release+featuring+even+more+security+for+you+++shouts+go+out+to+TMG+for+helping+to+generate+this+cool+sophie+germain+prime+number++++/C32L";
  15. // Base16: FBE1022E23D213E8ACFA9AE8B9DFADA3EA6B7AC7A7B7E95AB5EB2DF858921FEADE95E6AC7BE7DE6ADBAB8A783E7AF7A7FA6A2B7BEB1E72EAE2B72F9FA2BFB2A2EFBEFAC868BADB3E828FA8BADFADA3E4CC1BE7E8AFE85E9698A783EB68FA07A77AB6AD7BEB618ACF9CA2897EB28A6189EFA07AB99A8A7FA9AE299EFA7BA66DEAFEFBEFBF0B7D8B
  16. // Base10: 12745216229761186769575009943944198619149164746831579719941140425076456621824834322853258804883232842877311723249782818608677050956745409379781245497526069657222703636504651898833151008222772087491045206203033063108075098874712912417029101508315117935752962862335062591404043092163187352352197487303798807791605274487594646923
  17. const char *prime1080 = "FBE1022E23D213E8ACFA9AE8B9DFADA3EA6B7AC7A7B7E95AB5EB2DF858921FEADE95E6AC7BE7DE6ADBAB8A783E7AF7A7FA6A2B7BEB1E72EAE2B72F9FA2BFB2A2EFBEFAC868BADB3E828FA8BADFADA3E4CC1BE7E8AFE85E9698A783EB68FA07A77AB6AD7BEB618ACF9CA2897EB28A6189EFA07AB99A8A7FA9AE299EFA7BA66DEAFEFBEFBF0B7D8B";
  18. if (!BN_hex2bn(&b_prime, prime1080)) {
  19. sdprintf("BAD PRIME");
  20. return;
  21. }
  22. if (!BN_dec2bn(&b_generator, "2")) {
  23. sdprintf("BAD GENERATOR");
  24. return;
  25. }
  26. }
  27. void DH1080_uninit() {
  28. BN_clear_free(b_prime);
  29. BN_clear_free(b_generator);
  30. }
  31. /**
  32. * @brief Encode a string using FiSH's base64 algorithm (from FiSH/mIRC)
  33. * @note Any = padding is removed, and an 'A' is added if no padding was needed
  34. * @param bd::String str The string to encode
  35. * @returns Encoded string
  36. * @note Adapated from FiSH code
  37. */
  38. bd::String fishBase64Encode(const bd::String& str) {
  39. bd::String result(bd::base64Encode(str));
  40. // No padding, add an A on the end (base64-encoded NULL-terminator)
  41. if (result.rfind('=') == result.npos) {
  42. result += 'A';
  43. } else {
  44. // Remove padding
  45. while (result.rfind('=') != result.npos) {
  46. --result;
  47. }
  48. }
  49. return result;
  50. }
  51. /**
  52. * @brief Decode a string using FiSH's base64 algorithm (from FiSH/mIRC)
  53. * @param bd::String str The string to decode
  54. * @returns Decoded data
  55. * @note Adapated from FiSH code
  56. */
  57. bd::String fishBase64Decode(const bd::String& str) {
  58. bd::String temp(str);
  59. // Remove the 'A' NULL-terminator if present
  60. if (temp.length() % 4 == 1 && temp(-1, 1) == 'A') {
  61. --temp;
  62. }
  63. while (temp.length() % 4) {
  64. temp += '=';
  65. }
  66. return bd::base64Decode(temp);
  67. }
  68. void DH1080_gen(bd::String& privateKey, bd::String& publicKeyB64) {
  69. DH *dh = NULL;
  70. dh = DH_new();
  71. dh->p = BN_dup(b_prime);
  72. dh->g = BN_dup(b_generator);
  73. if (!DH_generate_key(dh)) {
  74. DH_free(dh);
  75. return;
  76. }
  77. // Get private key
  78. privateKey.resize(BN_num_bytes(dh->priv_key), 0);
  79. BN_bn2bin(dh->priv_key, reinterpret_cast<unsigned char*>(privateKey.mdata()));
  80. // Get public key
  81. bd::String publicKey;
  82. // Resize as the mdata() modification won't update the internal length, but resize() will
  83. publicKey.resize(static_cast<size_t>(BN_num_bytes(dh->pub_key)));
  84. BN_bn2bin(dh->pub_key, reinterpret_cast<unsigned char*>(publicKey.mdata()));;
  85. // base64 encode
  86. publicKeyB64 = fishBase64Encode(publicKey);
  87. DH_free(dh);
  88. }
  89. bool DH1080_comp(const bd::String privateKey, const bd::String theirPublicKeyB64, bd::String& sharedKey) {
  90. BIGNUM *b_myPrivkey = NULL, *b_HisPubkey = NULL;
  91. DH *dh = NULL;
  92. dh = DH_new();
  93. dh->p = BN_dup(b_prime);
  94. dh->g = BN_dup(b_generator);
  95. // Setup my private key
  96. b_myPrivkey = BN_bin2bn(reinterpret_cast<const unsigned char*>(privateKey.data()), privateKey.length(), NULL);
  97. dh->priv_key = b_myPrivkey;
  98. // Prep their public key
  99. bd::String theirPublicKey(fishBase64Decode(theirPublicKeyB64));
  100. b_HisPubkey = BN_bin2bn(reinterpret_cast<const unsigned char*>(theirPublicKey.data()), theirPublicKey.length(), NULL);
  101. // Compute the Shared key
  102. char *key = (char *)my_calloc(1, DH_size(dh));
  103. size_t len = DH_compute_key((unsigned char *)key, b_HisPubkey, dh);
  104. DH_free(dh);
  105. BN_clear_free(b_HisPubkey);
  106. if (len == static_cast<size_t>(-1)) {
  107. // Bad pub key
  108. unsigned long err = ERR_get_error();
  109. sdprintf("** DH Error: %s", ERR_error_string(err, NULL));
  110. free(key);
  111. sharedKey = ERR_error_string(err, NULL);
  112. return false;
  113. }
  114. SHA256_CTX c;
  115. bd::String SHA256Digest(static_cast<size_t>(SHA256_DIGEST_LENGTH));
  116. SHA256Digest.resize(SHA256_DIGEST_LENGTH);
  117. SHA256_Init(&c);
  118. SHA256_Update(&c, key, len);
  119. SHA256_Final(reinterpret_cast<unsigned char*>(SHA256Digest.mdata()), &c);
  120. sharedKey = fishBase64Encode(SHA256Digest);
  121. free(key);
  122. return true;
  123. }
  124. /* vim: set sts=2 sw=2 ts=8 et: */