From: Rudolf Polzer Date: Sat, 24 Apr 2010 18:11:20 +0000 (+0200) Subject: initial import of blind_id X-Git-Tag: xonotic-v0.1.0preview~58 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=b38fa6331d39d835a284697bd1c0906b3326d18e;p=xonotic%2Fd0_blind_id.git initial import of blind_id --- b38fa6331d39d835a284697bd1c0906b3326d18e diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8534658 --- /dev/null +++ b/Makefile @@ -0,0 +1,12 @@ +all: blind_id + +OBJECTS = d0.o d0_blind_id.o d0_iobuf.o d0_bignum-gmp.o sha1.o main.o + +blind_id: $(OBJECTS) + $(CC) $(LDFLAGS) -o $@ $^ +clean: + $(RM) blind_id $(OBJECTS) + +CFLAGS += -Wall -Wextra +CPPFLAGS += -I/opt/gmp/include +LDFLAGS += -L/opt/gmp/lib -Wl,-rpath,/opt/gmp/lib -lgmp -lm -lrt -s -O3 diff --git a/d0.c b/d0.c new file mode 100644 index 0000000..fd61cdb --- /dev/null +++ b/d0.c @@ -0,0 +1,6 @@ +#include "d0.h" + +#include + +void *(*d0_malloc)(size_t len) = malloc; +void (*d0_free)(void *p) = free; diff --git a/d0.h b/d0.h new file mode 100644 index 0000000..c792430 --- /dev/null +++ b/d0.h @@ -0,0 +1,12 @@ +#ifndef __D0_H__ +#define __D0_H__ + +#include // size_t + +#define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#define BOOL int + +extern void *(*d0_malloc)(size_t len); +extern void (*d0_free)(void *p); + +#endif diff --git a/d0_bignum-gmp.c b/d0_bignum-gmp.c new file mode 100644 index 0000000..5cd31c0 --- /dev/null +++ b/d0_bignum-gmp.c @@ -0,0 +1,249 @@ +#include "d0_bignum.h" + +#include + +struct d0_bignum_s +{ + mpz_t z; +}; + +static gmp_randstate_t RANDSTATE; + +#include +void d0_bignum_INITIALIZE() +{ + gmp_randinit_default(RANDSTATE); + gmp_randseed_ui(RANDSTATE, time(NULL)); // TODO seed +} + +void d0_bignum_SHUTDOWN() +{ + // free RANDSTATE +} + +BOOL d0_iobuf_write_bignum(d0_iobuf_t *buf, const d0_bignum_t *bignum) +{ + static unsigned char numbuf[65536]; + size_t count = 0; + numbuf[0] = mpz_sgn(bignum->z) & 3; + if((numbuf[0] & 3) != 0) // nonzero + { + count = (mpz_sizeinbase(bignum->z, 2) + 7) / 8; + if(count > sizeof(numbuf) - 1) + return 0; + mpz_export(numbuf+1, &count, 1, 1, 0, 0, bignum->z); + } + return d0_iobuf_write_packet(buf, numbuf, count + 1); +} + +d0_bignum_t *d0_iobuf_read_bignum(d0_iobuf_t *buf, d0_bignum_t *bignum) +{ + static unsigned char numbuf[65536]; + size_t count = sizeof(numbuf); + if(!d0_iobuf_read_packet(buf, numbuf, &count)) + return NULL; + if(count < 1) + return NULL; + if(!bignum) bignum = d0_bignum_new(); if(!bignum) return NULL; + if(numbuf[0] & 3) // nonzero + { + mpz_import(bignum->z, count-1, 1, 1, 0, 0, numbuf+1); + if(numbuf[0] & 2) // negative + mpz_neg(bignum->z, bignum->z); + } + else // zero + { + mpz_set_ui(bignum->z, 0); + } + return bignum; +} + +d0_bignum_t *d0_bignum_new() +{ + d0_bignum_t *b = d0_malloc(sizeof(d0_bignum_t)); + mpz_init(b->z); + return b; +} + +void d0_bignum_free(d0_bignum_t *a) +{ + mpz_clear(a->z); + d0_free(a); +} + +void d0_bignum_init(d0_bignum_t *b) +{ + mpz_init(b->z); +} + +void d0_bignum_clear(d0_bignum_t *a) +{ + mpz_clear(a->z); +} + +size_t d0_bignum_size(const d0_bignum_t *r) +{ + return mpz_sizeinbase(r->z, 2); +} + +int d0_bignum_cmp(const d0_bignum_t *a, const d0_bignum_t *b) +{ + return mpz_cmp(a->z, b->z); +} + +d0_bignum_t *d0_bignum_rand_range(d0_bignum_t *r, const d0_bignum_t *min, const d0_bignum_t *max) +{ + static d0_bignum_t *temp = NULL; if(!temp) temp = d0_bignum_new(); + if(!r) r = d0_bignum_new(); if(!r) return NULL; + mpz_sub(temp->z, max->z, min->z); + mpz_urandomm(r->z, RANDSTATE, temp->z); + mpz_add(r->z, r->z, min->z); + return r; +} + +d0_bignum_t *d0_bignum_rand_bit_atmost(d0_bignum_t *r, size_t n) +{ + if(!r) r = d0_bignum_new(); if(!r) return NULL; + mpz_urandomb(r->z, RANDSTATE, n); + return r; +} + +d0_bignum_t *d0_bignum_rand_bit_exact(d0_bignum_t *r, size_t n) +{ + if(!r) r = d0_bignum_new(); if(!r) return NULL; + mpz_urandomb(r->z, RANDSTATE, n-1); + mpz_setbit(r->z, n-1); + return r; +} + +d0_bignum_t *d0_bignum_zero(d0_bignum_t *r) +{ + return d0_bignum_int(r, 0); +} + +d0_bignum_t *d0_bignum_one(d0_bignum_t *r) +{ + return d0_bignum_int(r, 1); +} + +d0_bignum_t *d0_bignum_int(d0_bignum_t *r, int n) +{ + if(!r) r = d0_bignum_new(); if(!r) return NULL; + mpz_set_si(r->z, n); + return r; +} + +d0_bignum_t *d0_bignum_mov(d0_bignum_t *r, const d0_bignum_t *a) +{ + if(r == a) + return r; // trivial + if(!r) r = d0_bignum_new(); if(!r) return NULL; + mpz_set(r->z, a->z); + return r; +} + +d0_bignum_t *d0_bignum_neg(d0_bignum_t *r, const d0_bignum_t *a) +{ + if(!r) r = d0_bignum_new(); if(!r) return NULL; + mpz_neg(r->z, a->z); + return r; +} + +d0_bignum_t *d0_bignum_shl(d0_bignum_t *r, const d0_bignum_t *a, ssize_t n) +{ + if(!r) r = d0_bignum_new(); if(!r) return NULL; + if(n > 0) + mpz_mul_2exp(r->z, a->z, n); + else if(n < 0) + mpz_fdiv_q_2exp(r->z, a->z, -n); + else + mpz_set(r->z, a->z); + return r; +} + +d0_bignum_t *d0_bignum_add(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b) +{ + if(!r) r = d0_bignum_new(); if(!r) return NULL; + mpz_add(r->z, a->z, b->z); + return r; +} + +d0_bignum_t *d0_bignum_sub(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b) +{ + if(!r) r = d0_bignum_new(); if(!r) return NULL; + mpz_sub(r->z, a->z, b->z); + return r; +} + +d0_bignum_t *d0_bignum_mul(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b) +{ + if(!r) r = d0_bignum_new(); if(!r) return NULL; + mpz_mul(r->z, a->z, b->z); + return r; +} + +d0_bignum_t *d0_bignum_divmod(d0_bignum_t *q, d0_bignum_t *m, const d0_bignum_t *a, const d0_bignum_t *b) +{ + if(!q && !m) + m = d0_bignum_new(); + if(q) + if(m) + mpz_fdiv_qr(q->z, m->z, a->z, b->z); + else + mpz_fdiv_q(q->z, a->z, b->z); + else + mpz_fdiv_r(m->z, a->z, b->z); + if(m) + return m; + else + return q; +} + +d0_bignum_t *d0_bignum_mod_add(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b, const d0_bignum_t *m) +{ + r = d0_bignum_add(r, a, b); + mpz_fdiv_r(r->z, r->z, m->z); + return r; +} + +d0_bignum_t *d0_bignum_mod_mul(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b, const d0_bignum_t *m) +{ + r = d0_bignum_mul(r, a, b); + mpz_fdiv_r(r->z, r->z, m->z); + return r; +} + +d0_bignum_t *d0_bignum_mod_pow(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b, const d0_bignum_t *m) +{ + if(!r) r = d0_bignum_new(); if(!r) return NULL; + mpz_powm(r->z, a->z, b->z, m->z); + return r; +} + +BOOL d0_bignum_mod_inv(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *m) +{ + // here, r MUST be set, as otherwise we cannot return error state! + return mpz_invert(r->z, a->z, m->z); +} + +int d0_bignum_isprime(d0_bignum_t *r, int param) +{ + return mpz_probab_prime_p(r->z, param); +} + +d0_bignum_t *d0_bignum_gcd(d0_bignum_t *r, d0_bignum_t *s, d0_bignum_t *t, const d0_bignum_t *a, const d0_bignum_t *b) +{ + if(!r) r = d0_bignum_new(); if(!r) return NULL; + if(s) + mpz_gcdext(r->z, s->z, t ? t->z : NULL, a->z, b->z); + else if(t) + mpz_gcdext(r->z, t->z, NULL, b->z, a->z); + else + mpz_gcd(r->z, a->z, b->z); + return r; +} + +char *d0_bignum_tostring(const d0_bignum_t *x, unsigned int base) +{ + return mpz_get_str(NULL, base, x->z); +} diff --git a/d0_bignum.h b/d0_bignum.h new file mode 100644 index 0000000..7eb0e0a --- /dev/null +++ b/d0_bignum.h @@ -0,0 +1,38 @@ +#include "d0.h" +#include "d0_iobuf.h" + +typedef struct d0_bignum_s d0_bignum_t; + +WARN_UNUSED_RESULT BOOL d0_iobuf_write_bignum(d0_iobuf_t *buf, const d0_bignum_t *bignum); +WARN_UNUSED_RESULT d0_bignum_t *d0_iobuf_read_bignum(d0_iobuf_t *buf, d0_bignum_t *bignum); + +void d0_bignum_INITIALIZE(); +void d0_bignum_SHUTDOWN(); + +WARN_UNUSED_RESULT d0_bignum_t *d0_bignum_new(); +void d0_bignum_free(d0_bignum_t *a); +void d0_bignum_init(d0_bignum_t *b); +void d0_bignum_clear(d0_bignum_t *a); +WARN_UNUSED_RESULT size_t d0_bignum_size(const d0_bignum_t *r); +WARN_UNUSED_RESULT int d0_bignum_cmp(const d0_bignum_t *a, const d0_bignum_t *b); +WARN_UNUSED_RESULT d0_bignum_t *d0_bignum_rand_range(d0_bignum_t *r, const d0_bignum_t *min, const d0_bignum_t *max); +WARN_UNUSED_RESULT d0_bignum_t *d0_bignum_rand_bit_atmost(d0_bignum_t *r, size_t n); +WARN_UNUSED_RESULT d0_bignum_t *d0_bignum_rand_bit_exact(d0_bignum_t *r, size_t n); +WARN_UNUSED_RESULT d0_bignum_t *d0_bignum_zero(d0_bignum_t *r); +WARN_UNUSED_RESULT d0_bignum_t *d0_bignum_one(d0_bignum_t *r); +WARN_UNUSED_RESULT d0_bignum_t *d0_bignum_int(d0_bignum_t *r, int n); +WARN_UNUSED_RESULT d0_bignum_t *d0_bignum_mov(d0_bignum_t *r, const d0_bignum_t *a); +WARN_UNUSED_RESULT d0_bignum_t *d0_bignum_neg(d0_bignum_t *r, const d0_bignum_t *a); +WARN_UNUSED_RESULT d0_bignum_t *d0_bignum_shl(d0_bignum_t *r, const d0_bignum_t *a, ssize_t n); +WARN_UNUSED_RESULT d0_bignum_t *d0_bignum_add(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b); +WARN_UNUSED_RESULT d0_bignum_t *d0_bignum_sub(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b); +WARN_UNUSED_RESULT d0_bignum_t *d0_bignum_mul(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b); +WARN_UNUSED_RESULT d0_bignum_t *d0_bignum_divmod(d0_bignum_t *q, d0_bignum_t *m, const d0_bignum_t *a, const d0_bignum_t *b); // only do mod if both are NULL +WARN_UNUSED_RESULT d0_bignum_t *d0_bignum_mod_add(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b, const d0_bignum_t *m); +WARN_UNUSED_RESULT d0_bignum_t *d0_bignum_mod_mul(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b, const d0_bignum_t *m); +WARN_UNUSED_RESULT d0_bignum_t *d0_bignum_mod_pow(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *b, const d0_bignum_t *m); +WARN_UNUSED_RESULT BOOL d0_bignum_mod_inv(d0_bignum_t *r, const d0_bignum_t *a, const d0_bignum_t *m); +WARN_UNUSED_RESULT int d0_bignum_isprime(d0_bignum_t *r, int param); +WARN_UNUSED_RESULT d0_bignum_t *d0_bignum_gcd(d0_bignum_t *r, d0_bignum_t *s, d0_bignum_t *t, const d0_bignum_t *a, const d0_bignum_t *b); + +WARN_UNUSED_RESULT char *d0_bignum_tostring(const d0_bignum_t *x, unsigned int base); // allocates! diff --git a/d0_blind_id.c b/d0_blind_id.c new file mode 100644 index 0000000..1059ffe --- /dev/null +++ b/d0_blind_id.c @@ -0,0 +1,655 @@ +#include "d0_blind_id.h" + +#include +#include +#include "d0_bignum.h" +#include "sha1.h" + +// for zero knowledge, we need multiple instances of schnorr ID scheme... should normally be sequential +// parallel schnorr ID is not provably zero knowledge :( +// (evil verifier can know all questions in advance, so sequential is disadvantage for him) +// we'll just live with a 1:1048576 chance of cheating, and support reauthenticating + +#define SCHNORR_BITS 20 +// probability of cheat: 2^(-bits+1) + +#define SCHNORR_HASHSIZE 3 +// cannot be >= SHA_DIGEST_LENGTH +// *8 must be >= SCHNORR_BITS + +#define MSGSIZE 640 // ought to be enough for anyone + +struct d0_blind_id_s +{ + // signing (Xonotic pub and priv key) + d0_bignum_t *rsa_n, *rsa_e, *rsa_d; + + // public data (Schnorr ID) + d0_bignum_t *schnorr_G; + + // private data (player ID private key) + d0_bignum_t *schnorr_s; + + // public data (player ID public key, this is what the server gets to know) + d0_bignum_t *schnorr_4_to_s; + d0_bignum_t *schnorr_4_to_s_signature; + + // temp data + d0_bignum_t *rn; // random number blind signature + d0_bignum_t *r; // random number for schnorr ID + char xnbh[SCHNORR_HASHSIZE]; // init hash + d0_bignum_t *e; // challenge + char msg[MSGSIZE]; // message + size_t msglen; // message length +}; + +#define CHECK(x) do { if(!(x)) goto fail; } while(0) +#define CHECK_ASSIGN(var, value) do { d0_bignum_t *val; val = value; if(!val) goto fail; var = val; } while(0) + +static d0_bignum_t *zero, *one, *four, *temp0, *temp1, *temp2, *temp3, *temp4; + +void d0_blind_id_INITIALIZE() +{ + d0_bignum_INITIALIZE(); + CHECK_ASSIGN(zero, d0_bignum_int(zero, 0)); + CHECK_ASSIGN(one, d0_bignum_int(one, 1)); + CHECK_ASSIGN(four, d0_bignum_int(four, 4)); + CHECK_ASSIGN(temp0, d0_bignum_int(temp0, 0)); + CHECK_ASSIGN(temp1, d0_bignum_int(temp1, 0)); + CHECK_ASSIGN(temp2, d0_bignum_int(temp2, 0)); + CHECK_ASSIGN(temp3, d0_bignum_int(temp3, 0)); + CHECK_ASSIGN(temp4, d0_bignum_int(temp4, 0)); +fail: + ; +} + +void d0_blind_id_SHUTDOWN() +{ + d0_bignum_free(zero); + d0_bignum_free(one); + d0_bignum_free(four); + d0_bignum_free(temp0); + d0_bignum_free(temp1); + d0_bignum_free(temp2); + d0_bignum_free(temp3); + d0_bignum_free(temp4); + d0_bignum_SHUTDOWN(); +} + +// (G-1)/2 +d0_bignum_t *d0_dl_get_order(d0_bignum_t *o, const d0_bignum_t *G) +{ + CHECK_ASSIGN(o, d0_bignum_sub(o, G, one)); + CHECK(d0_bignum_shl(o, o, -1)); // order o = (G-1)/2 + return o; +fail: + return NULL; +} +// 2o+1 +d0_bignum_t *d0_dl_get_from_order(d0_bignum_t *G, const d0_bignum_t *o) +{ + CHECK_ASSIGN(G, d0_bignum_shl(G, o, 1)); + CHECK(d0_bignum_add(G, G, one)); + return G; +fail: + return NULL; +} + +BOOL d0_dl_generate_key(size_t size, d0_bignum_t *G) +{ + // using: temp0 + if(size < 16) + size = 16; + for(;;) + { + CHECK(d0_bignum_rand_bit_exact(temp0, size-1)); + if(d0_bignum_isprime(temp0, 0) == 0) + continue; + CHECK(d0_dl_get_from_order(G, temp0)); + if(d0_bignum_isprime(G, 10) == 0) + continue; + if(d0_bignum_isprime(temp0, 10) == 0) // finish the previous test + continue; + break; + } + return 1; +fail: + return 0; +} + +BOOL d0_rsa_generate_key(size_t size, const d0_bignum_t *e, d0_bignum_t *d, d0_bignum_t *n) +{ + // uses temp0 to temp4 + int fail = 0; + int gcdfail = 0; + if(size < 16) + size = 16; + int pb = (size + 1)/2; + int qb = size - pb; + for (;;) + { + CHECK(d0_bignum_rand_bit_exact(temp0, pb)); + if(d0_bignum_isprime(temp0, 10) == 0) + continue; + CHECK(d0_bignum_sub(temp2, temp0, one)); + CHECK(d0_bignum_gcd(temp4, NULL, NULL, temp2, e)); + if(!d0_bignum_cmp(temp4, one)) + break; + if(++gcdfail == 3) + return 0; + ++gcdfail; + } + gcdfail = 0; + for (;;) + { + CHECK(d0_bignum_rand_bit_exact(temp1, qb)); + if(!d0_bignum_cmp(temp1, temp0)) + { + if(++fail == 3) + return 0; + } + fail = 0; + if(d0_bignum_isprime(temp1, 10) == 0) + continue; + CHECK(d0_bignum_sub(temp3, temp1, one)); + CHECK(d0_bignum_gcd(temp4, NULL, NULL, temp3, e)); + if(!d0_bignum_cmp(temp4, one)) + break; + if(++gcdfail == 3) + return 0; + ++gcdfail; + } + + // n = temp0*temp1 + CHECK(d0_bignum_mul(n, temp0, temp1)); + + // d = e^-1 mod (temp0-1)(temp1-1) + CHECK(d0_bignum_mul(temp0, temp2, temp3)); + CHECK(d0_bignum_mod_inv(d, e, temp0)); + return 1; +fail: + return 0; +} + +void d0_blind_id_clear(d0_blind_id_t *ctx) +{ + if(ctx->rsa_n) d0_bignum_free(ctx->rsa_n); + if(ctx->rsa_e) d0_bignum_free(ctx->rsa_e); + if(ctx->rsa_d) d0_bignum_free(ctx->rsa_d); + if(ctx->schnorr_G) d0_bignum_free(ctx->schnorr_G); + if(ctx->schnorr_s) d0_bignum_free(ctx->schnorr_s); + if(ctx->schnorr_4_to_s) d0_bignum_free(ctx->schnorr_4_to_s); + if(ctx->schnorr_4_to_s_signature) d0_bignum_free(ctx->schnorr_4_to_s_signature); + if(ctx->rn) d0_bignum_free(ctx->rn); + if(ctx->r) d0_bignum_free(ctx->r); + if(ctx->e) d0_bignum_free(ctx->e); + memset(ctx, 0, sizeof(*ctx)); +} + +void d0_blind_id_copy(d0_blind_id_t *ctx, const d0_blind_id_t *src) +{ + d0_blind_id_clear(ctx); + if(src->rsa_n) ctx->rsa_n = d0_bignum_mov(NULL, src->rsa_n); + if(src->rsa_e) ctx->rsa_e = d0_bignum_mov(NULL, src->rsa_e); + if(src->rsa_d) ctx->rsa_d = d0_bignum_mov(NULL, src->rsa_d); + if(src->schnorr_G) ctx->schnorr_G = d0_bignum_mov(NULL, src->schnorr_G); + if(src->schnorr_s) ctx->schnorr_s = d0_bignum_mov(NULL, src->schnorr_s); + if(src->schnorr_4_to_s) ctx->schnorr_4_to_s = d0_bignum_mov(NULL, ctx->schnorr_G); + if(src->schnorr_4_to_s_signature) ctx->schnorr_4_to_s_signature = d0_bignum_mov(NULL, src->schnorr_4_to_s_signature); + if(src->rn) ctx->rn = d0_bignum_mov(NULL, src->rn); + if(src->r) ctx->r = d0_bignum_mov(NULL, src->r); + if(src->e) ctx->e = d0_bignum_mov(NULL, src->e); + // TODO xnbh, msg, msglen? +} + +WARN_UNUSED_RESULT BOOL d0_blind_id_generate_private_keys(d0_blind_id_t *ctx, int k) +{ + d0_blind_id_clear(ctx); + CHECK_ASSIGN(ctx->schnorr_G, d0_bignum_new()); + CHECK(d0_dl_generate_key(k, ctx->schnorr_G)); + CHECK_ASSIGN(ctx->rsa_e, d0_bignum_int(NULL, 65537)); + CHECK_ASSIGN(ctx->rsa_d, d0_bignum_new()); + CHECK_ASSIGN(ctx->rsa_n, d0_bignum_new()); + CHECK(d0_rsa_generate_key(k+1, ctx->rsa_e, ctx->rsa_d, ctx->rsa_n)); // must fit G for sure + return 1; +fail: + return 0; +} + +WARN_UNUSED_RESULT BOOL d0_blind_id_read_private_keys(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen) +{ + d0_iobuf_t *in = d0_iobuf_open_read(inbuf, inbuflen); + d0_blind_id_clear(ctx); + CHECK_ASSIGN(ctx->schnorr_G, d0_iobuf_read_bignum(in, NULL)); + CHECK_ASSIGN(ctx->rsa_n, d0_iobuf_read_bignum(in, NULL)); + CHECK_ASSIGN(ctx->rsa_e, d0_iobuf_read_bignum(in, NULL)); + CHECK_ASSIGN(ctx->rsa_d, d0_iobuf_read_bignum(in, NULL)); + return d0_iobuf_close(in, NULL); + +fail: + d0_iobuf_close(in, NULL); + return 0; +} + +WARN_UNUSED_RESULT BOOL d0_blind_id_read_public_keys(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen) +{ + d0_iobuf_t *in = d0_iobuf_open_read(inbuf, inbuflen); + d0_blind_id_clear(ctx); + CHECK_ASSIGN(ctx->schnorr_G, d0_iobuf_read_bignum(in, NULL)); + CHECK_ASSIGN(ctx->rsa_n, d0_iobuf_read_bignum(in, NULL)); + CHECK_ASSIGN(ctx->rsa_e, d0_iobuf_read_bignum(in, NULL)); + return d0_iobuf_close(in, NULL); + +fail: + d0_iobuf_close(in, NULL); + return 0; +} + +#define USING(x) if(!(ctx->x)) return 0 +#define WRITING(x,f) if(ctx->x) { f(ctx->x); ctx->x = NULL; } +#define REPLACING(x) + +WARN_UNUSED_RESULT BOOL d0_blind_id_write_private_keys(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen) +{ + USING(rsa_n); USING(rsa_e); USING(rsa_d); + + d0_iobuf_t *out = d0_iobuf_open_write(outbuf, *outbuflen); + CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_G)); + CHECK(d0_iobuf_write_bignum(out, ctx->rsa_n)); + CHECK(d0_iobuf_write_bignum(out, ctx->rsa_e)); + CHECK(d0_iobuf_write_bignum(out, ctx->rsa_d)); + return d0_iobuf_close(out, outbuflen); + +fail: + d0_iobuf_close(out, outbuflen); + return 0; +} + +WARN_UNUSED_RESULT BOOL d0_blind_id_write_public_keys(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen) +{ + USING(rsa_n); USING(rsa_e); USING(rsa_d); + + d0_iobuf_t *out = d0_iobuf_open_write(outbuf, *outbuflen); + CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_G)); + CHECK(d0_iobuf_write_bignum(out, ctx->rsa_n)); + CHECK(d0_iobuf_write_bignum(out, ctx->rsa_e)); + return d0_iobuf_close(out, outbuflen); + +fail: + if(!d0_iobuf_close(out, outbuflen)) + return 0; + return 0; +} + +WARN_UNUSED_RESULT BOOL d0_blind_id_generate_private_id_start(d0_blind_id_t *ctx) +{ + // temps: temp0 order + USING(schnorr_G); + REPLACING(schnorr_s); REPLACING(schnorr_4_to_s); + + CHECK(d0_dl_get_order(temp0, ctx->schnorr_G)); + CHECK_ASSIGN(ctx->schnorr_s, d0_bignum_rand_range(ctx->schnorr_s, zero, temp0)); + CHECK_ASSIGN(ctx->schnorr_4_to_s, d0_bignum_mod_pow(ctx->schnorr_4_to_s, four, ctx->schnorr_s, ctx->schnorr_G)); + return 1; + +fail: + return 0; +} + +WARN_UNUSED_RESULT BOOL d0_blind_id_generate_private_id_request(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen) +{ + // temps: temp0 temp1 + USING(rsa_n); USING(rsa_e); USING(schnorr_4_to_s); + REPLACING(rn); + + d0_iobuf_t *out = d0_iobuf_open_write(outbuf, *outbuflen); + + CHECK_ASSIGN(ctx->rn, d0_bignum_rand_bit_atmost(ctx->rn, d0_bignum_size(ctx->rsa_n))); + CHECK(d0_bignum_mod_pow(temp0, ctx->rn, ctx->rsa_e, ctx->rsa_n)); + CHECK(d0_bignum_mod_mul(temp1, ctx->schnorr_4_to_s, temp0, ctx->rsa_n)); + CHECK(d0_iobuf_write_bignum(out, temp1)); + return d0_iobuf_close(out, outbuflen); + +fail: + d0_iobuf_close(out, outbuflen); + return 0; +} + +WARN_UNUSED_RESULT BOOL d0_blind_id_answer_private_id_request(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen) +{ + // temps: temp0 temp1 + USING(rsa_d); USING(rsa_n); + + d0_iobuf_t *in = d0_iobuf_open_read(inbuf, inbuflen); + d0_iobuf_t *out = d0_iobuf_open_write(outbuf, *outbuflen); + + CHECK(d0_iobuf_read_bignum(in, temp0)); + CHECK(d0_bignum_mod_pow(temp1, temp0, ctx->rsa_d, ctx->rsa_n)); + CHECK(d0_iobuf_write_bignum(out, temp1)); + + d0_iobuf_close(in, NULL); + return d0_iobuf_close(out, outbuflen); + +fail: + d0_iobuf_close(in, NULL); + d0_iobuf_close(out, outbuflen); + return 0; +} + +WARN_UNUSED_RESULT BOOL d0_blind_id_finish_private_id_request(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen) +{ + // temps: temp0 temp1 + USING(rn); USING(rsa_n); + REPLACING(schnorr_4_to_s_signature); + + d0_iobuf_t *in = d0_iobuf_open_read(inbuf, inbuflen); + + CHECK(d0_iobuf_read_bignum(in, temp0)); + CHECK(d0_bignum_mod_inv(temp1, ctx->rn, ctx->rsa_n)); + CHECK_ASSIGN(ctx->schnorr_4_to_s_signature, d0_bignum_mod_mul(ctx->schnorr_4_to_s_signature, temp0, temp1, ctx->rsa_n)); + + return d0_iobuf_close(in, NULL); + +fail: + d0_iobuf_close(in, NULL); + return 0; +} + +WARN_UNUSED_RESULT BOOL d0_blind_id_read_private_id(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen) +{ + REPLACING(schnorr_s); REPLACING(schnorr_4_to_s); REPLACING(schnorr_4_to_s_signature); + + d0_iobuf_t *in = d0_iobuf_open_read(inbuf, inbuflen); + + CHECK_ASSIGN(ctx->schnorr_s, d0_iobuf_read_bignum(in, ctx->schnorr_s)); + CHECK_ASSIGN(ctx->schnorr_4_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_4_to_s)); + CHECK_ASSIGN(ctx->schnorr_4_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_4_to_s_signature)); + + return d0_iobuf_close(in, NULL); + +fail: + d0_iobuf_close(in, NULL); + return 0; +} + +WARN_UNUSED_RESULT BOOL d0_blind_id_read_public_id(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen) +{ + REPLACING(schnorr_4_to_s); REPLACING(schnorr_4_to_s_signature); + + d0_iobuf_t *in = d0_iobuf_open_read(inbuf, inbuflen); + + CHECK_ASSIGN(ctx->schnorr_4_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_4_to_s)); + CHECK_ASSIGN(ctx->schnorr_4_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_4_to_s_signature)); + + return d0_iobuf_close(in, NULL); + +fail: + d0_iobuf_close(in, NULL); + return 0; +} + +WARN_UNUSED_RESULT BOOL d0_blind_id_write_private_id(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen) +{ + USING(schnorr_s); USING(schnorr_4_to_s); USING(schnorr_4_to_s_signature); + + d0_iobuf_t *out = d0_iobuf_open_write(outbuf, *outbuflen); + + CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_s)); + CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_4_to_s)); + CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_4_to_s_signature)); + + return d0_iobuf_close(out, outbuflen); + +fail: + d0_iobuf_close(out, outbuflen); + return 0; +} + +WARN_UNUSED_RESULT BOOL d0_blind_id_write_public_id(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen) +{ + USING(schnorr_4_to_s); USING(schnorr_4_to_s_signature); + + d0_iobuf_t *out = d0_iobuf_open_write(outbuf, *outbuflen); + + CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_4_to_s)); + CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_4_to_s_signature)); + + return d0_iobuf_close(out, outbuflen); + +fail: + d0_iobuf_close(out, outbuflen); + return 0; +} + +WARN_UNUSED_RESULT BOOL d0_blind_id_authenticate_with_private_id_start(d0_blind_id_t *ctx, int is_first, char *msg, size_t msglen, char *outbuf, size_t *outbuflen) +// start = +// first run: send 4^s, 4^s signature +// 1. get random r, send HASH(4^r) +{ + if(is_first) + { + USING(schnorr_4_to_s); USING(schnorr_4_to_s_signature); + } + USING(schnorr_G); + REPLACING(r); + + d0_iobuf_t *out = d0_iobuf_open_write(outbuf, *outbuflen); + + if(is_first) + { + // send ID + CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_4_to_s)); + CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_4_to_s_signature)); + } + + // start schnorr ID scheme + // generate random number r; x = g^r; send hash of x, remember r, forget x + CHECK(d0_dl_get_order(temp0, ctx->schnorr_G)); + CHECK_ASSIGN(ctx->r, d0_bignum_rand_range(ctx->r, zero, temp0)); + CHECK(d0_bignum_mod_pow(temp0, four, ctx->r, ctx->schnorr_G)); + + // hash it, hash it, everybody hash it + unsigned char convbuf[1024]; + d0_iobuf_t *conv = d0_iobuf_open_write(convbuf, sizeof(convbuf)); + size_t sz; + CHECK(d0_iobuf_write_bignum(conv, temp0)); + CHECK(d0_iobuf_write_packet(conv, msg, msglen)); + CHECK(d0_iobuf_write_bignum(conv, temp0)); + d0_iobuf_close(conv, &sz); + conv = NULL; + CHECK(d0_iobuf_write_raw(out, sha(convbuf, sz), SCHNORR_HASHSIZE) == SCHNORR_HASHSIZE); + CHECK(d0_iobuf_write_packet(out, msg, msglen)); + + return d0_iobuf_close(out, outbuflen); + +fail: + d0_iobuf_close(out, outbuflen); + return 0; +} + +WARN_UNUSED_RESULT BOOL d0_blind_id_authenticate_with_private_id_challenge(d0_blind_id_t *ctx, int is_first, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen) +// first run: get 4^s, 4^s signature +// 1. check sig +// 2. save HASH(4^r) +// 3. send challenge e of SCHNORR_BITS +{ + if(is_first) + { + REPLACING(schnorr_4_to_s); REPLACING(k); REPLACING(schnorr_4_to_s_signature); + USING(schnorr_G); USING(rsa_n); + } + else + { + USING(schnorr_4_to_s_signature); USING(schnorr_4_to_s); + } + USING(rsa_e); USING(rsa_n); + REPLACING(e); REPLACING(msg); REPLACING(msglen); + + d0_iobuf_t *in = d0_iobuf_open_read(inbuf, inbuflen); + d0_iobuf_t *out = d0_iobuf_open_write(outbuf, *outbuflen); + + if(is_first) + { + CHECK_ASSIGN(ctx->schnorr_4_to_s, d0_iobuf_read_bignum(in, NULL)); + CHECK(d0_bignum_cmp(ctx->schnorr_4_to_s, zero) >= 0); + CHECK(d0_bignum_cmp(ctx->schnorr_4_to_s, ctx->schnorr_G) < 0); + CHECK_ASSIGN(ctx->schnorr_4_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_4_to_s_signature)); + CHECK(d0_bignum_cmp(ctx->schnorr_4_to_s_signature, zero) >= 0); + CHECK(d0_bignum_cmp(ctx->schnorr_4_to_s_signature, ctx->rsa_n) < 0); + } + + // check signature of key (t = k^d, so, t^e = k) + CHECK(d0_bignum_mod_pow(temp0, ctx->schnorr_4_to_s_signature, ctx->rsa_e, ctx->rsa_n)); + if(d0_bignum_cmp(temp0, ctx->schnorr_4_to_s)) + { + // FAIL (not signed by Xonotic) + goto fail; + // TODO: accept the key anyway, but mark as failed signature! + } + + CHECK(d0_iobuf_read_raw(in, ctx->xnbh, SCHNORR_HASHSIZE)); + ctx->msglen = MSGSIZE; + CHECK(d0_iobuf_read_packet(in, ctx->msg, &ctx->msglen)); + + // send challenge + CHECK_ASSIGN(ctx->e, d0_bignum_rand_bit_atmost(ctx->e, SCHNORR_BITS)); + + CHECK(d0_iobuf_write_bignum(out, ctx->e)); + + d0_iobuf_close(in, NULL); + return d0_iobuf_close(out, outbuflen); + +fail: + d0_iobuf_close(in, NULL); + d0_iobuf_close(out, outbuflen); + return 0; +} + +WARN_UNUSED_RESULT BOOL d0_blind_id_authenticate_with_private_id_response(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen) +// 1. read challenge e of SCHNORR_BITS +// 2. reply with r + s * e mod order +{ + // temps: 0 order, 1 prod, 2 y, 3 e + USING(schnorr_G); USING(schnorr_s); USING(r); + + d0_iobuf_t *in = d0_iobuf_open_read(inbuf, inbuflen); + d0_iobuf_t *out = d0_iobuf_open_write(outbuf, *outbuflen); + + CHECK(d0_iobuf_read_bignum(in, temp3)); + // TODO check if >= 2^SCHNORR_BITS or < 0, if yes, then fail (needed for zero knowledge) + CHECK(d0_bignum_cmp(temp3, zero) >= 0); + CHECK(d0_bignum_size(temp3) <= SCHNORR_BITS); + + // send response for schnorr ID scheme + // i.e. r + ctx->schnorr_s * temp3 + CHECK(d0_dl_get_order(temp0, ctx->schnorr_G)); + CHECK(d0_bignum_mod_mul(temp1, ctx->schnorr_s, temp3, temp0)); + CHECK(d0_bignum_mod_add(temp2, temp1, ctx->r, temp0)); + CHECK(d0_iobuf_write_bignum(out, temp2)); + + d0_iobuf_close(in, NULL); + return d0_iobuf_close(out, outbuflen); + +fail: + d0_iobuf_close(in, NULL); + d0_iobuf_close(out, outbuflen); + return 0; +} + +WARN_UNUSED_RESULT BOOL d0_blind_id_authenticate_with_private_id_verify(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *msg, ssize_t *msglen) +// 1. read y = r + s * e mod order +// 2. verify: g^y (g^s)^-e = g^(r+s*e-s*e) = g^r +// (check using H(g^r) which we know) +{ + // temps: 0 y 1 order + USING(e); USING(schnorr_G); + + d0_iobuf_t *in = d0_iobuf_open_read(inbuf, inbuflen); + + *msglen = -1; + CHECK(d0_dl_get_order(temp1, ctx->schnorr_G)); + CHECK(d0_iobuf_read_bignum(in, temp0)); + CHECK(d0_bignum_cmp(temp0, zero) >= 0); + CHECK(d0_bignum_cmp(temp0, temp1) < 0); + + // verify schnorr ID scheme + // we need 4^temp0 (g^s)^-e + CHECK(d0_bignum_neg(temp1, ctx->e)); + CHECK(d0_bignum_mod_pow(temp2, ctx->schnorr_4_to_s, temp1, ctx->schnorr_G)); + CHECK(d0_bignum_mod_pow(temp1, four, temp0, ctx->schnorr_G)); + CHECK(d0_bignum_mod_mul(temp3, temp1, temp2, ctx->schnorr_G)); + // hash must be equal to xnbh + + // hash it, hash it, everybody hash it + unsigned char convbuf[1024]; + d0_iobuf_t *conv = d0_iobuf_open_write(convbuf, sizeof(convbuf)); + size_t sz; + CHECK(d0_iobuf_write_bignum(conv, temp3)); + CHECK(d0_iobuf_write_packet(conv, ctx->msg, ctx->msglen)); + CHECK(d0_iobuf_write_bignum(conv, temp3)); + d0_iobuf_close(conv, &sz); + conv = NULL; + if(memcmp(sha(convbuf, sz), ctx->xnbh, SCHNORR_HASHSIZE)) + { + // FAIL (not owned by player) + goto fail; + } + + if(ctx->msglen <= (size_t) *msglen) + memcpy(msg, ctx->msg, ctx->msglen); + else + memcpy(msg, ctx->msg, *msglen); + *msglen = ctx->msglen; + + d0_iobuf_close(in, NULL); + return 1; + +fail: + d0_iobuf_close(in, NULL); + return 0; +} + +WARN_UNUSED_RESULT BOOL d0_blind_id_fingerprint64_public_id(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen) +{ + USING(schnorr_4_to_s); + + static unsigned char convbuf[1024]; + d0_iobuf_t *out = d0_iobuf_open_write(outbuf, *outbuflen); + d0_iobuf_t *conv = d0_iobuf_open_write(convbuf, sizeof(convbuf)); + + size_t n, sz; + + CHECK(d0_iobuf_write_bignum(conv, ctx->schnorr_4_to_s)); + CHECK(d0_iobuf_close(conv, &sz)); + conv = NULL; + + n = (*outbuflen / 4) * 3; + if(n > SHA_DIGESTSIZE) + n = SHA_DIGESTSIZE; + if(d0_iobuf_write_raw(out, sha(convbuf, sz), n) != n) + goto fail; + if(!d0_iobuf_conv_base64_out(out)) + goto fail; + + return d0_iobuf_close(out, outbuflen); + +fail: + if(conv) + if(!d0_iobuf_close(conv, &sz)) { } + if(!d0_iobuf_close(out, outbuflen)) + return 0; + return 0; +} + +d0_blind_id_t *d0_blind_id_new() +{ + d0_blind_id_t *b = d0_malloc(sizeof(d0_blind_id_t)); + memset(b, 0, sizeof(*b)); + return b; +} + +void d0_blind_id_free(d0_blind_id_t *a) +{ + d0_blind_id_clear(a); + d0_free(a); +} diff --git a/d0_blind_id.h b/d0_blind_id.h new file mode 100644 index 0000000..849285f --- /dev/null +++ b/d0_blind_id.h @@ -0,0 +1,29 @@ +#include "d0.h" + +typedef struct d0_blind_id_s d0_blind_id_t; + +WARN_UNUSED_RESULT d0_blind_id_t *d0_blind_id_new(); +void d0_blind_id_free(d0_blind_id_t *a); +void d0_blind_id_clear(d0_blind_id_t *ctx); +void d0_blind_id_copy(d0_blind_id_t *ctx, const d0_blind_id_t *src); +WARN_UNUSED_RESULT BOOL d0_blind_id_generate_private_keys(d0_blind_id_t *ctx, int k); +WARN_UNUSED_RESULT BOOL d0_blind_id_read_private_keys(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen); +WARN_UNUSED_RESULT BOOL d0_blind_id_read_public_keys(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen); +WARN_UNUSED_RESULT BOOL d0_blind_id_write_private_keys(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); +WARN_UNUSED_RESULT BOOL d0_blind_id_write_public_keys(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); +WARN_UNUSED_RESULT BOOL d0_blind_id_generate_private_id_start(d0_blind_id_t *ctx); +WARN_UNUSED_RESULT BOOL d0_blind_id_generate_private_id_request(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); +WARN_UNUSED_RESULT BOOL d0_blind_id_answer_private_id_request(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen); +WARN_UNUSED_RESULT BOOL d0_blind_id_finish_private_id_request(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen); +WARN_UNUSED_RESULT BOOL d0_blind_id_read_private_id(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen); +WARN_UNUSED_RESULT BOOL d0_blind_id_read_public_id(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen); +WARN_UNUSED_RESULT BOOL d0_blind_id_write_private_id(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); +WARN_UNUSED_RESULT BOOL d0_blind_id_write_public_id(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); +WARN_UNUSED_RESULT BOOL d0_blind_id_authenticate_with_private_id_start(d0_blind_id_t *ctx, int is_first, char *message, size_t msglen, char *outbuf, size_t *outbuflen); +WARN_UNUSED_RESULT BOOL d0_blind_id_authenticate_with_private_id_challenge(d0_blind_id_t *ctx, int is_first, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen); +WARN_UNUSED_RESULT BOOL d0_blind_id_authenticate_with_private_id_response(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen); +WARN_UNUSED_RESULT BOOL d0_blind_id_authenticate_with_private_id_verify(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *msg, ssize_t *msglen); +WARN_UNUSED_RESULT BOOL d0_blind_id_fingerprint64_public_id(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); + +void d0_blind_id_INITIALIZE(); +void d0_blind_id_SHUTDOWN(); diff --git a/d0_iobuf.c b/d0_iobuf.c new file mode 100644 index 0000000..7c676f4 --- /dev/null +++ b/d0_iobuf.c @@ -0,0 +1,148 @@ +#include "d0_iobuf.h" + +#include + +struct d0_iobuf_s +{ + const unsigned char *inbuf; + unsigned char *outbuf; + size_t inpos, outpos, inbuflen, outbuflen; + BOOL ok; +}; + +d0_iobuf_t *d0_iobuf_open_read(const void *buf, size_t len) +{ + d0_iobuf_t *b = d0_malloc(sizeof(d0_iobuf_t)); + b->inbuf = (const unsigned char *) buf; + b->outbuf = NULL; + b->inpos = b->outpos = 0; + b->inbuflen = len; + b->outbuflen = 0; + b->ok = 1; + return b; +} + +d0_iobuf_t *d0_iobuf_open_write(void *buf, size_t len) +{ + d0_iobuf_t *b = d0_malloc(sizeof(d0_iobuf_t)); + b->inbuf = (const unsigned char *) buf; + b->outbuf = (unsigned char *) buf; + b->inpos = b->outpos = 0; + b->inbuflen = len; + b->outbuflen = len; + b->ok = 1; + return b; +} + +BOOL d0_iobuf_close(d0_iobuf_t *buf, size_t *len) +{ + BOOL r = buf->ok; + if(len) + *len = buf->outpos; + d0_free(buf); + return r; +} + +size_t d0_iobuf_write_raw(d0_iobuf_t *buf, const void *s, size_t n) +{ + size_t nreal = n; + if(nreal > buf->outbuflen - buf->outpos) + { + buf->ok = 0; + nreal = buf->outbuflen - buf->outpos; + } + memcpy(buf->outbuf + buf->outpos, s, nreal); + buf->outpos += nreal; + return nreal; +} + +size_t d0_iobuf_read_raw(d0_iobuf_t *buf, void *s, size_t n) +{ + size_t nreal = n; + if(nreal > buf->inbuflen - buf->inpos) + { + buf->ok = 0; + nreal = buf->inbuflen - buf->inpos; + } + memcpy(s, buf->inbuf + buf->inpos, nreal); + buf->inpos += nreal; + return nreal; +} + +BOOL d0_iobuf_write_packet(d0_iobuf_t *buf, const void *s, size_t n) +{ + unsigned char c; + size_t nn = n; + while(nn) + { + c = nn & 255; + nn >>= 8; + if(d0_iobuf_write_raw(buf, &c, 1) != 1) + return 0; + } + c = 0; + if(d0_iobuf_write_raw(buf, &c, 1) != 1) + return 0; + if(d0_iobuf_write_raw(buf, s, n) != n) + return 0; + return 1; +} + +BOOL d0_iobuf_read_packet(d0_iobuf_t *buf, void *s, size_t *np) +{ + unsigned char c; + size_t n = 0; + size_t nn = 1; + do + { + if(d0_iobuf_read_raw(buf, &c, 1) != 1) + return 0; + n |= nn * c; + nn <<= 8; + } + while(c); + if(n > *np) + return 0; + if(d0_iobuf_read_raw(buf, s, n) != n) + return 0; + *np = n; + return 1; +} + +BOOL d0_iobuf_conv_base64_in(d0_iobuf_t *buf) +{ + // compand the in-buffer + return 0; +} + +static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static void base64_3to4(const unsigned char *in, unsigned char *out, int bytes) +{ + unsigned char i0 = (bytes > 0) ? in[0] : 0; + unsigned char i1 = (bytes > 1) ? in[1] : 0; + unsigned char i2 = (bytes > 2) ? in[2] : 0; + unsigned char o0 = base64[i0 >> 2]; + unsigned char o1 = base64[((i0 << 4) | (i1 >> 4)) & 077]; + unsigned char o2 = base64[((i1 << 2) | (i2 >> 6)) & 077]; + unsigned char o3 = base64[i2 & 077]; + out[0] = (bytes > 0) ? o0 : '?'; + out[1] = (bytes > 0) ? o1 : '?'; + out[2] = (bytes > 1) ? o2 : '='; + out[3] = (bytes > 2) ? o3 : '='; +} + +BOOL d0_iobuf_conv_base64_out(d0_iobuf_t *buf) +{ + size_t blocks, i; + // expand the out-buffer + blocks = ((buf->outpos + 2) / 3); + if(blocks*4 > buf->outbuflen) + return 0; + for(i = blocks; i > 0; ) + { + --i; + base64_3to4(buf->outbuf + 3*i, buf->outbuf + 4*i, buf->outpos - 3*i); + } + buf->outpos = blocks * 4; + return 1; +} diff --git a/d0_iobuf.h b/d0_iobuf.h new file mode 100644 index 0000000..396215d --- /dev/null +++ b/d0_iobuf.h @@ -0,0 +1,13 @@ +#include "d0.h" + +typedef struct d0_iobuf_s d0_iobuf_t; + +WARN_UNUSED_RESULT d0_iobuf_t *d0_iobuf_open_read(const void *buf, size_t len); // note: can read AND write! +WARN_UNUSED_RESULT d0_iobuf_t *d0_iobuf_open_write(void *buf, size_t len); // note: can read AND write! +WARN_UNUSED_RESULT BOOL d0_iobuf_conv_base64_in(d0_iobuf_t *buf); +WARN_UNUSED_RESULT BOOL d0_iobuf_conv_base64_out(d0_iobuf_t *buf); +BOOL d0_iobuf_close(d0_iobuf_t *buf, size_t *len); // don't warn +WARN_UNUSED_RESULT size_t d0_iobuf_write_raw(d0_iobuf_t *buf, const void *s, size_t n); +WARN_UNUSED_RESULT size_t d0_iobuf_read_raw(d0_iobuf_t *buf, void *s, size_t n); +WARN_UNUSED_RESULT BOOL d0_iobuf_write_packet(d0_iobuf_t *buf, const void *s, size_t n); +WARN_UNUSED_RESULT BOOL d0_iobuf_read_packet(d0_iobuf_t *buf, void *s, size_t *n); diff --git a/main.c b/main.c new file mode 100644 index 0000000..88bf520 --- /dev/null +++ b/main.c @@ -0,0 +1,103 @@ +#include "d0_blind_id.h" + +#include +#include +#include + +void bench(double *b) +{ + static struct timespec thistime, lasttime; + static double x = 0; + static double *lastclock = &x; + lasttime = thistime; + clock_gettime(CLOCK_MONOTONIC, &thistime); + *lastclock += (thistime.tv_sec - lasttime.tv_sec) + 0.000000001 * (thistime.tv_nsec - lasttime.tv_nsec); + lastclock = b; +} + +#include +volatile BOOL quit = 0; +void mysignal(int signo) +{ + (void) signo; + quit = 1; +} + +#include +int main(int argc, char **argv) +{ + char buf[65536]; size_t bufsize; + char buf2[65536]; size_t buf2size; ssize_t buf2ssize; + d0_blind_id_t *ctx_self, *ctx_other; + + d0_blind_id_INITIALIZE(); + ctx_self = d0_blind_id_new(); + ctx_other = d0_blind_id_new(); + + if(!d0_blind_id_generate_private_keys(ctx_self, 1024)) + errx(1, "keygen fail"); + bufsize = sizeof(buf); if(!d0_blind_id_write_public_keys(ctx_self, buf, &bufsize)) + errx(2, "writepub fail"); + if(!d0_blind_id_read_public_keys(ctx_other, buf, bufsize)) + errx(3, "readpub fail"); + + signal(SIGINT, mysignal); + + int n = 0; + double bench_gen = 0, bench_fp = 0, bench_stop = 0; + do + { + bench(&bench_gen); + bufsize = sizeof(buf); if(!d0_blind_id_generate_private_id_start(ctx_other)) + errx(4, "genid fail"); + bench(&bench_fp); + buf2size = sizeof(buf2) - 1; if(!d0_blind_id_fingerprint64_public_id(ctx_other, buf2, &buf2size)) + errx(4, "fp64 fail"); + bench(&bench_stop); + if(n % 1024 == 0) + printf("gen=%f fp=%f\n", n/bench_gen, n/bench_fp); + ++n; + } + while(!(quit || argc != 2 || (buf2size > strlen(argv[1]) && !memcmp(buf2, argv[1], strlen(argv[1]))))); + + buf2[buf2size] = 0; + printf("Generated key has ID: %s\n", buf2); + + bufsize = sizeof(buf); if(!d0_blind_id_generate_private_id_request(ctx_other, buf, &bufsize)) + errx(4, "genreq fail"); + buf2size = sizeof(buf2); if(!d0_blind_id_answer_private_id_request(ctx_self, buf, bufsize, buf2, &buf2size)) + errx(5, "ansreq fail"); + if(!d0_blind_id_finish_private_id_request(ctx_other, buf2, buf2size)) + errx(6, "finishreq fail"); + + bufsize = sizeof(buf); if(!d0_blind_id_write_public_id(ctx_other, buf, &bufsize)) + errx(7, "writepub2 fail"); + if(!d0_blind_id_read_public_id(ctx_self, buf, bufsize)) + errx(8, "readpub2 fail"); + + n = 0; + double bench_auth = 0, bench_chall = 0, bench_resp = 0, bench_verify = 0; + while(!quit) + { + bench(&bench_auth); + bufsize = sizeof(buf); if(!d0_blind_id_authenticate_with_private_id_start(ctx_other, 1, "hello world", 11, buf, &bufsize)) + errx(9, "start fail"); + bench(&bench_chall); + buf2size = sizeof(buf2); if(!d0_blind_id_authenticate_with_private_id_challenge(ctx_self, 1, buf, bufsize, buf2, &buf2size)) + errx(10, "challenge fail"); + bench(&bench_resp); + bufsize = sizeof(buf); if(!d0_blind_id_authenticate_with_private_id_response(ctx_other, buf2, buf2size, buf, &bufsize)) + errx(11, "response fail"); + bench(&bench_verify); + buf2ssize = sizeof(buf2); if(!d0_blind_id_authenticate_with_private_id_verify(ctx_self, buf, bufsize, buf2, &buf2ssize)) + errx(12, "verify fail"); + if(buf2ssize != 11 || memcmp(buf2, "hello world", 11)) + errx(13, "hello fail"); + bench(&bench_stop); + ++n; + if(n % 1024 == 0) + printf("auth=%f chall=%f resp=%f verify=%f\n", n/bench_auth, n/bench_chall, n/bench_resp, n/bench_verify); + } + + return 0; +} diff --git a/sha1.c b/sha1.c new file mode 100644 index 0000000..dfeda6f --- /dev/null +++ b/sha1.c @@ -0,0 +1,377 @@ +/* sha.c - Implementation of the Secure Hash Algorithm + * + * Copyright (C) 1995, A.M. Kuchling + * + * Distribute and use freely; there are no restrictions on further + * dissemination and usage except those imposed by the laws of your + * country of residence. + * + * Adapted to pike and some cleanup by Niels Möller. + */ + +/* $Id: sha1.c,v 1.6 2006/01/08 09:08:29 imipak Exp $ */ + +/* SHA: NIST's Secure Hash Algorithm */ + +/* Based on SHA code originally posted to sci.crypt by Peter Gutmann + in message <30ajo5$oe8@ccu2.auckland.ac.nz>. + Modified to test for endianness on creation of SHA objects by AMK. + Also, the original specification of SHA was found to have a weakness + by NSA/NIST. This code implements the fixed version of SHA. +*/ + +/* Here's the first paragraph of Peter Gutmann's posting: + +The following is my SHA (FIPS 180) code updated to allow use of the "fixed" +SHA, thanks to Jim Gillogly and an anonymous contributor for the information on +what's changed in the new version. The fix is a simple change which involves +adding a single rotate in the initial expansion function. It is unknown +whether this is an optimal solution to the problem which was discovered in the +SHA or whether it's simply a bandaid which fixes the problem with a minimum of +effort (for example the reengineering of a great many Capstone chips). +*/ + +#include +#include "sha1.h" + +void sha_copy(struct sha_ctx *dest, struct sha_ctx *src) +{ + unsigned int i; + + dest->count_l=src->count_l; + dest->count_h=src->count_h; + for(i=0; idigest[i]=src->digest[i]; + } + for(i=0; i < src->index; i++) + { + dest->block[i] = src->block[i]; + } + dest->index = src->index; +} + + +/* The SHA f()-functions. The f1 and f3 functions can be optimized to + save one boolean operation each - thanks to Rich Schroeppel, + rcs@cs.arizona.edu for discovering this */ + +#define f1(x,y,z) ( z ^ ( x & ( y ^ z ) ) ) /* Rounds 0-19 */ +#define f2(x,y,z) ( x ^ y ^ z ) /* Rounds 20-39 */ +#define f3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) ) /* Rounds 40-59 */ +#define f4(x,y,z) ( x ^ y ^ z ) /* Rounds 60-79 */ + +/* The SHA Mysterious Constants */ + +#define K1 0x5A827999L /* Rounds 0-19 */ +#define K2 0x6ED9EBA1L /* Rounds 20-39 */ +#define K3 0x8F1BBCDCL /* Rounds 40-59 */ +#define K4 0xCA62C1D6L /* Rounds 60-79 */ + +/* SHA initial values */ + +#define h0init 0x67452301L +#define h1init 0xEFCDAB89L +#define h2init 0x98BADCFEL +#define h3init 0x10325476L +#define h4init 0xC3D2E1F0L + +/* 32-bit rotate left - kludged with shifts */ + +#define ROTL(n,X) ( ( (X) << (n) ) | ( (X) >> ( 32 - (n) ) ) ) + +/* The initial expanding function. The hash function is defined over an + 80-word expanded input array W, where the first 16 are copies of the input + data, and the remaining 64 are defined by + + W[ i ] = W[ i - 16 ] ^ W[ i - 14 ] ^ W[ i - 8 ] ^ W[ i - 3 ] + + This implementation generates these values on the fly in a circular + buffer - thanks to Colin Plumb, colin@nyx10.cs.du.edu for this + optimization. + + The updated SHA changes the expanding function by adding a rotate of 1 + bit. Thanks to Jim Gillogly, jim@rand.org, and an anonymous contributor + for this information */ + +#define expand(W,i) ( W[ i & 15 ] = \ + ROTL( 1, ( W[ i & 15 ] ^ W[ (i - 14) & 15 ] ^ \ + W[ (i - 8) & 15 ] ^ W[ (i - 3) & 15 ] ) ) ) + + +/* The prototype SHA sub-round. The fundamental sub-round is: + + a' = e + ROTL( 5, a ) + f( b, c, d ) + k + data; + b' = a; + c' = ROTL( 30, b ); + d' = c; + e' = d; + + but this is implemented by unrolling the loop 5 times and renaming the + variables ( e, a, b, c, d ) = ( a', b', c', d', e' ) each iteration. + This code is then replicated 20 times for each of the 4 functions, using + the next 20 values from the W[] array each time */ + +#define subRound(a, b, c, d, e, f, k, data) \ + ( e += ROTL( 5, a ) + f( b, c, d ) + k + data, b = ROTL( 30, b ) ) + +/* Initialize the SHA values */ + +void sha_init(struct sha_ctx *ctx) +{ + /* Set the h-vars to their initial values */ + ctx->digest[ 0 ] = h0init; + ctx->digest[ 1 ] = h1init; + ctx->digest[ 2 ] = h2init; + ctx->digest[ 3 ] = h3init; + ctx->digest[ 4 ] = h4init; + + /* Initialize bit count */ + ctx->count_l = ctx->count_h = 0; + + /* Initialize buffer */ + ctx->index = 0; +} + +/* Perform the SHA transformation. Note that this code, like MD5, seems to + break some optimizing compilers due to the complexity of the expressions + and the size of the basic block. It may be necessary to split it into + sections, e.g. based on the four subrounds + + Note that this function destroys the data area */ + +static void sha_transform(struct sha_ctx *ctx, unsigned int *data ) +{ + register unsigned int A, B, C, D, E; /* Local vars */ + + /* Set up first buffer and local data buffer */ + A = ctx->digest[0]; + B = ctx->digest[1]; + C = ctx->digest[2]; + D = ctx->digest[3]; + E = ctx->digest[4]; + + /* Heavy mangling, in 4 sub-rounds of 20 interations each. */ + subRound( A, B, C, D, E, f1, K1, data[ 0] ); + subRound( E, A, B, C, D, f1, K1, data[ 1] ); + subRound( D, E, A, B, C, f1, K1, data[ 2] ); + subRound( C, D, E, A, B, f1, K1, data[ 3] ); + subRound( B, C, D, E, A, f1, K1, data[ 4] ); + subRound( A, B, C, D, E, f1, K1, data[ 5] ); + subRound( E, A, B, C, D, f1, K1, data[ 6] ); + subRound( D, E, A, B, C, f1, K1, data[ 7] ); + subRound( C, D, E, A, B, f1, K1, data[ 8] ); + subRound( B, C, D, E, A, f1, K1, data[ 9] ); + subRound( A, B, C, D, E, f1, K1, data[10] ); + subRound( E, A, B, C, D, f1, K1, data[11] ); + subRound( D, E, A, B, C, f1, K1, data[12] ); + subRound( C, D, E, A, B, f1, K1, data[13] ); + subRound( B, C, D, E, A, f1, K1, data[14] ); + subRound( A, B, C, D, E, f1, K1, data[15] ); + subRound( E, A, B, C, D, f1, K1, expand( data, 16 ) ); + subRound( D, E, A, B, C, f1, K1, expand( data, 17 ) ); + subRound( C, D, E, A, B, f1, K1, expand( data, 18 ) ); + subRound( B, C, D, E, A, f1, K1, expand( data, 19 ) ); + + subRound( A, B, C, D, E, f2, K2, expand( data, 20 ) ); + subRound( E, A, B, C, D, f2, K2, expand( data, 21 ) ); + subRound( D, E, A, B, C, f2, K2, expand( data, 22 ) ); + subRound( C, D, E, A, B, f2, K2, expand( data, 23 ) ); + subRound( B, C, D, E, A, f2, K2, expand( data, 24 ) ); + subRound( A, B, C, D, E, f2, K2, expand( data, 25 ) ); + subRound( E, A, B, C, D, f2, K2, expand( data, 26 ) ); + subRound( D, E, A, B, C, f2, K2, expand( data, 27 ) ); + subRound( C, D, E, A, B, f2, K2, expand( data, 28 ) ); + subRound( B, C, D, E, A, f2, K2, expand( data, 29 ) ); + subRound( A, B, C, D, E, f2, K2, expand( data, 30 ) ); + subRound( E, A, B, C, D, f2, K2, expand( data, 31 ) ); + subRound( D, E, A, B, C, f2, K2, expand( data, 32 ) ); + subRound( C, D, E, A, B, f2, K2, expand( data, 33 ) ); + subRound( B, C, D, E, A, f2, K2, expand( data, 34 ) ); + subRound( A, B, C, D, E, f2, K2, expand( data, 35 ) ); + subRound( E, A, B, C, D, f2, K2, expand( data, 36 ) ); + subRound( D, E, A, B, C, f2, K2, expand( data, 37 ) ); + subRound( C, D, E, A, B, f2, K2, expand( data, 38 ) ); + subRound( B, C, D, E, A, f2, K2, expand( data, 39 ) ); + + subRound( A, B, C, D, E, f3, K3, expand( data, 40 ) ); + subRound( E, A, B, C, D, f3, K3, expand( data, 41 ) ); + subRound( D, E, A, B, C, f3, K3, expand( data, 42 ) ); + subRound( C, D, E, A, B, f3, K3, expand( data, 43 ) ); + subRound( B, C, D, E, A, f3, K3, expand( data, 44 ) ); + subRound( A, B, C, D, E, f3, K3, expand( data, 45 ) ); + subRound( E, A, B, C, D, f3, K3, expand( data, 46 ) ); + subRound( D, E, A, B, C, f3, K3, expand( data, 47 ) ); + subRound( C, D, E, A, B, f3, K3, expand( data, 48 ) ); + subRound( B, C, D, E, A, f3, K3, expand( data, 49 ) ); + subRound( A, B, C, D, E, f3, K3, expand( data, 50 ) ); + subRound( E, A, B, C, D, f3, K3, expand( data, 51 ) ); + subRound( D, E, A, B, C, f3, K3, expand( data, 52 ) ); + subRound( C, D, E, A, B, f3, K3, expand( data, 53 ) ); + subRound( B, C, D, E, A, f3, K3, expand( data, 54 ) ); + subRound( A, B, C, D, E, f3, K3, expand( data, 55 ) ); + subRound( E, A, B, C, D, f3, K3, expand( data, 56 ) ); + subRound( D, E, A, B, C, f3, K3, expand( data, 57 ) ); + subRound( C, D, E, A, B, f3, K3, expand( data, 58 ) ); + subRound( B, C, D, E, A, f3, K3, expand( data, 59 ) ); + + subRound( A, B, C, D, E, f4, K4, expand( data, 60 ) ); + subRound( E, A, B, C, D, f4, K4, expand( data, 61 ) ); + subRound( D, E, A, B, C, f4, K4, expand( data, 62 ) ); + subRound( C, D, E, A, B, f4, K4, expand( data, 63 ) ); + subRound( B, C, D, E, A, f4, K4, expand( data, 64 ) ); + subRound( A, B, C, D, E, f4, K4, expand( data, 65 ) ); + subRound( E, A, B, C, D, f4, K4, expand( data, 66 ) ); + subRound( D, E, A, B, C, f4, K4, expand( data, 67 ) ); + subRound( C, D, E, A, B, f4, K4, expand( data, 68 ) ); + subRound( B, C, D, E, A, f4, K4, expand( data, 69 ) ); + subRound( A, B, C, D, E, f4, K4, expand( data, 70 ) ); + subRound( E, A, B, C, D, f4, K4, expand( data, 71 ) ); + subRound( D, E, A, B, C, f4, K4, expand( data, 72 ) ); + subRound( C, D, E, A, B, f4, K4, expand( data, 73 ) ); + subRound( B, C, D, E, A, f4, K4, expand( data, 74 ) ); + subRound( A, B, C, D, E, f4, K4, expand( data, 75 ) ); + subRound( E, A, B, C, D, f4, K4, expand( data, 76 ) ); + subRound( D, E, A, B, C, f4, K4, expand( data, 77 ) ); + subRound( C, D, E, A, B, f4, K4, expand( data, 78 ) ); + subRound( B, C, D, E, A, f4, K4, expand( data, 79 ) ); + + /* Build message digest */ + ctx->digest[0] += A; + ctx->digest[1] += B; + ctx->digest[2] += C; + ctx->digest[3] += D; + ctx->digest[4] += E; +} + + +static void sha_block(struct sha_ctx *ctx, unsigned char *block) +{ + unsigned int data[SHA_DATALEN]; + unsigned int i; + + /* Update block count */ + if (!++ctx->count_l) + { + ++ctx->count_h; + } + + /* Endian independent conversion */ + for (i = 0; iindex) + { /* Try to fill partial block */ + unsigned int left = SHA_DATASIZE - ctx->index; + if (len < left) + { + memcpy(ctx->block + ctx->index, buffer, len); + ctx->index += len; + return; /* Finished */ + } + else + { + memcpy(ctx->block + ctx->index, buffer, left); + sha_block(ctx, ctx->block); + buffer += left; + len -= left; + } + } + while (len >= SHA_DATASIZE) + { + sha_block(ctx, buffer); + buffer += SHA_DATASIZE; + len -= SHA_DATASIZE; + } + if ((ctx->index = len)) /* This assignment is intended */ + { + /* Buffer leftovers */ + memcpy(ctx->block, buffer, len); + } +} + +/* Final wrapup - pad to SHA_DATASIZE-byte boundary with the bit pattern + 1 0* (64-bit count of bits processed, MSB-first) */ + +void sha_final(struct sha_ctx *ctx) +{ + unsigned int data[SHA_DATALEN]; + unsigned int i; + unsigned int words; + + i = ctx->index; + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + ctx->block[i++] = 0x80; + + /* Fill rest of word */ + for( ; i & 3; i++) + { + ctx->block[i] = 0; + } + /* i is now a multiple of the word size 4 */ + words = i >> 2; + for (i = 0; i < words; i++) + { + data[i] = STRING2INT(ctx->block + 4*i); + } + + if (words > (SHA_DATALEN-2)) + { /* No room for length in this block. Process it and + * pad with another one */ + for (i = words ; i < SHA_DATALEN; i++) + { + data[i] = 0; + } + sha_transform(ctx, data); + for (i = 0; i < (SHA_DATALEN-2); i++) + { + data[i] = 0; + } + } + else + { + for (i = words ; i < SHA_DATALEN - 2; i++) + { + data[i] = 0; + } + } + /* Theres 512 = 2^9 bits in one block */ + data[SHA_DATALEN-2] = (ctx->count_h << 9) | (ctx->count_l >> 23); + data[SHA_DATALEN-1] = (ctx->count_l << 9) | (ctx->index << 3); + sha_transform(ctx, data); +} + +void sha_digest(struct sha_ctx *ctx, unsigned char *s) +{ + unsigned int i; + + if (s!=NULL) + { + for (i = 0; i < SHA_DIGESTLEN; i++) + { + *s++ = ctx->digest[i] >> 24; + *s++ = 0xff & (ctx->digest[i] >> 16); + *s++ = 0xff & (ctx->digest[i] >> 8); + *s++ = 0xff & ctx->digest[i]; + } + } +} + +unsigned char *sha(unsigned char *buffer, unsigned int len) +{ + static unsigned char buf[SHA_DIGESTSIZE]; + SHA_CTX s; + sha_init(&s); + sha_update(&s, buffer, len); + sha_final(&s); + sha_digest(&s, buf); + return buf; +} diff --git a/sha1.h b/sha1.h new file mode 100644 index 0000000..79dd900 --- /dev/null +++ b/sha1.h @@ -0,0 +1,29 @@ +#define SHA_DATASIZE 64 +#define SHA_DATALEN 16 +#define SHA_DIGESTSIZE 20 +#define SHA_DIGESTLEN 5 +/* The structure for storing SHA info */ + +typedef struct sha_ctx { + unsigned int digest[SHA_DIGESTLEN]; /* Message digest */ + unsigned int count_l, count_h; /* 64-bit block count */ + unsigned char block[SHA_DATASIZE]; /* SHA data buffer */ + unsigned int index; /* index into buffer */ +} SHA_CTX; + +void sha_init(struct sha_ctx *ctx); +void sha_update(struct sha_ctx *ctx, unsigned char *buffer, unsigned int len); +void sha_final(struct sha_ctx *ctx); +void sha_digest(struct sha_ctx *ctx, unsigned char *s); +void sha_copy(struct sha_ctx *dest, struct sha_ctx *src); + +#ifndef EXTRACT_UCHAR +#define EXTRACT_UCHAR(p) (*(unsigned char *)(p)) +#endif + +#define STRING2INT(s) ((((((EXTRACT_UCHAR(s) << 8) \ + | EXTRACT_UCHAR(s+1)) << 8) \ + | EXTRACT_UCHAR(s+2)) << 8) \ + | EXTRACT_UCHAR(s+3)) + +unsigned char *sha(unsigned char *buffer, unsigned int len);