// PAK is an encrypted key exchange protocol designed by Philip MacKenzie et al.
// It is patented and use outside Plan 9 requires you get a license.
// (All other EKE protocols are patented as well, by Lucent or others.)
#include <u.h>
#include <libc.h>
#include <mp.h>
#include <libsec.h>
#include "SConn.h"
#include "secstore.h"
// H = (sha(ver,C,sha(passphrase)))^r mod p,
// a hash function expensive to attack by brute force.
static void
longhash(char *ver, char *C, uchar *passwd, mpint *H)
{
uchar *Cp;
int i, n, nver, nC;
uchar buf[140], key[1];
// another, faster, hash function for each party to
// confirm that the other has the right secrets.
static void
shorthash(char *mess, char *C, char *S, char *m, char *mu, char *sigma, char *Hi, uchar *digest)
{
SHA1state *state;
state = sha1((uchar*)mess, strlen(mess), 0, 0);
state = sha1((uchar*)C, strlen(C), 0, state);
state = sha1((uchar*)S, strlen(S), 0, state);
state = sha1((uchar*)m, strlen(m), 0, state);
state = sha1((uchar*)mu, strlen(mu), 0, state);
state = sha1((uchar*)sigma, strlen(sigma), 0, state);
state = sha1((uchar*)Hi, strlen(Hi), 0, state);
state = sha1((uchar*)mess, strlen(mess), 0, state);
state = sha1((uchar*)C, strlen(C), 0, state);
state = sha1((uchar*)S, strlen(S), 0, state);
state = sha1((uchar*)m, strlen(m), 0, state);
state = sha1((uchar*)mu, strlen(mu), 0, state);
state = sha1((uchar*)sigma, strlen(sigma), 0, state);
sha1((uchar*)Hi, strlen(Hi), digest, state);
}
// On input, conn provides an open channel to the server;
// C is the name this client calls itself;
// pass is the user's passphrase
// On output, session secret has been set in conn
// (unless return code is negative, which means failure).
// If pS is not nil, it is set to the (alloc'd) name the server calls itself.
int
PAKclient(SConn *conn, char *C, char *pass, char **pS)
{
char *mess, *mess2, *eol, *S, *hexmu, *ks, *hexm, *hexsigma = nil, *hexHi;
char kc[2*SHA1dlen+1];
uchar digest[SHA1dlen];
int rc = -1, n;
mpint *x, *m = mpnew(0), *mu = mpnew(0), *sigma = mpnew(0);
mpint *H = mpnew(0), *Hi = mpnew(0);
hexHi = PAK_Hi(C, pass, H, Hi);
if(verbose)
fprint(2, "%s\n", feedback[H->p[0]&0x7]); // provide a clue to catch typos
// On input,
// mess contains first message;
// name is name this server should call itself.
// On output, session secret has been set in conn;
// if pw!=nil, then *pw points to PW struct for authenticated user.
// returns -1 if error
int
PAKserver(SConn *conn, char *S, char *mess, PW **pwp)
{
int rc = -1, n;
char mess2[Maxmsg+1], *eol;
char *C, ks[41], *kc, *hexm, *hexmu = nil, *hexsigma = nil, *hexHi = nil;
uchar digest[SHA1dlen];
mpint *H = mpnew(0), *Hi = mpnew(0);
mpint *y = nil, *m = mpnew(0), *mu = mpnew(0), *sigma = mpnew(0);
PW *pw = nil;
// secstore version and algorithm
snprint(mess2,Maxmsg,"%s\tPAK\n", VERSION);
n = strlen(mess2);
if(strncmp(mess,mess2,n) != 0){
writerr(conn, "protocol should start with ver alg");
return -1;
}
mess += n;
initPAKparams();