compress.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /* Copyright (c) 2004, Roger Dingledine.
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2017, The Tor Project, Inc. */
  4. /* See LICENSE for licensing information */
  5. /**
  6. * \file compress.c
  7. * \brief Common compression API.
  8. **/
  9. #include "orconfig.h"
  10. #include <stdlib.h>
  11. #include <stdio.h>
  12. #include <assert.h>
  13. #include <string.h>
  14. #include "torint.h"
  15. #ifdef HAVE_NETINET_IN_H
  16. #include <netinet/in.h>
  17. #endif
  18. #include "util.h"
  19. #include "torlog.h"
  20. #include "compress.h"
  21. #include "compress_zlib.h"
  22. /** @{ */
  23. /* These macros define the maximum allowable compression factor. Anything of
  24. * size greater than CHECK_FOR_COMPRESSION_BOMB_AFTER is not allowed to
  25. * have an uncompression factor (uncompressed size:compressed size ratio) of
  26. * any greater than MAX_UNCOMPRESSION_FACTOR.
  27. *
  28. * Picking a value for MAX_UNCOMPRESSION_FACTOR is a trade-off: we want it to
  29. * be small to limit the attack multiplier, but we also want it to be large
  30. * enough so that no legitimate document --even ones we might invent in the
  31. * future -- ever compresses by a factor of greater than
  32. * MAX_UNCOMPRESSION_FACTOR. Within those parameters, there's a reasonably
  33. * large range of possible values. IMO, anything over 8 is probably safe; IMO
  34. * anything under 50 is probably sufficient.
  35. */
  36. #define MAX_UNCOMPRESSION_FACTOR 25
  37. #define CHECK_FOR_COMPRESSION_BOMB_AFTER (1024*64)
  38. /** @} */
  39. /** Return true if uncompressing an input of size <b>in_size</b> to an input of
  40. * size at least <b>size_out</b> looks like a compression bomb. */
  41. int
  42. tor_compress_is_compression_bomb(size_t size_in, size_t size_out)
  43. {
  44. if (size_in == 0 || size_out < CHECK_FOR_COMPRESSION_BOMB_AFTER)
  45. return 0;
  46. return (size_out / size_in > MAX_UNCOMPRESSION_FACTOR);
  47. }
  48. /** Given <b>level</b> return the memory level. The memory level is needed for
  49. * the various compression backends used in Tor.
  50. */
  51. int
  52. tor_compress_memory_level(compression_level_t level)
  53. {
  54. switch (level) {
  55. default:
  56. case HIGH_COMPRESSION: return 8;
  57. case MEDIUM_COMPRESSION: return 7;
  58. case LOW_COMPRESSION: return 6;
  59. }
  60. }
  61. /** Given <b>in_len</b> bytes at <b>in</b>, compress them into a newly
  62. * allocated buffer, using the method described in <b>method</b>. Store the
  63. * compressed string in *<b>out</b>, and its length in *<b>out_len</b>.
  64. * Return 0 on success, -1 on failure.
  65. */
  66. int
  67. tor_compress(char **out, size_t *out_len,
  68. const char *in, size_t in_len,
  69. compress_method_t method)
  70. {
  71. if (method == GZIP_METHOD || method == ZLIB_METHOD)
  72. return tor_zlib_compress(out, out_len, in, in_len, method);
  73. return -1;
  74. }
  75. /** Given zero or more zlib-compressed or gzip-compressed strings of
  76. * total length
  77. * <b>in_len</b> bytes at <b>in</b>, uncompress them into a newly allocated
  78. * buffer, using the method described in <b>method</b>. Store the uncompressed
  79. * string in *<b>out</b>, and its length in *<b>out_len</b>. Return 0 on
  80. * success, -1 on failure.
  81. *
  82. * If <b>complete_only</b> is true, we consider a truncated input as a
  83. * failure; otherwise we decompress as much as we can. Warn about truncated
  84. * or corrupt inputs at <b>protocol_warn_level</b>.
  85. */
  86. int
  87. tor_uncompress(char **out, size_t *out_len,
  88. const char *in, size_t in_len,
  89. compress_method_t method,
  90. int complete_only,
  91. int protocol_warn_level)
  92. {
  93. if (method == GZIP_METHOD || method == ZLIB_METHOD)
  94. return tor_zlib_uncompress(out, out_len, in, in_len,
  95. method,
  96. complete_only,
  97. protocol_warn_level);
  98. return -1;
  99. }
  100. /** Try to tell whether the <b>in_len</b>-byte string in <b>in</b> is likely
  101. * to be compressed or not. If it is, return the likeliest compression method.
  102. * Otherwise, return UNKNOWN_METHOD.
  103. */
  104. compress_method_t
  105. detect_compression_method(const char *in, size_t in_len)
  106. {
  107. if (in_len > 2 && fast_memeq(in, "\x1f\x8b", 2)) {
  108. return GZIP_METHOD;
  109. } else if (in_len > 2 && (in[0] & 0x0f) == 8 &&
  110. (ntohs(get_uint16(in)) % 31) == 0) {
  111. return ZLIB_METHOD;
  112. } else {
  113. return UNKNOWN_METHOD;
  114. }
  115. }
  116. /** Internal state for an incremental compression/decompression. The body of
  117. * this struct is not exposed. */
  118. struct tor_compress_state_t {
  119. compress_method_t method; /**< The compression method. */
  120. union {
  121. tor_zlib_compress_state_t *zlib_state;
  122. } u; /**< Compression backend state. */
  123. };
  124. /** Construct and return a tor_compress_state_t object using <b>method</b>. If
  125. * <b>compress</b>, it's for compression; otherwise it's for decompression. */
  126. tor_compress_state_t *
  127. tor_compress_new(int compress, compress_method_t method,
  128. compression_level_t compression_level)
  129. {
  130. tor_compress_state_t *state;
  131. state = tor_malloc_zero(sizeof(tor_compress_state_t));
  132. state->method = method;
  133. switch (method) {
  134. case GZIP_METHOD:
  135. case ZLIB_METHOD: {
  136. tor_zlib_compress_state_t *zlib_state =
  137. tor_zlib_compress_new(compress, method, compression_level);
  138. if (zlib_state == NULL)
  139. goto err;
  140. state->u.zlib_state = zlib_state;
  141. break;
  142. }
  143. case NO_METHOD:
  144. case UNKNOWN_METHOD:
  145. goto err;
  146. }
  147. return state;
  148. err:
  149. tor_free(state);
  150. return NULL;
  151. }
  152. /** Compress/decompress some bytes using <b>state</b>. Read up to
  153. * *<b>in_len</b> bytes from *<b>in</b>, and write up to *<b>out_len</b> bytes
  154. * to *<b>out</b>, adjusting the values as we go. If <b>finish</b> is true,
  155. * we've reached the end of the input.
  156. *
  157. * Return TOR_COMPRESS_DONE if we've finished the entire
  158. * compression/decompression.
  159. * Return TOR_COMPRESS_OK if we're processed everything from the input.
  160. * Return TOR_COMPRESS_BUFFER_FULL if we're out of space on <b>out</b>.
  161. * Return TOR_COMPRESS_ERROR if the stream is corrupt.
  162. */
  163. tor_compress_output_t
  164. tor_compress_process(tor_compress_state_t *state,
  165. char **out, size_t *out_len,
  166. const char **in, size_t *in_len,
  167. int finish)
  168. {
  169. tor_assert(state != NULL);
  170. switch (state->method) {
  171. case GZIP_METHOD:
  172. case ZLIB_METHOD:
  173. return tor_zlib_compress_process(state->u.zlib_state,
  174. out, out_len, in, in_len,
  175. finish);
  176. case NO_METHOD:
  177. case UNKNOWN_METHOD:
  178. goto err;
  179. }
  180. err:
  181. return TOR_COMPRESS_ERROR;
  182. }
  183. /** Deallocate <b>state</b>. */
  184. void
  185. tor_compress_free(tor_compress_state_t *state)
  186. {
  187. if (state == NULL)
  188. return;
  189. switch (state->method) {
  190. case GZIP_METHOD:
  191. case ZLIB_METHOD:
  192. tor_zlib_compress_free(state->u.zlib_state);
  193. break;
  194. case NO_METHOD:
  195. case UNKNOWN_METHOD:
  196. break;
  197. }
  198. tor_free(state);
  199. }
  200. /** Return the approximate number of bytes allocated for <b>state</b>. */
  201. size_t
  202. tor_compress_state_size(const tor_compress_state_t *state)
  203. {
  204. tor_assert(state != NULL);
  205. switch (state->method) {
  206. case GZIP_METHOD:
  207. case ZLIB_METHOD:
  208. return tor_zlib_compress_state_size(state->u.zlib_state);
  209. case NO_METHOD:
  210. case UNKNOWN_METHOD:
  211. goto err;
  212. }
  213. err:
  214. return 0;
  215. }