16c0968e3SDavid du Colombier /*
26c0968e3SDavid du Colombier * Encapsulating Security Payload for IPsec for IPv4, rfc1827.
3da0b1336SDavid du Colombier * extended to IPv6.
4410ea80bSDavid du Colombier * rfc2104 defines hmac computation.
5c168f9f3SDavid du Colombier * currently only implements tunnel mode.
6410ea80bSDavid du Colombier * TODO: verify aes algorithms;
7410ea80bSDavid du Colombier * transport mode (host-to-host)
86c0968e3SDavid du Colombier */
97dd7cddfSDavid du Colombier #include "u.h"
107dd7cddfSDavid du Colombier #include "../port/lib.h"
117dd7cddfSDavid du Colombier #include "mem.h"
127dd7cddfSDavid du Colombier #include "dat.h"
137dd7cddfSDavid du Colombier #include "fns.h"
147dd7cddfSDavid du Colombier #include "../port/error.h"
157dd7cddfSDavid du Colombier
167dd7cddfSDavid du Colombier #include "ip.h"
17c168f9f3SDavid du Colombier #include "ipv6.h"
187dd7cddfSDavid du Colombier #include "libsec.h"
197dd7cddfSDavid du Colombier
20410ea80bSDavid du Colombier #define BITS2BYTES(bi) (((bi) + BI2BY - 1) / BI2BY)
21410ea80bSDavid du Colombier #define BYTES2BITS(by) ((by) * BI2BY)
22410ea80bSDavid du Colombier
23410ea80bSDavid du Colombier typedef struct Algorithm Algorithm;
24c168f9f3SDavid du Colombier typedef struct Esp4hdr Esp4hdr;
25c168f9f3SDavid du Colombier typedef struct Esp6hdr Esp6hdr;
26410ea80bSDavid du Colombier typedef struct Espcb Espcb;
27410ea80bSDavid du Colombier typedef struct Esphdr Esphdr;
28410ea80bSDavid du Colombier typedef struct Esppriv Esppriv;
297dd7cddfSDavid du Colombier typedef struct Esptail Esptail;
307dd7cddfSDavid du Colombier typedef struct Userhdr Userhdr;
317dd7cddfSDavid du Colombier
32410ea80bSDavid du Colombier enum {
33410ea80bSDavid du Colombier Encrypt,
34410ea80bSDavid du Colombier Decrypt,
35410ea80bSDavid du Colombier
360774058cSDavid du Colombier IP_ESPPROTO = 50, /* IP v4 and v6 protocol number */
37c168f9f3SDavid du Colombier Esp4hdrlen = IP4HDR + 8,
38c168f9f3SDavid du Colombier Esp6hdrlen = IP6HDR + 8,
390774058cSDavid du Colombier
40c168f9f3SDavid du Colombier Esptaillen = 2, /* does not include pad or auth data */
41c168f9f3SDavid du Colombier Userhdrlen = 4, /* user-visible header size - if enabled */
42410ea80bSDavid du Colombier
43410ea80bSDavid du Colombier Desblk = BITS2BYTES(64),
44410ea80bSDavid du Colombier Des3keysz = BITS2BYTES(192),
45410ea80bSDavid du Colombier
46410ea80bSDavid du Colombier Aesblk = BITS2BYTES(128),
47410ea80bSDavid du Colombier Aeskeysz = BITS2BYTES(128),
487dd7cddfSDavid du Colombier };
497dd7cddfSDavid du Colombier
507dd7cddfSDavid du Colombier struct Esphdr
517dd7cddfSDavid du Colombier {
52c168f9f3SDavid du Colombier uchar espspi[4]; /* Security parameter index */
53c168f9f3SDavid du Colombier uchar espseq[4]; /* Sequence number */
54410ea80bSDavid du Colombier uchar payload[];
55c168f9f3SDavid du Colombier };
56c168f9f3SDavid du Colombier
57c168f9f3SDavid du Colombier /*
58410ea80bSDavid du Colombier * tunnel-mode (network-to-network, etc.) layout is:
59410ea80bSDavid du Colombier * new IP hdrs | ESP hdr |
60410ea80bSDavid du Colombier * enc { orig IP hdrs | TCP/UDP hdr | user data | ESP trailer } | ESP ICV
61410ea80bSDavid du Colombier *
62410ea80bSDavid du Colombier * transport-mode (host-to-host) layout would be:
63410ea80bSDavid du Colombier * orig IP hdrs | ESP hdr |
64410ea80bSDavid du Colombier * enc { TCP/UDP hdr | user data | ESP trailer } | ESP ICV
65c168f9f3SDavid du Colombier */
66c168f9f3SDavid du Colombier struct Esp4hdr
67c168f9f3SDavid du Colombier {
686c0968e3SDavid du Colombier /* ipv4 header */
697dd7cddfSDavid du Colombier uchar vihl; /* Version and header length */
707dd7cddfSDavid du Colombier uchar tos; /* Type of service */
717dd7cddfSDavid du Colombier uchar length[2]; /* packet length */
727dd7cddfSDavid du Colombier uchar id[2]; /* Identification */
737dd7cddfSDavid du Colombier uchar frag[2]; /* Fragment information */
747dd7cddfSDavid du Colombier uchar Unused;
757dd7cddfSDavid du Colombier uchar espproto; /* Protocol */
767dd7cddfSDavid du Colombier uchar espplen[2]; /* Header plus data length */
777dd7cddfSDavid du Colombier uchar espsrc[4]; /* Ip source */
787dd7cddfSDavid du Colombier uchar espdst[4]; /* Ip destination */
797dd7cddfSDavid du Colombier
80c168f9f3SDavid du Colombier Esphdr;
81c168f9f3SDavid du Colombier };
82c168f9f3SDavid du Colombier
83c168f9f3SDavid du Colombier /* tunnel-mode layout */
84c168f9f3SDavid du Colombier struct Esp6hdr
85c168f9f3SDavid du Colombier {
86410ea80bSDavid du Colombier IPV6HDR;
87c168f9f3SDavid du Colombier Esphdr;
887dd7cddfSDavid du Colombier };
897dd7cddfSDavid du Colombier
907dd7cddfSDavid du Colombier struct Esptail
917dd7cddfSDavid du Colombier {
927dd7cddfSDavid du Colombier uchar pad;
937dd7cddfSDavid du Colombier uchar nexthdr;
947dd7cddfSDavid du Colombier };
957dd7cddfSDavid du Colombier
96410ea80bSDavid du Colombier /* IP-version-dependent data */
97410ea80bSDavid du Colombier typedef struct Versdep Versdep;
98410ea80bSDavid du Colombier struct Versdep
99410ea80bSDavid du Colombier {
100410ea80bSDavid du Colombier ulong version;
101410ea80bSDavid du Colombier ulong iphdrlen;
102410ea80bSDavid du Colombier ulong hdrlen; /* iphdrlen + esp hdr len */
103410ea80bSDavid du Colombier ulong spi;
104410ea80bSDavid du Colombier uchar laddr[IPaddrlen];
105410ea80bSDavid du Colombier uchar raddr[IPaddrlen];
106410ea80bSDavid du Colombier };
107410ea80bSDavid du Colombier
1087dd7cddfSDavid du Colombier /* header as seen by the user */
1097dd7cddfSDavid du Colombier struct Userhdr
1107dd7cddfSDavid du Colombier {
1116c0968e3SDavid du Colombier uchar nexthdr; /* next protocol */
1127dd7cddfSDavid du Colombier uchar unused[3];
1137dd7cddfSDavid du Colombier };
1147dd7cddfSDavid du Colombier
1157dd7cddfSDavid du Colombier struct Esppriv
1167dd7cddfSDavid du Colombier {
117*3468a491SDavid du Colombier uvlong in;
1187dd7cddfSDavid du Colombier ulong inerrors;
1197dd7cddfSDavid du Colombier };
1207dd7cddfSDavid du Colombier
1217dd7cddfSDavid du Colombier /*
1227dd7cddfSDavid du Colombier * protocol specific part of Conv
1237dd7cddfSDavid du Colombier */
1247dd7cddfSDavid du Colombier struct Espcb
1257dd7cddfSDavid du Colombier {
1267dd7cddfSDavid du Colombier int incoming;
127410ea80bSDavid du Colombier int header; /* user-level header */
1287dd7cddfSDavid du Colombier ulong spi;
1296c0968e3SDavid du Colombier ulong seq; /* last seq sent */
1306c0968e3SDavid du Colombier ulong window; /* for replay attacks */
131410ea80bSDavid du Colombier
1327dd7cddfSDavid du Colombier char *espalg;
1336c0968e3SDavid du Colombier void *espstate; /* other state for esp */
1346c0968e3SDavid du Colombier int espivlen; /* in bytes */
1357dd7cddfSDavid du Colombier int espblklen;
1367dd7cddfSDavid du Colombier int (*cipher)(Espcb*, uchar *buf, int len);
137410ea80bSDavid du Colombier
1387dd7cddfSDavid du Colombier char *ahalg;
1396c0968e3SDavid du Colombier void *ahstate; /* other state for esp */
1406c0968e3SDavid du Colombier int ahlen; /* auth data length in bytes */
1417dd7cddfSDavid du Colombier int ahblklen;
1427dd7cddfSDavid du Colombier int (*auth)(Espcb*, uchar *buf, int len, uchar *hash);
143410ea80bSDavid du Colombier DigestState *ds;
1447dd7cddfSDavid du Colombier };
1457dd7cddfSDavid du Colombier
1467dd7cddfSDavid du Colombier struct Algorithm
1477dd7cddfSDavid du Colombier {
1487dd7cddfSDavid du Colombier char *name;
1496c0968e3SDavid du Colombier int keylen; /* in bits */
150410ea80bSDavid du Colombier void (*init)(Espcb*, char* name, uchar *key, unsigned keylen);
1517dd7cddfSDavid du Colombier };
1527dd7cddfSDavid du Colombier
1537dd7cddfSDavid du Colombier static Conv* convlookup(Proto *esp, ulong spi);
1547dd7cddfSDavid du Colombier static char *setalg(Espcb *ecb, char **f, int n, Algorithm *alg);
1550774058cSDavid du Colombier static void espkick(void *x);
1560774058cSDavid du Colombier
157410ea80bSDavid du Colombier static void nullespinit(Espcb*, char*, uchar *key, unsigned keylen);
158410ea80bSDavid du Colombier static void des3espinit(Espcb*, char*, uchar *key, unsigned keylen);
159410ea80bSDavid du Colombier static void aescbcespinit(Espcb*, char*, uchar *key, unsigned keylen);
160410ea80bSDavid du Colombier static void aesctrespinit(Espcb*, char*, uchar *key, unsigned keylen);
161410ea80bSDavid du Colombier static void desespinit(Espcb *ecb, char *name, uchar *k, unsigned n);
1620774058cSDavid du Colombier
163410ea80bSDavid du Colombier static void nullahinit(Espcb*, char*, uchar *key, unsigned keylen);
164410ea80bSDavid du Colombier static void shaahinit(Espcb*, char*, uchar *key, unsigned keylen);
165410ea80bSDavid du Colombier static void aesahinit(Espcb*, char*, uchar *key, unsigned keylen);
166410ea80bSDavid du Colombier static void md5ahinit(Espcb*, char*, uchar *key, unsigned keylen);
1677dd7cddfSDavid du Colombier
1687dd7cddfSDavid du Colombier static Algorithm espalg[] =
1697dd7cddfSDavid du Colombier {
1707dd7cddfSDavid du Colombier "null", 0, nullespinit,
171410ea80bSDavid du Colombier "des3_cbc", 192, des3espinit, /* new rfc2451, des-ede3 */
172410ea80bSDavid du Colombier "aes_128_cbc", 128, aescbcespinit, /* new rfc3602 */
173410ea80bSDavid du Colombier "aes_ctr", 128, aesctrespinit, /* new rfc3686 */
1740774058cSDavid du Colombier "des_56_cbc", 64, desespinit, /* rfc2405, deprecated */
175410ea80bSDavid du Colombier /* rc4 was never required, was used in original bandt */
176410ea80bSDavid du Colombier // "rc4_128", 128, rc4espinit,
1777dd7cddfSDavid du Colombier nil, 0, nil,
1787dd7cddfSDavid du Colombier };
1797dd7cddfSDavid du Colombier
1807dd7cddfSDavid du Colombier static Algorithm ahalg[] =
1817dd7cddfSDavid du Colombier {
1827dd7cddfSDavid du Colombier "null", 0, nullahinit,
1830774058cSDavid du Colombier "hmac_sha1_96", 128, shaahinit, /* rfc2404 */
184410ea80bSDavid du Colombier "aes_xcbc_mac_96", 128, aesahinit, /* new rfc3566 */
1850774058cSDavid du Colombier "hmac_md5_96", 128, md5ahinit, /* rfc2403 */
1867dd7cddfSDavid du Colombier nil, 0, nil,
1877dd7cddfSDavid du Colombier };
1887dd7cddfSDavid du Colombier
1897dd7cddfSDavid du Colombier static char*
espconnect(Conv * c,char ** argv,int argc)1907dd7cddfSDavid du Colombier espconnect(Conv *c, char **argv, int argc)
1917dd7cddfSDavid du Colombier {
192410ea80bSDavid du Colombier char *p, *pp, *e = nil;
1937dd7cddfSDavid du Colombier ulong spi;
1947dd7cddfSDavid du Colombier Espcb *ecb = (Espcb*)c->ptcl;
1957dd7cddfSDavid du Colombier
1967dd7cddfSDavid du Colombier switch(argc) {
1977dd7cddfSDavid du Colombier default:
1987dd7cddfSDavid du Colombier e = "bad args to connect";
1997dd7cddfSDavid du Colombier break;
2007dd7cddfSDavid du Colombier case 2:
2017dd7cddfSDavid du Colombier p = strchr(argv[1], '!');
2027dd7cddfSDavid du Colombier if(p == nil){
2037dd7cddfSDavid du Colombier e = "malformed address";
2047dd7cddfSDavid du Colombier break;
2057dd7cddfSDavid du Colombier }
2067dd7cddfSDavid du Colombier *p++ = 0;
207410ea80bSDavid du Colombier if (parseip(c->raddr, argv[1]) == -1) {
208410ea80bSDavid du Colombier e = Ebadip;
209410ea80bSDavid du Colombier break;
210410ea80bSDavid du Colombier }
2117dd7cddfSDavid du Colombier findlocalip(c->p->f, c->laddr, c->raddr);
2127dd7cddfSDavid du Colombier ecb->incoming = 0;
2137dd7cddfSDavid du Colombier ecb->seq = 0;
2147dd7cddfSDavid du Colombier if(strcmp(p, "*") == 0) {
2157dd7cddfSDavid du Colombier qlock(c->p);
2167dd7cddfSDavid du Colombier for(;;) {
2177dd7cddfSDavid du Colombier spi = nrand(1<<16) + 256;
2187dd7cddfSDavid du Colombier if(convlookup(c->p, spi) == nil)
2197dd7cddfSDavid du Colombier break;
2207dd7cddfSDavid du Colombier }
2217dd7cddfSDavid du Colombier qunlock(c->p);
2227dd7cddfSDavid du Colombier ecb->spi = spi;
2237dd7cddfSDavid du Colombier ecb->incoming = 1;
2247dd7cddfSDavid du Colombier qhangup(c->wq, nil);
2257dd7cddfSDavid du Colombier } else {
2267dd7cddfSDavid du Colombier spi = strtoul(p, &pp, 10);
2277dd7cddfSDavid du Colombier if(pp == p) {
2287dd7cddfSDavid du Colombier e = "malformed address";
2297dd7cddfSDavid du Colombier break;
2307dd7cddfSDavid du Colombier }
2317dd7cddfSDavid du Colombier ecb->spi = spi;
2327dd7cddfSDavid du Colombier qhangup(c->rq, nil);
2337dd7cddfSDavid du Colombier }
2347dd7cddfSDavid du Colombier nullespinit(ecb, "null", nil, 0);
2357dd7cddfSDavid du Colombier nullahinit(ecb, "null", nil, 0);
2367dd7cddfSDavid du Colombier }
2377dd7cddfSDavid du Colombier Fsconnected(c, e);
2387dd7cddfSDavid du Colombier
2397dd7cddfSDavid du Colombier return e;
2407dd7cddfSDavid du Colombier }
2417dd7cddfSDavid du Colombier
2427dd7cddfSDavid du Colombier
2437dd7cddfSDavid du Colombier static int
espstate(Conv * c,char * state,int n)2447dd7cddfSDavid du Colombier espstate(Conv *c, char *state, int n)
2457dd7cddfSDavid du Colombier {
2467dd7cddfSDavid du Colombier return snprint(state, n, "%s", c->inuse?"Open\n":"Closed\n");
2477dd7cddfSDavid du Colombier }
2487dd7cddfSDavid du Colombier
2497dd7cddfSDavid du Colombier static void
espcreate(Conv * c)2507dd7cddfSDavid du Colombier espcreate(Conv *c)
2517dd7cddfSDavid du Colombier {
2523ff48bf5SDavid du Colombier c->rq = qopen(64*1024, Qmsg, 0, 0);
2533ff48bf5SDavid du Colombier c->wq = qopen(64*1024, Qkick, espkick, c);
2547dd7cddfSDavid du Colombier }
2557dd7cddfSDavid du Colombier
2567dd7cddfSDavid du Colombier static void
espclose(Conv * c)2577dd7cddfSDavid du Colombier espclose(Conv *c)
2587dd7cddfSDavid du Colombier {
2597dd7cddfSDavid du Colombier Espcb *ecb;
2607dd7cddfSDavid du Colombier
2617dd7cddfSDavid du Colombier qclose(c->rq);
2627dd7cddfSDavid du Colombier qclose(c->wq);
2637dd7cddfSDavid du Colombier qclose(c->eq);
2647dd7cddfSDavid du Colombier ipmove(c->laddr, IPnoaddr);
2657dd7cddfSDavid du Colombier ipmove(c->raddr, IPnoaddr);
2667dd7cddfSDavid du Colombier
2677dd7cddfSDavid du Colombier ecb = (Espcb*)c->ptcl;
2687dd7cddfSDavid du Colombier free(ecb->espstate);
2697dd7cddfSDavid du Colombier free(ecb->ahstate);
2707dd7cddfSDavid du Colombier memset(ecb, 0, sizeof(Espcb));
2717dd7cddfSDavid du Colombier }
2727dd7cddfSDavid du Colombier
273c168f9f3SDavid du Colombier static int
convipvers(Conv * c)274410ea80bSDavid du Colombier convipvers(Conv *c)
275c168f9f3SDavid du Colombier {
276c168f9f3SDavid du Colombier if((memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
277c168f9f3SDavid du Colombier memcmp(c->laddr, v4prefix, IPv4off) == 0) ||
278c168f9f3SDavid du Colombier ipcmp(c->raddr, IPnoaddr) == 0)
279c168f9f3SDavid du Colombier return V4;
280c168f9f3SDavid du Colombier else
281c168f9f3SDavid du Colombier return V6;
282c168f9f3SDavid du Colombier }
283c168f9f3SDavid du Colombier
284410ea80bSDavid du Colombier static int
pktipvers(Fs * f,Block ** bpp)285410ea80bSDavid du Colombier pktipvers(Fs *f, Block **bpp)
286410ea80bSDavid du Colombier {
287410ea80bSDavid du Colombier if (*bpp == nil || BLEN(*bpp) == 0) {
288410ea80bSDavid du Colombier /* get enough to identify the IP version */
289410ea80bSDavid du Colombier *bpp = pullupblock(*bpp, IP4HDR);
290410ea80bSDavid du Colombier if(*bpp == nil) {
291410ea80bSDavid du Colombier netlog(f, Logesp, "esp: short packet\n");
292410ea80bSDavid du Colombier return 0;
293410ea80bSDavid du Colombier }
294410ea80bSDavid du Colombier }
295410ea80bSDavid du Colombier return (((Esp4hdr*)(*bpp)->rp)->vihl & 0xf0) == IP_VER4? V4: V6;
296410ea80bSDavid du Colombier }
297410ea80bSDavid du Colombier
298410ea80bSDavid du Colombier static void
getverslens(int version,Versdep * vp)299410ea80bSDavid du Colombier getverslens(int version, Versdep *vp)
300410ea80bSDavid du Colombier {
301410ea80bSDavid du Colombier vp->version = version;
302410ea80bSDavid du Colombier switch(vp->version) {
303410ea80bSDavid du Colombier case V4:
304410ea80bSDavid du Colombier vp->iphdrlen = IP4HDR;
305410ea80bSDavid du Colombier vp->hdrlen = Esp4hdrlen;
306410ea80bSDavid du Colombier break;
307410ea80bSDavid du Colombier case V6:
308410ea80bSDavid du Colombier vp->iphdrlen = IP6HDR;
309410ea80bSDavid du Colombier vp->hdrlen = Esp6hdrlen;
310410ea80bSDavid du Colombier break;
311410ea80bSDavid du Colombier default:
312410ea80bSDavid du Colombier panic("esp: getverslens version %d wrong", version);
313410ea80bSDavid du Colombier }
314410ea80bSDavid du Colombier }
315410ea80bSDavid du Colombier
316410ea80bSDavid du Colombier static void
getpktspiaddrs(uchar * pkt,Versdep * vp)317410ea80bSDavid du Colombier getpktspiaddrs(uchar *pkt, Versdep *vp)
318410ea80bSDavid du Colombier {
319410ea80bSDavid du Colombier Esp4hdr *eh4;
320410ea80bSDavid du Colombier Esp6hdr *eh6;
321410ea80bSDavid du Colombier
322410ea80bSDavid du Colombier switch(vp->version) {
323410ea80bSDavid du Colombier case V4:
324410ea80bSDavid du Colombier eh4 = (Esp4hdr*)pkt;
325410ea80bSDavid du Colombier v4tov6(vp->raddr, eh4->espsrc);
326410ea80bSDavid du Colombier v4tov6(vp->laddr, eh4->espdst);
327410ea80bSDavid du Colombier vp->spi = nhgetl(eh4->espspi);
328410ea80bSDavid du Colombier break;
329410ea80bSDavid du Colombier case V6:
330410ea80bSDavid du Colombier eh6 = (Esp6hdr*)pkt;
331410ea80bSDavid du Colombier ipmove(vp->raddr, eh6->src);
332410ea80bSDavid du Colombier ipmove(vp->laddr, eh6->dst);
333410ea80bSDavid du Colombier vp->spi = nhgetl(eh6->espspi);
334410ea80bSDavid du Colombier break;
335410ea80bSDavid du Colombier default:
336410ea80bSDavid du Colombier panic("esp: getpktspiaddrs vp->version %ld wrong", vp->version);
337410ea80bSDavid du Colombier }
338410ea80bSDavid du Colombier }
339410ea80bSDavid du Colombier
340410ea80bSDavid du Colombier /*
341410ea80bSDavid du Colombier * encapsulate next IP packet on x's write queue in IP/ESP packet
342410ea80bSDavid du Colombier * and initiate output of the result.
343410ea80bSDavid du Colombier */
3443ff48bf5SDavid du Colombier static void
espkick(void * x)3453ff48bf5SDavid du Colombier espkick(void *x)
3467dd7cddfSDavid du Colombier {
347410ea80bSDavid du Colombier int nexthdr, payload, pad, align;
348410ea80bSDavid du Colombier uchar *auth;
349410ea80bSDavid du Colombier Block *bp;
3503ff48bf5SDavid du Colombier Conv *c = x;
351c168f9f3SDavid du Colombier Esp4hdr *eh4;
352c168f9f3SDavid du Colombier Esp6hdr *eh6;
353410ea80bSDavid du Colombier Espcb *ecb;
3547dd7cddfSDavid du Colombier Esptail *et;
3557dd7cddfSDavid du Colombier Userhdr *uh;
356410ea80bSDavid du Colombier Versdep vers;
3577dd7cddfSDavid du Colombier
358410ea80bSDavid du Colombier getverslens(convipvers(c), &vers);
3597dd7cddfSDavid du Colombier bp = qget(c->wq);
3607dd7cddfSDavid du Colombier if(bp == nil)
3617dd7cddfSDavid du Colombier return;
3627dd7cddfSDavid du Colombier
3637dd7cddfSDavid du Colombier qlock(c);
3647dd7cddfSDavid du Colombier ecb = c->ptcl;
3657dd7cddfSDavid du Colombier
3667dd7cddfSDavid du Colombier if(ecb->header) {
3677dd7cddfSDavid du Colombier /* make sure the message has a User header */
368c168f9f3SDavid du Colombier bp = pullupblock(bp, Userhdrlen);
3697dd7cddfSDavid du Colombier if(bp == nil) {
3707dd7cddfSDavid du Colombier qunlock(c);
3717dd7cddfSDavid du Colombier return;
3727dd7cddfSDavid du Colombier }
3737dd7cddfSDavid du Colombier uh = (Userhdr*)bp->rp;
3747dd7cddfSDavid du Colombier nexthdr = uh->nexthdr;
375c168f9f3SDavid du Colombier bp->rp += Userhdrlen;
3767dd7cddfSDavid du Colombier } else {
3776c0968e3SDavid du Colombier nexthdr = 0; /* what should this be? */
3787dd7cddfSDavid du Colombier }
3797dd7cddfSDavid du Colombier
3807dd7cddfSDavid du Colombier payload = BLEN(bp) + ecb->espivlen;
3817dd7cddfSDavid du Colombier
3827dd7cddfSDavid du Colombier /* Make space to fit ip header */
383410ea80bSDavid du Colombier bp = padblock(bp, vers.hdrlen + ecb->espivlen);
384410ea80bSDavid du Colombier getpktspiaddrs(bp->rp, &vers);
3857dd7cddfSDavid du Colombier
3867dd7cddfSDavid du Colombier align = 4;
3877dd7cddfSDavid du Colombier if(ecb->espblklen > align)
3887dd7cddfSDavid du Colombier align = ecb->espblklen;
3897dd7cddfSDavid du Colombier if(align % ecb->ahblklen != 0)
3907dd7cddfSDavid du Colombier panic("espkick: ahblklen is important after all");
391c168f9f3SDavid du Colombier pad = (align-1) - (payload + Esptaillen-1)%align;
3927dd7cddfSDavid du Colombier
3937dd7cddfSDavid du Colombier /*
3947dd7cddfSDavid du Colombier * Make space for tail
3957dd7cddfSDavid du Colombier * this is done by calling padblock with a negative size
3967dd7cddfSDavid du Colombier * Padblock does not change bp->wp!
3977dd7cddfSDavid du Colombier */
398c168f9f3SDavid du Colombier bp = padblock(bp, -(pad+Esptaillen+ecb->ahlen));
399c168f9f3SDavid du Colombier bp->wp += pad+Esptaillen+ecb->ahlen;
4007dd7cddfSDavid du Colombier
401410ea80bSDavid du Colombier et = (Esptail*)(bp->rp + vers.hdrlen + payload + pad);
4027dd7cddfSDavid du Colombier
4036c0968e3SDavid du Colombier /* fill in tail */
4047dd7cddfSDavid du Colombier et->pad = pad;
4057dd7cddfSDavid du Colombier et->nexthdr = nexthdr;
4067dd7cddfSDavid du Colombier
407410ea80bSDavid du Colombier /* encrypt the payload */
408410ea80bSDavid du Colombier ecb->cipher(ecb, bp->rp + vers.hdrlen, payload + pad + Esptaillen);
409410ea80bSDavid du Colombier auth = bp->rp + vers.hdrlen + payload + pad + Esptaillen;
4107dd7cddfSDavid du Colombier
411410ea80bSDavid du Colombier /* fill in head; construct a new IP header and an ESP header */
412410ea80bSDavid du Colombier if (vers.version == V4) {
413410ea80bSDavid du Colombier eh4 = (Esp4hdr *)bp->rp;
414c168f9f3SDavid du Colombier eh4->vihl = IP_VER4;
415c168f9f3SDavid du Colombier v6tov4(eh4->espsrc, c->laddr);
416c168f9f3SDavid du Colombier v6tov4(eh4->espdst, c->raddr);
417c168f9f3SDavid du Colombier eh4->espproto = IP_ESPPROTO;
418c168f9f3SDavid du Colombier eh4->frag[0] = 0;
419c168f9f3SDavid du Colombier eh4->frag[1] = 0;
420410ea80bSDavid du Colombier
421410ea80bSDavid du Colombier hnputl(eh4->espspi, ecb->spi);
422410ea80bSDavid du Colombier hnputl(eh4->espseq, ++ecb->seq);
423c168f9f3SDavid du Colombier } else {
424410ea80bSDavid du Colombier eh6 = (Esp6hdr *)bp->rp;
425c168f9f3SDavid du Colombier eh6->vcf[0] = IP_VER6;
426c168f9f3SDavid du Colombier ipmove(eh6->src, c->laddr);
427c168f9f3SDavid du Colombier ipmove(eh6->dst, c->raddr);
428c168f9f3SDavid du Colombier eh6->proto = IP_ESPPROTO;
429410ea80bSDavid du Colombier
430410ea80bSDavid du Colombier hnputl(eh6->espspi, ecb->spi);
431410ea80bSDavid du Colombier hnputl(eh6->espseq, ++ecb->seq);
432c168f9f3SDavid du Colombier }
4337dd7cddfSDavid du Colombier
434410ea80bSDavid du Colombier /* compute secure hash */
435410ea80bSDavid du Colombier ecb->auth(ecb, bp->rp + vers.iphdrlen, (vers.hdrlen - vers.iphdrlen) +
436c168f9f3SDavid du Colombier payload + pad + Esptaillen, auth);
4377dd7cddfSDavid du Colombier
4387dd7cddfSDavid du Colombier qunlock(c);
4396c0968e3SDavid du Colombier /* print("esp: pass down: %uld\n", BLEN(bp)); */
440410ea80bSDavid du Colombier if (vers.version == V4)
441a6a9e072SDavid du Colombier ipoput4(c->p->f, bp, 0, c->ttl, c->tos, c);
442c168f9f3SDavid du Colombier else
443c168f9f3SDavid du Colombier ipoput6(c->p->f, bp, 0, c->ttl, c->tos, c);
4447dd7cddfSDavid du Colombier }
4457dd7cddfSDavid du Colombier
446410ea80bSDavid du Colombier /*
447410ea80bSDavid du Colombier * decapsulate IP packet from IP/ESP packet in bp and
448410ea80bSDavid du Colombier * pass the result up the spi's Conv's read queue.
449410ea80bSDavid du Colombier */
4507dd7cddfSDavid du Colombier void
espiput(Proto * esp,Ipifc *,Block * bp)4519a747e4fSDavid du Colombier espiput(Proto *esp, Ipifc*, Block *bp)
4527dd7cddfSDavid du Colombier {
453410ea80bSDavid du Colombier int payload, nexthdr;
454410ea80bSDavid du Colombier uchar *auth, *espspi;
4557dd7cddfSDavid du Colombier Conv *c;
4567dd7cddfSDavid du Colombier Espcb *ecb;
457410ea80bSDavid du Colombier Esptail *et;
4587dd7cddfSDavid du Colombier Fs *f;
459410ea80bSDavid du Colombier Userhdr *uh;
460410ea80bSDavid du Colombier Versdep vers;
4617dd7cddfSDavid du Colombier
4627dd7cddfSDavid du Colombier f = esp->f;
463410ea80bSDavid du Colombier
464410ea80bSDavid du Colombier getverslens(pktipvers(f, &bp), &vers);
465410ea80bSDavid du Colombier
466410ea80bSDavid du Colombier bp = pullupblock(bp, vers.hdrlen + Esptaillen);
467c168f9f3SDavid du Colombier if(bp == nil) {
468c168f9f3SDavid du Colombier netlog(f, Logesp, "esp: short packet\n");
469c168f9f3SDavid du Colombier return;
470c168f9f3SDavid du Colombier }
471410ea80bSDavid du Colombier getpktspiaddrs(bp->rp, &vers);
4727dd7cddfSDavid du Colombier
4737dd7cddfSDavid du Colombier qlock(esp);
4747dd7cddfSDavid du Colombier /* Look for a conversation structure for this port */
475410ea80bSDavid du Colombier c = convlookup(esp, vers.spi);
4767dd7cddfSDavid du Colombier if(c == nil) {
4777dd7cddfSDavid du Colombier qunlock(esp);
4787133e0eeSDavid du Colombier netlog(f, Logesp, "esp: no conv %I -> %I!%lud\n", vers.raddr,
479410ea80bSDavid du Colombier vers.laddr, vers.spi);
4807dd7cddfSDavid du Colombier icmpnoconv(f, bp);
4817dd7cddfSDavid du Colombier freeblist(bp);
4827dd7cddfSDavid du Colombier return;
4837dd7cddfSDavid du Colombier }
4847dd7cddfSDavid du Colombier
4857dd7cddfSDavid du Colombier qlock(c);
4867dd7cddfSDavid du Colombier qunlock(esp);
4877dd7cddfSDavid du Colombier
4887dd7cddfSDavid du Colombier ecb = c->ptcl;
4896c0968e3SDavid du Colombier /* too hard to do decryption/authentication on block lists */
4907dd7cddfSDavid du Colombier if(bp->next)
4917dd7cddfSDavid du Colombier bp = concatblock(bp);
4927dd7cddfSDavid du Colombier
493410ea80bSDavid du Colombier if(BLEN(bp) < vers.hdrlen + ecb->espivlen + Esptaillen + ecb->ahlen) {
4947dd7cddfSDavid du Colombier qunlock(c);
4957133e0eeSDavid du Colombier netlog(f, Logesp, "esp: short block %I -> %I!%lud\n", vers.raddr,
496410ea80bSDavid du Colombier vers.laddr, vers.spi);
4977dd7cddfSDavid du Colombier freeb(bp);
4987dd7cddfSDavid du Colombier return;
4997dd7cddfSDavid du Colombier }
5007dd7cddfSDavid du Colombier
5017dd7cddfSDavid du Colombier auth = bp->wp - ecb->ahlen;
502410ea80bSDavid du Colombier espspi = vers.version == V4? ((Esp4hdr*)bp->rp)->espspi:
503c168f9f3SDavid du Colombier ((Esp6hdr*)bp->rp)->espspi;
504410ea80bSDavid du Colombier
505410ea80bSDavid du Colombier /* compute secure hash and authenticate */
506c168f9f3SDavid du Colombier if(!ecb->auth(ecb, espspi, auth - espspi, auth)) {
5077dd7cddfSDavid du Colombier qunlock(c);
508410ea80bSDavid du Colombier print("esp: bad auth %I -> %I!%ld\n", vers.raddr, vers.laddr, vers.spi);
5097133e0eeSDavid du Colombier netlog(f, Logesp, "esp: bad auth %I -> %I!%lud\n", vers.raddr,
510410ea80bSDavid du Colombier vers.laddr, vers.spi);
5117dd7cddfSDavid du Colombier freeb(bp);
5127dd7cddfSDavid du Colombier return;
5137dd7cddfSDavid du Colombier }
5147dd7cddfSDavid du Colombier
515410ea80bSDavid du Colombier payload = BLEN(bp) - vers.hdrlen - ecb->ahlen;
5167dd7cddfSDavid du Colombier if(payload <= 0 || payload % 4 != 0 || payload % ecb->espblklen != 0) {
5177dd7cddfSDavid du Colombier qunlock(c);
5187133e0eeSDavid du Colombier netlog(f, Logesp, "esp: bad length %I -> %I!%lud payload=%d BLEN=%lud\n",
519410ea80bSDavid du Colombier vers.raddr, vers.laddr, vers.spi, payload, BLEN(bp));
5207dd7cddfSDavid du Colombier freeb(bp);
5217dd7cddfSDavid du Colombier return;
5227dd7cddfSDavid du Colombier }
523410ea80bSDavid du Colombier
524410ea80bSDavid du Colombier /* decrypt payload */
525410ea80bSDavid du Colombier if(!ecb->cipher(ecb, bp->rp + vers.hdrlen, payload)) {
5267dd7cddfSDavid du Colombier qunlock(c);
527410ea80bSDavid du Colombier print("esp: cipher failed %I -> %I!%ld: %s\n", vers.raddr, vers.laddr, vers.spi, up->errstr);
5287133e0eeSDavid du Colombier netlog(f, Logesp, "esp: cipher failed %I -> %I!%lud: %s\n",
529410ea80bSDavid du Colombier vers.raddr, vers.laddr, vers.spi, up->errstr);
5307dd7cddfSDavid du Colombier freeb(bp);
5317dd7cddfSDavid du Colombier return;
5327dd7cddfSDavid du Colombier }
5337dd7cddfSDavid du Colombier
534c168f9f3SDavid du Colombier payload -= Esptaillen;
535410ea80bSDavid du Colombier et = (Esptail*)(bp->rp + vers.hdrlen + payload);
5367dd7cddfSDavid du Colombier payload -= et->pad + ecb->espivlen;
5377dd7cddfSDavid du Colombier nexthdr = et->nexthdr;
5387dd7cddfSDavid du Colombier if(payload <= 0) {
5397dd7cddfSDavid du Colombier qunlock(c);
5407133e0eeSDavid du Colombier netlog(f, Logesp, "esp: short packet after decrypt %I -> %I!%lud\n",
541410ea80bSDavid du Colombier vers.raddr, vers.laddr, vers.spi);
5427dd7cddfSDavid du Colombier freeb(bp);
5437dd7cddfSDavid du Colombier return;
5447dd7cddfSDavid du Colombier }
5457dd7cddfSDavid du Colombier
5466c0968e3SDavid du Colombier /* trim packet */
547410ea80bSDavid du Colombier bp->rp += vers.hdrlen + ecb->espivlen; /* toss original IP & ESP hdrs */
5487dd7cddfSDavid du Colombier bp->wp = bp->rp + payload;
5497dd7cddfSDavid du Colombier if(ecb->header) {
550c168f9f3SDavid du Colombier /* assume Userhdrlen < Esp4hdrlen < Esp6hdrlen */
551c168f9f3SDavid du Colombier bp->rp -= Userhdrlen;
5527dd7cddfSDavid du Colombier uh = (Userhdr*)bp->rp;
553c168f9f3SDavid du Colombier memset(uh, 0, Userhdrlen);
5547dd7cddfSDavid du Colombier uh->nexthdr = nexthdr;
5557dd7cddfSDavid du Colombier }
5567dd7cddfSDavid du Colombier
557410ea80bSDavid du Colombier /* ingress filtering here? */
558410ea80bSDavid du Colombier
5597dd7cddfSDavid du Colombier if(qfull(c->rq)){
560410ea80bSDavid du Colombier netlog(f, Logesp, "esp: qfull %I -> %I.%uld\n", vers.raddr,
561410ea80bSDavid du Colombier vers.laddr, vers.spi);
5627dd7cddfSDavid du Colombier freeblist(bp);
5637dd7cddfSDavid du Colombier }else {
5647dd7cddfSDavid du Colombier // print("esp: pass up: %uld\n", BLEN(bp));
565410ea80bSDavid du Colombier qpass(c->rq, bp); /* pass packet up the read queue */
5667dd7cddfSDavid du Colombier }
5677dd7cddfSDavid du Colombier
5687dd7cddfSDavid du Colombier qunlock(c);
5697dd7cddfSDavid du Colombier }
5707dd7cddfSDavid du Colombier
5717dd7cddfSDavid du Colombier char*
espctl(Conv * c,char ** f,int n)5727dd7cddfSDavid du Colombier espctl(Conv *c, char **f, int n)
5737dd7cddfSDavid du Colombier {
5747dd7cddfSDavid du Colombier Espcb *ecb = c->ptcl;
5757dd7cddfSDavid du Colombier char *e = nil;
5767dd7cddfSDavid du Colombier
5777dd7cddfSDavid du Colombier if(strcmp(f[0], "esp") == 0)
5787dd7cddfSDavid du Colombier e = setalg(ecb, f, n, espalg);
5797dd7cddfSDavid du Colombier else if(strcmp(f[0], "ah") == 0)
5807dd7cddfSDavid du Colombier e = setalg(ecb, f, n, ahalg);
5817dd7cddfSDavid du Colombier else if(strcmp(f[0], "header") == 0)
5827dd7cddfSDavid du Colombier ecb->header = 1;
5837dd7cddfSDavid du Colombier else if(strcmp(f[0], "noheader") == 0)
5847dd7cddfSDavid du Colombier ecb->header = 0;
5857dd7cddfSDavid du Colombier else
5867dd7cddfSDavid du Colombier e = "unknown control request";
5877dd7cddfSDavid du Colombier return e;
5887dd7cddfSDavid du Colombier }
5897dd7cddfSDavid du Colombier
590410ea80bSDavid du Colombier /* called from icmp(v6) for unreachable hosts, time exceeded, etc. */
5917dd7cddfSDavid du Colombier void
espadvise(Proto * esp,Block * bp,char * msg)5927dd7cddfSDavid du Colombier espadvise(Proto *esp, Block *bp, char *msg)
5937dd7cddfSDavid du Colombier {
5947dd7cddfSDavid du Colombier Conv *c;
595410ea80bSDavid du Colombier Versdep vers;
5967dd7cddfSDavid du Colombier
597410ea80bSDavid du Colombier getverslens(pktipvers(esp->f, &bp), &vers);
598410ea80bSDavid du Colombier getpktspiaddrs(bp->rp, &vers);
5997dd7cddfSDavid du Colombier
6007dd7cddfSDavid du Colombier qlock(esp);
601410ea80bSDavid du Colombier c = convlookup(esp, vers.spi);
6027dd7cddfSDavid du Colombier if(c != nil) {
6037dd7cddfSDavid du Colombier qhangup(c->rq, msg);
6047dd7cddfSDavid du Colombier qhangup(c->wq, msg);
6057dd7cddfSDavid du Colombier }
6067dd7cddfSDavid du Colombier qunlock(esp);
6077dd7cddfSDavid du Colombier freeblist(bp);
6087dd7cddfSDavid du Colombier }
6097dd7cddfSDavid du Colombier
6107dd7cddfSDavid du Colombier int
espstats(Proto * esp,char * buf,int len)6117dd7cddfSDavid du Colombier espstats(Proto *esp, char *buf, int len)
6127dd7cddfSDavid du Colombier {
6137dd7cddfSDavid du Colombier Esppriv *upriv;
6147dd7cddfSDavid du Colombier
6157dd7cddfSDavid du Colombier upriv = esp->priv;
616*3468a491SDavid du Colombier return snprint(buf, len, "%llud %lud\n",
6177dd7cddfSDavid du Colombier upriv->in,
6187dd7cddfSDavid du Colombier upriv->inerrors);
6197dd7cddfSDavid du Colombier }
6207dd7cddfSDavid du Colombier
6217dd7cddfSDavid du Colombier static int
esplocal(Conv * c,char * buf,int len)6227dd7cddfSDavid du Colombier esplocal(Conv *c, char *buf, int len)
6237dd7cddfSDavid du Colombier {
6247dd7cddfSDavid du Colombier Espcb *ecb = c->ptcl;
6257dd7cddfSDavid du Colombier int n;
6267dd7cddfSDavid du Colombier
6277dd7cddfSDavid du Colombier qlock(c);
6287dd7cddfSDavid du Colombier if(ecb->incoming)
6297dd7cddfSDavid du Colombier n = snprint(buf, len, "%I!%uld\n", c->laddr, ecb->spi);
6307dd7cddfSDavid du Colombier else
6317dd7cddfSDavid du Colombier n = snprint(buf, len, "%I\n", c->laddr);
6327dd7cddfSDavid du Colombier qunlock(c);
6337dd7cddfSDavid du Colombier return n;
6347dd7cddfSDavid du Colombier }
6357dd7cddfSDavid du Colombier
6367dd7cddfSDavid du Colombier static int
espremote(Conv * c,char * buf,int len)6377dd7cddfSDavid du Colombier espremote(Conv *c, char *buf, int len)
6387dd7cddfSDavid du Colombier {
6397dd7cddfSDavid du Colombier Espcb *ecb = c->ptcl;
6407dd7cddfSDavid du Colombier int n;
6417dd7cddfSDavid du Colombier
6427dd7cddfSDavid du Colombier qlock(c);
6437dd7cddfSDavid du Colombier if(ecb->incoming)
6447dd7cddfSDavid du Colombier n = snprint(buf, len, "%I\n", c->raddr);
6457dd7cddfSDavid du Colombier else
6467dd7cddfSDavid du Colombier n = snprint(buf, len, "%I!%uld\n", c->raddr, ecb->spi);
6477dd7cddfSDavid du Colombier qunlock(c);
6487dd7cddfSDavid du Colombier return n;
6497dd7cddfSDavid du Colombier }
6507dd7cddfSDavid du Colombier
6517dd7cddfSDavid du Colombier static Conv*
convlookup(Proto * esp,ulong spi)6527dd7cddfSDavid du Colombier convlookup(Proto *esp, ulong spi)
6537dd7cddfSDavid du Colombier {
6547dd7cddfSDavid du Colombier Conv *c, **p;
6557dd7cddfSDavid du Colombier Espcb *ecb;
6567dd7cddfSDavid du Colombier
6577dd7cddfSDavid du Colombier for(p=esp->conv; *p; p++){
6587dd7cddfSDavid du Colombier c = *p;
6597dd7cddfSDavid du Colombier ecb = c->ptcl;
6607dd7cddfSDavid du Colombier if(ecb->incoming && ecb->spi == spi)
6617dd7cddfSDavid du Colombier return c;
6627dd7cddfSDavid du Colombier }
6637dd7cddfSDavid du Colombier return nil;
6647dd7cddfSDavid du Colombier }
6657dd7cddfSDavid du Colombier
6667dd7cddfSDavid du Colombier static char *
setalg(Espcb * ecb,char ** f,int n,Algorithm * alg)6677dd7cddfSDavid du Colombier setalg(Espcb *ecb, char **f, int n, Algorithm *alg)
6687dd7cddfSDavid du Colombier {
6697dd7cddfSDavid du Colombier uchar *key;
670*3468a491SDavid du Colombier int c, nbyte, nchar;
671*3468a491SDavid du Colombier uint i;
6727dd7cddfSDavid du Colombier
673*3468a491SDavid du Colombier if(n < 2 || n > 3)
6747dd7cddfSDavid du Colombier return "bad format";
6757dd7cddfSDavid du Colombier for(; alg->name; alg++)
6767dd7cddfSDavid du Colombier if(strcmp(f[1], alg->name) == 0)
6777dd7cddfSDavid du Colombier break;
6787dd7cddfSDavid du Colombier if(alg->name == nil)
6797dd7cddfSDavid du Colombier return "unknown algorithm";
6807dd7cddfSDavid du Colombier
6817dd7cddfSDavid du Colombier nbyte = (alg->keylen + 7) >> 3;
682*3468a491SDavid du Colombier if (n == 2)
683*3468a491SDavid du Colombier nchar = 0;
684*3468a491SDavid du Colombier else
6857dd7cddfSDavid du Colombier nchar = strlen(f[2]);
686*3468a491SDavid du Colombier if(nchar != 2 * nbyte) /* TODO: maybe < is ok */
687*3468a491SDavid du Colombier return "key not required length";
688*3468a491SDavid du Colombier /* convert hex digits from ascii, in place */
6897dd7cddfSDavid du Colombier for(i=0; i<nchar; i++) {
6907dd7cddfSDavid du Colombier c = f[2][i];
6917dd7cddfSDavid du Colombier if(c >= '0' && c <= '9')
6927dd7cddfSDavid du Colombier f[2][i] -= '0';
6937dd7cddfSDavid du Colombier else if(c >= 'a' && c <= 'f')
6947dd7cddfSDavid du Colombier f[2][i] -= 'a'-10;
6957dd7cddfSDavid du Colombier else if(c >= 'A' && c <= 'F')
6967dd7cddfSDavid du Colombier f[2][i] -= 'A'-10;
6977dd7cddfSDavid du Colombier else
698*3468a491SDavid du Colombier return "non-hex character in key";
6997dd7cddfSDavid du Colombier }
700*3468a491SDavid du Colombier /* collapse hex digits into complete bytes in reverse order in key */
7017dd7cddfSDavid du Colombier key = smalloc(nbyte);
702*3468a491SDavid du Colombier for(i = 0; i < nchar && i/2 < nbyte; i++) {
7037dd7cddfSDavid du Colombier c = f[2][nchar-i-1];
7047dd7cddfSDavid du Colombier if(i&1)
7057dd7cddfSDavid du Colombier c <<= 4;
706*3468a491SDavid du Colombier key[i/2] |= c;
7077dd7cddfSDavid du Colombier }
7087dd7cddfSDavid du Colombier
7097dd7cddfSDavid du Colombier alg->init(ecb, alg->name, key, alg->keylen);
7107dd7cddfSDavid du Colombier free(key);
7117dd7cddfSDavid du Colombier return nil;
7127dd7cddfSDavid du Colombier }
7137dd7cddfSDavid du Colombier
714410ea80bSDavid du Colombier
715410ea80bSDavid du Colombier /*
716410ea80bSDavid du Colombier * null encryption
717410ea80bSDavid du Colombier */
718410ea80bSDavid du Colombier
7197dd7cddfSDavid du Colombier static int
nullcipher(Espcb *,uchar *,int)7207dd7cddfSDavid du Colombier nullcipher(Espcb*, uchar*, int)
7217dd7cddfSDavid du Colombier {
7227dd7cddfSDavid du Colombier return 1;
7237dd7cddfSDavid du Colombier }
7247dd7cddfSDavid du Colombier
7257dd7cddfSDavid du Colombier static void
nullespinit(Espcb * ecb,char * name,uchar *,unsigned)726410ea80bSDavid du Colombier nullespinit(Espcb *ecb, char *name, uchar*, unsigned)
7277dd7cddfSDavid du Colombier {
7287dd7cddfSDavid du Colombier ecb->espalg = name;
7297dd7cddfSDavid du Colombier ecb->espblklen = 1;
7307dd7cddfSDavid du Colombier ecb->espivlen = 0;
7317dd7cddfSDavid du Colombier ecb->cipher = nullcipher;
7327dd7cddfSDavid du Colombier }
7337dd7cddfSDavid du Colombier
7347dd7cddfSDavid du Colombier static int
nullauth(Espcb *,uchar *,int,uchar *)7357dd7cddfSDavid du Colombier nullauth(Espcb*, uchar*, int, uchar*)
7367dd7cddfSDavid du Colombier {
7377dd7cddfSDavid du Colombier return 1;
7387dd7cddfSDavid du Colombier }
7397dd7cddfSDavid du Colombier
7407dd7cddfSDavid du Colombier static void
nullahinit(Espcb * ecb,char * name,uchar *,unsigned)741410ea80bSDavid du Colombier nullahinit(Espcb *ecb, char *name, uchar*, unsigned)
7427dd7cddfSDavid du Colombier {
7437dd7cddfSDavid du Colombier ecb->ahalg = name;
7447dd7cddfSDavid du Colombier ecb->ahblklen = 1;
7457dd7cddfSDavid du Colombier ecb->ahlen = 0;
7467dd7cddfSDavid du Colombier ecb->auth = nullauth;
7477dd7cddfSDavid du Colombier }
7487dd7cddfSDavid du Colombier
749410ea80bSDavid du Colombier
750410ea80bSDavid du Colombier /*
751410ea80bSDavid du Colombier * sha1
752410ea80bSDavid du Colombier */
753410ea80bSDavid du Colombier
754410ea80bSDavid du Colombier static void
seanq_hmac_sha1(uchar hash[SHA1dlen],uchar * t,long tlen,uchar * key,long klen)7557dd7cddfSDavid du Colombier seanq_hmac_sha1(uchar hash[SHA1dlen], uchar *t, long tlen, uchar *key, long klen)
7567dd7cddfSDavid du Colombier {
7577dd7cddfSDavid du Colombier int i;
758410ea80bSDavid du Colombier uchar ipad[Hmacblksz+1], opad[Hmacblksz+1], innerhash[SHA1dlen];
7597dd7cddfSDavid du Colombier DigestState *digest;
7607dd7cddfSDavid du Colombier
761410ea80bSDavid du Colombier memset(ipad, 0x36, Hmacblksz);
762410ea80bSDavid du Colombier memset(opad, 0x5c, Hmacblksz);
763410ea80bSDavid du Colombier ipad[Hmacblksz] = opad[Hmacblksz] = 0;
7647dd7cddfSDavid du Colombier for(i = 0; i < klen; i++){
7657dd7cddfSDavid du Colombier ipad[i] ^= key[i];
7667dd7cddfSDavid du Colombier opad[i] ^= key[i];
7677dd7cddfSDavid du Colombier }
768410ea80bSDavid du Colombier digest = sha1(ipad, Hmacblksz, nil, nil);
7697dd7cddfSDavid du Colombier sha1(t, tlen, innerhash, digest);
770410ea80bSDavid du Colombier digest = sha1(opad, Hmacblksz, nil, nil);
7717dd7cddfSDavid du Colombier sha1(innerhash, SHA1dlen, hash, digest);
7727dd7cddfSDavid du Colombier }
7737dd7cddfSDavid du Colombier
7747dd7cddfSDavid du Colombier static int
shaauth(Espcb * ecb,uchar * t,int tlen,uchar * auth)7757dd7cddfSDavid du Colombier shaauth(Espcb *ecb, uchar *t, int tlen, uchar *auth)
7767dd7cddfSDavid du Colombier {
7777dd7cddfSDavid du Colombier int r;
778410ea80bSDavid du Colombier uchar hash[SHA1dlen];
7797dd7cddfSDavid du Colombier
7807dd7cddfSDavid du Colombier memset(hash, 0, SHA1dlen);
781410ea80bSDavid du Colombier seanq_hmac_sha1(hash, t, tlen, (uchar*)ecb->ahstate, BITS2BYTES(128));
7827dd7cddfSDavid du Colombier r = memcmp(auth, hash, ecb->ahlen) == 0;
7837dd7cddfSDavid du Colombier memmove(auth, hash, ecb->ahlen);
7847dd7cddfSDavid du Colombier return r;
7857dd7cddfSDavid du Colombier }
7867dd7cddfSDavid du Colombier
7877dd7cddfSDavid du Colombier static void
shaahinit(Espcb * ecb,char * name,uchar * key,unsigned klen)788410ea80bSDavid du Colombier shaahinit(Espcb *ecb, char *name, uchar *key, unsigned klen)
7897dd7cddfSDavid du Colombier {
7907dd7cddfSDavid du Colombier if(klen != 128)
7917dd7cddfSDavid du Colombier panic("shaahinit: bad keylen");
792410ea80bSDavid du Colombier klen /= BI2BY;
7937dd7cddfSDavid du Colombier
7947dd7cddfSDavid du Colombier ecb->ahalg = name;
7957dd7cddfSDavid du Colombier ecb->ahblklen = 1;
796410ea80bSDavid du Colombier ecb->ahlen = BITS2BYTES(96);
7977dd7cddfSDavid du Colombier ecb->auth = shaauth;
7987dd7cddfSDavid du Colombier ecb->ahstate = smalloc(klen);
7997dd7cddfSDavid du Colombier memmove(ecb->ahstate, key, klen);
8007dd7cddfSDavid du Colombier }
8017dd7cddfSDavid du Colombier
802410ea80bSDavid du Colombier
803410ea80bSDavid du Colombier /*
804410ea80bSDavid du Colombier * aes
805410ea80bSDavid du Colombier */
806410ea80bSDavid du Colombier
807410ea80bSDavid du Colombier /* ah_aes_xcbc_mac_96, rfc3566 */
808410ea80bSDavid du Colombier static int
aesahauth(Espcb * ecb,uchar * t,int tlen,uchar * auth)809410ea80bSDavid du Colombier aesahauth(Espcb *ecb, uchar *t, int tlen, uchar *auth)
810410ea80bSDavid du Colombier {
811410ea80bSDavid du Colombier int r;
812410ea80bSDavid du Colombier uchar hash[AESdlen];
813410ea80bSDavid du Colombier
814410ea80bSDavid du Colombier memset(hash, 0, AESdlen);
815*3468a491SDavid du Colombier ecb->ds = hmac_aes(t, tlen, (uchar*)ecb->ahstate, BITS2BYTES(96), hash,
816410ea80bSDavid du Colombier ecb->ds);
817410ea80bSDavid du Colombier r = memcmp(auth, hash, ecb->ahlen) == 0;
818410ea80bSDavid du Colombier memmove(auth, hash, ecb->ahlen);
819410ea80bSDavid du Colombier return r;
820410ea80bSDavid du Colombier }
821410ea80bSDavid du Colombier
822410ea80bSDavid du Colombier static void
aesahinit(Espcb * ecb,char * name,uchar * key,unsigned klen)823410ea80bSDavid du Colombier aesahinit(Espcb *ecb, char *name, uchar *key, unsigned klen)
824410ea80bSDavid du Colombier {
825410ea80bSDavid du Colombier if(klen != 128)
826410ea80bSDavid du Colombier panic("aesahinit: keylen not 128");
827410ea80bSDavid du Colombier klen /= BI2BY;
828410ea80bSDavid du Colombier
829410ea80bSDavid du Colombier ecb->ahalg = name;
830410ea80bSDavid du Colombier ecb->ahblklen = 1;
831410ea80bSDavid du Colombier ecb->ahlen = BITS2BYTES(96);
832410ea80bSDavid du Colombier ecb->auth = aesahauth;
833410ea80bSDavid du Colombier ecb->ahstate = smalloc(klen);
834410ea80bSDavid du Colombier memmove(ecb->ahstate, key, klen);
835410ea80bSDavid du Colombier }
836410ea80bSDavid du Colombier
837410ea80bSDavid du Colombier static int
aescbccipher(Espcb * ecb,uchar * p,int n)838410ea80bSDavid du Colombier aescbccipher(Espcb *ecb, uchar *p, int n) /* 128-bit blocks */
839410ea80bSDavid du Colombier {
840410ea80bSDavid du Colombier uchar tmp[AESbsize], q[AESbsize];
841410ea80bSDavid du Colombier uchar *pp, *tp, *ip, *eip, *ep;
842410ea80bSDavid du Colombier AESstate *ds = ecb->espstate;
843410ea80bSDavid du Colombier
844410ea80bSDavid du Colombier ep = p + n;
845410ea80bSDavid du Colombier if(ecb->incoming) {
846410ea80bSDavid du Colombier memmove(ds->ivec, p, AESbsize);
847410ea80bSDavid du Colombier p += AESbsize;
848410ea80bSDavid du Colombier while(p < ep){
849410ea80bSDavid du Colombier memmove(tmp, p, AESbsize);
850410ea80bSDavid du Colombier aes_decrypt(ds->dkey, ds->rounds, p, q);
851410ea80bSDavid du Colombier memmove(p, q, AESbsize);
852410ea80bSDavid du Colombier tp = tmp;
853410ea80bSDavid du Colombier ip = ds->ivec;
854410ea80bSDavid du Colombier for(eip = ip + AESbsize; ip < eip; ){
855410ea80bSDavid du Colombier *p++ ^= *ip;
856410ea80bSDavid du Colombier *ip++ = *tp++;
857410ea80bSDavid du Colombier }
858410ea80bSDavid du Colombier }
859410ea80bSDavid du Colombier } else {
860410ea80bSDavid du Colombier memmove(p, ds->ivec, AESbsize);
861410ea80bSDavid du Colombier for(p += AESbsize; p < ep; p += AESbsize){
862410ea80bSDavid du Colombier pp = p;
863410ea80bSDavid du Colombier ip = ds->ivec;
864410ea80bSDavid du Colombier for(eip = ip + AESbsize; ip < eip; )
865410ea80bSDavid du Colombier *pp++ ^= *ip++;
866410ea80bSDavid du Colombier aes_encrypt(ds->ekey, ds->rounds, p, q);
867410ea80bSDavid du Colombier memmove(ds->ivec, q, AESbsize);
868410ea80bSDavid du Colombier memmove(p, q, AESbsize);
869410ea80bSDavid du Colombier }
870410ea80bSDavid du Colombier }
871410ea80bSDavid du Colombier return 1;
872410ea80bSDavid du Colombier }
873410ea80bSDavid du Colombier
874410ea80bSDavid du Colombier static void
aescbcespinit(Espcb * ecb,char * name,uchar * k,unsigned n)875410ea80bSDavid du Colombier aescbcespinit(Espcb *ecb, char *name, uchar *k, unsigned n)
876410ea80bSDavid du Colombier {
877410ea80bSDavid du Colombier uchar key[Aeskeysz], ivec[Aeskeysz];
878410ea80bSDavid du Colombier int i;
879410ea80bSDavid du Colombier
880410ea80bSDavid du Colombier n = BITS2BYTES(n);
881410ea80bSDavid du Colombier if(n > Aeskeysz)
882410ea80bSDavid du Colombier n = Aeskeysz;
883410ea80bSDavid du Colombier memset(key, 0, sizeof(key));
884410ea80bSDavid du Colombier memmove(key, k, n);
885410ea80bSDavid du Colombier for(i = 0; i < Aeskeysz; i++)
886410ea80bSDavid du Colombier ivec[i] = nrand(256);
887410ea80bSDavid du Colombier ecb->espalg = name;
888410ea80bSDavid du Colombier ecb->espblklen = Aesblk;
889410ea80bSDavid du Colombier ecb->espivlen = Aesblk;
890410ea80bSDavid du Colombier ecb->cipher = aescbccipher;
891410ea80bSDavid du Colombier ecb->espstate = smalloc(sizeof(AESstate));
892410ea80bSDavid du Colombier setupAESstate(ecb->espstate, key, n /* keybytes */, ivec);
893410ea80bSDavid du Colombier }
894410ea80bSDavid du Colombier
895410ea80bSDavid du Colombier static int
aesctrcipher(Espcb * ecb,uchar * p,int n)896410ea80bSDavid du Colombier aesctrcipher(Espcb *ecb, uchar *p, int n) /* 128-bit blocks */
897410ea80bSDavid du Colombier {
898410ea80bSDavid du Colombier uchar tmp[AESbsize], q[AESbsize];
899410ea80bSDavid du Colombier uchar *pp, *tp, *ip, *eip, *ep;
900410ea80bSDavid du Colombier AESstate *ds = ecb->espstate;
901410ea80bSDavid du Colombier
902410ea80bSDavid du Colombier ep = p + n;
903410ea80bSDavid du Colombier if(ecb->incoming) {
904410ea80bSDavid du Colombier memmove(ds->ivec, p, AESbsize);
905410ea80bSDavid du Colombier p += AESbsize;
906410ea80bSDavid du Colombier while(p < ep){
907410ea80bSDavid du Colombier memmove(tmp, p, AESbsize);
908410ea80bSDavid du Colombier aes_decrypt(ds->dkey, ds->rounds, p, q);
909410ea80bSDavid du Colombier memmove(p, q, AESbsize);
910410ea80bSDavid du Colombier tp = tmp;
911410ea80bSDavid du Colombier ip = ds->ivec;
912410ea80bSDavid du Colombier for(eip = ip + AESbsize; ip < eip; ){
913410ea80bSDavid du Colombier *p++ ^= *ip;
914410ea80bSDavid du Colombier *ip++ = *tp++;
915410ea80bSDavid du Colombier }
916410ea80bSDavid du Colombier }
917410ea80bSDavid du Colombier } else {
918410ea80bSDavid du Colombier memmove(p, ds->ivec, AESbsize);
919410ea80bSDavid du Colombier for(p += AESbsize; p < ep; p += AESbsize){
920410ea80bSDavid du Colombier pp = p;
921410ea80bSDavid du Colombier ip = ds->ivec;
922410ea80bSDavid du Colombier for(eip = ip + AESbsize; ip < eip; )
923410ea80bSDavid du Colombier *pp++ ^= *ip++;
924410ea80bSDavid du Colombier aes_encrypt(ds->ekey, ds->rounds, p, q);
925410ea80bSDavid du Colombier memmove(ds->ivec, q, AESbsize);
926410ea80bSDavid du Colombier memmove(p, q, AESbsize);
927410ea80bSDavid du Colombier }
928410ea80bSDavid du Colombier }
929410ea80bSDavid du Colombier return 1;
930410ea80bSDavid du Colombier }
931410ea80bSDavid du Colombier
932410ea80bSDavid du Colombier static void
aesctrespinit(Espcb * ecb,char * name,uchar * k,unsigned n)933410ea80bSDavid du Colombier aesctrespinit(Espcb *ecb, char *name, uchar *k, unsigned n)
934410ea80bSDavid du Colombier {
935410ea80bSDavid du Colombier uchar key[Aesblk], ivec[Aesblk];
936410ea80bSDavid du Colombier int i;
937410ea80bSDavid du Colombier
938410ea80bSDavid du Colombier n = BITS2BYTES(n);
939410ea80bSDavid du Colombier if(n > Aeskeysz)
940410ea80bSDavid du Colombier n = Aeskeysz;
941410ea80bSDavid du Colombier memset(key, 0, sizeof(key));
942410ea80bSDavid du Colombier memmove(key, k, n);
943410ea80bSDavid du Colombier for(i = 0; i < Aesblk; i++)
944410ea80bSDavid du Colombier ivec[i] = nrand(256);
945410ea80bSDavid du Colombier ecb->espalg = name;
946410ea80bSDavid du Colombier ecb->espblklen = Aesblk;
947410ea80bSDavid du Colombier ecb->espivlen = Aesblk;
948410ea80bSDavid du Colombier ecb->cipher = aesctrcipher;
949410ea80bSDavid du Colombier ecb->espstate = smalloc(sizeof(AESstate));
950410ea80bSDavid du Colombier setupAESstate(ecb->espstate, key, n /* keybytes */, ivec);
951410ea80bSDavid du Colombier }
952410ea80bSDavid du Colombier
953410ea80bSDavid du Colombier
954410ea80bSDavid du Colombier /*
955410ea80bSDavid du Colombier * md5
956410ea80bSDavid du Colombier */
957410ea80bSDavid du Colombier
958410ea80bSDavid du Colombier static void
seanq_hmac_md5(uchar hash[MD5dlen],uchar * t,long tlen,uchar * key,long klen)9597dd7cddfSDavid du Colombier seanq_hmac_md5(uchar hash[MD5dlen], uchar *t, long tlen, uchar *key, long klen)
9607dd7cddfSDavid du Colombier {
9617dd7cddfSDavid du Colombier int i;
962410ea80bSDavid du Colombier uchar ipad[Hmacblksz+1], opad[Hmacblksz+1], innerhash[MD5dlen];
9637dd7cddfSDavid du Colombier DigestState *digest;
9647dd7cddfSDavid du Colombier
965410ea80bSDavid du Colombier memset(ipad, 0x36, Hmacblksz);
966410ea80bSDavid du Colombier memset(opad, 0x5c, Hmacblksz);
967410ea80bSDavid du Colombier ipad[Hmacblksz] = opad[Hmacblksz] = 0;
9687dd7cddfSDavid du Colombier for(i = 0; i < klen; i++){
9697dd7cddfSDavid du Colombier ipad[i] ^= key[i];
9707dd7cddfSDavid du Colombier opad[i] ^= key[i];
9717dd7cddfSDavid du Colombier }
972410ea80bSDavid du Colombier digest = md5(ipad, Hmacblksz, nil, nil);
9737dd7cddfSDavid du Colombier md5(t, tlen, innerhash, digest);
974410ea80bSDavid du Colombier digest = md5(opad, Hmacblksz, nil, nil);
9757dd7cddfSDavid du Colombier md5(innerhash, MD5dlen, hash, digest);
9767dd7cddfSDavid du Colombier }
9777dd7cddfSDavid du Colombier
9787dd7cddfSDavid du Colombier static int
md5auth(Espcb * ecb,uchar * t,int tlen,uchar * auth)9797dd7cddfSDavid du Colombier md5auth(Espcb *ecb, uchar *t, int tlen, uchar *auth)
9807dd7cddfSDavid du Colombier {
9817dd7cddfSDavid du Colombier uchar hash[MD5dlen];
9827dd7cddfSDavid du Colombier int r;
9837dd7cddfSDavid du Colombier
9847dd7cddfSDavid du Colombier memset(hash, 0, MD5dlen);
985410ea80bSDavid du Colombier seanq_hmac_md5(hash, t, tlen, (uchar*)ecb->ahstate, BITS2BYTES(128));
9867dd7cddfSDavid du Colombier r = memcmp(auth, hash, ecb->ahlen) == 0;
9877dd7cddfSDavid du Colombier memmove(auth, hash, ecb->ahlen);
9887dd7cddfSDavid du Colombier return r;
9897dd7cddfSDavid du Colombier }
9907dd7cddfSDavid du Colombier
9917dd7cddfSDavid du Colombier static void
md5ahinit(Espcb * ecb,char * name,uchar * key,unsigned klen)992410ea80bSDavid du Colombier md5ahinit(Espcb *ecb, char *name, uchar *key, unsigned klen)
9937dd7cddfSDavid du Colombier {
9947dd7cddfSDavid du Colombier if(klen != 128)
9957dd7cddfSDavid du Colombier panic("md5ahinit: bad keylen");
996410ea80bSDavid du Colombier klen = BITS2BYTES(klen);
9977dd7cddfSDavid du Colombier ecb->ahalg = name;
9987dd7cddfSDavid du Colombier ecb->ahblklen = 1;
999410ea80bSDavid du Colombier ecb->ahlen = BITS2BYTES(96);
10007dd7cddfSDavid du Colombier ecb->auth = md5auth;
10017dd7cddfSDavid du Colombier ecb->ahstate = smalloc(klen);
10027dd7cddfSDavid du Colombier memmove(ecb->ahstate, key, klen);
10037dd7cddfSDavid du Colombier }
10047dd7cddfSDavid du Colombier
1005410ea80bSDavid du Colombier
1006410ea80bSDavid du Colombier /*
1007410ea80bSDavid du Colombier * des, single and triple
1008410ea80bSDavid du Colombier */
1009410ea80bSDavid du Colombier
10107dd7cddfSDavid du Colombier static int
descipher(Espcb * ecb,uchar * p,int n)10117dd7cddfSDavid du Colombier descipher(Espcb *ecb, uchar *p, int n)
10127dd7cddfSDavid du Colombier {
10137dd7cddfSDavid du Colombier DESstate *ds = ecb->espstate;
10147dd7cddfSDavid du Colombier
10157dd7cddfSDavid du Colombier if(ecb->incoming) {
1016410ea80bSDavid du Colombier memmove(ds->ivec, p, Desblk);
1017410ea80bSDavid du Colombier desCBCdecrypt(p + Desblk, n - Desblk, ds);
10187dd7cddfSDavid du Colombier } else {
1019410ea80bSDavid du Colombier memmove(p, ds->ivec, Desblk);
1020410ea80bSDavid du Colombier desCBCencrypt(p + Desblk, n - Desblk, ds);
10217dd7cddfSDavid du Colombier }
1022410ea80bSDavid du Colombier return 1;
1023410ea80bSDavid du Colombier }
1024410ea80bSDavid du Colombier
1025410ea80bSDavid du Colombier static int
des3cipher(Espcb * ecb,uchar * p,int n)1026410ea80bSDavid du Colombier des3cipher(Espcb *ecb, uchar *p, int n)
1027410ea80bSDavid du Colombier {
1028410ea80bSDavid du Colombier DES3state *ds = ecb->espstate;
1029410ea80bSDavid du Colombier
1030410ea80bSDavid du Colombier if(ecb->incoming) {
1031410ea80bSDavid du Colombier memmove(ds->ivec, p, Desblk);
1032410ea80bSDavid du Colombier des3CBCdecrypt(p + Desblk, n - Desblk, ds);
1033410ea80bSDavid du Colombier } else {
1034410ea80bSDavid du Colombier memmove(p, ds->ivec, Desblk);
1035410ea80bSDavid du Colombier des3CBCencrypt(p + Desblk, n - Desblk, ds);
10367dd7cddfSDavid du Colombier }
10377dd7cddfSDavid du Colombier return 1;
10387dd7cddfSDavid du Colombier }
10397dd7cddfSDavid du Colombier
10407dd7cddfSDavid du Colombier static void
desespinit(Espcb * ecb,char * name,uchar * k,unsigned n)1041410ea80bSDavid du Colombier desespinit(Espcb *ecb, char *name, uchar *k, unsigned n)
10427dd7cddfSDavid du Colombier {
1043410ea80bSDavid du Colombier uchar key[Desblk], ivec[Desblk];
10447dd7cddfSDavid du Colombier int i;
10457dd7cddfSDavid du Colombier
1046410ea80bSDavid du Colombier n = BITS2BYTES(n);
1047410ea80bSDavid du Colombier if(n > Desblk)
1048410ea80bSDavid du Colombier n = Desblk;
10497dd7cddfSDavid du Colombier memset(key, 0, sizeof(key));
10507dd7cddfSDavid du Colombier memmove(key, k, n);
1051410ea80bSDavid du Colombier for(i = 0; i < Desblk; i++)
10527dd7cddfSDavid du Colombier ivec[i] = nrand(256);
10537dd7cddfSDavid du Colombier ecb->espalg = name;
1054410ea80bSDavid du Colombier ecb->espblklen = Desblk;
1055410ea80bSDavid du Colombier ecb->espivlen = Desblk;
1056410ea80bSDavid du Colombier
10577dd7cddfSDavid du Colombier ecb->cipher = descipher;
10587dd7cddfSDavid du Colombier ecb->espstate = smalloc(sizeof(DESstate));
10597dd7cddfSDavid du Colombier setupDESstate(ecb->espstate, key, ivec);
10607dd7cddfSDavid du Colombier }
10617dd7cddfSDavid du Colombier
1062410ea80bSDavid du Colombier static void
des3espinit(Espcb * ecb,char * name,uchar * k,unsigned n)1063410ea80bSDavid du Colombier des3espinit(Espcb *ecb, char *name, uchar *k, unsigned n)
1064410ea80bSDavid du Colombier {
1065410ea80bSDavid du Colombier uchar key[3][Desblk], ivec[Desblk];
1066410ea80bSDavid du Colombier int i;
1067410ea80bSDavid du Colombier
1068410ea80bSDavid du Colombier n = BITS2BYTES(n);
1069410ea80bSDavid du Colombier if(n > Des3keysz)
1070410ea80bSDavid du Colombier n = Des3keysz;
1071410ea80bSDavid du Colombier memset(key, 0, sizeof(key));
1072410ea80bSDavid du Colombier memmove(key, k, n);
1073410ea80bSDavid du Colombier for(i = 0; i < Desblk; i++)
1074410ea80bSDavid du Colombier ivec[i] = nrand(256);
1075410ea80bSDavid du Colombier ecb->espalg = name;
1076410ea80bSDavid du Colombier ecb->espblklen = Desblk;
1077410ea80bSDavid du Colombier ecb->espivlen = Desblk;
1078410ea80bSDavid du Colombier
1079410ea80bSDavid du Colombier ecb->cipher = des3cipher;
1080410ea80bSDavid du Colombier ecb->espstate = smalloc(sizeof(DES3state));
1081410ea80bSDavid du Colombier setupDES3state(ecb->espstate, key, ivec);
1082410ea80bSDavid du Colombier }
1083410ea80bSDavid du Colombier
1084410ea80bSDavid du Colombier
1085410ea80bSDavid du Colombier /*
1086410ea80bSDavid du Colombier * interfacing to devip
1087410ea80bSDavid du Colombier */
1088c168f9f3SDavid du Colombier void
espinit(Fs * fs)1089c168f9f3SDavid du Colombier espinit(Fs *fs)
1090c168f9f3SDavid du Colombier {
1091c168f9f3SDavid du Colombier Proto *esp;
1092c168f9f3SDavid du Colombier
1093c168f9f3SDavid du Colombier esp = smalloc(sizeof(Proto));
1094c168f9f3SDavid du Colombier esp->priv = smalloc(sizeof(Esppriv));
1095c168f9f3SDavid du Colombier esp->name = "esp";
1096c168f9f3SDavid du Colombier esp->connect = espconnect;
1097c168f9f3SDavid du Colombier esp->announce = nil;
1098c168f9f3SDavid du Colombier esp->ctl = espctl;
1099c168f9f3SDavid du Colombier esp->state = espstate;
1100c168f9f3SDavid du Colombier esp->create = espcreate;
1101c168f9f3SDavid du Colombier esp->close = espclose;
1102c168f9f3SDavid du Colombier esp->rcv = espiput;
1103c168f9f3SDavid du Colombier esp->advise = espadvise;
1104c168f9f3SDavid du Colombier esp->stats = espstats;
1105c168f9f3SDavid du Colombier esp->local = esplocal;
1106c168f9f3SDavid du Colombier esp->remote = espremote;
1107c168f9f3SDavid du Colombier esp->ipproto = IP_ESPPROTO;
1108c168f9f3SDavid du Colombier esp->nc = Nchans;
1109c168f9f3SDavid du Colombier esp->ptclsize = sizeof(Espcb);
1110c168f9f3SDavid du Colombier
1111c168f9f3SDavid du Colombier Fsproto(fs, esp);
1112c168f9f3SDavid du Colombier }
1113