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