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