1 /* torrent.c - create BitTorrent files and calculate BitTorrent InfoHash (BTIH).
2 *
3 * Copyright (c) 2010, Aleksey Kravchenko <rhash.admin@gmail.com>
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
17 #include <string.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <assert.h>
21 #include <time.h> /* time() */
22
23 #include "byte_order.h"
24 #include "algorithms.h"
25 #include "hex.h"
26 #include "torrent.h"
27
28 #ifdef USE_OPENSSL
29 #define SHA1_INIT(ctx) ((pinit_t)ctx->sha_init)(&ctx->sha1_context)
30 #define SHA1_UPDATE(ctx, msg, size) ((pupdate_t)ctx->sha_update)(&ctx->sha1_context, (msg), (size))
31 #define SHA1_FINAL(ctx, result) ((pfinal_t)ctx->sha_final)(&ctx->sha1_context, (result))
32 #else
33 #define SHA1_INIT(ctx) rhash_sha1_init(&ctx->sha1_context)
34 #define SHA1_UPDATE(ctx, msg, size) rhash_sha1_update(&ctx->sha1_context, (msg), (size))
35 #define SHA1_FINAL(ctx, result) rhash_sha1_final(&ctx->sha1_context, (result))
36 #endif
37
38 #define BT_MIN_HASH_LENGTH 16384
39 /** size of a SHA1 hash in bytes */
40 #define BT_HASH_SIZE 20
41 /** number of SHA1 hashes to store together in one block */
42 #define BT_BLOCK_SIZE 256
43 #define BT_BLOCK_SIZE_IN_BYTES (BT_BLOCK_SIZE * BT_HASH_SIZE)
44
45 /**
46 * Initialize torrent context before calculating hash.
47 *
48 * @param ctx context to initialize
49 */
bt_init(torrent_ctx * ctx)50 void bt_init(torrent_ctx* ctx)
51 {
52 memset(ctx, 0, sizeof(torrent_ctx));
53 ctx->piece_length = BT_MIN_HASH_LENGTH;
54 assert(BT_MIN_HASH_LENGTH == bt_default_piece_length(0));
55
56 #ifdef USE_OPENSSL
57 {
58 /* get the methods of the selected SHA1 algorithm */
59 rhash_hash_info* sha1_info = &rhash_info_table[3];
60 assert(sha1_info->info->hash_id == RHASH_SHA1);
61 assert(sha1_info->context_size <= (sizeof(sha1_ctx) + sizeof(unsigned long)));
62 ctx->sha_init = sha1_info->init;
63 ctx->sha_update = sha1_info->update;
64 ctx->sha_final = sha1_info->final;
65 }
66 #endif
67
68 SHA1_INIT(ctx);
69 }
70
71 /**
72 * Free memory allocated by properties of torrent_vect structure.
73 *
74 * @param vect vector to clean
75 */
bt_vector_clean(torrent_vect * vect)76 static void bt_vector_clean(torrent_vect* vect)
77 {
78 size_t i;
79 for (i = 0; i < vect->size; i++) {
80 free(vect->array[i]);
81 }
82 free(vect->array);
83 }
84
85 /**
86 * Clean up torrent context by freeing all dynamically
87 * allocated memory.
88 *
89 * @param ctx torrent algorithm context
90 */
bt_cleanup(torrent_ctx * ctx)91 void bt_cleanup(torrent_ctx* ctx)
92 {
93 assert(ctx != NULL);
94
95 /* destroy arrays */
96 bt_vector_clean(&ctx->hash_blocks);
97 bt_vector_clean(&ctx->files);
98 bt_vector_clean(&ctx->announce);
99
100 free(ctx->program_name);
101 free(ctx->content.str);
102 ctx->program_name = 0;
103 ctx->content.str = 0;
104 }
105
106 static void bt_generate_torrent(torrent_ctx* ctx);
107
108 /**
109 * Add an item to vector.
110 *
111 * @param vect vector to add item to
112 * @param item the item to add
113 * @return non-zero on success, zero on fail
114 */
bt_vector_add_ptr(torrent_vect * vect,void * item)115 static int bt_vector_add_ptr(torrent_vect* vect, void* item)
116 {
117 /* check if vector contains enough space for the next item */
118 if (vect->size >= vect->allocated) {
119 size_t size = (vect->allocated == 0 ? 128 : vect->allocated * 2);
120 void* new_array = realloc(vect->array, size * sizeof(void*));
121 if (new_array == NULL) return 0; /* failed: no memory */
122 vect->array = (void**)new_array;
123 vect->allocated = size;
124 }
125 /* add new item to the vector */
126 vect->array[vect->size] = item;
127 vect->size++;
128 return 1;
129 }
130
131 /**
132 * Store a SHA1 hash of a processed file piece.
133 *
134 * @param ctx torrent algorithm context
135 * @return non-zero on success, zero on fail
136 */
bt_store_piece_sha1(torrent_ctx * ctx)137 static int bt_store_piece_sha1(torrent_ctx* ctx)
138 {
139 unsigned char* block;
140 unsigned char* hash;
141
142 if ((ctx->piece_count % BT_BLOCK_SIZE) == 0) {
143 block = (unsigned char*)malloc(BT_BLOCK_SIZE_IN_BYTES);
144 if (block == NULL || !bt_vector_add_ptr(&ctx->hash_blocks, block)) {
145 if (block) free(block);
146 return 0;
147 }
148 } else {
149 block = (unsigned char*)(ctx->hash_blocks.array[ctx->piece_count / BT_BLOCK_SIZE]);
150 }
151
152 hash = &block[BT_HASH_SIZE * (ctx->piece_count % BT_BLOCK_SIZE)];
153 SHA1_FINAL(ctx, hash); /* write the hash */
154 ctx->piece_count++;
155 return 1;
156 }
157
158 /**
159 * A filepath and filesize information.
160 */
161 typedef struct bt_file_info
162 {
163 uint64_t size;
164 char path[1];
165 } bt_file_info;
166
167 /**
168 * Add a file info into the batch of files of given torrent.
169 *
170 * @param ctx torrent algorithm context
171 * @param path file path
172 * @param filesize file size
173 * @return non-zero on success, zero on fail
174 */
bt_add_file(torrent_ctx * ctx,const char * path,uint64_t filesize)175 int bt_add_file(torrent_ctx* ctx, const char* path, uint64_t filesize)
176 {
177 size_t len = strlen(path);
178 bt_file_info* info = (bt_file_info*)malloc(sizeof(uint64_t) + len + 1);
179 if (info == NULL) {
180 ctx->error = 1;
181 return 0;
182 }
183
184 info->size = filesize;
185 memcpy(info->path, path, len + 1);
186 if (!bt_vector_add_ptr(&ctx->files, info)) {
187 free(info);
188 return 0;
189 }
190
191 /* recalculate piece length (but only if hashing not started yet) */
192 if (ctx->piece_count == 0 && ctx->index == 0) {
193 /* note: in case of batch of files should use a total batch size */
194 ctx->piece_length = bt_default_piece_length(filesize);
195 }
196 return 1;
197 }
198
199 /**
200 * Calculate message hash.
201 * Can be called repeatedly with chunks of the message to be hashed.
202 *
203 * @param ctx the algorithm context containing current hashing state
204 * @param msg message chunk
205 * @param size length of the message chunk
206 */
bt_update(torrent_ctx * ctx,const void * msg,size_t size)207 void bt_update(torrent_ctx* ctx, const void* msg, size_t size)
208 {
209 const unsigned char* pmsg = (const unsigned char*)msg;
210 size_t rest = (size_t)(ctx->piece_length - ctx->index);
211 assert(ctx->index < ctx->piece_length);
212
213 while (size > 0) {
214 size_t left = (size < rest ? size : rest);
215 SHA1_UPDATE(ctx, pmsg, left);
216 if (size < rest) {
217 ctx->index += left;
218 break;
219 }
220 bt_store_piece_sha1(ctx);
221 SHA1_INIT(ctx);
222 ctx->index = 0;
223
224 pmsg += rest;
225 size -= rest;
226 rest = ctx->piece_length;
227 }
228 }
229
230 /**
231 * Finalize hashing and optionally store calculated hash into the given array.
232 * If the result parameter is NULL, the hash is not stored, but it is
233 * accessible by bt_get_btih().
234 *
235 * @param ctx the algorithm context containing current hashing state
236 * @param result pointer to the array store message hash into
237 */
bt_final(torrent_ctx * ctx,unsigned char result[20])238 void bt_final(torrent_ctx* ctx, unsigned char result[20])
239 {
240 if (ctx->index > 0) {
241 bt_store_piece_sha1(ctx); /* flush buffered data */
242 }
243
244 bt_generate_torrent(ctx);
245 if (result) memcpy(result, ctx->btih, btih_hash_size);
246 }
247
248 /* BitTorrent functions */
249
250 /**
251 * Grow, if needed, the torrent_str buffer to ensure it contains
252 * at least (length + 1) characters.
253 *
254 * @param ctx the torrent algorithm context
255 * @param length length of the string, the allocated buffer must contain
256 * @return 1 on success, 0 on error
257 */
bt_str_ensure_length(torrent_ctx * ctx,size_t length)258 static int bt_str_ensure_length(torrent_ctx* ctx, size_t length)
259 {
260 char* new_str;
261 if (length >= ctx->content.allocated && !ctx->error) {
262 length++; /* allocate one character more */
263 if (length < 64) length = 64;
264 else length = (length + 255) & ~255;
265 new_str = (char*)realloc(ctx->content.str, length);
266 if (new_str == NULL) {
267 ctx->error = 1;
268 ctx->content.allocated = 0;
269 return 0;
270 }
271 ctx->content.str = new_str;
272 ctx->content.allocated = length;
273 }
274 return 1;
275 }
276
277 /**
278 * Append a null-terminated string to the string string buffer.
279 *
280 * @param ctx the torrent algorithm context
281 * @param text the null-terminated string to append
282 */
bt_str_append(torrent_ctx * ctx,const char * text)283 static void bt_str_append(torrent_ctx* ctx, const char* text)
284 {
285 size_t length = strlen(text);
286 if (!bt_str_ensure_length(ctx, ctx->content.length + length + 1))
287 return;
288 assert(ctx->content.str != 0);
289 memcpy(ctx->content.str + ctx->content.length, text, length + 1);
290 ctx->content.length += length;
291 }
292
293 /**
294 * B-encode given integer.
295 *
296 * @param ctx the torrent algorithm context
297 * @param name B-encoded string to prepend the number or NULL
298 * @param number the integer to output
299 */
bt_bencode_int(torrent_ctx * ctx,const char * name,uint64_t number)300 static void bt_bencode_int(torrent_ctx* ctx, const char* name, uint64_t number)
301 {
302 char* p;
303 if (name)
304 bt_str_append(ctx, name);
305
306 /* add up to 20 digits and 2 letters */
307 if (!bt_str_ensure_length(ctx, ctx->content.length + 22))
308 return;
309 p = ctx->content.str + ctx->content.length;
310 *(p++) = 'i';
311 p += rhash_sprintI64(p, number);
312 *(p++) = 'e';
313 *p = '\0'; /* terminate string with \0 */
314
315 ctx->content.length = (p - ctx->content.str);
316 }
317
318 /**
319 * B-encode a string.
320 *
321 * @param ctx the torrent algorithm context
322 * @param name B-encoded string to prepend or NULL
323 * @param str the string to encode
324 */
bt_bencode_str(torrent_ctx * ctx,const char * name,const char * str)325 static void bt_bencode_str(torrent_ctx* ctx, const char* name, const char* str)
326 {
327 const size_t string_length = strlen(str);
328 int number_length;
329 char* p;
330
331 if (name)
332 bt_str_append(ctx, name);
333 if (!bt_str_ensure_length(ctx, ctx->content.length + string_length + 21))
334 return;
335 p = ctx->content.str + ctx->content.length;
336 p += (number_length = rhash_sprintI64(p, string_length));
337 ctx->content.length += string_length + number_length + 1;
338
339 *(p++) = ':';
340 memcpy(p, str, string_length + 1); /* copy with trailing '\0' */
341 }
342
343 /**
344 * B-encode array of SHA1 hashes of file pieces.
345 *
346 * @param ctx pointer to the torrent structure containing SHA1 hashes
347 */
bt_bencode_pieces(torrent_ctx * ctx)348 static void bt_bencode_pieces(torrent_ctx* ctx)
349 {
350 const size_t pieces_length = ctx->piece_count * BT_HASH_SIZE;
351 size_t bytes_left, i;
352 int number_length;
353 char* p;
354
355 if (!bt_str_ensure_length(ctx, ctx->content.length + pieces_length + 21))
356 return;
357 p = ctx->content.str + ctx->content.length;
358 p += (number_length = rhash_sprintI64(p, pieces_length));
359 ctx->content.length += pieces_length + number_length + 1;
360
361 *(p++) = ':';
362 p[pieces_length] = '\0'; /* terminate with \0 just in case */
363
364 for (bytes_left = pieces_length, i = 0; bytes_left > 0; i++)
365 {
366 size_t size = (bytes_left < BT_BLOCK_SIZE_IN_BYTES ? bytes_left : BT_BLOCK_SIZE_IN_BYTES);
367 memcpy(p, ctx->hash_blocks.array[i], size);
368 bytes_left -= size;
369 p += size;
370 }
371 }
372
373 /**
374 * Calculate default torrent piece length, using uTorrent algorithm.
375 * Algorithm:
376 * length = 16K for total_size < 16M,
377 * length = 8M for total_size >= 4G,
378 * length = top_bit(total_size) / 1024 otherwise.
379 *
380 * @param total_size total hashed batch size of torrent file
381 * @return piece length used by torrent file
382 */
bt_default_piece_length(uint64_t total_size)383 size_t bt_default_piece_length(uint64_t total_size)
384 {
385 uint64_t hi_bit;
386 if (total_size < 16777216) return BT_MIN_HASH_LENGTH;
387 if (total_size >= I64(4294967296) ) return 8388608;
388 for (hi_bit = 16777216 << 1; hi_bit <= total_size; hi_bit <<= 1);
389 return (size_t)(hi_bit >> 10);
390 }
391
392 /* get file basename */
bt_get_basename(const char * path)393 static const char* bt_get_basename(const char* path)
394 {
395 const char* p = strchr(path, '\0') - 1;
396 for (; p >= path && *p != '/' && *p != '\\'; p--);
397 return (p + 1);
398 }
399
400 /* extract batchname from the path, modifies the path buffer */
get_batch_name(char * path)401 static const char* get_batch_name(char* path)
402 {
403 char* p = (char*)bt_get_basename(path) - 1;
404 for (; p > path && (*p == '/' || *p == '\\'); p--) *p = 0;
405 if (p <= path) return "BATCH_DIR";
406 return bt_get_basename(path);
407 }
408
409 /* write file size and path */
bt_file_info_append(torrent_ctx * ctx,const char * length_name,const char * path_name,bt_file_info * info)410 static void bt_file_info_append(torrent_ctx* ctx, const char* length_name,
411 const char* path_name, bt_file_info* info)
412 {
413 bt_bencode_int(ctx, length_name, info->size);
414 /* store the file basename */
415 bt_bencode_str(ctx, path_name, bt_get_basename(info->path));
416 }
417
418 /**
419 * Generate torrent file content
420 * @see http://wiki.theory.org/BitTorrentSpecification
421 *
422 * @param ctx the torrent algorithm context
423 */
bt_generate_torrent(torrent_ctx * ctx)424 static void bt_generate_torrent(torrent_ctx* ctx)
425 {
426 uint64_t total_size = 0;
427 size_t info_start_pos;
428
429 assert(ctx->content.str == NULL);
430
431 if (ctx->piece_length == 0) {
432 if (ctx->files.size == 1) {
433 total_size = ((bt_file_info*)ctx->files.array[0])->size;
434 }
435 ctx->piece_length = bt_default_piece_length(total_size);
436 }
437
438 if ((ctx->options & BT_OPT_INFOHASH_ONLY) == 0) {
439 /* write the torrent header */
440 bt_str_append(ctx, "d");
441 if (ctx->announce.array && ctx->announce.size > 0) {
442 bt_bencode_str(ctx, "8:announce", ctx->announce.array[0]);
443
444 /* if more than one announce url */
445 if (ctx->announce.size > 1) {
446 /* add the announce-list key-value pair */
447 size_t i;
448 bt_str_append(ctx, "13:announce-listll");
449
450 for (i = 0; i < ctx->announce.size; i++) {
451 if (i > 0) {
452 bt_str_append(ctx, "el");
453 }
454 bt_bencode_str(ctx, 0, ctx->announce.array[i]);
455 }
456 bt_str_append(ctx, "ee");
457 }
458 }
459
460 if (ctx->program_name) {
461 bt_bencode_str(ctx, "10:created by", ctx->program_name);
462 }
463 bt_bencode_int(ctx, "13:creation date", (uint64_t)time(NULL));
464
465 bt_str_append(ctx, "8:encoding5:UTF-8");
466 }
467
468 /* write the essential for BTIH part of the torrent file */
469
470 bt_str_append(ctx, "4:infod"); /* start the info dictionary */
471 info_start_pos = ctx->content.length - 1;
472
473 if (ctx->files.size > 1) {
474 size_t i;
475
476 /* process batch torrent */
477 bt_str_append(ctx, "5:filesl"); /* start list of files */
478
479 /* write length and path for each file in the batch */
480 for (i = 0; i < ctx->files.size; i++) {
481 bt_file_info_append(ctx, "d6:length", "4:pathl",
482 (bt_file_info*)ctx->files.array[i]);
483 bt_str_append(ctx, "ee");
484 }
485 /* note: get_batch_name modifies path, so should be called here */
486 bt_bencode_str(ctx, "e4:name", get_batch_name(
487 ((bt_file_info*)ctx->files.array[0])->path));
488 }
489 else if (ctx->files.size > 0) {
490 /* write size and basename of the first file */
491 /* in the non-batch mode other files are ignored */
492 bt_file_info_append(ctx, "6:length", "4:name",
493 (bt_file_info*)ctx->files.array[0]);
494 }
495
496 bt_bencode_int(ctx, "12:piece length", ctx->piece_length);
497 bt_str_append(ctx, "6:pieces");
498 bt_bencode_pieces(ctx);
499
500 if (ctx->options & BT_OPT_PRIVATE) {
501 bt_str_append(ctx, "7:privatei1e");
502 }
503 bt_str_append(ctx, "ee");
504
505 /* calculate BTIH */
506 SHA1_INIT(ctx);
507 SHA1_UPDATE(ctx, (unsigned char*)ctx->content.str + info_start_pos,
508 ctx->content.length - info_start_pos - 1);
509 SHA1_FINAL(ctx, ctx->btih);
510 }
511
512 /* Getters/Setters */
513
514 /**
515 * Get BTIH (BitTorrent Info Hash) value.
516 *
517 * @param ctx the torrent algorithm context
518 * @return the 20-bytes long BTIH value
519 */
bt_get_btih(torrent_ctx * ctx)520 unsigned char* bt_get_btih(torrent_ctx* ctx)
521 {
522 return ctx->btih;
523 }
524
525 /**
526 * Set the torrent algorithm options.
527 *
528 * @param ctx the torrent algorithm context
529 * @param options the options to set
530 */
bt_set_options(torrent_ctx * ctx,unsigned options)531 void bt_set_options(torrent_ctx* ctx, unsigned options)
532 {
533 ctx->options = options;
534 }
535
536 #if defined(__STRICT_ANSI__)
537 /* define strdup for gcc -ansi */
bt_strdup(const char * str)538 static char* bt_strdup(const char* str)
539 {
540 size_t len = strlen(str);
541 char* res = (char*)malloc(len + 1);
542 if (res) memcpy(res, str, len + 1);
543 return res;
544 }
545 #define strdup bt_strdup
546 #endif /* __STRICT_ANSI__ */
547
548 /**
549 * Set optional name of the program generating the torrent
550 * for storing into torrent file.
551 *
552 * @param ctx the torrent algorithm context
553 * @param name the program name
554 * @return non-zero on success, zero on error
555 */
bt_set_program_name(torrent_ctx * ctx,const char * name)556 int bt_set_program_name(torrent_ctx* ctx, const char* name)
557 {
558 ctx->program_name = strdup(name);
559 return (ctx->program_name != NULL);
560 }
561
562 /**
563 * Set length of a file piece.
564 *
565 * @param ctx the torrent algorithm context
566 * @param piece_length the piece length in bytes
567 */
bt_set_piece_length(torrent_ctx * ctx,size_t piece_length)568 void bt_set_piece_length(torrent_ctx* ctx, size_t piece_length)
569 {
570 ctx->piece_length = piece_length;
571 }
572
573 /**
574 * Add a tracker announce-URL to the torrent file.
575 *
576 * @param ctx the torrent algorithm context
577 * @param announce_url the announce URL of the tracker
578 * @return non-zero on success, zero on error
579 */
bt_add_announce(torrent_ctx * ctx,const char * announce_url)580 int bt_add_announce(torrent_ctx* ctx, const char* announce_url)
581 {
582 char* url_copy;
583 if (!announce_url || announce_url[0] == '\0') return 0;
584 url_copy = strdup(announce_url);
585 if (!url_copy) return 0;
586 if (bt_vector_add_ptr(&ctx->announce, url_copy))
587 return 1;
588 free(url_copy);
589 return 0;
590 }
591
592 /**
593 * Get the content of generated torrent file.
594 *
595 * @param ctx the torrent algorithm context
596 * @param pstr pointer to pointer receiving the buffer with file content
597 * @return length of the torrent file content
598 */
bt_get_text(torrent_ctx * ctx,char ** pstr)599 size_t bt_get_text(torrent_ctx* ctx, char** pstr)
600 {
601 assert(ctx->content.str);
602 *pstr = ctx->content.str;
603 return ctx->content.length;
604 }
605