BBS2chProxyAuth.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. #include <curl/curl.h>
  2. #include <time.h>
  3. #include <string.h>
  4. #include <stdio.h>
  5. #if defined(USE_GNUTLS)
  6. #include <gnutls/gnutls.h>
  7. #include <gnutls/crypto.h>
  8. #elif defined(__APPLE__)
  9. #define USE_CC_CRYPT 1
  10. #include <CommonCrypto/CommonDigest.h>
  11. #elif defined(_WIN32)
  12. #include <windows.h>
  13. #include <wincrypt.h>
  14. #else
  15. #include <openssl/sha.h>
  16. #endif
  17. #include <sstream>
  18. #include <iomanip>
  19. #include "BBS2chProxyAuth.h"
  20. #include "DataStorage.h"
  21. #define SID_UPDATE_INTERVAL (60*60)
  22. #ifdef USE_CC_CRYPT
  23. #define SHA256_CTX CC_SHA256_CTX
  24. #define SHA256_Init CC_SHA256_Init
  25. #define SHA256_Update CC_SHA256_Update
  26. #define SHA256_Final CC_SHA256_Final
  27. #endif
  28. extern char *proxy_server;
  29. extern long proxy_port;
  30. extern long proxy_type;
  31. extern long timeout;
  32. extern char *user_agent;
  33. extern char *appKey;
  34. extern char *hmacKey;
  35. extern char *api_ua_auth;
  36. extern char *x_2ch_ua_auth;
  37. extern int force_ipv4;
  38. extern char *api_server;
  39. extern int force_5chnet_https;
  40. extern CURLSH *curl_share;
  41. extern void log_printf(int level, const char *format ...);
  42. typedef struct
  43. {
  44. #ifdef _WIN32
  45. HCRYPTPROV prov;
  46. HCRYPTHASH sha;
  47. #elif defined(USE_GNUTLS)
  48. gnutls_hmac_hd_t hmac;
  49. #else
  50. SHA256_CTX sha;
  51. #endif
  52. unsigned char keybuf[64];
  53. } hmac_sha256_t;
  54. static void HMAC_SHA256_Init(hmac_sha256_t *hmac, const void *key, int length)
  55. {
  56. #ifdef _WIN32
  57. int i;
  58. CryptAcquireContext(&hmac->prov,NULL,NULL,PROV_RSA_AES,CRYPT_VERIFYCONTEXT);
  59. if(length > 64) {
  60. unsigned char digest[32];
  61. HCRYPTHASH sha;
  62. DWORD bufLength = 32;
  63. CryptCreateHash(hmac->prov,CALG_SHA_256,0,0,&sha);
  64. CryptHashData(sha,(PBYTE)key,length,0);
  65. CryptGetHashParam(sha,HP_HASHVAL,hmac->keybuf,&bufLength,0);
  66. CryptDestroyHash(sha);
  67. }
  68. else memcpy(hmac->keybuf,key,length);
  69. for(i=length;i<64;i++) hmac->keybuf[i] = 0;
  70. for(i=0;i<64;i++) hmac->keybuf[i] ^= 0x36;
  71. CryptCreateHash(hmac->prov,CALG_SHA_256,0,0,&hmac->sha);
  72. CryptHashData(hmac->sha,hmac->keybuf,64,0);
  73. #elif defined(USE_GNUTLS)
  74. gnutls_hmac_init(&hmac->hmac, GNUTLS_MAC_SHA256, key, length);
  75. #else
  76. int i;
  77. if(length > 64) {
  78. unsigned char digest[32];
  79. SHA256_CTX sha;
  80. SHA256_Init(&sha);
  81. SHA256_Update(&sha,key,length);
  82. SHA256_Final(digest,&sha);
  83. memcpy(hmac->keybuf,digest,32);
  84. length = 32;
  85. }
  86. else memcpy(hmac->keybuf,key,length);
  87. for(i=length;i<64;i++) hmac->keybuf[i] = 0;
  88. for(i=0;i<64;i++) hmac->keybuf[i] ^= 0x36;
  89. SHA256_Init(&hmac->sha);
  90. SHA256_Update(&hmac->sha,hmac->keybuf,64);
  91. #endif
  92. }
  93. static void HMAC_SHA256_Update(hmac_sha256_t *hmac, const void *data, int length)
  94. {
  95. #ifdef _WIN32
  96. CryptHashData(hmac->sha,(PBYTE)data,length,0);
  97. #elif defined(USE_GNUTLS)
  98. gnutls_hmac(hmac->hmac, data, length);
  99. #else
  100. SHA256_Update(&hmac->sha,data,length);
  101. #endif
  102. }
  103. static void HMAC_SHA256_Final(hmac_sha256_t *hmac, unsigned char *md)
  104. {
  105. #ifdef _WIN32
  106. DWORD i, bufLength = 32;
  107. CryptGetHashParam(hmac->sha,HP_HASHVAL,md,&bufLength,0);
  108. CryptDestroyHash(hmac->sha);
  109. HCRYPTHASH sha;
  110. CryptCreateHash(hmac->prov,CALG_SHA_256,0,0,&sha);
  111. for(i=0;i<64;i++) hmac->keybuf[i] ^= 0x36 ^ 0x5c;
  112. CryptHashData(sha,hmac->keybuf,64,0);
  113. CryptHashData(sha,md,32,0);
  114. CryptGetHashParam(sha,HP_HASHVAL,md,&bufLength,0);
  115. CryptDestroyHash(sha);
  116. CryptReleaseContext(hmac->prov, 0);
  117. #elif defined(USE_GNUTLS)
  118. gnutls_hmac_deinit(hmac->hmac, md);
  119. #else
  120. int i;
  121. SHA256_Final(md,&hmac->sha);
  122. SHA256_CTX sha;
  123. SHA256_Init(&sha);
  124. for(i=0;i<64;i++) hmac->keybuf[i] ^= 0x36 ^ 0x5c;
  125. SHA256_Update(&sha,hmac->keybuf,64);
  126. SHA256_Update(&sha,md,32);
  127. SHA256_Final(md,&sha);
  128. #endif
  129. }
  130. static size_t write_callback_download(char *buffer, size_t size, size_t nitems, void *userdata)
  131. {
  132. DataStorage *data = reinterpret_cast<DataStorage *>(userdata);
  133. size_t downloaded = size*nitems;
  134. data->appendBytes(buffer, downloaded);
  135. return downloaded;
  136. }
  137. bool BBS2chProxyAuth::updateSID(void)
  138. {
  139. int ct = time(0);
  140. bool ret = false;
  141. CURL *curl;
  142. pthread_mutex_lock(mutex);
  143. if(ct < expire) {
  144. ret = true;
  145. goto last;
  146. }
  147. curl = curl_easy_init();
  148. if(curl) {
  149. CURLcode res;
  150. struct curl_slist *headers = NULL;
  151. DataStorage *dat = new DataStorage();
  152. char gateway[1024];
  153. if(force_5chnet_https) sprintf(gateway,"https://%s/v1/auth/",api_server);
  154. else sprintf(gateway,"http://%s/v1/auth/",api_server);
  155. if(curl_share) curl_easy_setopt(curl, CURLOPT_SHARE, curl_share);
  156. curl_easy_setopt(curl, CURLOPT_URL, gateway);
  157. curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
  158. curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
  159. curl_easy_setopt(curl, CURLOPT_ENCODING, "");
  160. curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback_download);
  161. curl_easy_setopt(curl, CURLOPT_WRITEDATA, dat);
  162. curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
  163. curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
  164. if(force_ipv4) curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
  165. if(proxy_server) {
  166. curl_easy_setopt(curl, CURLOPT_PROXY, proxy_server);
  167. curl_easy_setopt(curl, CURLOPT_PROXYPORT, proxy_port);
  168. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, proxy_type);
  169. }
  170. curl_easy_setopt(curl, CURLOPT_USERAGENT, api_ua_auth?api_ua_auth:"");
  171. if(x_2ch_ua_auth) headers = curl_slist_append(headers, x_2ch_ua_auth);
  172. if(headers) curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
  173. curl_easy_setopt(curl, CURLOPT_POST, 1L);
  174. std::stringstream postData;
  175. std::stringstream msg;
  176. postData << "ID=&PW=&KY=" << appKey << "&CT=" << ct << "&HB=";
  177. msg << appKey << ct;
  178. hmac_sha256_t hmac;
  179. unsigned char digest[32];
  180. HMAC_SHA256_Init(&hmac, hmacKey, strlen(hmacKey));
  181. HMAC_SHA256_Update(&hmac, msg.str().c_str(), msg.str().length());
  182. HMAC_SHA256_Final(&hmac, digest);
  183. for(int i=0;i<32;i++) {
  184. postData << std::hex << std::setw(2) << std::setfill('0') << (unsigned int)digest[i];
  185. }
  186. #if LIBCURL_VERSION_NUM >= 0x071101
  187. curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, postData.str().c_str());
  188. #else
  189. std::string postDataStr = postData.str();
  190. curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postDataStr.c_str());
  191. #endif
  192. res = curl_easy_perform(curl);
  193. if(res == CURLE_OK) {
  194. long statusCode;
  195. curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE, &statusCode);
  196. //fprintf(stderr,"%ld\n",statusCode);
  197. if(statusCode == 200) {
  198. dat->appendBytes("",1);
  199. char *ptr = strchr(dat->bytes,':');
  200. if(ptr && !strncmp(dat->bytes,"SESSION-ID=Monazilla",20)) {
  201. sid = std::string(ptr+1);
  202. expire = ct + SID_UPDATE_INTERVAL;
  203. ret = true;
  204. log_printf(1,"Updated SID: %s\n",sid.c_str());
  205. }
  206. else {
  207. log_printf(0,"Cannot update SID: %s\n",dat->bytes);
  208. }
  209. }
  210. else {
  211. log_printf(0,"Cannot update SID: API gateway returned %ld\n",statusCode);
  212. }
  213. }
  214. else log_printf(0,"curl error while updating SID: %s\n",curl_easy_strerror(res));
  215. curl_slist_free_all(headers);
  216. curl_easy_cleanup(curl);
  217. delete dat;
  218. }
  219. last:
  220. pthread_mutex_unlock(mutex);
  221. return ret;
  222. }
  223. const std::string BBS2chProxyAuth::requestBodyForURL(const char *url)
  224. {
  225. if(!this->updateSID() || sid.empty()) return "";
  226. std::stringstream postData;
  227. std::stringstream msg;
  228. postData << "sid=" << sid << "&appkey=" << appKey << "&hobo=";
  229. msg << strstr(url,"/v1/") << sid << appKey;
  230. hmac_sha256_t hmac;
  231. unsigned char digest[32];
  232. HMAC_SHA256_Init(&hmac, hmacKey, strlen(hmacKey));
  233. HMAC_SHA256_Update(&hmac, msg.str().c_str(), msg.str().length());
  234. HMAC_SHA256_Final(&hmac, digest);
  235. for(int i=0;i<32;i++) {
  236. postData << std::hex << std::setw(2) << std::setfill('0') << (unsigned int)digest[i];
  237. }
  238. return postData.str();
  239. }