pak.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. // PAK is an encrypted key exchange protocol designed by Philip MacKenzie et al.
  2. // It is patented and use outside Plan 9 requires you get a license.
  3. // (All other EKE protocols are patented as well, by Lucent or others.)
  4. #include <u.h>
  5. #include <libc.h>
  6. #include <mp.h>
  7. #include <libsec.h>
  8. #include "SConn.h"
  9. #include "secstore.h"
  10. extern int verbose;
  11. extern char VERSION[] = "secstore";
  12. static char *feedback[] = {"alpha","bravo","charlie","delta","echo","foxtrot","golf","hotel"};
  13. typedef struct PAKparams{
  14. mpint *q, *p, *r, *g;
  15. } PAKparams;
  16. static PAKparams *pak;
  17. // from seed EB7B6E35F7CD37B511D96C67D6688CC4DD440E1E
  18. static void
  19. initPAKparams(void)
  20. {
  21. if(pak)
  22. return;
  23. pak = (PAKparams*)emalloc(sizeof(*pak));
  24. pak->q = strtomp("E0F0EF284E10796C5A2A511E94748BA03C795C13", nil, 16, nil);
  25. pak->p = strtomp("C41CFBE4D4846F67A3DF7DE9921A49D3B42DC33728427AB159CEC8CBB"
  26. "DB12B5F0C244F1A734AEB9840804EA3C25036AD1B61AFF3ABBC247CD4B384224567A86"
  27. "3A6F020E7EE9795554BCD08ABAD7321AF27E1E92E3DB1C6E7E94FAAE590AE9C48F96D9"
  28. "3D178E809401ABE8A534A1EC44359733475A36A70C7B425125062B1142D",
  29. nil, 16, nil);
  30. pak->r = strtomp("DF310F4E54A5FEC5D86D3E14863921E834113E060F90052AD332B3241"
  31. "CEF2497EFA0303D6344F7C819691A0F9C4A773815AF8EAECFB7EC1D98F039F17A32A7E"
  32. "887D97251A927D093F44A55577F4D70444AEBD06B9B45695EC23962B175F266895C67D"
  33. "21C4656848614D888A4", nil, 16, nil);
  34. pak->g = strtomp("2F1C308DC46B9A44B52DF7DACCE1208CCEF72F69C743ADD4D23271734"
  35. "44ED6E65E074694246E07F9FD4AE26E0FDDD9F54F813C40CB9BCD4338EA6F242AB94CD"
  36. "410E676C290368A16B1A3594877437E516C53A6EEE5493A038A017E955E218E7819734"
  37. "E3E2A6E0BAE08B14258F8C03CC1B30E0DDADFCF7CEDF0727684D3D255F1",
  38. nil, 16, nil);
  39. }
  40. // H = (sha(ver,C,sha(passphrase)))^r mod p,
  41. // a hash function expensive to attack by brute force.
  42. static void
  43. longhash(char *ver, char *C, uchar *passwd, mpint *H)
  44. {
  45. uchar *Cp;
  46. int i, n, nver, nC;
  47. uchar buf[140], key[1];
  48. nver = strlen(ver);
  49. nC = strlen(C);
  50. n = nver + nC + SHA1dlen;
  51. Cp = (uchar*)emalloc(n);
  52. memmove(Cp, ver, nver);
  53. memmove(Cp+nver, C, nC);
  54. memmove(Cp+nver+nC, passwd, SHA1dlen);
  55. for(i = 0; i < 7; i++){
  56. key[0] = 'A'+i;
  57. hmac_sha1(Cp, n, key, sizeof key, buf+i*SHA1dlen, nil);
  58. }
  59. memset(Cp, 0, n);
  60. free(Cp);
  61. betomp(buf, sizeof buf, H);
  62. mpmod(H, pak->p, H);
  63. mpexp(H, pak->r, pak->p, H);
  64. }
  65. // Hi = H^-1 mod p
  66. char *
  67. PAK_Hi(char *C, char *passphrase, mpint *H, mpint *Hi)
  68. {
  69. uchar passhash[SHA1dlen];
  70. sha1((uchar *)passphrase, strlen(passphrase), passhash, nil);
  71. initPAKparams();
  72. longhash(VERSION, C, passhash, H);
  73. mpinvert(H, pak->p, Hi);
  74. return mptoa(Hi, 64, nil, 0);
  75. }
  76. // another, faster, hash function for each party to
  77. // confirm that the other has the right secrets.
  78. static void
  79. shorthash(char *mess, char *C, char *S, char *m, char *mu, char *sigma, char *Hi, uchar *digest)
  80. {
  81. SHA1state *state;
  82. state = sha1((uchar*)mess, strlen(mess), 0, 0);
  83. state = sha1((uchar*)C, strlen(C), 0, state);
  84. state = sha1((uchar*)S, strlen(S), 0, state);
  85. state = sha1((uchar*)m, strlen(m), 0, state);
  86. state = sha1((uchar*)mu, strlen(mu), 0, state);
  87. state = sha1((uchar*)sigma, strlen(sigma), 0, state);
  88. state = sha1((uchar*)Hi, strlen(Hi), 0, state);
  89. state = sha1((uchar*)mess, strlen(mess), 0, state);
  90. state = sha1((uchar*)C, strlen(C), 0, state);
  91. state = sha1((uchar*)S, strlen(S), 0, state);
  92. state = sha1((uchar*)m, strlen(m), 0, state);
  93. state = sha1((uchar*)mu, strlen(mu), 0, state);
  94. state = sha1((uchar*)sigma, strlen(sigma), 0, state);
  95. sha1((uchar*)Hi, strlen(Hi), digest, state);
  96. }
  97. // On input, conn provides an open channel to the server;
  98. // C is the name this client calls itself;
  99. // pass is the user's passphrase
  100. // On output, session secret has been set in conn
  101. // (unless return code is negative, which means failure).
  102. // If pS is not nil, it is set to the (alloc'd) name the server calls itself.
  103. int
  104. PAKclient(SConn *conn, char *C, char *pass, char **pS)
  105. {
  106. char *mess, *mess2, *eol, *S, *hexmu, *ks, *hexm, *hexsigma = nil, *hexHi;
  107. char kc[2*SHA1dlen+1];
  108. uchar digest[SHA1dlen];
  109. int rc = -1, n;
  110. mpint *x, *m = mpnew(0), *mu = mpnew(0), *sigma = mpnew(0);
  111. mpint *H = mpnew(0), *Hi = mpnew(0);
  112. hexHi = PAK_Hi(C, pass, H, Hi);
  113. if(verbose)
  114. fprint(2,"%s\n", feedback[H->p[0]&0x7]); // provide a clue to catch typos
  115. // random 1<=x<=q-1; send C, m=g**x H
  116. x = mprand(240, genrandom, nil);
  117. mpmod(x, pak->q, x);
  118. if(mpcmp(x, mpzero) == 0)
  119. mpassign(mpone, x);
  120. mpexp(pak->g, x, pak->p, m);
  121. mpmul(m, H, m);
  122. mpmod(m, pak->p, m);
  123. hexm = mptoa(m, 64, nil, 0);
  124. mess = (char*)emalloc(2*Maxmsg+2);
  125. mess2 = mess+Maxmsg+1;
  126. snprint(mess, Maxmsg, "%s\tPAK\nC=%s\nm=%s\n", VERSION, C, hexm);
  127. conn->write(conn, (uchar*)mess, strlen(mess));
  128. // recv g**y, S, check hash1(g**xy)
  129. if(readstr(conn, mess) < 0){
  130. fprint(2, "error: %s\n", mess);
  131. writerr(conn, "couldn't read g**y");
  132. goto done;
  133. }
  134. eol = strchr(mess, '\n');
  135. if(strncmp("mu=", mess, 3) != 0 || !eol || strncmp("\nk=", eol, 3) != 0){
  136. writerr(conn, "verifier syntax error");
  137. goto done;
  138. }
  139. hexmu = mess+3;
  140. *eol = 0;
  141. ks = eol+3;
  142. eol = strchr(ks, '\n');
  143. if(!eol || strncmp("\nS=", eol, 3) != 0){
  144. writerr(conn, "verifier syntax error for secstore 1.0");
  145. goto done;
  146. }
  147. *eol = 0;
  148. S = eol+3;
  149. eol = strchr(S, '\n');
  150. if(!eol){
  151. writerr(conn, "verifier syntax error for secstore 1.0");
  152. goto done;
  153. }
  154. *eol = 0;
  155. if(pS)
  156. *pS = estrdup(S);
  157. strtomp(hexmu, nil, 64, mu);
  158. mpexp(mu, x, pak->p, sigma);
  159. hexsigma = mptoa(sigma, 64, nil, 0);
  160. shorthash("server", C, S, hexm, hexmu, hexsigma, hexHi, digest);
  161. enc64(kc, sizeof kc, digest, SHA1dlen);
  162. if(strcmp(ks, kc) != 0){
  163. writerr(conn, "verifier didn't match");
  164. goto done;
  165. }
  166. // send hash2(g**xy)
  167. shorthash("client", C, S, hexm, hexmu, hexsigma, hexHi, digest);
  168. enc64(kc, sizeof kc, digest, SHA1dlen);
  169. snprint(mess2, Maxmsg, "k'=%s\n", kc);
  170. conn->write(conn, (uchar*)mess2, strlen(mess2));
  171. // set session key
  172. shorthash("session", C, S, hexm, hexmu, hexsigma, hexHi, digest);
  173. memset(hexsigma, 0, strlen(hexsigma));
  174. n = conn->secret(conn, digest, 0);
  175. memset(digest, 0, SHA1dlen);
  176. if(n < 0){
  177. writerr(conn, "can't set secret");
  178. goto done;
  179. }
  180. rc = 0;
  181. done:
  182. mpfree(x);
  183. mpfree(sigma);
  184. mpfree(mu);
  185. mpfree(m);
  186. mpfree(Hi);
  187. mpfree(H);
  188. free(hexsigma);
  189. free(hexHi);
  190. free(hexm);
  191. free(mess);
  192. return rc;
  193. }
  194. // On input,
  195. // mess contains first message;
  196. // name is name this server should call itself.
  197. // On output, session secret has been set in conn;
  198. // if pw!=nil, then *pw points to PW struct for authenticated user.
  199. // returns -1 if error
  200. int
  201. PAKserver(SConn *conn, char *S, char *mess, PW **pwp)
  202. {
  203. int rc = -1, n;
  204. char mess2[Maxmsg+1], *eol;
  205. char *C, ks[41], *kc, *hexm, *hexmu = nil, *hexsigma = nil, *hexHi = nil;
  206. uchar digest[SHA1dlen];
  207. mpint *H = mpnew(0), *Hi = mpnew(0);
  208. mpint *y = nil, *m = mpnew(0), *mu = mpnew(0), *sigma = mpnew(0);
  209. PW *pw = nil;
  210. // secstore version and algorithm
  211. snprint(mess2,Maxmsg,"%s\tPAK\n", VERSION);
  212. n = strlen(mess2);
  213. if(strncmp(mess,mess2,n) != 0){
  214. writerr(conn, "protocol should start with ver alg");
  215. return -1;
  216. }
  217. mess += n;
  218. initPAKparams();
  219. // parse first message into C, m
  220. eol = strchr(mess, '\n');
  221. if(strncmp("C=", mess, 2) != 0 || !eol){
  222. fprint(2,"mess[1]=%s\n", mess);
  223. writerr(conn, "PAK version mismatch");
  224. goto done;
  225. }
  226. C = mess+2;
  227. *eol = 0;
  228. hexm = eol+3;
  229. eol = strchr(hexm, '\n');
  230. if(strncmp("m=", hexm-2, 2) != 0 || !eol){
  231. writerr(conn, "PAK version mismatch");
  232. goto done;
  233. }
  234. *eol = 0;
  235. strtomp(hexm, nil, 64, m);
  236. mpmod(m, pak->p, m);
  237. // lookup client
  238. if((pw = getPW(C,0)) == nil) {
  239. snprint(mess2, sizeof mess2, "%r");
  240. writerr(conn, mess2);
  241. goto done;
  242. }
  243. if(mpcmp(m, mpzero) == 0) {
  244. writerr(conn, "account exists");
  245. freePW(pw);
  246. pw = nil;
  247. goto done;
  248. }
  249. hexHi = mptoa(pw->Hi, 64, nil, 0);
  250. // random y, mu=g**y, sigma=g**xy
  251. y = mprand(240, genrandom, nil);
  252. mpmod(y, pak->q, y);
  253. if(mpcmp(y, mpzero) == 0){
  254. mpassign(mpone, y);
  255. }
  256. mpexp(pak->g, y, pak->p, mu);
  257. mpmul(m, pw->Hi, m);
  258. mpmod(m, pak->p, m);
  259. mpexp(m, y, pak->p, sigma);
  260. // send g**y, hash1(g**xy)
  261. hexmu = mptoa(mu, 64, nil, 0);
  262. hexsigma = mptoa(sigma, 64, nil, 0);
  263. shorthash("server", C, S, hexm, hexmu, hexsigma, hexHi, digest);
  264. enc64(ks, sizeof ks, digest, SHA1dlen);
  265. snprint(mess2, sizeof mess2, "mu=%s\nk=%s\nS=%s\n", hexmu, ks, S);
  266. conn->write(conn, (uchar*)mess2, strlen(mess2));
  267. // recv hash2(g**xy)
  268. if(readstr(conn, mess2) < 0){
  269. writerr(conn, "couldn't read verifier");
  270. goto done;
  271. }
  272. eol = strchr(mess2, '\n');
  273. if(strncmp("k'=", mess2, 3) != 0 || !eol){
  274. writerr(conn, "verifier syntax error");
  275. goto done;
  276. }
  277. kc = mess2+3;
  278. *eol = 0;
  279. shorthash("client", C, S, hexm, hexmu, hexsigma, hexHi, digest);
  280. enc64(ks, sizeof ks, digest, SHA1dlen);
  281. if(strcmp(ks, kc) != 0) {
  282. rc = -2;
  283. goto done;
  284. }
  285. // set session key
  286. shorthash("session", C, S, hexm, hexmu, hexsigma, hexHi, digest);
  287. n = conn->secret(conn, digest, 1);
  288. if(n < 0){
  289. writerr(conn, "can't set secret");
  290. goto done;
  291. }
  292. rc = 0;
  293. done:
  294. if(rc<0 && pw){
  295. pw->failed++;
  296. putPW(pw);
  297. }
  298. if(rc==0 && pw && pw->failed>0){
  299. pw->failed = 0;
  300. putPW(pw);
  301. }
  302. if(pwp)
  303. *pwp = pw;
  304. else
  305. freePW(pw);
  306. free(hexsigma);
  307. free(hexHi);
  308. free(hexmu);
  309. mpfree(y);
  310. mpfree(sigma);
  311. mpfree(mu);
  312. mpfree(m);
  313. mpfree(Hi);
  314. mpfree(H);
  315. return rc;
  316. }