rhash.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. /* rhash.c - implementation of LibRHash library calls
  2. *
  3. * Copyright (c) 2008, Aleksey Kravchenko <[email protected]>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any
  6. * purpose with or without fee is hereby granted.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  9. * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  10. * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  11. * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  12. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  13. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  14. * PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. /* modifier for Windows DLL */
  17. #if (defined(_WIN32) || defined(__CYGWIN__)) && defined(RHASH_EXPORTS)
  18. # define RHASH_API __declspec(dllexport)
  19. #endif
  20. /* macros for large file support, must be defined before any include file */
  21. #define _LARGEFILE64_SOURCE
  22. #define _FILE_OFFSET_BITS 64
  23. #include "ustd.h" /* Need this first within CMake. */
  24. #include "rhash.h"
  25. #include "algorithms.h"
  26. #include "byte_order.h"
  27. #include "hex.h"
  28. #include "util.h"
  29. #include <assert.h>
  30. #include <errno.h>
  31. #include <stdlib.h>
  32. #include <stddef.h>
  33. #include <string.h>
  34. #define STATE_ACTIVE 0xb01dbabe
  35. #define STATE_STOPED 0xdeadbeef
  36. #define STATE_DELETED 0xdecea5ed
  37. #define RCTX_AUTO_FINAL 0x1
  38. #define RCTX_FINALIZED 0x2
  39. #define RCTX_FINALIZED_MASK (RCTX_AUTO_FINAL | RCTX_FINALIZED)
  40. #define RHPR_FORMAT (RHPR_RAW | RHPR_HEX | RHPR_BASE32 | RHPR_BASE64)
  41. #define RHPR_MODIFIER (RHPR_UPPERCASE | RHPR_URLENCODE | RHPR_REVERSE)
  42. void rhash_library_init(void)
  43. {
  44. rhash_init_algorithms(RHASH_ALL_HASHES);
  45. #ifdef USE_OPENSSL
  46. rhash_plug_openssl();
  47. #endif
  48. }
  49. int RHASH_API rhash_count(void)
  50. {
  51. return rhash_info_size;
  52. }
  53. /* LOW-LEVEL LIBRHASH INTERFACE */
  54. RHASH_API rhash rhash_init(unsigned hash_id)
  55. {
  56. unsigned tail_bit_index; /* index of hash_id trailing bit */
  57. unsigned num = 0; /* number of hashes to compute */
  58. rhash_context_ext* rctx = NULL; /* allocated rhash context */
  59. size_t hash_size_sum = 0; /* size of hash contexts to store in rctx */
  60. unsigned i, bit_index, id;
  61. struct rhash_hash_info* info;
  62. size_t aligned_size;
  63. char* phash_ctx;
  64. hash_id &= RHASH_ALL_HASHES;
  65. if (hash_id == 0) {
  66. errno = EINVAL;
  67. return NULL;
  68. }
  69. tail_bit_index = rhash_ctz(hash_id); /* get trailing bit index */
  70. assert(tail_bit_index < RHASH_HASH_COUNT);
  71. id = 1 << tail_bit_index;
  72. if (hash_id == id) {
  73. /* handle the most common case of only one hash */
  74. num = 1;
  75. info = &rhash_info_table[tail_bit_index];
  76. hash_size_sum = info->context_size;
  77. } else {
  78. /* another case: hash_id contains several hashes */
  79. for (bit_index = tail_bit_index; id <= hash_id; bit_index++, id = id << 1) {
  80. assert(id != 0);
  81. assert(bit_index < RHASH_HASH_COUNT);
  82. info = &rhash_info_table[bit_index];
  83. if (hash_id & id) {
  84. /* align sizes by 8 bytes */
  85. aligned_size = (info->context_size + 7) & ~7;
  86. hash_size_sum += aligned_size;
  87. num++;
  88. }
  89. }
  90. assert(num > 1);
  91. }
  92. /* align the size of the rhash context common part */
  93. aligned_size = ((offsetof(rhash_context_ext, vector) + sizeof(rhash_vector_item) * num) + 7) & ~7;
  94. assert(aligned_size >= sizeof(rhash_context_ext));
  95. /* allocate rhash context with enough memory to store contexts of all used hashes */
  96. rctx = (rhash_context_ext*)malloc(aligned_size + hash_size_sum);
  97. if (rctx == NULL) return NULL;
  98. /* initialize common fields of the rhash context */
  99. memset(rctx, 0, sizeof(rhash_context_ext));
  100. rctx->rc.hash_id = hash_id;
  101. rctx->flags = RCTX_AUTO_FINAL; /* turn on auto-final by default */
  102. rctx->state = STATE_ACTIVE;
  103. rctx->hash_vector_size = num;
  104. /* aligned hash contexts follows rctx->vector[num] in the same memory block */
  105. phash_ctx = (char*)rctx + aligned_size;
  106. assert(phash_ctx >= (char*)&rctx->vector[num]);
  107. /* initialize context for every hash in a loop */
  108. for (bit_index = tail_bit_index, id = 1 << tail_bit_index, i = 0;
  109. id <= hash_id; bit_index++, id = id << 1)
  110. {
  111. /* check if a hash function with given id shall be included into rctx */
  112. if ((hash_id & id) != 0) {
  113. info = &rhash_info_table[bit_index];
  114. assert(info->context_size > 0);
  115. assert(((phash_ctx - (char*)0) & 7) == 0); /* hash context is aligned */
  116. assert(info->init != NULL);
  117. rctx->vector[i].hash_info = info;
  118. rctx->vector[i].context = phash_ctx;
  119. #if 0
  120. /* BTIH initialization is complex, save pointer for later */
  121. if ((id & RHASH_BTIH) != 0) rctx->bt_ctx = phash_ctx;
  122. #endif
  123. phash_ctx += (info->context_size + 7) & ~7;
  124. /* initialize the i-th hash context */
  125. info->init(rctx->vector[i].context);
  126. i++;
  127. }
  128. }
  129. return &rctx->rc; /* return allocated and initialized rhash context */
  130. }
  131. void rhash_free(rhash ctx)
  132. {
  133. rhash_context_ext* const ectx = (rhash_context_ext*)ctx;
  134. unsigned i;
  135. if (ctx == 0) return;
  136. assert(ectx->hash_vector_size <= RHASH_HASH_COUNT);
  137. ectx->state = STATE_DELETED; /* mark memory block as being removed */
  138. /* clean the hash functions, which require additional clean up */
  139. for (i = 0; i < ectx->hash_vector_size; i++) {
  140. struct rhash_hash_info* info = ectx->vector[i].hash_info;
  141. if (info->cleanup != 0) {
  142. info->cleanup(ectx->vector[i].context);
  143. }
  144. }
  145. free(ectx);
  146. }
  147. RHASH_API void rhash_reset(rhash ctx)
  148. {
  149. rhash_context_ext* const ectx = (rhash_context_ext*)ctx;
  150. unsigned i;
  151. assert(ectx->hash_vector_size > 0);
  152. assert(ectx->hash_vector_size <= RHASH_HASH_COUNT);
  153. ectx->state = STATE_ACTIVE; /* re-activate the structure */
  154. /* re-initialize every hash in a loop */
  155. for (i = 0; i < ectx->hash_vector_size; i++) {
  156. struct rhash_hash_info* info = ectx->vector[i].hash_info;
  157. if (info->cleanup != 0) {
  158. info->cleanup(ectx->vector[i].context);
  159. }
  160. assert(info->init != NULL);
  161. info->init(ectx->vector[i].context);
  162. }
  163. ectx->flags &= ~RCTX_FINALIZED; /* clear finalized state */
  164. }
  165. RHASH_API int rhash_update(rhash ctx, const void* message, size_t length)
  166. {
  167. rhash_context_ext* const ectx = (rhash_context_ext*)ctx;
  168. unsigned i;
  169. assert(ectx->hash_vector_size <= RHASH_HASH_COUNT);
  170. if (ectx->state != STATE_ACTIVE) return 0; /* do nothing if canceled */
  171. ctx->msg_size += length;
  172. /* call update method for every algorithm */
  173. for (i = 0; i < ectx->hash_vector_size; i++) {
  174. struct rhash_hash_info* info = ectx->vector[i].hash_info;
  175. assert(info->update != 0);
  176. info->update(ectx->vector[i].context, message, length);
  177. }
  178. return 0; /* no error processing at the moment */
  179. }
  180. RHASH_API int rhash_final(rhash ctx, unsigned char* first_result)
  181. {
  182. unsigned i = 0;
  183. unsigned char buffer[130];
  184. unsigned char* out = (first_result ? first_result : buffer);
  185. rhash_context_ext* const ectx = (rhash_context_ext*)ctx;
  186. assert(ectx->hash_vector_size <= RHASH_HASH_COUNT);
  187. /* skip final call if already finalized and auto-final is on */
  188. if ((ectx->flags & RCTX_FINALIZED_MASK) ==
  189. (RCTX_AUTO_FINAL | RCTX_FINALIZED)) return 0;
  190. /* call final method for every algorithm */
  191. for (i = 0; i < ectx->hash_vector_size; i++) {
  192. struct rhash_hash_info* info = ectx->vector[i].hash_info;
  193. assert(info->final != 0);
  194. assert(info->info->digest_size < sizeof(buffer));
  195. info->final(ectx->vector[i].context, out);
  196. out = buffer;
  197. }
  198. ectx->flags |= RCTX_FINALIZED;
  199. return 0; /* no error processing at the moment */
  200. }
  201. /**
  202. * Store digest for given hash_id.
  203. * If hash_id is zero, function stores digest for a hash with the lowest id found in the context.
  204. * For nonzero hash_id the context must contain it, otherwise function silently does nothing.
  205. *
  206. * @param ctx rhash context
  207. * @param hash_id id of hash to retrieve or zero for hash with the lowest available id
  208. * @param result buffer to put the hash into
  209. */
  210. static void rhash_put_digest(rhash ctx, unsigned hash_id, unsigned char* result)
  211. {
  212. rhash_context_ext* const ectx = (rhash_context_ext*)ctx;
  213. unsigned i;
  214. rhash_vector_item* item;
  215. struct rhash_hash_info* info;
  216. unsigned char* digest;
  217. assert(ectx);
  218. assert(ectx->hash_vector_size > 0 && ectx->hash_vector_size <= RHASH_HASH_COUNT);
  219. /* finalize context if not yet finalized and auto-final is on */
  220. if ((ectx->flags & RCTX_FINALIZED_MASK) == RCTX_AUTO_FINAL) {
  221. rhash_final(ctx, NULL);
  222. }
  223. if (hash_id == 0) {
  224. item = &ectx->vector[0]; /* get the first hash */
  225. info = item->hash_info;
  226. } else {
  227. for (i = 0;; i++) {
  228. if (i >= ectx->hash_vector_size) {
  229. return; /* hash_id not found, do nothing */
  230. }
  231. item = &ectx->vector[i];
  232. info = item->hash_info;
  233. if (info->info->hash_id == hash_id) break;
  234. }
  235. }
  236. digest = ((unsigned char*)item->context + info->digest_diff);
  237. if (info->info->flags & F_SWAP32) {
  238. assert((info->info->digest_size & 3) == 0);
  239. /* NB: the next call is correct only for multiple of 4 byte size */
  240. rhash_swap_copy_str_to_u32(result, 0, digest, info->info->digest_size);
  241. } else if (info->info->flags & F_SWAP64) {
  242. rhash_swap_copy_u64_to_str(result, digest, info->info->digest_size);
  243. } else {
  244. memcpy(result, digest, info->info->digest_size);
  245. }
  246. }
  247. RHASH_API void rhash_set_callback(rhash ctx, rhash_callback_t callback, void* callback_data)
  248. {
  249. ((rhash_context_ext*)ctx)->callback = (void*)callback;
  250. ((rhash_context_ext*)ctx)->callback_data = callback_data;
  251. }
  252. /* HIGH-LEVEL LIBRHASH INTERFACE */
  253. RHASH_API int rhash_msg(unsigned hash_id, const void* message, size_t length, unsigned char* result)
  254. {
  255. rhash ctx;
  256. hash_id &= RHASH_ALL_HASHES;
  257. ctx = rhash_init(hash_id);
  258. if (ctx == NULL) return -1;
  259. rhash_update(ctx, message, length);
  260. rhash_final(ctx, result);
  261. rhash_free(ctx);
  262. return 0;
  263. }
  264. RHASH_API int rhash_file_update(rhash ctx, FILE* fd)
  265. {
  266. rhash_context_ext* const ectx = (rhash_context_ext*)ctx;
  267. const size_t block_size = 8192;
  268. unsigned char* buffer;
  269. unsigned char* pmem;
  270. size_t length = 0, align8;
  271. int res = 0;
  272. if (ectx->state != STATE_ACTIVE) return 0; /* do nothing if canceled */
  273. if (ctx == NULL) {
  274. errno = EINVAL;
  275. return -1;
  276. }
  277. pmem = (unsigned char*)malloc(block_size + 8);
  278. if (!pmem) return -1; /* errno is set to ENOMEM according to UNIX 98 */
  279. align8 = ((unsigned char*)0 - pmem) & 7;
  280. buffer = pmem + align8;
  281. while (!feof(fd)) {
  282. /* stop if canceled */
  283. if (ectx->state != STATE_ACTIVE) break;
  284. length = fread(buffer, 1, block_size, fd);
  285. if (ferror(fd)) {
  286. res = -1; /* note: errno contains error code */
  287. break;
  288. } else if (length) {
  289. rhash_update(ctx, buffer, length);
  290. if (ectx->callback) {
  291. ((rhash_callback_t)ectx->callback)(ectx->callback_data, ectx->rc.msg_size);
  292. }
  293. }
  294. }
  295. free(buffer);
  296. return res;
  297. }
  298. RHASH_API int rhash_file(unsigned hash_id, const char* filepath, unsigned char* result)
  299. {
  300. FILE* fd;
  301. rhash ctx;
  302. int res;
  303. hash_id &= RHASH_ALL_HASHES;
  304. if (hash_id == 0) {
  305. errno = EINVAL;
  306. return -1;
  307. }
  308. if ((fd = fopen(filepath, "rb")) == NULL) return -1;
  309. if ((ctx = rhash_init(hash_id)) == NULL) {
  310. fclose(fd);
  311. return -1;
  312. }
  313. res = rhash_file_update(ctx, fd); /* hash the file */
  314. fclose(fd);
  315. rhash_final(ctx, result);
  316. rhash_free(ctx);
  317. return res;
  318. }
  319. #ifdef _WIN32 /* windows only function */
  320. #include <share.h>
  321. RHASH_API int rhash_wfile(unsigned hash_id, const wchar_t* filepath, unsigned char* result)
  322. {
  323. FILE* fd;
  324. rhash ctx;
  325. int res;
  326. hash_id &= RHASH_ALL_HASHES;
  327. if (hash_id == 0) {
  328. errno = EINVAL;
  329. return -1;
  330. }
  331. if ((fd = _wfsopen(filepath, L"rb", _SH_DENYWR)) == NULL) return -1;
  332. if ((ctx = rhash_init(hash_id)) == NULL) {
  333. fclose(fd);
  334. return -1;
  335. }
  336. res = rhash_file_update(ctx, fd); /* hash the file */
  337. fclose(fd);
  338. rhash_final(ctx, result);
  339. rhash_free(ctx);
  340. return res;
  341. }
  342. #endif
  343. /* RHash information functions */
  344. #if 0
  345. RHASH_API int rhash_is_base32(unsigned hash_id)
  346. {
  347. /* fast method is just to test a bit-mask */
  348. return ((hash_id & (RHASH_TTH | RHASH_AICH)) != 0);
  349. }
  350. #endif
  351. RHASH_API int rhash_get_digest_size(unsigned hash_id)
  352. {
  353. hash_id &= RHASH_ALL_HASHES;
  354. if (hash_id == 0 || (hash_id & (hash_id - 1)) != 0) return -1;
  355. return (int)rhash_info_table[rhash_ctz(hash_id)].info->digest_size;
  356. }
  357. RHASH_API int rhash_get_hash_length(unsigned hash_id)
  358. {
  359. const rhash_info* info = rhash_info_by_id(hash_id);
  360. return (int)(info ? (info->flags & F_BS32 ?
  361. BASE32_LENGTH(info->digest_size) : info->digest_size * 2) : 0);
  362. }
  363. RHASH_API const char* rhash_get_name(unsigned hash_id)
  364. {
  365. const rhash_info* info = rhash_info_by_id(hash_id);
  366. return (info ? info->name : 0);
  367. }
  368. RHASH_API const char* rhash_get_magnet_name(unsigned hash_id)
  369. {
  370. const rhash_info* info = rhash_info_by_id(hash_id);
  371. return (info ? info->magnet_name : 0);
  372. }
  373. #if 0
  374. static size_t rhash_get_magnet_url_size(const char* filepath,
  375. rhash context, unsigned hash_mask, int flags)
  376. {
  377. size_t size = 0; /* count terminating '\0' */
  378. unsigned bit, hash = context->hash_id & hash_mask;
  379. /* RHPR_NO_MAGNET, RHPR_FILESIZE */
  380. if ((flags & RHPR_NO_MAGNET) == 0) {
  381. size += 8;
  382. }
  383. if ((flags & RHPR_FILESIZE) != 0) {
  384. uint64_t num = context->msg_size;
  385. size += 4;
  386. if (num == 0) size++;
  387. else {
  388. for (; num; num /= 10, size++);
  389. }
  390. }
  391. if (filepath) {
  392. size += 4 + rhash_urlencode(NULL, filepath, strlen(filepath), 0);
  393. }
  394. /* loop through hash values */
  395. for (bit = hash & -(int)hash; bit <= hash; bit <<= 1) {
  396. const char* name;
  397. if ((bit & hash) == 0) continue;
  398. if ((name = rhash_get_magnet_name(bit)) == 0) continue;
  399. size += (7 + 2) + strlen(name);
  400. size += rhash_print(NULL, context, bit,
  401. (bit & RHASH_SHA1 ? RHPR_BASE32 : 0));
  402. }
  403. return size;
  404. }
  405. RHASH_API size_t rhash_print_magnet(char* output, const char* filepath,
  406. rhash context, unsigned hash_mask, int flags)
  407. {
  408. int i;
  409. const char* begin = output;
  410. if (output == NULL)
  411. return rhash_get_magnet_url_size(filepath, context, hash_mask, flags);
  412. /* RHPR_NO_MAGNET, RHPR_FILESIZE */
  413. if ((flags & RHPR_NO_MAGNET) == 0) {
  414. strcpy(output, "magnet:?");
  415. output += 8;
  416. }
  417. if ((flags & RHPR_FILESIZE) != 0) {
  418. strcpy(output, "xl=");
  419. output += 3;
  420. output += rhash_sprintI64(output, context->msg_size);
  421. *(output++) = '&';
  422. }
  423. flags &= RHPR_UPPERCASE;
  424. if (filepath) {
  425. strcpy(output, "dn=");
  426. output += 3;
  427. output += rhash_urlencode(output, filepath, strlen(filepath), flags);
  428. *(output++) = '&';
  429. }
  430. for (i = 0; i < 2; i++) {
  431. unsigned bit;
  432. unsigned hash = context->hash_id & hash_mask;
  433. hash = (i == 0 ? hash & (RHASH_ED2K | RHASH_AICH)
  434. : hash & ~(RHASH_ED2K | RHASH_AICH));
  435. if (!hash) continue;
  436. /* loop through hash values */
  437. for (bit = hash & -(int)hash; bit <= hash; bit <<= 1) {
  438. const char* name;
  439. if ((bit & hash) == 0) continue;
  440. if (!(name = rhash_get_magnet_name(bit))) continue;
  441. strcpy(output, "xt=urn:");
  442. output += 7;
  443. strcpy(output, name);
  444. output += strlen(name);
  445. *(output++) = ':';
  446. output += rhash_print(output, context, bit,
  447. (bit & RHASH_SHA1 ? flags | RHPR_BASE32 : flags));
  448. *(output++) = '&';
  449. }
  450. }
  451. output[-1] = '\0'; /* terminate the line */
  452. return (output - begin);
  453. }
  454. /* HASH SUM OUTPUT INTERFACE */
  455. size_t rhash_print_bytes(char* output, const unsigned char* bytes, size_t size, int flags)
  456. {
  457. size_t result_length;
  458. int upper_case = (flags & RHPR_UPPERCASE);
  459. int format = (flags & ~RHPR_MODIFIER);
  460. switch (format) {
  461. case RHPR_HEX:
  462. result_length = size * 2;
  463. rhash_byte_to_hex(output, bytes, size, upper_case);
  464. break;
  465. case RHPR_BASE32:
  466. result_length = BASE32_LENGTH(size);
  467. rhash_byte_to_base32(output, bytes, size, upper_case);
  468. break;
  469. case RHPR_BASE64:
  470. result_length = rhash_base64_url_encoded_helper(output, bytes, size, (flags & RHPR_URLENCODE), upper_case);
  471. break;
  472. default:
  473. if (flags & RHPR_URLENCODE) {
  474. result_length = rhash_urlencode(output, (char*)bytes, size, upper_case);
  475. } else {
  476. memcpy(output, bytes, size);
  477. result_length = size;
  478. }
  479. break;
  480. }
  481. return result_length;
  482. }
  483. size_t RHASH_API rhash_print(char* output, rhash context, unsigned hash_id, int flags)
  484. {
  485. const rhash_info* info;
  486. unsigned char digest[80];
  487. size_t digest_size;
  488. info = (hash_id != 0 ? rhash_info_by_id(hash_id) :
  489. ((rhash_context_ext*)context)->vector[0].hash_info->info);
  490. if (info == NULL) return 0;
  491. digest_size = info->digest_size;
  492. assert(digest_size <= 64);
  493. flags &= (RHPR_FORMAT | RHPR_MODIFIER);
  494. if ((flags & RHPR_FORMAT) == 0) {
  495. /* use default format if not specified by flags */
  496. flags |= (info->flags & RHASH_INFO_BASE32 ? RHPR_BASE32 : RHPR_HEX);
  497. }
  498. if (output == NULL) {
  499. size_t multiplier = (flags & RHPR_URLENCODE ? 3 : 1);
  500. switch (flags & RHPR_FORMAT) {
  501. case RHPR_HEX:
  502. return (digest_size * 2);
  503. case RHPR_BASE32:
  504. return BASE32_LENGTH(digest_size);
  505. case RHPR_BASE64:
  506. return BASE64_LENGTH(digest_size) * multiplier;
  507. default:
  508. return digest_size * multiplier;
  509. }
  510. }
  511. /* note: use info->hash_id, cause hash_id can be 0 */
  512. rhash_put_digest(context, info->hash_id, digest);
  513. if ((flags & ~RHPR_UPPERCASE) == (RHPR_REVERSE | RHPR_HEX)) {
  514. /* reverse the digest */
  515. unsigned char* p = digest;
  516. unsigned char* r = digest + digest_size - 1;
  517. char tmp;
  518. for (; p < r; p++, r--) {
  519. tmp = *p;
  520. *p = *r;
  521. *r = tmp;
  522. }
  523. }
  524. return rhash_print_bytes(output, digest, digest_size, flags);
  525. }
  526. #if (defined(_WIN32) || defined(__CYGWIN__)) && defined(RHASH_EXPORTS)
  527. #include <windows.h>
  528. BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved);
  529. BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved)
  530. {
  531. (void)hModule;
  532. (void)reserved;
  533. switch (reason) {
  534. case DLL_PROCESS_ATTACH:
  535. rhash_library_init();
  536. break;
  537. case DLL_PROCESS_DETACH:
  538. /*rhash_library_free();*/
  539. case DLL_THREAD_ATTACH:
  540. case DLL_THREAD_DETACH:
  541. break;
  542. }
  543. return TRUE;
  544. }
  545. #endif
  546. #define PVOID2UPTR(p) ((rhash_uptr_t)(((char*)(p)) + 0))
  547. RHASH_API rhash_uptr_t rhash_transmit(unsigned msg_id, void* dst, rhash_uptr_t ldata, rhash_uptr_t rdata)
  548. {
  549. /* for messages working with rhash context */
  550. rhash_context_ext* const ctx = (rhash_context_ext*)dst;
  551. switch (msg_id) {
  552. case RMSG_GET_CONTEXT:
  553. {
  554. unsigned i;
  555. for (i = 0; i < ctx->hash_vector_size; i++) {
  556. struct rhash_hash_info* info = ctx->vector[i].hash_info;
  557. if (info->info->hash_id == (unsigned)ldata)
  558. return PVOID2UPTR(ctx->vector[i].context);
  559. }
  560. return (rhash_uptr_t)0;
  561. }
  562. case RMSG_CANCEL:
  563. /* mark rhash context as canceled, in a multithreaded program */
  564. atomic_compare_and_swap(&ctx->state, STATE_ACTIVE, STATE_STOPED);
  565. return 0;
  566. case RMSG_IS_CANCELED:
  567. return (ctx->state == STATE_STOPED);
  568. case RMSG_GET_FINALIZED:
  569. return ((ctx->flags & RCTX_FINALIZED) != 0);
  570. case RMSG_SET_AUTOFINAL:
  571. ctx->flags &= ~RCTX_AUTO_FINAL;
  572. if (ldata) ctx->flags |= RCTX_AUTO_FINAL;
  573. break;
  574. /* OpenSSL related messages */
  575. #ifdef USE_OPENSSL
  576. case RMSG_SET_OPENSSL_MASK:
  577. rhash_openssl_hash_mask = (unsigned)ldata;
  578. break;
  579. case RMSG_GET_OPENSSL_MASK:
  580. return rhash_openssl_hash_mask;
  581. #endif
  582. case RMSG_GET_OPENSSL_SUPPORTED_MASK:
  583. return rhash_get_openssl_supported_hash_mask();
  584. case RMSG_GET_OPENSSL_AVAILABLE_MASK:
  585. return rhash_get_openssl_available_hash_mask();
  586. default:
  587. return RHASH_ERROR; /* unknown message */
  588. }
  589. return 0;
  590. }
  591. #endif