--- /dev/null
+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
--- /dev/null
+#include "d0.h"
+
+#include <stdlib.h>
+
+void *(*d0_malloc)(size_t len) = malloc;
+void (*d0_free)(void *p) = free;
--- /dev/null
+#ifndef __D0_H__
+#define __D0_H__
+
+#include <stdlib.h> // 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
--- /dev/null
+#include "d0_bignum.h"
+
+#include <gmp.h>
+
+struct d0_bignum_s
+{
+ mpz_t z;
+};
+
+static gmp_randstate_t RANDSTATE;
+
+#include <time.h>
+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);
+}
--- /dev/null
+#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!
--- /dev/null
+#include "d0_blind_id.h"
+
+#include <stdio.h>
+#include <string.h>
+#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);
+}
--- /dev/null
+#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();
--- /dev/null
+#include "d0_iobuf.h"
+
+#include <string.h>
+
+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;
+}
--- /dev/null
+#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);
--- /dev/null
+#include "d0_blind_id.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+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 <sys/signal.h>
+volatile BOOL quit = 0;
+void mysignal(int signo)
+{
+ (void) signo;
+ quit = 1;
+}
+
+#include <err.h>
+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;
+}
--- /dev/null
+/* 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 <string.h>
+#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; i<SHA_DIGESTLEN; i++)
+ {
+ dest->digest[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; i<SHA_DATALEN; i++, block += 4)
+ {
+ data[i] = STRING2INT(block);
+ }
+
+ sha_transform(ctx, data);
+}
+
+void sha_update(struct sha_ctx *ctx, unsigned char *buffer, unsigned int len)
+{
+ if (ctx->index)
+ { /* 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;
+}
--- /dev/null
+#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);