pak.c 9.6 KB

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