From d2357e6961b3b3a80c51f03e0e01e7c80c5c0415 Mon Sep 17 00:00:00 2001 From: aiju Date: Wed, 6 Jun 2012 16:43:15 +0200 Subject: [PATCH] added ecdsa to factotum --- sys/include/libsec.h | 4 +- sys/src/cmd/auth/factotum/dat.h | 1 + sys/src/cmd/auth/factotum/ecdsa.c | 204 ++++++++++++++++++++++++++++++ sys/src/cmd/auth/factotum/fs.c | 1 + sys/src/cmd/auth/factotum/mkfile | 1 + sys/src/libsec/port/ecc.c | 55 ++++++++ 6 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 sys/src/cmd/auth/factotum/ecdsa.c diff --git a/sys/include/libsec.h b/sys/include/libsec.h index bc20ab847..a9c24b91c 100644 --- a/sys/include/libsec.h +++ b/sys/include/libsec.h @@ -435,5 +435,7 @@ int ecverify(ECdomain *, ECpoint *); int ecpubverify(ECdomain *, ECpub *); void ecdsasign(ECdomain *, ECpriv *, uchar *, int, mpint *, mpint *); int ecdsaverify(ECdomain *, ECpub *, uchar *, int, mpint *, mpint *); +void base58enc(uchar *, char *, int); +int base58dec(char *, uchar *, int); -DigestState* ripemd160(uchar *, ulong, uchar *, DigestState *); \ No newline at end of file +DigestState* ripemd160(uchar *, ulong, uchar *, DigestState *); diff --git a/sys/src/cmd/auth/factotum/dat.h b/sys/src/cmd/auth/factotum/dat.h index c8203cafa..b36f869e5 100644 --- a/sys/src/cmd/auth/factotum/dat.h +++ b/sys/src/cmd/auth/factotum/dat.h @@ -237,3 +237,4 @@ extern Proto rsa; /* rsa.c */ extern Proto wep; /* wep.c */ /* extern Proto srs; /* srs.c */ extern Proto httpdigest; /* httpdigest.c */ +extern Proto ecdsa; diff --git a/sys/src/cmd/auth/factotum/ecdsa.c b/sys/src/cmd/auth/factotum/ecdsa.c new file mode 100644 index 000000000..d21c97299 --- /dev/null +++ b/sys/src/cmd/auth/factotum/ecdsa.c @@ -0,0 +1,204 @@ +#include "dat.h" + +enum { + CHaveKey, + CHaveText, + Maxphase +}; + +static ECdomain dom; + +static char *phasenames[] = { + "CHaveKey", + "CHaveText", +}; + +struct State { + ECpriv p; + char *sign; +}; + +static int +decryptkey(Fsstate *fss, char *key, char *password) +{ + uchar keyenc[53], hash[32], ivec[AESbsize]; + AESstate s; + State *st; + char buf[100]; + + if(base58dec(key, keyenc, 53) < 0) + return failure(fss, "invalid base58"); + sha2_256((uchar *)password, strlen(password), hash, nil); + sha2_256(hash, 32, hash, nil); + genrandom(ivec, sizeof ivec); + setupAESstate(&s, hash, 32, keyenc+37); + aesCBCdecrypt(keyenc, 37, &s); + memset(buf, 0, sizeof buf); + base58enc(keyenc, buf, 37); + if(keyenc[0] != 0x80) + return failure(fss, "invalid key '%s'", buf); + sha2_256(keyenc, 33, hash, nil); + sha2_256(hash, 32, hash, nil); + if(memcmp(keyenc + 33, hash, 4) != 0) + return failure(fss, "checksum error"); + st = fss->ps; + st->p.d = betomp(keyenc + 1, 32, nil); + st->p.x = mpnew(0); + st->p.y = mpnew(0); + ecmul(&dom, dom.G, st->p.d, &st->p); + return RpcOk; +} + +static int +ecdsainit(Proto *, Fsstate *fss) +{ + int iscli; + Key *k; + Keyinfo ki; + int ret; + char *key, *password; + Attr *attr; + + if(dom.p == nil){ + dom.p = strtomp("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", nil, 16, nil); + dom.a = uitomp(0, nil); + dom.b = uitomp(7, nil); + dom.n = strtomp("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", nil, 16, nil); + dom.h = uitomp(1, nil); + dom.G = strtoec(&dom, "0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", nil, nil); + } + if((iscli = isclient(_strfindattr(fss->attr, "role"))) < 0) + return failure(fss, nil); + if(iscli==0) + return failure(fss, "ecdsa server unimplemented"); + mkkeyinfo(&ki, fss, nil); + ret = findkey(&k, &ki, "key? !password?"); + if(ret == RpcOk){ + key = _strfindattr(k->attr, "key"); + password = _strfindattr(k->privattr, "!password"); + + }else{ + if(!_strfindattr(fss->attr, "dom")) + return ret; + attr = _copyattr(fss->attr); + _delattr(attr, "key"); + mkkeyinfo(&ki, fss, attr); + ret = findkey(&k, &ki, "dom? !password?"); + if(ret != RpcOk) + return ret; + key = _strfindattr(fss->attr, "key"); + password = _strfindattr(k->privattr, "!password"); + } + if(key == nil || password == nil) + return RpcNeedkey; + fss->ps = malloc(sizeof(State)); + ret = decryptkey(fss, key, password); + if(ret != RpcOk) + return ret; + + setattrs(fss->attr, k->attr); + fss->phasename = phasenames; + fss->maxphase = Maxphase; + fss->phase = CHaveKey; + return RpcOk; +} + +static char * +derencode(mpint *r, mpint *s) +{ + uchar buf[100], rk[33], sk[33]; + char *str; + int rl, sl, i; + + mptobe(r, rk, 32, nil); + mptobe(s, sk, 32, nil); + rl = (mpsignif(r) + 7)/8; + sl = (mpsignif(s) + 7)/8; + if(rk[0] & 0x80){ + memmove(rk + 1, rk, 32); + rk[0] = 0; + rl++; + } + if(sk[0] & 0x80){ + memmove(sk + 1, sk, 32); + sk[0] = 0; + sl++; + } + buf[0] = 0x30; + buf[1] = 4 + rl + sl; + buf[2] = 0x02; + buf[3] = rl; + memmove(buf + 4, rk, rl); + buf[4 + rl] = 0x02; + buf[5 + rl] = sl; + memmove(buf + 6 + rl, sk, sl); + str = malloc(1024); + for(i = 0; i < 6 + rl + sl; i++) + sprint(str + 2 * i, "%.2x", buf[i]); + return str; +} + +static int +ecdsawrite(Fsstate *fss, void *va, uint n) +{ + State *st; + uchar hash[32]; + mpint *r, *s; + + st = fss->ps; + switch(fss->phase){ + default: + return phaseerror(fss, "write"); + case CHaveKey: + sha2_256(va, n, hash, nil); + sha2_256(hash, 32, hash, nil); + r = mpnew(0); + s = mpnew(0); + ecdsasign(&dom, &st->p, hash, 32, r, s); + st->sign = derencode(r, s); + mpfree(r); + mpfree(s); + fss->phase = CHaveText; + return RpcOk; + } +} + +static int +ecdsaread(Fsstate *fss, void *va, uint *n) +{ + switch(fss->phase){ + default: + return phaseerror(fss, "read"); + case CHaveText: + *n = snprint(va, *n, ((State *)fss->ps)->sign); + fss->phase = Established; + return RpcOk; + } +} + +static void +ecdsaclose(Fsstate *fss) +{ + State *st; + + st = fss->ps; + if(st->p.x != nil){ + mpfree(st->p.x); + mpfree(st->p.y); + mpfree(st->p.d); + } + if(st->sign != nil) + free(st->sign); + free(st); + fss->ps = nil; +} + +Proto ecdsa = { + .name = "ecdsa", + .init = ecdsainit, + .read = ecdsaread, + .write = ecdsawrite, + .close = ecdsaclose, + .addkey = replacekey, + .keyprompt= "key? !password?", +}; diff --git a/sys/src/cmd/auth/factotum/fs.c b/sys/src/cmd/auth/factotum/fs.c index 7d204aa09..78176f781 100644 --- a/sys/src/cmd/auth/factotum/fs.c +++ b/sys/src/cmd/auth/factotum/fs.c @@ -40,6 +40,7 @@ prototab[] = &rsa, &vnc, &wep, + &ecdsa, nil, }; diff --git a/sys/src/cmd/auth/factotum/mkfile b/sys/src/cmd/auth/factotum/mkfile index 1bdf31a62..fe1bb1526 100644 --- a/sys/src/cmd/auth/factotum/mkfile +++ b/sys/src/cmd/auth/factotum/mkfile @@ -13,6 +13,7 @@ PROTO=\ pass.$O\ rsa.$O\ wep.$O\ + ecdsa.$O\ FOFILES=\ $PROTO\ diff --git a/sys/src/libsec/port/ecc.c b/sys/src/libsec/port/ecc.c index eb5c593af..27e647d46 100644 --- a/sys/src/libsec/port/ecc.c +++ b/sys/src/libsec/port/ecc.c @@ -482,3 +482,58 @@ ecdsaverify(ECdomain *dom, ECpub *pub, uchar *dig, int len, mpint *r, mpint *s) mpfree(S.y); return ret; } + +static char *code = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + +void +base58enc(uchar *src, char *dst, int len) +{ + mpint *n, *r, *b; + char *sdst, t; + + sdst = dst; + n = betomp(src, len, nil); + b = uitomp(58, nil); + r = mpnew(0); + while(mpcmp(n, mpzero) != 0){ + mpdiv(n, b, n, r); + *dst++ = code[mptoui(r)]; + } + for(; *src == 0; src++) + *dst++ = code[0]; + dst--; + while(dst > sdst){ + t = *sdst; + *sdst++ = *dst; + *dst-- = t; + } +} + +int +base58dec(char *src, uchar *dst, int len) +{ + mpint *n, *b, *r; + char *t; + + n = mpnew(0); + r = mpnew(0); + b = uitomp(58, nil); + for(; *src; src++){ + t = strchr(code, *src); + if(t == nil){ + mpfree(n); + mpfree(r); + mpfree(b); + werrstr("invalid base58 char"); + return -1; + } + uitomp(t - code, r); + mpmul(n, b, n); + mpadd(n, r, n); + } + mptobe(n, dst, len, nil); + mpfree(n); + mpfree(r); + mpfree(b); + return 0; +}