added ecdsa to factotum

This commit is contained in:
aiju 2012-06-06 16:43:15 +02:00
parent 46efa642ad
commit d2357e6961
6 changed files with 265 additions and 1 deletions

View file

@ -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 *);

View file

@ -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;

View file

@ -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?",
};

View file

@ -40,6 +40,7 @@ prototab[] =
&rsa,
&vnc,
&wep,
&ecdsa,
nil,
};

View file

@ -13,6 +13,7 @@ PROTO=\
pass.$O\
rsa.$O\
wep.$O\
ecdsa.$O\
FOFILES=\
$PROTO\

View file

@ -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;
}