/* * Encapsulating Security Payload for IPsec for IPv4, rfc1827. * rfc2104 defines hmac computation. * currently only implements tunnel mode. * TODO: verify aes algorithms; * transport mode (host-to-host) */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h" #include "ip.h"#include "ipv6.h"#include "libsec.h" #define BITS2BYTES(bi) (((bi) + BI2BY - 1) / BI2BY)#define BYTES2BITS(by) ((by) * BI2BY) typedef struct Algorithm Algorithm;typedef struct Esp4hdr Esp4hdr;typedef struct Esp6hdr Esp6hdr;typedef struct Espcb Espcb;typedef struct Esphdr Esphdr;typedef struct Esppriv Esppriv;typedef struct Esptail Esptail;typedef struct Userhdr Userhdr;typedef struct Window Window; enum { Encrypt, Decrypt, IP_ESPPROTO = 50, /* IP v4 and v6 protocol number */ Esp4hdrlen = IP4HDR + 8, Esp6hdrlen = IP6HDR + 8, Esptaillen = 2, /* does not include pad or auth data */ Userhdrlen = 4, /* user-visible header size - if enabled */ Desblk = BITS2BYTES(64), Des3keysz = BITS2BYTES(192), Aesblk = BITS2BYTES(128), Aeskeysz = BITS2BYTES(128),}; struct Esphdr{ uchar espspi[4]; /* Security parameter index */ uchar espseq[4]; /* Sequence number */ uchar payload[];}; /* * tunnel-mode (network-to-network, etc.) layout is: * new IP hdrs | ESP hdr | * enc { orig IP hdrs | TCP/UDP hdr | user data | ESP trailer } | ESP ICV * * transport-mode (host-to-host) layout would be: * orig IP hdrs | ESP hdr | * enc { TCP/UDP hdr | user data | ESP trailer } | ESP ICV */struct Esp4hdr{ /* ipv4 header */ uchar vihl; /* Version and header length */ uchar tos; /* Type of service */ uchar length[2]; /* packet length */ uchar id[2]; /* Identification */ uchar frag[2]; /* Fragment information */ uchar Unused; uchar espproto; /* Protocol */ uchar espplen[2]; /* Header plus data length */ uchar espsrc[4]; /* Ip source */ uchar espdst[4]; /* Ip destination */ Esphdr;}; /* tunnel-mode layout */struct Esp6hdr{ IPV6HDR; Esphdr;}; struct Esptail{ uchar pad; uchar nexthdr;}; /* IP-version-dependent data */typedef struct Versdep Versdep;struct Versdep{ ulong version; ulong iphdrlen; ulong hdrlen; /* iphdrlen + esp hdr len */ ulong spi; ulong seq; uchar laddr[IPaddrlen]; uchar raddr[IPaddrlen];}; /* header as seen by the user */struct Userhdr{ uchar nexthdr; /* next protocol */ uchar unused[3];}; /* MIB II counters; http://www.icir.org/fenner/mibs/htmllint/IPSEC-SA-MON-MIB.html */enum { /* ipsecSaEsp ... */ InUserOctets, InPackets, /* just the payload */ InDecryptErrors, InAuthErrors, InReplayErrors, InPolicyErrors, InPadErrors, InOtherRxErr, OutUserOctets, OutPackets, OutSendErrors, /* non-MIB? */ InSpiUnknown, InSeqFastfwd, InDropQpass, Nstats,}; static char *statnames[Nstats] = {[InUserOctets] "InUserOctets",[InPackets] "InPackets",[InDecryptErrors] "InDecryptErrors",[InAuthErrors] "InAuthErrors",[InReplayErrors] "InReplayErrors",[InPolicyErrors] "InPolicyErrors",[InPadErrors] "InPadErrors",[InOtherRxErr] "InOtherRxErr", [OutUserOctets] "OutUserOctets",[OutPackets] "OutPackets",[OutSendErrors] "OutSendErrors", [InSpiUnknown] "InSpiUnknown",[InSeqFastfwd] "InSeqFastfwd",[InDropQpass] "InDropQpass", }; struct Esppriv{ uvlong stats[Nstats];}; struct Window{ uchar w0set; /* unknown how this is properly set */ ulong w0; uvlong w;}; /* * protocol specific part of Conv */struct Espcb{ int incoming; int header; /* user-level header */ ulong spi; ulong seq; /* last seq sent */ Window; /* for replay attacks */ char *espalg; void *espstate; /* other state for esp */ int espivlen; /* in bytes */ int espblklen; int (*cipher)(Espcb*, uchar *buf, int len); char *ahalg; void *ahstate; /* other state for esp */ int ahlen; /* auth data length in bytes */ int ahblklen; int (*auth)(Espcb*, uchar *buf, int len, uchar *hash); DigestState *ds;}; struct Algorithm{ char *name; int keylen; /* in bits */ void (*init)(Espcb*, char* name, uchar *key, unsigned keylen);}; static Conv* convlookup(Proto *esp, ulong spi);static char *setalg(Espcb *ecb, char **f, int n, Algorithm *alg);static void espkick(void *x); static void nullespinit(Espcb*, char*, uchar *key, unsigned keylen);static void des3espinit(Espcb*, char*, uchar *key, unsigned keylen);static void aescbcespinit(Espcb*, char*, uchar *key, unsigned keylen);static void aesctrespinit(Espcb*, char*, uchar *key, unsigned keylen);static void desespinit(Espcb *ecb, char *name, uchar *k, unsigned n); static void nullahinit(Espcb*, char*, uchar *key, unsigned keylen);static void shaahinit(Espcb*, char*, uchar *key, unsigned keylen);static void aesahinit(Espcb*, char*, uchar *key, unsigned keylen);static void md5ahinit(Espcb*, char*, uchar *key, unsigned keylen); static Algorithm espalg[] ={ "null", 0, nullespinit, "des3_cbc", 192, des3espinit, /* new rfc2451, des-ede3 */ "aes_128_cbc", 128, aescbcespinit, /* new rfc3602 */ "aes_ctr", 128, aesctrespinit, /* new rfc3686 */ "des_56_cbc", 64, desespinit, /* rfc2405, deprecated */ /* rc4 was never required, was used in original bandt */// "rc4_128", 128, rc4espinit, nil, 0, nil,}; static Algorithm ahalg[] ={ "null", 0, nullahinit, "hmac_sha1_96", 128, shaahinit, /* rfc2404 */ "aes_xcbc_mac_96", 128, aesahinit, /* new rfc3566 */ "hmac_md5_96", 128, md5ahinit, /* rfc2403 */ nil, 0, nil,}; voidespstat(Proto *esp, int stat, uint n){ Esppriv *p; p = esp->priv; p->stats[stat] += n;} static intckwindow(Proto *esp, Window *w, ulong seq){ long δ; if(w->w0set == 0){ w->w0set = 1; w->w0 = seq - 1; } δ = seq - w->w0 - 1; if(δ < 0 || w->w & 1ull << 63 - δ) return -1; if(δ > 63){ netlog(esp->f, Logesp, "long drop seq %lud %lud\n", seq, w->w0); espstat(esp, InSeqFastfwd, 1); w->w <<= δ - 32; w->w0 += δ - 32; δ = 32; } w->w |= 1ull<<63 - δ; while(w->w & 1ull<<63 || δ >= 32 && δ <= 63){ w->w0++; w->w <<= 1; δ--; } return 0;} static char*espconnect(Conv *c, char **argv, int argc){ char *p, *pp, *e = nil; ulong spi; Espcb *ecb = (Espcb*)c->ptcl; switch(argc) { default: e = "bad args to connect"; break; case 2: p = strchr(argv[1], '!'); if(p == nil){ e = "malformed address"; break; } *p++ = 0; if (parseip(c->raddr, argv[1]) == -1) { e = Ebadip; break; } findlocalip(c->p->f, c->laddr, c->raddr); ecb->incoming = 0; ecb->seq = 0; if(strcmp(p, "*") == 0) { qlock(c->p); for(;;) { spi = nrand(1<<16) + 256; if(convlookup(c->p, spi) == nil) break; } qunlock(c->p); ecb->spi = spi; ecb->incoming = 1; qhangup(c->wq, nil); } else { spi = strtoul(p, &pp, 10); if(pp == p) { e = "malformed address"; break; } ecb->spi = spi; qhangup(c->rq, nil); } nullespinit(ecb, "null", nil, 0); nullahinit(ecb, "null", nil, 0); } Fsconnected(c, e); return e;} static intespstate(Conv *c, char *state, int n){ return snprint(state, n, "%s", c->inuse?"Open\n":"Closed\n");} static voidespcreate(Conv *c){ c->rq = qopen(64*1024, Qmsg, 0, 0); c->wq = qopen(64*1024, Qkick, espkick, c);} static voidespclose(Conv *c){ Espcb *ecb; qclose(c->rq); qclose(c->wq); qclose(c->eq); ipmove(c->laddr, IPnoaddr); ipmove(c->raddr, IPnoaddr); ecb = (Espcb*)c->ptcl; free(ecb->espstate); free(ecb->ahstate); memset(ecb, 0, sizeof(Espcb));} static intconvipvers(Conv *c){ if((memcmp(c->raddr, v4prefix, IPv4off) == 0 && memcmp(c->laddr, v4prefix, IPv4off) == 0) || ipcmp(c->raddr, IPnoaddr) == 0) return V4; else return V6;} static intpktipvers(Fs *f, Block **bpp){ if (*bpp == nil || BLEN(*bpp) == 0) { /* get enough to identify the IP version */ *bpp = pullupblock(*bpp, IP4HDR); if(*bpp == nil) { netlog(f, Logesp, "esp: short packet\n"); return 0; } } return (((Esp4hdr*)(*bpp)->rp)->vihl & 0xf0) == IP_VER4? V4: V6;} static voidgetverslens(int version, Versdep *vp){ vp->version = version; switch(vp->version) { case V4: vp->iphdrlen = IP4HDR; vp->hdrlen = Esp4hdrlen; break; case V6: vp->iphdrlen = IP6HDR; vp->hdrlen = Esp6hdrlen; break; default: panic("esp: getverslens version %d wrong", version); }} static voidgetpktspiaddrs(uchar *pkt, Versdep *vp){ Esp4hdr *eh4; Esp6hdr *eh6; switch(vp->version) { case V4: eh4 = (Esp4hdr*)pkt; v4tov6(vp->raddr, eh4->espsrc); v4tov6(vp->laddr, eh4->espdst); vp->spi = nhgetl(eh4->espspi); vp->seq = nhgetl(eh4->espseq); break; case V6: eh6 = (Esp6hdr*)pkt; ipmove(vp->raddr, eh6->src); ipmove(vp->laddr, eh6->dst); vp->spi = nhgetl(eh6->espspi); vp->seq = nhgetl(eh6->espseq); break; default: panic("esp: getpktspiaddrs vp->version %ld wrong", vp->version); }} /* * encapsulate next IP packet on x's write queue in IP/ESP packet * and initiate output of the result. */static voidespkick(void *x){ int nexthdr, payload, pad, align, ulen; uchar *auth; Block *bp; Conv *c = x; Esp4hdr *eh4; Esp6hdr *eh6; Espcb *ecb; Esptail *et; Userhdr *uh; Versdep vers; getverslens(convipvers(c), &vers); bp = qget(c->wq); if(bp == nil) return; qlock(c); ecb = c->ptcl; if(ecb->header) { /* make sure the message has a User header */ bp = pullupblock(bp, Userhdrlen); if(bp == nil) { qunlock(c); return; } uh = (Userhdr*)bp->rp; nexthdr = uh->nexthdr; bp->rp += Userhdrlen; } else { nexthdr = 0; /* what should this be? */ } ulen = BLEN(bp); payload = ulen + ecb->espivlen; /* Make space to fit ip header */ bp = padblock(bp, vers.hdrlen + ecb->espivlen); getpktspiaddrs(bp->rp, &vers); align = 4; if(ecb->espblklen > align) align = ecb->espblklen; if(align % ecb->ahblklen != 0) panic("espkick: ahblklen is important after all"); pad = (align-1) - (payload + Esptaillen-1)%align; /* * Make space for tail * this is done by calling padblock with a negative size * Padblock does not change bp->wp! */ bp = padblock(bp, -(pad+Esptaillen+ecb->ahlen)); bp->wp += pad+Esptaillen+ecb->ahlen; et = (Esptail*)(bp->rp + vers.hdrlen + payload + pad); /* fill in tail */ et->pad = pad; et->nexthdr = nexthdr; /* encrypt the payload */ ecb->cipher(ecb, bp->rp + vers.hdrlen, payload + pad + Esptaillen);Lines 1–500 of 1232. Load more
/* * Encapsulating Security Payload for IPsec for IPv4, rfc1827. * rfc2104 defines hmac computation. * currently only implements tunnel mode. * TODO: verify aes algorithms; * transport mode (host-to-host) */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "ip.h" #include "ipv6.h" #include "libsec.h" #define BITS2BYTES(bi) (((bi) + BI2BY - 1) / BI2BY) #define BYTES2BITS(by) ((by) * BI2BY) typedef struct Algorithm Algorithm; typedef struct Esp4hdr Esp4hdr; typedef struct Esp6hdr Esp6hdr; typedef struct Espcb Espcb; typedef struct Esphdr Esphdr; typedef struct Esppriv Esppriv; typedef struct Esptail Esptail; typedef struct Userhdr Userhdr; typedef struct Window Window; enum { Encrypt, Decrypt, IP_ESPPROTO = 50, /* IP v4 and v6 protocol number */ Esp4hdrlen = IP4HDR + 8, Esp6hdrlen = IP6HDR + 8, Esptaillen = 2, /* does not include pad or auth data */ Userhdrlen = 4, /* user-visible header size - if enabled */ Desblk = BITS2BYTES(64), Des3keysz = BITS2BYTES(192), Aesblk = BITS2BYTES(128), Aeskeysz = BITS2BYTES(128), }; struct Esphdr { uchar espspi[4]; /* Security parameter index */ uchar espseq[4]; /* Sequence number */ uchar payload[]; }; /* * tunnel-mode (network-to-network, etc.) layout is: * new IP hdrs | ESP hdr | * enc { orig IP hdrs | TCP/UDP hdr | user data | ESP trailer } | ESP ICV * * transport-mode (host-to-host) layout would be: * orig IP hdrs | ESP hdr | * enc { TCP/UDP hdr | user data | ESP trailer } | ESP ICV */ struct Esp4hdr { /* ipv4 header */ uchar vihl; /* Version and header length */ uchar tos; /* Type of service */ uchar length[2]; /* packet length */ uchar id[2]; /* Identification */ uchar frag[2]; /* Fragment information */ uchar Unused; uchar espproto; /* Protocol */ uchar espplen[2]; /* Header plus data length */ uchar espsrc[4]; /* Ip source */ uchar espdst[4]; /* Ip destination */ Esphdr; }; /* tunnel-mode layout */ struct Esp6hdr { IPV6HDR; Esphdr; }; struct Esptail { uchar pad; uchar nexthdr; }; /* IP-version-dependent data */ typedef struct Versdep Versdep; struct Versdep { ulong version; ulong iphdrlen; ulong hdrlen; /* iphdrlen + esp hdr len */ ulong spi; ulong seq; uchar laddr[IPaddrlen]; uchar raddr[IPaddrlen]; }; /* header as seen by the user */ struct Userhdr { uchar nexthdr; /* next protocol */ uchar unused[3]; }; /* MIB II counters; http://www.icir.org/fenner/mibs/htmllint/IPSEC-SA-MON-MIB.html */ enum { /* ipsecSaEsp ... */ InUserOctets, InPackets, /* just the payload */ InDecryptErrors, InAuthErrors, InReplayErrors, InPolicyErrors, InPadErrors, InOtherRxErr, OutUserOctets, OutPackets, OutSendErrors, /* non-MIB? */ InSpiUnknown, InSeqFastfwd, InDropQpass, Nstats, }; static char *statnames[Nstats] = { [InUserOctets] "InUserOctets", [InPackets] "InPackets", [InDecryptErrors] "InDecryptErrors", [InAuthErrors] "InAuthErrors", [InReplayErrors] "InReplayErrors", [InPolicyErrors] "InPolicyErrors", [InPadErrors] "InPadErrors", [InOtherRxErr] "InOtherRxErr", [OutUserOctets] "OutUserOctets", [OutPackets] "OutPackets", [OutSendErrors] "OutSendErrors", [InSpiUnknown] "InSpiUnknown", [InSeqFastfwd] "InSeqFastfwd", [InDropQpass] "InDropQpass", }; struct Esppriv { uvlong stats[Nstats]; }; struct Window { uchar w0set; /* unknown how this is properly set */ ulong w0; uvlong w; }; /* * protocol specific part of Conv */ struct Espcb { int incoming; int header; /* user-level header */ ulong spi; ulong seq; /* last seq sent */ Window; /* for replay attacks */ char *espalg; void *espstate; /* other state for esp */ int espivlen; /* in bytes */ int espblklen; int (*cipher)(Espcb*, uchar *buf, int len); char *ahalg; void *ahstate; /* other state for esp */ int ahlen; /* auth data length in bytes */ int ahblklen; int (*auth)(Espcb*, uchar *buf, int len, uchar *hash); DigestState *ds; }; struct Algorithm { char *name; int keylen; /* in bits */ void (*init)(Espcb*, char* name, uchar *key, unsigned keylen); }; static Conv* convlookup(Proto *esp, ulong spi); static char *setalg(Espcb *ecb, char **f, int n, Algorithm *alg); static void espkick(void *x); static void nullespinit(Espcb*, char*, uchar *key, unsigned keylen); static void des3espinit(Espcb*, char*, uchar *key, unsigned keylen); static void aescbcespinit(Espcb*, char*, uchar *key, unsigned keylen); static void aesctrespinit(Espcb*, char*, uchar *key, unsigned keylen); static void desespinit(Espcb *ecb, char *name, uchar *k, unsigned n); static void nullahinit(Espcb*, char*, uchar *key, unsigned keylen); static void shaahinit(Espcb*, char*, uchar *key, unsigned keylen); static void aesahinit(Espcb*, char*, uchar *key, unsigned keylen); static void md5ahinit(Espcb*, char*, uchar *key, unsigned keylen); static Algorithm espalg[] = { "null", 0, nullespinit, "des3_cbc", 192, des3espinit, /* new rfc2451, des-ede3 */ "aes_128_cbc", 128, aescbcespinit, /* new rfc3602 */ "aes_ctr", 128, aesctrespinit, /* new rfc3686 */ "des_56_cbc", 64, desespinit, /* rfc2405, deprecated */ /* rc4 was never required, was used in original bandt */ // "rc4_128", 128, rc4espinit, nil, 0, nil, }; static Algorithm ahalg[] = { "null", 0, nullahinit, "hmac_sha1_96", 128, shaahinit, /* rfc2404 */ "aes_xcbc_mac_96", 128, aesahinit, /* new rfc3566 */ "hmac_md5_96", 128, md5ahinit, /* rfc2403 */ nil, 0, nil, }; void espstat(Proto *esp, int stat, uint n) { Esppriv *p; p = esp->priv; p->stats[stat] += n; } static int ckwindow(Proto *esp, Window *w, ulong seq) { long δ; if(w->w0set == 0){ w->w0set = 1; w->w0 = seq - 1; } δ = seq - w->w0 - 1; if(δ < 0 || w->w & 1ull << 63 - δ) return -1; if(δ > 63){ netlog(esp->f, Logesp, "long drop seq %lud %lud\n", seq, w->w0); espstat(esp, InSeqFastfwd, 1); w->w <<= δ - 32; w->w0 += δ - 32; δ = 32; } w->w |= 1ull<<63 - δ; while(w->w & 1ull<<63 || δ >= 32 && δ <= 63){ w->w0++; w->w <<= 1; δ--; } return 0; } static char* espconnect(Conv *c, char **argv, int argc) { char *p, *pp, *e = nil; ulong spi; Espcb *ecb = (Espcb*)c->ptcl; switch(argc) { default: e = "bad args to connect"; break; case 2: p = strchr(argv[1], '!'); if(p == nil){ e = "malformed address"; break; } *p++ = 0; if (parseip(c->raddr, argv[1]) == -1) { e = Ebadip; break; } findlocalip(c->p->f, c->laddr, c->raddr); ecb->incoming = 0; ecb->seq = 0; if(strcmp(p, "*") == 0) { qlock(c->p); for(;;) { spi = nrand(1<<16) + 256; if(convlookup(c->p, spi) == nil) break; } qunlock(c->p); ecb->spi = spi; ecb->incoming = 1; qhangup(c->wq, nil); } else { spi = strtoul(p, &pp, 10); if(pp == p) { e = "malformed address"; break; } ecb->spi = spi; qhangup(c->rq, nil); } nullespinit(ecb, "null", nil, 0); nullahinit(ecb, "null", nil, 0); } Fsconnected(c, e); return e; } static int espstate(Conv *c, char *state, int n) { return snprint(state, n, "%s", c->inuse?"Open\n":"Closed\n"); } static void espcreate(Conv *c) { c->rq = qopen(64*1024, Qmsg, 0, 0); c->wq = qopen(64*1024, Qkick, espkick, c); } static void espclose(Conv *c) { Espcb *ecb; qclose(c->rq); qclose(c->wq); qclose(c->eq); ipmove(c->laddr, IPnoaddr); ipmove(c->raddr, IPnoaddr); ecb = (Espcb*)c->ptcl; free(ecb->espstate); free(ecb->ahstate); memset(ecb, 0, sizeof(Espcb)); } static int convipvers(Conv *c) { if((memcmp(c->raddr, v4prefix, IPv4off) == 0 && memcmp(c->laddr, v4prefix, IPv4off) == 0) || ipcmp(c->raddr, IPnoaddr) == 0) return V4; else return V6; } static int pktipvers(Fs *f, Block **bpp) { if (*bpp == nil || BLEN(*bpp) == 0) { /* get enough to identify the IP version */ *bpp = pullupblock(*bpp, IP4HDR); if(*bpp == nil) { netlog(f, Logesp, "esp: short packet\n"); return 0; } } return (((Esp4hdr*)(*bpp)->rp)->vihl & 0xf0) == IP_VER4? V4: V6; } static void getverslens(int version, Versdep *vp) { vp->version = version; switch(vp->version) { case V4: vp->iphdrlen = IP4HDR; vp->hdrlen = Esp4hdrlen; break; case V6: vp->iphdrlen = IP6HDR; vp->hdrlen = Esp6hdrlen; break; default: panic("esp: getverslens version %d wrong", version); } } static void getpktspiaddrs(uchar *pkt, Versdep *vp) { Esp4hdr *eh4; Esp6hdr *eh6; switch(vp->version) { case V4: eh4 = (Esp4hdr*)pkt; v4tov6(vp->raddr, eh4->espsrc); v4tov6(vp->laddr, eh4->espdst); vp->spi = nhgetl(eh4->espspi); vp->seq = nhgetl(eh4->espseq); break; case V6: eh6 = (Esp6hdr*)pkt; ipmove(vp->raddr, eh6->src); ipmove(vp->laddr, eh6->dst); vp->spi = nhgetl(eh6->espspi); vp->seq = nhgetl(eh6->espseq); break; default: panic("esp: getpktspiaddrs vp->version %ld wrong", vp->version); } } /* * encapsulate next IP packet on x's write queue in IP/ESP packet * and initiate output of the result. */ static void espkick(void *x) { int nexthdr, payload, pad, align, ulen; uchar *auth; Block *bp; Conv *c = x; Esp4hdr *eh4; Esp6hdr *eh6; Espcb *ecb; Esptail *et; Userhdr *uh; Versdep vers; getverslens(convipvers(c), &vers); bp = qget(c->wq); if(bp == nil) return; qlock(c); ecb = c->ptcl; if(ecb->header) { /* make sure the message has a User header */ bp = pullupblock(bp, Userhdrlen); if(bp == nil) { qunlock(c); return; } uh = (Userhdr*)bp->rp; nexthdr = uh->nexthdr; bp->rp += Userhdrlen; } else { nexthdr = 0; /* what should this be? */ } ulen = BLEN(bp); payload = ulen + ecb->espivlen; /* Make space to fit ip header */ bp = padblock(bp, vers.hdrlen + ecb->espivlen); getpktspiaddrs(bp->rp, &vers); align = 4; if(ecb->espblklen > align) align = ecb->espblklen; if(align % ecb->ahblklen != 0) panic("espkick: ahblklen is important after all"); pad = (align-1) - (payload + Esptaillen-1)%align; /* * Make space for tail * this is done by calling padblock with a negative size * Padblock does not change bp->wp! */ bp = padblock(bp, -(pad+Esptaillen+ecb->ahlen)); bp->wp += pad+Esptaillen+ecb->ahlen; et = (Esptail*)(bp->rp + vers.hdrlen + payload + pad); /* fill in tail */ et->pad = pad; et->nexthdr = nexthdr; /* encrypt the payload */ ecb->cipher(ecb, bp->rp + vers.hdrlen, payload + pad + Esptaillen);