URI:
       trsa.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       trsa.c (4863B)
       ---
            1 #include "std.h"
            2 #include "dat.h"
            3 
            4 /*
            5  * RSA authentication.
            6  *
            7  * Encrypt/Decrypt:
            8  *        start n=xxx ek=xxx
            9  *        write msg
           10  *        read encrypt/decrypt(msg)
           11  *
           12  * Sign (PKCS #1 using hash=sha1 or hash=md5)
           13  *        start n=xxx ek=xxx
           14  *        write hash(msg)
           15  *        read signature(hash(msg))
           16  *
           17  * Verify:
           18  *        start n=xxx ek=xxx
           19  *        write hash(msg)
           20  *        write signature(hash(msg))
           21  *        read ok or fail
           22  *
           23  * all numbers are hexadecimal biginits parsable with strtomp.
           24  * must be lower case for attribute matching in start.
           25  */
           26 
           27 static int
           28 xrsadecrypt(Conv *c)
           29 {
           30         char *txt, buf[4096], *role;
           31         int n, ret;
           32         mpint *m, *mm;
           33         Key *k;
           34         RSApriv *key;
           35 
           36         ret = -1;
           37         txt = nil;
           38         m = nil;
           39         mm = nil;
           40 
           41         /* fetch key */
           42         c->state = "keylookup";
           43         k = keylookup("%A", c->attr);
           44         if(k == nil)
           45                 goto out;
           46         key = k->priv;
           47 
           48         /* make sure have private half if needed */
           49         role = strfindattr(c->attr, "role");
           50         if(strcmp(role, "decrypt") == 0 && !key->c2){
           51                 werrstr("missing private half of key -- cannot decrypt");
           52                 goto out;
           53         }
           54 
           55         /* read text */
           56         c->state = "read";
           57         if((n=convreadm(c, &txt)) < 0)
           58                 goto out;
           59         if(n < 32){
           60                 convprint(c, "data too short");
           61                 goto out;
           62         }
           63 
           64         /* encrypt/decrypt */
           65         m = betomp((uchar*)txt, n, nil);
           66         if(m == nil)
           67                 goto out;
           68         if(strcmp(role, "decrypt") == 0)
           69                 mm = rsadecrypt(key, m, nil);
           70         else
           71                 mm = rsaencrypt(&key->pub, m, nil);
           72         if(mm == nil)
           73                 goto out;
           74         n = mptobe(mm, (uchar*)buf, sizeof buf, nil);
           75 
           76         /* send response */
           77         c->state = "write";
           78         convwrite(c, buf, n);
           79         ret = 0;
           80 
           81 out:
           82         mpfree(m);
           83         mpfree(mm);
           84         keyclose(k);
           85         free(txt);
           86         return ret;
           87 }
           88 
           89 static int
           90 xrsasign(Conv *c)
           91 {
           92         char *hash, *role;
           93         int dlen, n, ret;
           94         DigestAlg *hashfn;
           95         Key *k;
           96         RSApriv *key;
           97         uchar sig[1024], digest[64];
           98         char *sig2;
           99 
          100         ret = -1;
          101 
          102         /* fetch key */
          103         c->state = "keylookup";
          104         k = keylookup("%A", c->attr);
          105         if(k == nil)
          106                 goto out;
          107 
          108         /* make sure have private half if needed */
          109         key = k->priv;
          110         role = strfindattr(c->attr, "role");
          111         if(strcmp(role, "sign") == 0 && !key->c2){
          112                 werrstr("missing private half of key -- cannot sign");
          113                 goto out;
          114         }
          115 
          116         /* get hash type from key */
          117         hash = strfindattr(k->attr, "hash");
          118         if(hash == nil)
          119                 hash = "sha1";
          120         if(strcmp(hash, "sha1") == 0){
          121                 hashfn = sha1;
          122                 dlen = SHA1dlen;
          123         }else if(strcmp(hash, "md5") == 0){
          124                 hashfn = md5;
          125                 dlen = MD5dlen;
          126         }else{
          127                 werrstr("unknown hash function %s", hash);
          128                 goto out;
          129         }
          130 
          131         /* read hash */
          132         c->state = "read hash";
          133         if((n=convread(c, digest, dlen)) < 0)
          134                 goto out;
          135 
          136         if(strcmp(role, "sign") == 0){
          137                 /* sign */
          138                 if((n=rsasign(key, hashfn, digest, dlen, sig, sizeof sig)) < 0)
          139                         goto out;
          140 
          141                 /* write */
          142                 convwrite(c, sig, n);
          143         }else{
          144                 /* read signature */
          145                 if((n = convreadm(c, &sig2)) < 0)
          146                         goto out;
          147 
          148                 /* verify */
          149                 if(rsaverify(&key->pub, hashfn, digest, dlen, (uchar*)sig2, n) == 0)
          150                         convprint(c, "ok");
          151                 else
          152                         convprint(c, "signature does not verify");
          153                 free(sig2);
          154         }
          155         ret = 0;
          156 
          157 out:
          158         keyclose(k);
          159         return ret;
          160 }
          161 
          162 /*
          163  * convert to canonical form (lower case)
          164  * for use in attribute matches.
          165  */
          166 static void
          167 strlwr(char *a)
          168 {
          169         for(; *a; a++){
          170                 if('A' <= *a && *a <= 'Z')
          171                         *a += 'a' - 'A';
          172         }
          173 }
          174 
          175 static RSApriv*
          176 readrsapriv(Key *k)
          177 {
          178         char *a;
          179         RSApriv *priv;
          180 
          181         priv = rsaprivalloc();
          182 
          183         if((a=strfindattr(k->attr, "ek"))==nil
          184         || (priv->pub.ek=strtomp(a, nil, 16, nil))==nil)
          185                 goto Error;
          186         strlwr(a);
          187         if((a=strfindattr(k->attr, "n"))==nil
          188         || (priv->pub.n=strtomp(a, nil, 16, nil))==nil)
          189                 goto Error;
          190         strlwr(a);
          191         if(k->privattr == nil)        /* only public half */
          192                 return priv;
          193 
          194         if((a=strfindattr(k->privattr, "!p"))==nil
          195         || (priv->p=strtomp(a, nil, 16, nil))==nil)
          196                 goto Error;
          197         strlwr(a);
          198         if((a=strfindattr(k->privattr, "!q"))==nil
          199         || (priv->q=strtomp(a, nil, 16, nil))==nil)
          200                 goto Error;
          201         strlwr(a);
          202         if(!probably_prime(priv->p, 20) || !probably_prime(priv->q, 20)) {
          203                 werrstr("rsa: p or q not prime");
          204                 goto Error;
          205         }
          206         if((a=strfindattr(k->privattr, "!kp"))==nil
          207         || (priv->kp=strtomp(a, nil, 16, nil))==nil)
          208                 goto Error;
          209         strlwr(a);
          210         if((a=strfindattr(k->privattr, "!kq"))==nil
          211         || (priv->kq=strtomp(a, nil, 16, nil))==nil)
          212                 goto Error;
          213         strlwr(a);
          214         if((a=strfindattr(k->privattr, "!c2"))==nil
          215         || (priv->c2=strtomp(a, nil, 16, nil))==nil)
          216                 goto Error;
          217         strlwr(a);
          218         if((a=strfindattr(k->privattr, "!dk"))==nil
          219         || (priv->dk=strtomp(a, nil, 16, nil))==nil)
          220                 goto Error;
          221         strlwr(a);
          222         return priv;
          223 
          224 Error:
          225         rsaprivfree(priv);
          226         return nil;
          227 }
          228 
          229 static int
          230 rsacheck(Key *k)
          231 {
          232         static int first = 1;
          233 
          234         if(first){
          235                 fmtinstall('B', mpfmt);
          236                 first = 0;
          237         }
          238 
          239         if((k->priv = readrsapriv(k)) == nil){
          240                 werrstr("malformed key data");
          241                 return -1;
          242         }
          243         return 0;
          244 }
          245 
          246 static void
          247 rsaclose(Key *k)
          248 {
          249         rsaprivfree(k->priv);
          250         k->priv = nil;
          251 }
          252 
          253 static Role
          254 rsaroles[] =
          255 {
          256         "sign",        xrsasign,
          257         "verify",        xrsasign,        /* public operation */
          258         "decrypt",        xrsadecrypt,
          259         "encrypt",        xrsadecrypt,        /* public operation */
          260         0
          261 };
          262 
          263 Proto rsa = {
          264         "rsa",
          265         rsaroles,
          266         nil,
          267         rsacheck,
          268         rsaclose
          269 };