dots

Personal dotfiles
git clone git://git.gormless.xyz/dots.git
Log | Files | Refs

rsa.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 };