tInitial commit - libeech - bittorrent library
(HTM) git clone git://z3bra.org/libeech.git
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
(DIR) commit 25c4a9d5da6502bfe86acf4b83a58097397c3e00
(HTM) Author: z3bra <contactatz3bradotorg>
Date: Tue, 17 Oct 2017 19:27:29 +0200
Initial commit
Diffstat:
A LICENSE | 13 +++++++++++++
A README | 34 +++++++++++++++++++++++++++++++
A be.c | 318 +++++++++++++++++++++++++++++++
A be.h | 29 +++++++++++++++++++++++++++++
A config.mk | 12 ++++++++++++
A libeech.c | 67 +++++++++++++++++++++++++++++++
A libeech.h | 16 ++++++++++++++++
A makefile | 23 +++++++++++++++++++++++
A sha1.c | 272 +++++++++++++++++++++++++++++++
A sha1.h | 19 +++++++++++++++++++
A torrent.c | 22 ++++++++++++++++++++++
A util.c | 18 ++++++++++++++++++
A util.h | 3 +++
13 files changed, 846 insertions(+), 0 deletions(-)
---
(DIR) diff --git a/LICENSE b/LICENSE
t@@ -0,0 +1,13 @@
+Copyright (c) 2016 Willy Goiffon <willyatmailoodotorg>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
(DIR) diff --git a/README b/README
t@@ -0,0 +1,34 @@
+libeech
+=======
+
+BitTorrent library
+
+The libeech BitTorrent library (will) implement all the functionality
+described in the bittorrent protocol RFC[0], as well as the distributed
+hash table (DHT) protocol[1].
+
+Installation
+------------
+Edit the `config.mk` file to match your setup, then run:
+
+ $ make
+ # make install
+
+Usage
+-----
+Include the header file as follow:
+
+ #include <libeech.h>
+
+Link your program against it with
+
+ cc pgm.c -leech -o pgm
+
+Until v1.0 is complete, please check the `leec.h` for the API.
+
+License
+-------
+ISC License. See LICENSE file for copyright and license details.
+
+[0] http://jonas.nitro.dk/bittorrent/bittorrent-rfc.html
+[1] https://en.wikipedia.org/wiki/Distributed_hash_table
(DIR) diff --git a/be.c b/be.c
t@@ -0,0 +1,318 @@
+/* See LICENSE file for copyright and license details. */
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+
+#include "be.h"
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#define MAX(a,b) ((a)>(b)?(a):(b))
+
+int
+beinit(struct be *b, char *s, size_t l)
+{
+ if (!b || !s || !l)
+ return -1;
+
+ memset(b, 0, sizeof(*b));
+ b->start = s;
+ b->end = b->start + l - 1;
+ b->off = b->start;
+
+ return 0;
+}
+
+int
+beatol(char **str, long *l)
+{
+ long s = 1;
+ long v = 0;
+ char *sp = *str;
+
+ if (!sp)
+ return -1;
+
+ /* define the sign of our number */
+ if (*sp == '-') {
+ s = -1;
+ sp++;
+ /* -0 is invalid, even for "-03" */
+ if (*sp == '0')
+ return -1;
+ }
+
+ /* 0 followed by a number is considered invalid */
+ if (sp[0] == '0' && isdigit(sp[1]))
+ return -1;
+
+ /* read out number until next non-number, or end of string */
+ while(isdigit(*sp)) {
+ v *= 10;
+ v += *sp++ - '0';
+ }
+
+ if (l)
+ *l = v * s;
+
+ /* move initial pointer to the actual read data */
+ *str = sp;
+
+ return 0;
+}
+
+ssize_t
+beint(struct be *b, long *n)
+{
+ char *sp;
+ long num;
+
+ if (!b)
+ return -1;
+
+ sp = b->off;
+
+ if (*(sp++) != 'i')
+ return -1;
+
+ beatol(&sp, &num);
+
+ if (*sp != 'e')
+ return -1;
+
+ if (n)
+ *n = num;
+
+ return sp - b->off + 1;
+}
+
+ssize_t
+bestr(struct be *b, char **s, size_t *l)
+{
+ char *sp;
+ ssize_t len;
+
+ if (!b)
+ return -1;
+
+ sp = b->off;
+
+ if (beatol(&sp, &len) < 0)
+ return -1;
+
+ if (len < 0 || *sp++ != ':')
+ return -1;
+
+ if (s)
+ *s = sp;
+
+ if (l)
+ *l = (size_t)len;
+
+ return sp - b->off + len;
+}
+
+ssize_t
+belist(struct be *b, size_t *n)
+{
+ size_t c = 0;
+ struct be i;
+
+ if (!b)
+ return -1;
+
+ beinit(&i, b->off, b->end - b->off + 1);
+
+ while(belistover(&i)) {
+ belistnext(&i);
+ c++;
+ }
+
+ if (*i.off == 'e')
+ i.off++;
+
+ if (n)
+ *n = c;
+
+ return i.off - b->off;
+}
+
+ssize_t
+bedict(struct be *b, size_t *n)
+{
+ size_t c = 0;
+ struct be i;
+
+ if (!b)
+ return -1;
+
+ beinit(&i, b->off, b->end - b->off + 1);
+
+ while(!belistover(&i)) {
+ bedictnext(&i, NULL, NULL, NULL);
+ c++;
+ }
+
+ if (*i.off == 'e')
+ i.off++;
+
+ if (n)
+ *n = c;
+
+ return i.off - b->off;
+}
+
+int
+belistover(struct be *b) {
+ return b->off >= b->end || *b->off == 'e';
+}
+
+int
+belistnext(struct be *b)
+{
+ if (!b || *b->off == 'e')
+ return -1;
+
+ if (b->off == b->start && *b->off == 'l') {
+ b->off++;
+ return 0;
+ }
+
+ return benext(b) > 0;
+}
+
+int
+bedictnext(struct be *b, char **k, size_t *l, struct be *v)
+{
+ if (!b || *b->off == 'e')
+ return -1;
+
+ /* move to first element if we're at the start */
+ if (b->off == b->start && *b->off == 'd')
+ b->off++;
+
+ /* retrieve key name and length */
+ if (bestr(b, k, l) < 0)
+ return -1;
+
+ if (benext(b) > 0 && v)
+ beinit(v, b->off, b->end - b->off + 1);
+
+ return benext(b) > 0;
+}
+
+ssize_t
+benext(struct be *b)
+{
+ int r = 0;
+
+ if (!b)
+ return -1;
+
+ /* check for end of buffer */
+ if (b->off >= b->end)
+ return -1;
+
+ /* TODO: implement betype() */
+ switch(betype(b)) {
+ case 'i':
+ r = beint(b, NULL);
+ break;
+ case 'l':
+ r = belist(b, NULL);
+ break;
+ case 'd':
+ r = bedict(b, NULL);
+ break;
+ case 's':
+ r = bestr(b, NULL, NULL);
+ break;
+ }
+
+ b->off += r;
+
+ return r;
+}
+
+char
+betype(struct be *b)
+{
+ switch(*b->off) {
+ case 'i':
+ case 'l':
+ case 'd':
+ return *b->off;
+ break; /* NOTREACHED */
+ }
+ return isdigit(*b->off) ? 's' : 0;
+}
+
+int
+bekv(struct be *b, char *k, size_t l, struct be *v)
+{
+ char *key = NULL;
+ size_t klen = 0;
+ struct be i;
+
+ if (!b)
+ return -1;
+
+ if (*b->off != 'd')
+ return -1;
+
+ beinit(&i, b->off, b->end - b->off + 1);
+
+ /* search the data 'till the end */
+ while (!belistover(&i) && bedictnext(&i, &key, &klen, v)) {
+ /* we found our key! */
+ if (!strncmp(k, key, MIN(l, klen)))
+ return 0;
+
+ /* recursive call to search inner dictionaries */
+ if (betype(&i) == 'd' && !bekv(&i, k, l, v))
+ return 0;
+ }
+
+ /* couldn't find anything, sorry */
+ return -1;
+}
+
+int
+bepath(struct be *b, char **p, size_t l)
+{
+ char *s;
+ size_t r;
+ struct be i;
+
+ if (!b || betype(b) != 'l')
+ return -1;
+
+ beinit(&i, b->off, b->end - b->off + 1);
+
+ while(belistnext(&i) && !belistover(&i)) {
+ if (!bestr(&i, &s, &r))
+ continue;
+ strncat(*p, "/", l);
+ strncat(*p, s, r);
+ }
+ return 0;
+}
+
+char *
+bekstr(struct be *b, char *k, size_t kl)
+{
+ char *sp;
+ size_t vl;
+ struct be v;
+ static char s[LINE_MAX];
+
+ memset(s, 0, LINE_MAX);
+ if (bekv(b, k, kl, &v) < 0)
+ return NULL;
+ if (bestr(&v, &sp, &vl) < 0)
+ return NULL;
+
+ memcpy(s, sp, MIN(vl, LINE_MAX));
+ s[MIN(vl, LINE_MAX - 1)] = 0;
+
+ return s;
+}
(DIR) diff --git a/be.h b/be.h
t@@ -0,0 +1,29 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef _BE_H
+#define _BE_H
+
+#include <stdint.h>
+#include <unistd.h>
+
+struct be {
+ char *start;
+ char *end;
+ char *off;
+};
+
+int beinit(struct be *, char *, size_t);
+int beatol(char **, long *);
+ssize_t beint(struct be *, long *);
+ssize_t bestr(struct be *, char **, size_t *);
+ssize_t belist(struct be *, size_t *);
+ssize_t bedict(struct be *, size_t *);
+ssize_t benext(struct be *);
+int belistover(struct be *);
+int belistnext(struct be *);
+int bedictnext(struct be *, char **, size_t *, struct be *);
+char betype(struct be *);
+int bekv(struct be *, char *, size_t, struct be *);
+int bepath(struct be *, char **, size_t);
+char * bekstr(struct be *, char *, size_t);
+
+#endif
(DIR) diff --git a/config.mk b/config.mk
t@@ -0,0 +1,12 @@
+VERSION = 0.0
+
+CC = cc
+LD = ${CC}
+
+PREFIX = /usr/local
+MANDIR = ${PREFIX}/man
+
+CPPFLAGS = -DVERSION=\"${VERSION}\"
+CFLAGS = ${CPPFLAGS} -Wall -Wextra -pedantic -g
+LDFLAGS =
+LDLIBS =
(DIR) diff --git a/libeech.c b/libeech.c
t@@ -0,0 +1,67 @@
+/* See LICENSE file for copyright and license details. */
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "be.h"
+#include "sha1.h"
+#include "util.h"
+#include "libeech.h"
+
+static char * peerid();
+
+static char *
+peerid()
+{
+ int n;
+ char hexa[40];
+ unsigned char hash[20];
+ static char peerid[21] = "-GT0000-XXXXXXXXXXXX";
+
+ srand(time(NULL)); /* good-enough seed */
+ n = rand();
+ snprintf(hexa, 40, "%08x%08x\n", n, ~n);
+ sha1((unsigned char *)hexa, 16, hash);
+ memcpy(peerid + 8, tohex(hash, hexa, 12), 12);
+
+ return peerid;
+}
+
+int
+glch_loadtorrent(struct torrent *t, char *path)
+{
+ FILE *f;
+ char *b, *sp;
+ struct stat sb;
+ /* read torrent file into a memory buffer */
+ if (stat(path, &sb))
+ return -1;
+ if (!(f = fopen(path, "r")))
+ return -1;
+ b = malloc(sb.st_size);
+ fread(b, 1, sb.st_size, f);
+ b[sb.st_size - 1] = '\0';
+ fclose(f);
+
+ /* retrieve "announce" key */
+ beinit(&t->be, b, sb.st_size);
+ sp = bekstr(&t->be, "announce", 8);
+ if (!sp)
+ return -1;
+ memcpy(t->tr, sp, strlen(sp));
+
+ sp = peerid();
+ if (!sp)
+ return -1;
+ memcpy(t->id, sp, 20);
+ t->id[20] = 0;
+
+ return 0;
+}
(DIR) diff --git a/libeech.h b/libeech.h
t@@ -0,0 +1,16 @@
+/* See LICENSE file for copyright and license details. */
+#include <limits.h>
+
+#include "be.h"
+
+#define PCESIZ 1048576
+#define BLKSIZ 16384
+#define MSGSIZ ((BLKSIZ) + 13)
+
+struct torrent {
+ char id[21];
+ char tr[PATH_MAX];
+ struct be be;
+};
+
+int glch_loadtorrent(struct torrent *, char *);
(DIR) diff --git a/makefile b/makefile
t@@ -0,0 +1,23 @@
+include config.mk
+
+all: libeech.a torrent
+libeech.a: libeech.a(libeech.o) libeech.a(util.o) libeech.a(be.o) libeech.a(sha1.o)
+libeech.o: libeech.c libeech.h
+
+torrent: torrent.c libeech.a
+ $(CC) $< -I. -L. -leech -o $@
+.o.a:
+ $(AR) rcs $@ $<
+
+install: libeech.a libeech.h
+ mkdir -p $(DESTDIR)$(PREFIX)/lib
+ mkdir -p $(DESTDIR)$(PREFIX)/include
+ cp libeech.a $(DESTDIR)$(PREFIX)/lib/
+ cp libeech.h $(DESTDIR)$(PREFIX)/include/
+
+uninstall:
+ rm $(DESTDIR)$(PREFIX)/lib/libeech.a
+ rm $(DESTDIR)$(PREFIX)/include/libeech.h
+
+clean:
+ rm -f libeech.a torrent *.o
(DIR) diff --git a/sha1.c b/sha1.c
t@@ -0,0 +1,272 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "sha1.h"
+
+#define F0(x,y,z) (z ^ (x & (y ^ z)))
+#define F1(x,y,z) (x ^ y ^ z)
+#define F2(x,y,z) ((x & y) | (z & (x | y)))
+#define F3(x,y,z) (x ^ y ^ z)
+
+#define ROL(x,n) ( (((x)<<(n))&(UINT32_MAX))|(((x)>>(sizeof(x)*8-(n)))&(UINT32_MAX)) )
+
+#define MAX(x, y) ( ((x)>(y))?(x):(y) )
+#define MIN(x, y) ( ((x)<(y))?(x):(y) )
+
+#define STORE32L(x, y) \
+ do { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } while(0)
+
+#define LOAD32L(x, y) \
+ do { x = ((uint32_t)((y)[3] & 255)<<24) | \
+ ((uint32_t)((y)[2] & 255)<<16) | \
+ ((uint32_t)((y)[1] & 255)<<8) | \
+ ((uint32_t)((y)[0] & 255)); } while(0)
+
+#define STORE64L(x, y) \
+ do { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
+ (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
+ (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } while(0)
+
+#define LOAD64L(x, y) \
+ do { x = (((uint64_t)((y)[7] & 255))<<56)|(((uint64_t)((y)[6] & 255))<<48)| \
+ (((uint64_t)((y)[5] & 255))<<40)|(((uint64_t)((y)[4] & 255))<<32)| \
+ (((uint64_t)((y)[3] & 255))<<24)|(((uint64_t)((y)[2] & 255))<<16)| \
+ (((uint64_t)((y)[1] & 255))<<8)|(((uint64_t)((y)[0] & 255))); } while(0)
+
+#define STORE32H(x, y) \
+ do { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
+ (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } while(0)
+
+#define LOAD32H(x, y) \
+ do { x = ((uint32_t)((y)[0] & 255)<<24) | \
+ ((uint32_t)((y)[1] & 255)<<16) | \
+ ((uint32_t)((y)[2] & 255)<<8) | \
+ ((uint32_t)((y)[3] & 255)); } while(0)
+
+#define STORE64H(x, y) \
+do { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } while(0)
+
+#define LOAD64H(x, y) \
+do { x = (((uint64_t)((y)[0] & 255))<<56)|(((uint64_t)((y)[1] & 255))<<48) | \
+ (((uint64_t)((y)[2] & 255))<<40)|(((uint64_t)((y)[3] & 255))<<32) | \
+ (((uint64_t)((y)[4] & 255))<<24)|(((uint64_t)((y)[5] & 255))<<16) | \
+ (((uint64_t)((y)[6] & 255))<<8)|(((uint64_t)((y)[7] & 255))); } while(0)
+
+static int sha1_compress(sha1_context *md, unsigned char *buf)
+{
+ uint32_t a,b,c,d,e,W[80],i;
+
+ /* copy the state into 512-bits into W[0..15] */
+ for (i = 0; i < 16; i++) {
+ LOAD32H(W[i], buf + (4*i));
+ }
+
+ /* copy state */
+ a = md->state[0];
+ b = md->state[1];
+ c = md->state[2];
+ d = md->state[3];
+ e = md->state[4];
+
+ /* expand it */
+ for (i = 16; i < 80; i++) {
+ W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);
+ }
+
+ /* compress */
+ /* round one */
+ #define FF0(a,b,c,d,e,i) e = (ROL(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROL(b, 30);
+ #define FF1(a,b,c,d,e,i) e = (ROL(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROL(b, 30);
+ #define FF2(a,b,c,d,e,i) e = (ROL(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROL(b, 30);
+ #define FF3(a,b,c,d,e,i) e = (ROL(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROL(b, 30);
+
+ for (i = 0; i < 20; ) {
+ FF0(a,b,c,d,e,i++);
+ FF0(e,a,b,c,d,i++);
+ FF0(d,e,a,b,c,i++);
+ FF0(c,d,e,a,b,i++);
+ FF0(b,c,d,e,a,i++);
+ }
+
+ /* round two */
+ for (; i < 40; ) {
+ FF1(a,b,c,d,e,i++);
+ FF1(e,a,b,c,d,i++);
+ FF1(d,e,a,b,c,i++);
+ FF1(c,d,e,a,b,i++);
+ FF1(b,c,d,e,a,i++);
+ }
+
+ /* round three */
+ for (; i < 60; ) {
+ FF2(a,b,c,d,e,i++);
+ FF2(e,a,b,c,d,i++);
+ FF2(d,e,a,b,c,i++);
+ FF2(c,d,e,a,b,i++);
+ FF2(b,c,d,e,a,i++);
+ }
+
+ /* round four */
+ for (; i < 80; ) {
+ FF3(a,b,c,d,e,i++);
+ FF3(e,a,b,c,d,i++);
+ FF3(d,e,a,b,c,i++);
+ FF3(c,d,e,a,b,i++);
+ FF3(b,c,d,e,a,i++);
+ }
+
+ #undef FF0
+ #undef FF1
+ #undef FF2
+ #undef FF3
+
+ /* store */
+ md->state[0] = md->state[0] + a;
+ md->state[1] = md->state[1] + b;
+ md->state[2] = md->state[2] + c;
+ md->state[3] = md->state[3] + d;
+ md->state[4] = md->state[4] + e;
+
+ return 0;
+}
+
+/**
+ Initialize the hash state
+ @param md The hash state you wish to initialize
+ @return 0 if successful
+*/
+int sha1_init(sha1_context * md)
+{
+ if (md == NULL) return 1;
+ md->state[0] = 0x67452301UL;
+ md->state[1] = 0xefcdab89UL;
+ md->state[2] = 0x98badcfeUL;
+ md->state[3] = 0x10325476UL;
+ md->state[4] = 0xc3d2e1f0UL;
+ md->curlen = 0;
+ md->length = 0;
+ return 0;
+}
+
+/**
+ Process a block of memory though the hash
+ @param md The hash state
+ @param in The data to hash
+ @param inlen The length of the data (octets)
+ @return 0 if successful
+*/
+int sha1_process (sha1_context * md, const unsigned char *in, unsigned long inlen)
+{
+ size_t n;
+ size_t i;
+ int err;
+ if (md == NULL) return 1;
+ if (in == NULL) return 1;
+ if (md->curlen > sizeof(md->buf)) {
+ return 1;
+ }
+ if ((md->length + inlen) < md->length) {
+ return 1;
+ }
+ while (inlen > 0) {
+ if (md->curlen == 0 && inlen >= 64) {
+ if ((err = sha1_compress (md, (unsigned char *)in)) != 0) {
+ return err;
+ }
+ md->length += 64 * 8;
+ in += 64;
+ inlen -= 64;
+ } else {
+ n = MIN(inlen, (64 - md->curlen));
+ for (i = 0; i < n; i++) {
+ md->buf[md->curlen + i] = in[i];
+ }
+ md->curlen += n;
+ in += n;
+ inlen -= n;
+ if (md->curlen == 64) {
+ if ((err = sha1_compress (md, md->buf)) != 0) {
+ return err;
+ }
+ md->length += 8*64;
+ md->curlen = 0;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (20 bytes)
+ @return 0 if successful
+*/
+int sha1_done(sha1_context * md, unsigned char *out)
+{
+ int i;
+
+ if (md == NULL) return 1;
+ if (out == NULL) return 1;
+
+ if (md->curlen >= sizeof(md->buf)) {
+ return 1;
+ }
+
+ /* increase the length of the message */
+ md->length += md->curlen * 8;
+
+ /* append the '1' bit */
+ md->buf[md->curlen++] = (unsigned char)0x80;
+
+ /* if the length is currently above 56 bytes we append zeros
+ * then compress. Then we can fall back to padding zeros and length
+ * encoding like normal.
+ */
+ if (md->curlen > 56) {
+ while (md->curlen < 64) {
+ md->buf[md->curlen++] = (unsigned char)0;
+ }
+ sha1_compress(md, md->buf);
+ md->curlen = 0;
+ }
+
+ /* pad upto 56 bytes of zeroes */
+ while (md->curlen < 56) {
+ md->buf[md->curlen++] = (unsigned char)0;
+ }
+
+ /* store length */
+ STORE64H(md->length, md->buf+56);
+ sha1_compress(md, md->buf);
+
+ /* copy output */
+ for (i = 0; i < 5; i++) {
+ STORE32H(md->state[i], out+(4*i));
+ }
+ return 0;
+}
+
+int sha1(const unsigned char *msg, size_t len, unsigned char *hash)
+{
+ sha1_context ctx;
+ int ret;
+ if ((ret = sha1_init(&ctx))) return ret;
+ if ((ret = sha1_process(&ctx, msg, len))) return ret;
+ if ((ret = sha1_done(&ctx, hash))) return ret;
+ return 0;
+}
(DIR) diff --git a/sha1.h b/sha1.h
t@@ -0,0 +1,19 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+typedef struct {
+ uint64_t length;
+ uint32_t state[5], curlen;
+ unsigned char buf[64];
+} sha1_context;
+
+int sha1_init(sha1_context * md);
+int sha1_process(sha1_context * md, const unsigned char *in, unsigned long inlen);
+int sha1_done(sha1_context * md, unsigned char *hash);
+int sha1(const unsigned char *in, size_t len, unsigned char *hash);
(DIR) diff --git a/torrent.c b/torrent.c
t@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <libeech.h>
+
+int
+main(int argc, char *argv[])
+{
+ struct torrent t;
+
+ if (argc < 2) {
+ fprintf(stderr, "%s TORRENT\n", argv[0]);
+ return -1;
+ }
+
+ if (!glch_loadtorrent(&t, argv[1])) {
+ printf("Peer ID: %s\n", t.id);
+ printf("Tracker: %s\n", t.tr);
+ }
+
+ return 0;
+}
(DIR) diff --git a/util.c b/util.c
t@@ -0,0 +1,18 @@
+/* See LICENSE file for copyright and license details. */
+#include <string.h>
+
+char *
+tohex(unsigned char *in, char *out, size_t len)
+{
+ size_t i, j;
+ char hex[] = "0123456789abcdef";
+
+ memset(out, 0, len*2 + 1);
+ for (i=0, j=0; i<len; i++, j++) {
+ out[j] = hex[in[i] >> 4];
+ out[++j] = hex[in[i] & 15];
+ }
+
+ return out;
+}
+
(DIR) diff --git a/util.h b/util.h
t@@ -0,0 +1,3 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdlib.h>
+char * tohex(unsigned char *, char *, size_t);