obfusc.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. * Stand-alone tool to access the Puzzles obfuscation algorithm.
  3. *
  4. * To deobfuscate, use "obfusc -d":
  5. *
  6. * obfusc -d reads binary data from stdin, writes to stdout
  7. * obfusc -d <hex string> works on the given hex string instead of stdin
  8. * obfusc -d -h writes a hex string instead of binary to stdout
  9. *
  10. * To obfuscate, "obfusc -e":
  11. *
  12. * obfusc -e reads binary from stdin, writes hex to stdout
  13. * obfusc -e <hex string> works on the given hex string instead of stdin
  14. * obfusc -e -b writes binary instead of text to stdout
  15. *
  16. * The default output format is hex for -e and binary for -d
  17. * because that's the way obfuscation is generally used in
  18. * Puzzles. Either of -b and -h can always be specified to set it
  19. * explicitly.
  20. *
  21. * Data read from standard input is assumed always to be binary;
  22. * data provided on the command line is taken to be hex.
  23. */
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <stdarg.h>
  27. #include <string.h>
  28. #include <errno.h>
  29. #include "puzzles.h"
  30. static bool self_tests(void)
  31. {
  32. bool ok = true;
  33. #define FAILED (ok = false, "failed")
  34. /*
  35. * A few simple test vectors for the obfuscator.
  36. *
  37. * First test: the 28-bit stream 1234567. This divides up
  38. * into 1234 and 567[0]. The SHA of 56 70 30 (appending
  39. * "0") is 15ce8ab946640340bbb99f3f48fd2c45d1a31d30. Thus,
  40. * we XOR the 16-bit string 15CE into the input 1234 to get
  41. * 07FA. Next, we SHA that with "0": the SHA of 07 FA 30 is
  42. * 3370135c5e3da4fed937adc004a79533962b6391. So we XOR the
  43. * 12-bit string 337 into the input 567 to get 650. Thus
  44. * our output is 07FA650.
  45. */
  46. {
  47. unsigned char bmp1[] = "\x12\x34\x56\x70";
  48. obfuscate_bitmap(bmp1, 28, false);
  49. printf("test 1 encode: %s\n",
  50. memcmp(bmp1, "\x07\xfa\x65\x00", 4) ? FAILED : "passed");
  51. obfuscate_bitmap(bmp1, 28, true);
  52. printf("test 1 decode: %s\n",
  53. memcmp(bmp1, "\x12\x34\x56\x70", 4) ? FAILED : "passed");
  54. }
  55. /*
  56. * Second test: a long string to make sure we switch from
  57. * one SHA to the next correctly. My input string this time
  58. * is simply fifty bytes of zeroes.
  59. */
  60. {
  61. unsigned char bmp2[50];
  62. unsigned char bmp2a[50];
  63. memset(bmp2, 0, 50);
  64. memset(bmp2a, 0, 50);
  65. obfuscate_bitmap(bmp2, 50 * 8, false);
  66. /*
  67. * SHA of twenty-five zero bytes plus "0" is
  68. * b202c07b990c01f6ff2d544707f60e506019b671. SHA of
  69. * twenty-five zero bytes plus "1" is
  70. * fcb1d8b5a2f6b592fe6780b36aa9d65dd7aa6db9. Thus our
  71. * first half becomes
  72. * b202c07b990c01f6ff2d544707f60e506019b671fcb1d8b5a2.
  73. *
  74. * SHA of that lot plus "0" is
  75. * 10b0af913db85d37ca27f52a9f78bba3a80030db. SHA of the
  76. * same string plus "1" is
  77. * 3d01d8df78e76d382b8106f480135a1bc751d725. So the
  78. * second half becomes
  79. * 10b0af913db85d37ca27f52a9f78bba3a80030db3d01d8df78.
  80. */
  81. printf("test 2 encode: %s\n",
  82. memcmp(bmp2, "\xb2\x02\xc0\x7b\x99\x0c\x01\xf6\xff\x2d\x54"
  83. "\x47\x07\xf6\x0e\x50\x60\x19\xb6\x71\xfc\xb1\xd8"
  84. "\xb5\xa2\x10\xb0\xaf\x91\x3d\xb8\x5d\x37\xca\x27"
  85. "\xf5\x2a\x9f\x78\xbb\xa3\xa8\x00\x30\xdb\x3d\x01"
  86. "\xd8\xdf\x78", 50) ? FAILED : "passed");
  87. obfuscate_bitmap(bmp2, 50 * 8, true);
  88. printf("test 2 decode: %s\n",
  89. memcmp(bmp2, bmp2a, 50) ? FAILED : "passed");
  90. }
  91. #undef FAILED
  92. return ok;
  93. }
  94. int main(int argc, char **argv)
  95. {
  96. enum { BINARY, DEFAULT, HEX } outputmode = DEFAULT;
  97. char *inhex = NULL;
  98. unsigned char *data;
  99. int datalen;
  100. enum { UNKNOWN, DECODE, ENCODE, SELFTEST } mode = UNKNOWN;
  101. bool doing_opts = true;
  102. while (--argc > 0) {
  103. char *p = *++argv;
  104. if (doing_opts && *p == '-') {
  105. if (!strcmp(p, "--")) {
  106. doing_opts = 0;
  107. continue;
  108. }
  109. p++;
  110. while (*p) {
  111. switch (*p) {
  112. case 'e':
  113. mode = ENCODE;
  114. break;
  115. case 'd':
  116. mode = DECODE;
  117. break;
  118. case 't':
  119. mode = SELFTEST;
  120. break;
  121. case 'b':
  122. outputmode = BINARY;
  123. break;
  124. case 'h':
  125. outputmode = HEX;
  126. break;
  127. default:
  128. fprintf(stderr, "obfusc: unrecognised option '-%c'\n",
  129. *p);
  130. return 1;
  131. }
  132. p++;
  133. }
  134. } else {
  135. if (!inhex) {
  136. inhex = p;
  137. } else {
  138. fprintf(stderr, "obfusc: expected at most one argument\n");
  139. return 1;
  140. }
  141. }
  142. }
  143. if (mode == UNKNOWN) {
  144. fprintf(stderr, "usage: obfusc < -e | -d > [ -b | -h ] [hex data]\n");
  145. fprintf(stderr, " or: obfusc -t to run self-tests\n");
  146. return 0;
  147. }
  148. if (mode == SELFTEST) {
  149. return self_tests() ? 0 : 1;
  150. }
  151. if (outputmode == DEFAULT)
  152. outputmode = (mode == DECODE ? BINARY : HEX);
  153. if (inhex) {
  154. datalen = strlen(inhex) / 2;
  155. data = hex2bin(inhex, datalen);
  156. } else {
  157. int datasize = 4096;
  158. datalen = 0;
  159. data = snewn(datasize, unsigned char);
  160. while (1) {
  161. int ret = fread(data + datalen, 1, datasize - datalen, stdin);
  162. if (ret < 0) {
  163. fprintf(stderr, "obfusc: read: %s\n", strerror(errno));
  164. return 1;
  165. } else if (ret == 0) {
  166. break;
  167. } else {
  168. datalen += ret;
  169. if (datasize - datalen < 4096) {
  170. datasize = datalen * 5 / 4 + 4096;
  171. data = sresize(data, datasize, unsigned char);
  172. }
  173. }
  174. }
  175. }
  176. obfuscate_bitmap(data, datalen * 8, mode == DECODE);
  177. if (outputmode == BINARY) {
  178. int ret = fwrite(data, 1, datalen, stdout);
  179. if (ret < 0) {
  180. fprintf(stderr, "obfusc: write: %s\n", strerror(errno));
  181. return 1;
  182. }
  183. } else {
  184. int i;
  185. for (i = 0; i < datalen; i++)
  186. printf("%02x", data[i]);
  187. printf("\n");
  188. }
  189. return 0;
  190. }