#include "std.h" #include "dat.h" /* * RSA authentication. * * Encrypt/Decrypt: * start n=xxx ek=xxx * write msg * read encrypt/decrypt(msg) * * Sign (PKCS #1 using hash=sha1 or hash=md5) * start n=xxx ek=xxx * write hash(msg) * read signature(hash(msg)) * * Verify: * start n=xxx ek=xxx * write hash(msg) * write signature(hash(msg)) * read ok or fail * * all numbers are hexadecimal biginits parsable with strtomp. * must be lower case for attribute matching in start. */ static int xrsadecrypt(Conv *c) { char *txt, buf[4096], *role; int n, ret; mpint *m, *mm; Key *k; RSApriv *key; ret = -1; txt = nil; m = nil; mm = nil; /* fetch key */ c->state = "keylookup"; k = keylookup("%A", c->attr); if(k == nil) goto out; key = k->priv; /* make sure have private half if needed */ role = strfindattr(c->attr, "role"); if(strcmp(role, "decrypt") == 0 && !key->c2){ werrstr("missing private half of key -- cannot decrypt"); goto out; } /* read text */ c->state = "read"; if((n=convreadm(c, &txt)) < 0) goto out; if(n < 32){ convprint(c, "data too short"); goto out; } /* encrypt/decrypt */ m = betomp((uchar*)txt, n, nil); if(m == nil) goto out; if(strcmp(role, "decrypt") == 0) mm = rsadecrypt(key, m, nil); else mm = rsaencrypt(&key->pub, m, nil); if(mm == nil) goto out; n = mptobe(mm, (uchar*)buf, sizeof buf, nil); /* send response */ c->state = "write"; convwrite(c, buf, n); ret = 0; out: mpfree(m); mpfree(mm); keyclose(k); free(txt); return ret; } static int xrsasign(Conv *c) { char *hash, *role; int dlen, n, ret; DigestAlg *hashfn; Key *k; RSApriv *key; uchar sig[1024], digest[64]; char *sig2; ret = -1; /* fetch key */ c->state = "keylookup"; k = keylookup("%A", c->attr); if(k == nil) goto out; /* make sure have private half if needed */ key = k->priv; role = strfindattr(c->attr, "role"); if(strcmp(role, "sign") == 0 && !key->c2){ werrstr("missing private half of key -- cannot sign"); goto out; } /* get hash type from key */ hash = strfindattr(k->attr, "hash"); if(hash == nil) hash = "sha1"; if(strcmp(hash, "sha1") == 0){ hashfn = sha1; dlen = SHA1dlen; }else if(strcmp(hash, "md5") == 0){ hashfn = md5; dlen = MD5dlen; }else{ werrstr("unknown hash function %s", hash); goto out; } /* read hash */ c->state = "read hash"; if((n=convread(c, digest, dlen)) < 0) goto out; if(strcmp(role, "sign") == 0){ /* sign */ if((n=rsasign(key, hashfn, digest, dlen, sig, sizeof sig)) < 0) goto out; /* write */ convwrite(c, sig, n); }else{ /* read signature */ if((n = convreadm(c, &sig2)) < 0) goto out; /* verify */ if(rsaverify(&key->pub, hashfn, digest, dlen, (uchar*)sig2, n) == 0) convprint(c, "ok"); else convprint(c, "signature does not verify"); free(sig2); } ret = 0; out: keyclose(k); return ret; } /* * convert to canonical form (lower case) * for use in attribute matches. */ static void strlwr(char *a) { for(; *a; a++){ if('A' <= *a && *a <= 'Z') *a += 'a' - 'A'; } } static RSApriv* readrsapriv(Key *k) { char *a; RSApriv *priv; priv = rsaprivalloc(); if((a=strfindattr(k->attr, "ek"))==nil || (priv->pub.ek=strtomp(a, nil, 16, nil))==nil) goto Error; strlwr(a); if((a=strfindattr(k->attr, "n"))==nil || (priv->pub.n=strtomp(a, nil, 16, nil))==nil) goto Error; strlwr(a); if(k->privattr == nil) /* only public half */ return priv; if((a=strfindattr(k->privattr, "!p"))==nil || (priv->p=strtomp(a, nil, 16, nil))==nil) goto Error; strlwr(a); if((a=strfindattr(k->privattr, "!q"))==nil || (priv->q=strtomp(a, nil, 16, nil))==nil) goto Error; strlwr(a); if(!probably_prime(priv->p, 20) || !probably_prime(priv->q, 20)) { werrstr("rsa: p or q not prime"); goto Error; } if((a=strfindattr(k->privattr, "!kp"))==nil || (priv->kp=strtomp(a, nil, 16, nil))==nil) goto Error; strlwr(a); if((a=strfindattr(k->privattr, "!kq"))==nil || (priv->kq=strtomp(a, nil, 16, nil))==nil) goto Error; strlwr(a); if((a=strfindattr(k->privattr, "!c2"))==nil || (priv->c2=strtomp(a, nil, 16, nil))==nil) goto Error; strlwr(a); if((a=strfindattr(k->privattr, "!dk"))==nil || (priv->dk=strtomp(a, nil, 16, nil))==nil) goto Error; strlwr(a); return priv; Error: rsaprivfree(priv); return nil; } static int rsacheck(Key *k) { static int first = 1; if(first){ fmtinstall('B', mpfmt); first = 0; } if((k->priv = readrsapriv(k)) == nil){ werrstr("malformed key data"); return -1; } return 0; } static void rsaclose(Key *k) { rsaprivfree(k->priv); k->priv = nil; } static Role rsaroles[] = { "sign", xrsasign, "verify", xrsasign, /* public operation */ "decrypt", xrsadecrypt, "encrypt", xrsadecrypt, /* public operation */ 0 }; Proto rsa = { "rsa", rsaroles, nil, rsacheck, rsaclose };