]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet6/esp_core.c
xnu-2782.30.5.tar.gz
[apple/xnu.git] / bsd / netinet6 / esp_core.c
index 22ff54d80ae941ee27dc1faa46dbd04f1bf7940b..b5236fdd7db9c6bdb978f1298d68b20c36471fb1 100644 (file)
@@ -1,4 +1,33 @@
-/*     $KAME: esp_core.c,v 1.11 2000/02/22 14:04:15 itojun Exp $       */
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ * 
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*     $FreeBSD: src/sys/netinet6/esp_core.c,v 1.1.2.4 2002/03/26 10:12:29 ume Exp $   */
+/*     $KAME: esp_core.c,v 1.50 2000/11/02 12:27:38 itojun Exp $       */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -30,9 +59,6 @@
  */
 
 #define _IP_VHL
-#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__)
-#include "opt_inet.h"
-#endif
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -46,6 +72,8 @@
 #include <sys/kernel.h>
 #include <sys/syslog.h>
 
+#include <kern/locks.h>
+
 #include <net/if.h>
 #include <net/route.h>
 
 #endif
 
 #include <netinet6/ipsec.h>
+#if INET6
+#include <netinet6/ipsec6.h>
+#endif
 #include <netinet6/ah.h>
+#if INET6
+#include <netinet6/ah6.h>
+#endif
 #include <netinet6/esp.h>
+#if INET6
+#include <netinet6/esp6.h>
+#endif
+#include <netinet6/esp_rijndael.h>
 #include <net/pfkeyv2.h>
 #include <netkey/keydb.h>
-#include <crypto/des/des.h>
-#include <crypto/blowfish/blowfish.h>
-#include <crypto/cast128/cast128.h>
-#include <crypto/rc5/rc5.h>
+#include <netkey/key.h>
+#include <libkern/crypto/des.h>
 
 #include <net/net_osdep.h>
 
-static int esp_null_mature __P((struct secasvar *));
-static int esp_null_ivlen __P((struct secasvar *));
-static int esp_null_decrypt __P((struct mbuf *, size_t,
-       struct secasvar *, struct esp_algorithm *, int));
-static int esp_null_encrypt __P((struct mbuf *, size_t, size_t,
-       struct secasvar *, struct esp_algorithm *, int));
-static int esp_descbc_mature __P((struct secasvar *));
-static int esp_descbc_ivlen __P((struct secasvar *));
-static int esp_descbc_decrypt __P((struct mbuf *, size_t,
-       struct secasvar *, struct esp_algorithm *, int));
-static int esp_descbc_encrypt __P((struct mbuf *, size_t, size_t,
-       struct secasvar *, struct esp_algorithm *, int));
-static int esp_cbc_mature __P((struct secasvar *));
-static int esp_blowfish_cbc_decrypt __P((struct mbuf *, size_t,
-       struct secasvar *, struct esp_algorithm *, int));
-static int esp_blowfish_cbc_encrypt __P((struct mbuf *, size_t,
-       size_t, struct secasvar *, struct esp_algorithm *, int));
-static int esp_blowfish_cbc_ivlen __P((struct secasvar *));
-static int esp_cast128cbc_ivlen __P((struct secasvar *));
-static int esp_cast128cbc_decrypt __P((struct mbuf *, size_t,
-       struct secasvar *, struct esp_algorithm *, int));
-static int esp_cast128cbc_encrypt __P((struct mbuf *, size_t, size_t,
-       struct secasvar *, struct esp_algorithm *, int));
-static int esp_3descbc_ivlen __P((struct secasvar *));
-static int esp_3descbc_decrypt __P((struct mbuf *, size_t,
-       struct secasvar *, struct esp_algorithm *, int));
-static int esp_3descbc_encrypt __P((struct mbuf *, size_t, size_t,
-       struct secasvar *, struct esp_algorithm *, int));
-static int esp_rc5cbc_ivlen __P((struct secasvar *));
-static int esp_rc5cbc_decrypt __P((struct mbuf *, size_t,
-       struct secasvar *, struct esp_algorithm *, int));
-static int esp_rc5cbc_encrypt __P((struct mbuf *, size_t, size_t,
-       struct secasvar *, struct esp_algorithm *, int));
-static void esp_increment_iv __P((struct secasvar *));
-static caddr_t mbuf_find_offset __P((struct mbuf *, size_t, size_t));
-
-/* NOTE: The order depends on SADB_EALG_x in netkey/keyv2.h */
-struct esp_algorithm esp_algorithms[] = {
-       { 0, 0, 0, 0, 0, 0, 0, },
-       { 8, esp_descbc_mature, 64, 64,
-               esp_descbc_ivlen, esp_descbc_decrypt, esp_descbc_encrypt, },
-       { 8, esp_cbc_mature, 192, 192,
-               esp_3descbc_ivlen, esp_3descbc_decrypt, esp_3descbc_encrypt, },
-       { 1, esp_null_mature, 0, 2048,
-               esp_null_ivlen, esp_null_decrypt, esp_null_encrypt, },
-       { 8, esp_cbc_mature, 40, 448,
-               esp_blowfish_cbc_ivlen, esp_blowfish_cbc_decrypt,
-               esp_blowfish_cbc_encrypt, },
-       { 8, esp_cbc_mature, 40, 128,
-               esp_cast128cbc_ivlen, esp_cast128cbc_decrypt,
-               esp_cast128cbc_encrypt, },
-       { 8, esp_cbc_mature, 40, 2040,
-               esp_rc5cbc_ivlen, esp_rc5cbc_decrypt, esp_rc5cbc_encrypt, },
+#include <sys/kdebug.h>
+#define DBG_LAYER_BEG          NETDBG_CODE(DBG_NETIPSEC, 1)
+#define DBG_LAYER_END          NETDBG_CODE(DBG_NETIPSEC, 3)
+#define DBG_FNC_ESPAUTH                NETDBG_CODE(DBG_NETIPSEC, (8 << 8))
+#define MAX_SBUF_LEN            2000
+
+extern lck_mtx_t *sadb_mutex;
+
+static int esp_null_mature(struct secasvar *);
+static int esp_null_decrypt(struct mbuf *, size_t,
+       struct secasvar *, const struct esp_algorithm *, int);
+static int esp_null_encrypt(struct mbuf *, size_t, size_t,
+       struct secasvar *, const struct esp_algorithm *, int);
+static int esp_descbc_mature(struct secasvar *);
+static int esp_descbc_ivlen(const struct esp_algorithm *,
+       struct secasvar *);
+static int esp_des_schedule(const struct esp_algorithm *,
+       struct secasvar *);
+static int esp_des_schedlen(const struct esp_algorithm *);
+static int esp_des_blockdecrypt(const struct esp_algorithm *,
+       struct secasvar *, u_int8_t *, u_int8_t *);
+static int esp_des_blockencrypt(const struct esp_algorithm *,
+       struct secasvar *, u_int8_t *, u_int8_t *);
+static int esp_cbc_mature(struct secasvar *);
+static int esp_3des_schedule(const struct esp_algorithm *,
+       struct secasvar *);
+static int esp_3des_schedlen(const struct esp_algorithm *);
+static int esp_3des_blockdecrypt(const struct esp_algorithm *,
+       struct secasvar *, u_int8_t *, u_int8_t *);
+static int esp_3des_blockencrypt(const struct esp_algorithm *,
+       struct secasvar *, u_int8_t *, u_int8_t *);
+static int esp_common_ivlen(const struct esp_algorithm *,
+       struct secasvar *);
+static int esp_cbc_decrypt(struct mbuf *, size_t,
+       struct secasvar *, const struct esp_algorithm *, int);
+static int esp_cbc_encrypt(struct mbuf *, size_t, size_t,
+       struct secasvar *, const struct esp_algorithm *, int);
+
+#define MAXIVLEN       16
+
+static const struct esp_algorithm des_cbc =
+       { 8, -1, esp_descbc_mature, 64, 64, esp_des_schedlen,
+               "des-cbc",
+               esp_descbc_ivlen, esp_cbc_decrypt,
+               esp_cbc_encrypt, esp_des_schedule,
+               esp_des_blockdecrypt, esp_des_blockencrypt, };
+static const struct esp_algorithm des3_cbc =
+       { 8, 8, esp_cbc_mature, 192, 192, esp_3des_schedlen,
+               "3des-cbc",
+               esp_common_ivlen, esp_cbc_decrypt,
+               esp_cbc_encrypt, esp_3des_schedule,
+               esp_3des_blockdecrypt, esp_3des_blockencrypt, };
+static const struct esp_algorithm null_esp =
+       { 1, 0, esp_null_mature, 0, 2048, 0, "null",
+               esp_common_ivlen, esp_null_decrypt,
+               esp_null_encrypt, NULL, NULL, NULL };
+static const struct esp_algorithm aes_cbc =
+       { 16, 16, esp_cbc_mature, 128, 256, esp_aes_schedlen,
+               "aes-cbc",
+               esp_common_ivlen, esp_cbc_decrypt_aes,
+               esp_cbc_encrypt_aes, esp_aes_schedule,
+               0, 0 };
+
+static const struct esp_algorithm *esp_algorithms[] = {
+       &des_cbc,
+       &des3_cbc,
+       &null_esp,
+       &aes_cbc
 };
 
-/*
- * mbuf assumption: foo_encrypt() assumes that IV part is placed in a single
- * mbuf, not across multiple mbufs.
- */
+const struct esp_algorithm *
+esp_algorithm_lookup(idx)
+       int idx;
+{
+       switch (idx) {
+       case SADB_EALG_DESCBC:
+               return &des_cbc;
+       case SADB_EALG_3DESCBC:
+               return &des3_cbc;
+       case SADB_EALG_NULL:
+               return &null_esp;
+       case SADB_X_EALG_RIJNDAELCBC:
+               return &aes_cbc;
+       default:
+               return NULL;
+       }
+}
 
-static int
-esp_null_mature(sav)
+int
+esp_max_ivlen()
+{
+       int idx;
+       int ivlen;
+
+       ivlen = 0;
+       for (idx = 0; idx < sizeof(esp_algorithms)/sizeof(esp_algorithms[0]);
+            idx++) {
+               if (esp_algorithms[idx]->ivlenval > ivlen)
+                       ivlen = esp_algorithms[idx]->ivlenval;
+       }
+
+       return ivlen;
+}
+
+int
+esp_schedule(algo, sav)
+       const struct esp_algorithm *algo;
        struct secasvar *sav;
 {
-       /* anything is okay */
-       return 0;
+       int error;
+
+       /* check for key length */
+       if (_KEYBITS(sav->key_enc) < algo->keymin ||
+           _KEYBITS(sav->key_enc) > algo->keymax) {
+               ipseclog((LOG_ERR,
+                   "esp_schedule %s: unsupported key length %d: "
+                   "needs %d to %d bits\n", algo->name, _KEYBITS(sav->key_enc),
+                   algo->keymin, algo->keymax));
+               return EINVAL;
+       }
+
+       lck_mtx_lock(sadb_mutex);
+       /* already allocated */
+       if (sav->sched && sav->schedlen != 0) {
+               lck_mtx_unlock(sadb_mutex);
+               return 0;
+       }
+       /* no schedule necessary */
+       if (!algo->schedule || !algo->schedlen) {
+               lck_mtx_unlock(sadb_mutex);
+               return 0;
+       }
+        
+       sav->schedlen = (*algo->schedlen)(algo);
+       if ((signed) sav->schedlen < 0) {
+               lck_mtx_unlock(sadb_mutex);
+               return EINVAL;
+       }
+
+//#### that malloc should be replaced by a saved buffer...
+       sav->sched = _MALLOC(sav->schedlen, M_SECA, M_DONTWAIT);
+       if (!sav->sched) {
+               sav->schedlen = 0;
+               lck_mtx_unlock(sadb_mutex);
+               return ENOBUFS;
+       }
+
+       error = (*algo->schedule)(algo, sav);
+       if (error) {
+               ipseclog((LOG_ERR, "esp_schedule %s: error %d\n",
+                   algo->name, error));
+               bzero(sav->sched, sav->schedlen);
+               FREE(sav->sched, M_SECA);
+               sav->sched = NULL;
+               sav->schedlen = 0;
+       }
+       lck_mtx_unlock(sadb_mutex);
+       return error;
 }
 
 static int
-esp_null_ivlen(sav)
-       struct secasvar *sav;
+esp_null_mature(
+       __unused struct secasvar *sav)
 {
+
+       /* anything is okay */
        return 0;
 }
 
 static int
-esp_null_decrypt(m, off, sav, algo, ivlen)
-       struct mbuf *m;
-       size_t off;             /* offset to ESP header */
-       struct secasvar *sav;
-       struct esp_algorithm *algo;
-       int ivlen;
+esp_null_decrypt(
+       __unused struct mbuf *m,
+       __unused size_t off,            /* offset to ESP header */
+       __unused struct secasvar *sav,
+       __unused const struct esp_algorithm *algo,
+       __unused int ivlen)
 {
+
        return 0; /* do nothing */
 }
 
 static int
-esp_null_encrypt(m, off, plen, sav, algo, ivlen)
-       struct mbuf *m;
-       size_t off;     /* offset to ESP header */
-       size_t plen;    /* payload length (to be encrypted) */
-       struct secasvar *sav;
-       struct esp_algorithm *algo;
-       int ivlen;
+esp_null_encrypt(
+       __unused struct mbuf *m,
+       __unused size_t off,    /* offset to ESP header */
+       __unused size_t plen,   /* payload length (to be encrypted) */
+       __unused struct secasvar *sav,
+       __unused const struct esp_algorithm *algo,
+       __unused int ivlen)
 {
+
        return 0; /* do nothing */
 }
 
@@ -171,7 +303,7 @@ static int
 esp_descbc_mature(sav)
        struct secasvar *sav;
 {
-       struct esp_algorithm *algo;
+       const struct esp_algorithm *algo;
 
        if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B)) {
                ipseclog((LOG_ERR, "esp_cbc_mature: "
@@ -183,9 +315,16 @@ esp_descbc_mature(sav)
                ipseclog((LOG_ERR, "esp_descbc_mature: no key is given.\n"));
                return 1;
        }
-       algo = &esp_algorithms[sav->alg_enc];
-       if (_KEYBITS(sav->key_enc) < algo->keymin
-        || algo->keymax < _KEYBITS(sav->key_enc)) {
+
+       algo = esp_algorithm_lookup(sav->alg_enc);
+       if (!algo) {
+               ipseclog((LOG_ERR,
+                   "esp_descbc_mature: unsupported algorithm.\n"));
+               return 1;
+       }
+
+       if (_KEYBITS(sav->key_enc) < algo->keymin ||
+           _KEYBITS(sav->key_enc) > algo->keymax) {
                ipseclog((LOG_ERR,
                    "esp_descbc_mature: invalid key length %d.\n",
                    _KEYBITS(sav->key_enc)));
@@ -193,7 +332,7 @@ esp_descbc_mature(sav)
        }
 
        /* weak key check */
-       if (des_is_weak_key((C_Block *)_KEYBUF(sav->key_enc))) {
+       if (des_is_weak_key((des_cblock *)_KEYBUF(sav->key_enc))) {
                ipseclog((LOG_ERR,
                    "esp_descbc_mature: weak key was passed.\n"));
                return 1;
@@ -203,241 +342,66 @@ esp_descbc_mature(sav)
 }
 
 static int
-esp_descbc_ivlen(sav)
-       struct secasvar *sav;
+esp_descbc_ivlen(
+       __unused const struct esp_algorithm *algo,
+       struct secasvar *sav)
 {
-       if (sav && (sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B))
-               return 4;
 
-       if (sav && !(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_DERIV))
-               return 4;
-       else
+       if (!sav)
                return 8;
+       if ((sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_IV4B))
+               return 4;
+       if (!(sav->flags & SADB_X_EXT_OLD) && (sav->flags & SADB_X_EXT_DERIV))
+               return 4;
+       return 8;
 }
 
 static int
-esp_descbc_decrypt(m, off, sav, algo, ivlen)
-       struct mbuf *m;
-       size_t off;             /* offset to ESP header */
-       struct secasvar *sav;
-       struct esp_algorithm *algo;
-       int ivlen;
+esp_des_schedlen(
+       __unused const struct esp_algorithm *algo)
 {
-       size_t ivoff = 0;
-       size_t bodyoff = 0;
-       u_int8_t *iv;
-       size_t plen;
-       u_int8_t tiv[8];
-       int derived;
-
-       derived = 0;
-       /* sanity check */
-       if (ivlen != sav->ivlen) {
-               ipseclog((LOG_ERR, "esp_descbc_decrypt: bad ivlen %d/%d\n",
-                   ivlen, sav->ivlen));
-               return EINVAL;
-       }
-       if (_KEYBITS(sav->key_enc) < algo->keymin
-        || algo->keymax < _KEYBITS(sav->key_enc)) {
-               ipseclog((LOG_ERR, "esp_descbc_decrypt: bad keylen %d\n",
-                   _KEYBITS(sav->key_enc)));
-               return EINVAL;
-       }
-
-       if (sav->flags & SADB_X_EXT_OLD) {
-               /* RFC 1827 */
-               ivoff = off + sizeof(struct esp);
-               bodyoff = off + sizeof(struct esp) + ivlen;
-               derived = 0;
-       } else {
-               /* RFC 2406 */
-               if (sav->flags & SADB_X_EXT_DERIV) {
-                       /*
-                        * draft-ietf-ipsec-ciph-des-derived-00.txt
-                        * uses sequence number field as IV field.
-                        * This draft has been deleted, but you can get from
-                        * ftp://ftp.kame.net/pub/internet-drafts/.
-                        */
-                       ivoff = off + sizeof(struct esp);
-                       bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t);
-                       ivlen = sizeof(u_int32_t);
-                       derived = 1;
-               } else {
-                       ivoff = off + sizeof(struct newesp);
-                       bodyoff = off + sizeof(struct newesp) + ivlen;
-                       derived = 0;
-               }
-       }
-       if (ivlen == 4) {
-               iv = &tiv[0];
-               m_copydata(m, ivoff, 4, &tiv[0]);
-               m_copydata(m, ivoff, 4, &tiv[4]);
-               tiv[4] ^= 0xff;
-               tiv[5] ^= 0xff;
-               tiv[6] ^= 0xff;
-               tiv[7] ^= 0xff;
-       } else if (ivlen == 8) {
-               iv = &tiv[0];
-               m_copydata(m, ivoff, 8, &tiv[0]);
-       } else {
-               ipseclog((LOG_ERR, "esp_descbc_decrypt: unsupported ivlen %d\n",
-                   ivlen));
-               return EINVAL;
-       }
-
-       plen = m->m_pkthdr.len;
-       if (plen < bodyoff)
-               panic("esp_descbc_decrypt: too short packet: len=%lu",
-                   (u_long)plen);
-       plen -= bodyoff;
-
-       if (plen % 8) {
-               ipseclog((LOG_ERR, "esp_descbc_decrypt: "
-                   "payload length must be multiple of 8\n"));
-               return EINVAL;
-       }
+       return sizeof(des_ecb_key_schedule);
+}
 
-    {
-       int deserr;
-       des_key_schedule ks;
+static int
+esp_des_schedule(
+       __unused const struct esp_algorithm *algo,
+       struct secasvar *sav)
+{
 
-       deserr = des_key_sched((C_Block *)_KEYBUF(sav->key_enc), ks);
-       if (deserr != 0) {
-               ipseclog((LOG_ERR,
-                   "esp_descbc_decrypt: key error %d\n", deserr));
+       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
+       if (des_ecb_key_sched((des_cblock *)_KEYBUF(sav->key_enc),
+           (des_ecb_key_schedule *)sav->sched))
                return EINVAL;
-       }
-
-       des_cbc_encrypt(m, bodyoff, plen, ks, (C_Block *)iv, DES_DECRYPT);
-
-       /* for safety */
-       bzero(&ks, sizeof(des_key_schedule));
-    }
-
-       /* for safety */
-       bzero(&tiv[0], sizeof(tiv));
+       else
+               return 0;
+}
 
+static int
+esp_des_blockdecrypt(
+       __unused const struct esp_algorithm *algo,
+       struct secasvar *sav,
+       u_int8_t *s,
+       u_int8_t *d)
+{
+       /* assumption: d has a good alignment */
+       bcopy(s, d, sizeof(DES_LONG) * 2);
+       des_ecb_encrypt((des_cblock *)d, (des_cblock *)d,
+           (des_ecb_key_schedule *)sav->sched, DES_DECRYPT);
        return 0;
 }
 
 static int
-esp_descbc_encrypt(m, off, plen, sav, algo, ivlen)
-       struct mbuf *m;
-       size_t off;     /* offset to ESP header */
-       size_t plen;    /* payload length (to be decrypted) */
-       struct secasvar *sav;
-       struct esp_algorithm *algo;
-       int ivlen;
+esp_des_blockencrypt(
+       __unused const struct esp_algorithm *algo,
+       struct secasvar *sav,
+       u_int8_t *s,
+       u_int8_t *d)
 {
-       size_t ivoff = 0;
-       size_t bodyoff = 0;
-       u_int8_t *iv;
-       u_int8_t tiv[8];
-       int derived;
-
-       derived = 0;
-
-       /* sanity check */
-       if (plen % 8) {
-               ipseclog((LOG_ERR, "esp_descbc_encrypt: "
-                   "payload length must be multiple of 8\n"));
-               return EINVAL;
-       }
-       if (sav->ivlen != ivlen) {
-               ipseclog((LOG_ERR, "esp_descbc_encrypt: bad ivlen %d/%d\n",
-                   ivlen, sav->ivlen));
-               return EINVAL;
-       }
-       if (_KEYBITS(sav->key_enc) < algo->keymin
-        || algo->keymax < _KEYBITS(sav->key_enc)) {
-               ipseclog((LOG_ERR, "esp_descbc_encrypt: bad keylen %d\n",
-                   _KEYBITS(sav->key_enc)));
-               return EINVAL;
-       }
-
-       if (sav->flags & SADB_X_EXT_OLD) {
-               /* RFC 1827 */
-               /*
-                * draft-ietf-ipsec-ciph-des-derived-00.txt
-                * uses sequence number field as IV field.
-                * This draft has been deleted, see above.
-                */
-               ivoff = off + sizeof(struct esp);
-               bodyoff = off + sizeof(struct esp) + ivlen;
-               derived = 0;
-       } else {
-               /* RFC 2406 */
-               if (sav->flags & SADB_X_EXT_DERIV) {
-                       /*
-                        * draft-ietf-ipsec-ciph-des-derived-00.txt
-                        * uses sequence number field as IV field.
-                        * This draft has been deleted, see above.
-                        */
-                       ivoff = off + sizeof(struct esp);
-                       bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t);
-                       ivlen = sizeof(u_int32_t);
-                       derived = 1;
-               } else {
-                       ivoff = off + sizeof(struct newesp);
-                       bodyoff = off + sizeof(struct newesp) + ivlen;
-                       derived = 0;
-               }
-       }
-
-       if (m->m_pkthdr.len < bodyoff)
-               panic("assumption failed: mbuf too short");
-       iv = mbuf_find_offset(m, ivoff, ivlen);
-       if (!iv)
-               panic("assumption failed: bad mbuf chain");
-       if (ivlen == 4) {
-               if (!derived) {
-                       bcopy(sav->iv, &tiv[0], 4);
-                       bcopy(sav->iv, &tiv[4], 4);
-                       tiv[4] ^= 0xff;
-                       tiv[5] ^= 0xff;
-                       tiv[6] ^= 0xff;
-                       tiv[7] ^= 0xff;
-                       bcopy(&tiv[0], iv, 4);
-                       iv = &tiv[0];
-               } else {
-                       bcopy(iv, &tiv[0], 4);
-                       bcopy(iv, &tiv[4], 4);
-                       tiv[4] ^= 0xff;
-                       tiv[5] ^= 0xff;
-                       tiv[6] ^= 0xff;
-                       tiv[7] ^= 0xff;
-                       iv = &tiv[0];
-               }
-       } else if (ivlen == 8)
-               bcopy((caddr_t)sav->iv, (caddr_t)iv, ivlen);
-       else {
-               ipseclog((LOG_ERR,
-                   "esp_descbc_encrypt: unsupported ivlen %d\n", ivlen));
-               return EINVAL;
-       }
-
-    {
-       int deserr;
-       des_key_schedule ks;
-
-       deserr = des_key_sched((C_Block *)_KEYBUF(sav->key_enc), ks);
-       if (deserr != 0) {
-               ipseclog((LOG_ERR,
-                   "esp_descbc_encrypt: key error %d\n", deserr));
-               return EINVAL;
-       }
-
-       des_cbc_encrypt(m, bodyoff, plen, ks, (C_Block *)iv, DES_ENCRYPT);
-
-       /* for safety */
-       bzero(&ks, sizeof(des_key_schedule));
-    }
-
-       esp_increment_iv(sav);
-
-       /* for safety */
-       bzero(&tiv[0], sizeof(tiv));
-
+       /* assumption: d has a good alignment */
+       bcopy(s, d, sizeof(DES_LONG) * 2);
+       des_ecb_encrypt((des_cblock *)d, (des_cblock *)d,
+           (des_ecb_key_schedule *)sav->sched, DES_ENCRYPT);
        return 0;
 }
 
@@ -446,7 +410,7 @@ esp_cbc_mature(sav)
        struct secasvar *sav;
 {
        int keylen;
-       struct esp_algorithm *algo;
+       const struct esp_algorithm *algo;
 
        if (sav->flags & SADB_X_EXT_OLD) {
                ipseclog((LOG_ERR,
@@ -460,31 +424,44 @@ esp_cbc_mature(sav)
        }
 
        if (!sav->key_enc) {
+               ipseclog((LOG_ERR, "esp_cbc_mature: no key is given.\n"));
+               return 1;
+       }
+
+       algo = esp_algorithm_lookup(sav->alg_enc);
+       if (!algo) {
                ipseclog((LOG_ERR,
-                   "esp_cbc_mature: no key is given.\n"));
+                   "esp_cbc_mature: unsupported algorithm.\n"));
                return 1;
        }
-       algo = &esp_algorithms[sav->alg_enc];
+
        keylen = sav->key_enc->sadb_key_bits;
        if (keylen < algo->keymin || algo->keymax < keylen) {
-               ipseclog((LOG_ERR, "esp_cbc_mature: invalid key length %d.\n",
-                   sav->key_enc->sadb_key_bits));
+               ipseclog((LOG_ERR,
+                   "esp_cbc_mature %s: invalid key length %d.\n",
+                   algo->name, sav->key_enc->sadb_key_bits));
                return 1;
        }
        switch (sav->alg_enc) {
        case SADB_EALG_3DESCBC:
                /* weak key check */
-               if (des_is_weak_key((C_Block *)_KEYBUF(sav->key_enc))
-                || des_is_weak_key((C_Block *)(_KEYBUF(sav->key_enc) + 8))
-                || des_is_weak_key((C_Block *)(_KEYBUF(sav->key_enc) + 16))) {
+               if (des_is_weak_key((des_cblock *)_KEYBUF(sav->key_enc)) ||
+                   des_is_weak_key((des_cblock *)(_KEYBUF(sav->key_enc) + 8)) ||
+                   des_is_weak_key((des_cblock *)(_KEYBUF(sav->key_enc) + 16))) {
                        ipseclog((LOG_ERR,
-                           "esp_cbc_mature: weak key was passed.\n"));
+                           "esp_cbc_mature %s: weak key was passed.\n",
+                           algo->name));
                        return 1;
                }
                break;
-       case SADB_EALG_BLOWFISHCBC:
-       case SADB_EALG_CAST128CBC:
-       case SADB_EALG_RC5CBC:
+       case SADB_X_EALG_RIJNDAELCBC:
+               /* allows specific key sizes only */
+               if (!(keylen == 128 || keylen == 192 || keylen == 256)) {
+                       ipseclog((LOG_ERR,
+                           "esp_cbc_mature %s: invalid key length %d.\n",
+                           algo->name, keylen));
+                       return 1;
+               }
                break;
        }
 
@@ -492,692 +469,526 @@ esp_cbc_mature(sav)
 }
 
 static int
-esp_blowfish_cbc_decrypt(m, off, sav, algo, ivlen)
-       struct mbuf *m;
-       size_t off;             /* offset to ESP header */
-       struct secasvar *sav;
-       struct esp_algorithm *algo;
-       int ivlen;
+esp_3des_schedlen(
+       __unused const struct esp_algorithm *algo)
 {
-       size_t ivoff;
-       size_t bodyoff;
-       u_int8_t *iv;
-       u_int8_t tiv[8];
-       size_t plen;
-       static BF_KEY key;      /* made static to avoid kernel stack overflow */
-       int s;
-
-       /* sanity check */
-       if (sav->ivlen != ivlen) {
-               ipseclog((LOG_ERR,
-                   "esp_blowfish_cbc_decrypt: bad ivlen %d/%d\n",
-                   ivlen, sav->ivlen));
-               return EINVAL;
-       }
-       if (_KEYBITS(sav->key_enc) < algo->keymin
-        || algo->keymax < _KEYBITS(sav->key_enc)) {
-               ipseclog((LOG_ERR,
-                   "esp_blowfish_cbc_decrypt: unsupported key length %d: "
-                   "need %d to %d bits\n", _KEYBITS(sav->key_enc),
-                   algo->keymin, algo->keymax));
-               return EINVAL;
-       }
-       if (sav->flags & SADB_X_EXT_OLD) {
-               ipseclog((LOG_ERR,
-                   "esp_blowfish_cbc_decrypt: unsupported ESP version\n"));
-               return EINVAL;
-       }
-       if (ivlen != 8) {
-               ipseclog((LOG_ERR,
-                   "esp_blowfish_cbc_decrypt: unsupported ivlen %d\n", ivlen));
-               return EINVAL;
-       }
 
-       ivoff = off + sizeof(struct newesp);
-       bodyoff = off + sizeof(struct newesp) + ivlen;
-       iv = &tiv[0];
-       m_copydata(m, ivoff, 8, &tiv[0]);
+       return sizeof(des3_ecb_key_schedule);
+}
 
-       plen = m->m_pkthdr.len;
-       if (plen < bodyoff)
-               panic("esp_blowfish_cbc_decrypt: too short packet: len=%lu",
-                   (u_long)plen);
-       plen -= bodyoff;
+static int
+esp_3des_schedule(
+       __unused const struct esp_algorithm *algo,
+       struct secasvar *sav)
+{
+       lck_mtx_assert(sadb_mutex, LCK_MTX_ASSERT_OWNED);
 
-       if (plen % 8) {
-               ipseclog((LOG_ERR, "esp_blowfish_cbc_decrypt: "
-                       "payload length must be multiple of 8\n"));
+       if (des3_ecb_key_sched((des_cblock *)_KEYBUF(sav->key_enc),
+           (des3_ecb_key_schedule *)sav->sched))
                return EINVAL;
-       }
-
-#if __NetBSD__
-       s = splsoftnet();       /* XXX correct? */
-#else
-       s = splnet();   /* XXX correct? */
-#endif
-
-       BF_set_key(&key, _KEYBITS(sav->key_enc) / 8, _KEYBUF(sav->key_enc));
-       BF_cbc_encrypt_m(m, bodyoff, plen, &key, iv, BF_DECRYPT);
-
-       /* for safety */
-       bzero(&key, sizeof(BF_KEY));
-
-       splx(s);
-
-       /* for safety */
-       bzero(&tiv[0], sizeof(tiv));
-
-       return 0;
+       else
+               return 0;
 }
 
 static int
-esp_blowfish_cbc_encrypt(m, off, plen, sav, algo, ivlen)
-       struct mbuf *m;
-       size_t off;     /* offset to ESP header */
-       size_t plen;    /* payload length (to be decrypted) */
-       struct secasvar *sav;
-       struct esp_algorithm *algo;
-       int ivlen;
+esp_3des_blockdecrypt(
+       __unused const struct esp_algorithm *algo,
+       struct secasvar *sav,
+       u_int8_t *s,
+       u_int8_t *d)
 {
-       size_t ivoff;
-       size_t bodyoff;
-       u_int8_t *iv;
-       static BF_KEY key;      /* made static to avoid kernel stack overflow */
-       int s;
-
-       /* sanity check */
-       if (plen % 8) {
-               ipseclog((LOG_ERR, "esp_blowfish_cbc_encrypt: "
-                   "payload length must be multiple of 8\n"));
-               return EINVAL;
-       }
-       if (sav->ivlen != ivlen) {
-               ipseclog((LOG_ERR,
-                   "esp_blowfish_cbc_encrypt: bad ivlen %d/%d\n",
-                   ivlen, sav->ivlen));
-               return EINVAL;
-       }
-       if (_KEYBITS(sav->key_enc) < algo->keymin
-        || algo->keymax < _KEYBITS(sav->key_enc)) {
-               ipseclog((LOG_ERR,
-                   "esp_blowfish_cbc_encrypt: unsupported key length %d: "
-                   "need %d to %d bits\n", _KEYBITS(sav->key_enc),
-                   algo->keymin, algo->keymax));
-               return EINVAL;
-       }
-       if (sav->flags & SADB_X_EXT_OLD) {
-               ipseclog((LOG_ERR,
-                   "esp_blowfish_cbc_encrypt: unsupported ESP version\n"));
-               return EINVAL;
-       }
-       if (ivlen != 8) {
-               ipseclog((LOG_ERR,
-                   "esp_blowfish_cbc_encrypt: unsupported ivlen %d\n", ivlen));
-               return EINVAL;
-       }
-
-       ivoff = off + sizeof(struct newesp);
-       bodyoff = off + sizeof(struct newesp) + ivlen;
-
-       if (m->m_pkthdr.len < bodyoff)
-               panic("assumption failed: mbuf too short");
-       iv = mbuf_find_offset(m, ivoff, ivlen);
-       if (!iv)
-               panic("assumption failed: bad mbuf chain");
-
-       bcopy((caddr_t)sav->iv, (caddr_t)iv, ivlen);
-
-#if __NetBSD__
-       s = splsoftnet();       /* XXX correct? */
-#else
-       s = splnet();   /* XXX correct? */
-#endif
-
-       BF_set_key(&key, _KEYBITS(sav->key_enc) / 8, _KEYBUF(sav->key_enc));
-       BF_cbc_encrypt_m(m, bodyoff, plen, &key, iv, BF_ENCRYPT);
-
-       /* for safety */
-       bzero(&key, sizeof(BF_KEY));
-
-       splx(s);
-
-       esp_increment_iv(sav);
-
+       /* assumption: d has a good alignment */
+       bcopy(s, d, sizeof(DES_LONG) * 2);
+       des3_ecb_encrypt((des_cblock *)d, (des_cblock *)d,
+                        (des3_ecb_key_schedule *)sav->sched, DES_DECRYPT);
        return 0;
 }
 
 static int
-esp_blowfish_cbc_ivlen(sav)
-       struct secasvar *sav;
+esp_3des_blockencrypt(
+       __unused const struct esp_algorithm *algo,
+       struct secasvar *sav,
+       u_int8_t *s,
+       u_int8_t *d)
 {
-       return 8;
+       /* assumption: d has a good alignment */
+       bcopy(s, d, sizeof(DES_LONG) * 2);
+       des3_ecb_encrypt((des_cblock *)d, (des_cblock *)d,
+                        (des3_ecb_key_schedule *)sav->sched, DES_ENCRYPT);
+       return 0;
 }
 
 static int
-esp_cast128cbc_ivlen(sav)
-       struct secasvar *sav;
+esp_common_ivlen(
+       const struct esp_algorithm *algo,
+       __unused struct secasvar *sav)
 {
-       return 8;
+
+       if (!algo)
+               panic("esp_common_ivlen: unknown algorithm");
+       return algo->ivlenval;
 }
 
 static int
-esp_cast128cbc_decrypt(m, off, sav, algo, ivlen)
+esp_cbc_decrypt(m, off, sav, algo, ivlen)
        struct mbuf *m;
        size_t off;
        struct secasvar *sav;
-       struct esp_algorithm *algo;
+       const struct esp_algorithm *algo;
        int ivlen;
 {
-       size_t ivoff;
-       size_t bodyoff;
-       u_int8_t iv[8];
-       size_t plen;
-
-       /* sanity check */
-       if (ivlen != sav->ivlen) {
-               ipseclog((LOG_ERR, "esp_cast128cbc_decrypt: bad ivlen %d/%d\n",
-                   ivlen, sav->ivlen));
-               return EINVAL;
-       }
-       if (_KEYBITS(sav->key_enc) < algo->keymin
-        || _KEYBITS(sav->key_enc) > algo->keymax) {
-               ipseclog((LOG_ERR,
-                   "esp_cast128cbc_decrypt: unsupported key length %d: "
-                   "need %d to %d bits\n", _KEYBITS(sav->key_enc),
-                   algo->keymin, algo->keymax));
-               return EINVAL;
-       }
-       if (sav->flags & SADB_X_EXT_OLD) {
-               ipseclog((LOG_ERR,
-                   "esp_cast128cbc_decrypt: unsupported ESP version\n"));
-               return EINVAL;
-       }
-       if (ivlen != 8) {
-               ipseclog((LOG_ERR,
-                   "esp_cast128cbc_decrypt: unsupported ivlen %d\n", ivlen));
-               return EINVAL;
-       }
-
-       ivoff = off + sizeof(struct newesp);
-       bodyoff = off + sizeof(struct newesp) + ivlen;
-
-       /* copy mbuf's IV into iv */
-       m_copydata(m, ivoff, 8, iv);
-
-       plen = m->m_pkthdr.len;
-       if (plen < bodyoff) {
-               panic("esp_cast128cbc_decrypt: too short packet: len=%lu\n",
-                   (u_long)plen);
-       }
-       plen -= bodyoff;
+       struct mbuf *s;
+       struct mbuf *d, *d0, *dp;
+       int soff, doff; /* offset from the head of chain, to head of this mbuf */
+       int sn, dn;     /* offset from the head of the mbuf, to meat */
+       size_t ivoff, bodyoff;
+       u_int8_t iv[MAXIVLEN] __attribute__((aligned(4))), *ivp;
+       u_int8_t *sbuf = NULL, *sp, *sp_unaligned;
+       u_int8_t *p, *q;
+       struct mbuf *scut;
+       int scutoff;
+       int i, result = 0;
+       int blocklen;
+       int derived;
 
-       if (plen % 8) {
-               ipseclog((LOG_ERR, "esp_cast128cbc_decrypt: "
-                   "payload length must be multiple of 8\n"));
+       if (ivlen != sav->ivlen || ivlen > sizeof(iv)) {
+               ipseclog((LOG_ERR, "esp_cbc_decrypt %s: "
+                   "unsupported ivlen %d\n", algo->name, ivlen));
+               m_freem(m);
                return EINVAL;
        }
 
-       /* decrypt */
-    {
-       u_int8_t key[16];
-       u_int32_t subkey[32];
-
-       bzero(key, sizeof(key));
-       bcopy(_KEYBUF(sav->key_enc), key, _KEYLEN(sav->key_enc));
-
-       set_cast128_subkey(subkey, key);
-       cast128_cbc_process(m, bodyoff, plen, subkey, iv,
-                               _KEYBITS(sav->key_enc) / 8, CAST128_DECRYPT);
-
-       /* for safety */
-       bzero(subkey, sizeof(subkey));
-       bzero(key, sizeof(key));
-    }
-
-       return 0;
-}
+       /* assumes blocklen == padbound */
+       blocklen = algo->padbound;
 
-static int
-esp_cast128cbc_encrypt(m, off, plen, sav, algo, ivlen)
-       struct mbuf *m;
-       size_t off;
-       size_t plen;
-       struct secasvar *sav;
-       struct esp_algorithm *algo;
-       int ivlen;
-{
-       size_t ivoff;
-       size_t bodyoff;
-       u_int8_t *iv;
-
-       /* sanity check */
-       if (plen % 8) {
-               ipseclog((LOG_ERR, "esp_cast128cbc_encrypt: "
-                   "payload length must be multiple of 8\n"));
-               return EINVAL;
-       }
-       if (sav->ivlen != ivlen) {
-               ipseclog((LOG_ERR, "esp_cast128cbc_encrypt: bad ivlen %d/%d\n",
-                   ivlen, sav->ivlen));
-               return EINVAL;
-       }
-       if (_KEYBITS(sav->key_enc) < algo->keymin
-        || _KEYBITS(sav->key_enc) > algo->keymax) {
-               ipseclog((LOG_ERR,
-                   "esp_cast128cbc_encrypt: unsupported key length %d: "
-                   "needs %d to %d bits\n", _KEYBITS(sav->key_enc),
-                   algo->keymin, algo->keymax));
+#if DIAGNOSTIC
+       if (blocklen > sizeof(iv)) {
+               ipseclog((LOG_ERR, "esp_cbc_decrypt %s: "
+                   "unsupported blocklen %d\n", algo->name, blocklen));
+               m_freem(m);
                return EINVAL;
        }
+#endif
+
        if (sav->flags & SADB_X_EXT_OLD) {
-               ipseclog((LOG_ERR,
-                   "esp_cast128cbc_encrypt: unsupported ESP version\n"));
-               return EINVAL;
-       }
-       if (ivlen != 8) {
-               ipseclog((LOG_ERR,
-                   "esp_cast128cbc_encrypt: unsupported ivlen %d\n", ivlen));
-               return EINVAL;
+               /* RFC 1827 */
+               ivoff = off + sizeof(struct esp);
+               bodyoff = off + sizeof(struct esp) + ivlen;
+               derived = 0;
+       } else {
+               /* RFC 2406 */
+               if (sav->flags & SADB_X_EXT_DERIV) {
+                       /*
+                        * draft-ietf-ipsec-ciph-des-derived-00.txt
+                        * uses sequence number field as IV field.
+                        */
+                       ivoff = off + sizeof(struct esp);
+                       bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t);
+                       ivlen = sizeof(u_int32_t);
+                       derived = 1;
+               } else {
+                       ivoff = off + sizeof(struct newesp);
+                       bodyoff = off + sizeof(struct newesp) + ivlen;
+                       derived = 0;
+               }
        }
 
-       ivoff = off + sizeof(struct newesp);
-       bodyoff = off + sizeof(struct newesp) + ivlen;
-
-       if (m->m_pkthdr.len < bodyoff)
-               panic("assumption failed: mbuf too short");
-       iv = mbuf_find_offset(m, ivoff, ivlen);
-       if (!iv)
-               panic("assumption failed: bad mbuf chain");
-
-       bcopy(sav->iv, iv, ivlen);
-
-       /* encrypt */
-    {
-       u_int8_t key[16];
-       u_int32_t subkey[32];
-
-       bzero(key, sizeof(key));
-       bcopy(_KEYBUF(sav->key_enc), key, _KEYLEN(sav->key_enc));
+       /* grab iv */
+       m_copydata(m, ivoff, ivlen, (caddr_t) iv);
 
-       set_cast128_subkey(subkey, key);
-       cast128_cbc_process(m, bodyoff, plen, subkey, iv,
-                               _KEYBITS(sav->key_enc) / 8, CAST128_ENCRYPT);
-
-       /* for safety */
-       bzero(subkey, sizeof(subkey));
-       bzero(key, sizeof(key));
-    }
-
-       esp_increment_iv(sav);
-
-       return 0;
-}
-
-static int
-esp_3descbc_ivlen(sav)
-       struct secasvar *sav;
-{
-       return 8;
-}
-
-static int
-esp_3descbc_decrypt(m, off, sav, algo, ivlen)
-       struct mbuf *m;
-       size_t off;
-       struct secasvar *sav;
-       struct esp_algorithm *algo;
-       int ivlen;
-{
-       size_t ivoff;
-       size_t bodyoff;
-       u_int8_t *iv;
-       size_t plen;
-       u_int8_t tiv[8];
-
-       /* sanity check */
-       if (ivlen != sav->ivlen) {
-               ipseclog((LOG_ERR, "esp_3descbc_decrypt: bad ivlen %d/%d\n",
-                   ivlen, sav->ivlen));
-               return EINVAL;
-       }
-       if (_KEYBITS(sav->key_enc) < algo->keymin
-        || algo->keymax < _KEYBITS(sav->key_enc)) {
-               ipseclog((LOG_ERR, "esp_3descbc_decrypt: bad keylen %d\n",
-                   _KEYBITS(sav->key_enc)));
-               return EINVAL;
-       }
-       if (sav->flags & SADB_X_EXT_OLD) {
-               ipseclog((LOG_ERR,
-                   "esp_3descbc_decrypt: unsupported ESP version\n"));
-               return EINVAL;
-       }
-       if (ivlen != 8) {
-               ipseclog((LOG_ERR,
-                   "esp_3descbc_decrypt: unsupported ivlen %d\n", ivlen));
+       /* extend iv */
+       if (ivlen == blocklen)
+               ;
+       else if (ivlen == 4 && blocklen == 8) {
+               bcopy(&iv[0], &iv[4], 4);
+               iv[4] ^= 0xff;
+               iv[5] ^= 0xff;
+               iv[6] ^= 0xff;
+               iv[7] ^= 0xff;
+       } else {
+               ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
+                   "unsupported ivlen/blocklen: %d %d\n",
+                   algo->name, ivlen, blocklen));
+               m_freem(m);
                return EINVAL;
        }
 
-       ivoff = off + sizeof(struct newesp);
-       bodyoff = off + sizeof(struct newesp) + ivlen;
-       iv = &tiv[0];
-       m_copydata(m, ivoff, 8, &tiv[0]);
-
-       plen = m->m_pkthdr.len;
-       if (plen < bodyoff)
-               panic("esp_3descbc_decrypt: too short packet: len=%lu",
-                  (u_long)plen);
-
-       plen -= bodyoff;
-
-       if (plen % 8) {
-               ipseclog((LOG_ERR, "esp_3descbc_decrypt: "
-                   "payload length must be multiple of 8\n"));
+       if (m->m_pkthdr.len < bodyoff) {
+               ipseclog((LOG_ERR, "esp_cbc_decrypt %s: bad len %d/%lu\n",
+                   algo->name, m->m_pkthdr.len, (u_int32_t)bodyoff));
+               m_freem(m);
                return EINVAL;
        }
-
-       /* decrypt packet */
-    {
-       int deserr[3];
-       des_key_schedule ks[3];
-
-       deserr[0] = des_key_sched((C_Block *)_KEYBUF(sav->key_enc),ks[0]);
-       deserr[1] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 8), ks[1]);
-       deserr[2] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 16), ks[2]);
-       if ((deserr[0] != 0) || (deserr[1] != 0) || (deserr[2] != 0)) {
-               ipseclog((LOG_ERR, "esp_3descbc_decrypt: key error %d/%d/%d\n",
-                   deserr[0], deserr[1], deserr[2]));
+       if ((m->m_pkthdr.len - bodyoff) % blocklen) {
+               ipseclog((LOG_ERR, "esp_cbc_decrypt %s: "
+                   "payload length must be multiple of %d\n",
+                   algo->name, blocklen));
+               m_freem(m);
                return EINVAL;
        }
 
-       des_3cbc_process(m, bodyoff, plen, ks, (C_Block *)iv, DES_DECRYPT);
+       s = m;
+       d = d0 = dp = NULL;
+       soff = doff = sn = dn = 0;
+       ivp = sp = NULL;
 
-       /* for safety */
-       bzero(ks[0], sizeof(des_key_schedule)*3);
-    }
+       /* skip bodyoff */
+       while (soff < bodyoff) {
+               if (soff + s->m_len > bodyoff) {
+                       sn = bodyoff - soff;
+                       break;
+               }
 
-       /* for safety */
-       bzero(&tiv[0], sizeof(tiv));
+               soff += s->m_len;
+               s = s->m_next;
+       }
+       scut = s;
+       scutoff = sn;
+
+       /* skip over empty mbuf */
+       while (s && s->m_len == 0)
+               s = s->m_next;
+
+       // Allocate blocksized buffer for unaligned or non-contiguous access
+       sbuf = (u_int8_t *)_MALLOC(blocklen, M_SECA, M_DONTWAIT);
+       if (sbuf == NULL)
+               return ENOBUFS;
+       while (soff < m->m_pkthdr.len) {
+               /* source */
+               if (sn + blocklen <= s->m_len) {
+                       /* body is continuous */
+                       sp = mtod(s, u_int8_t *) + sn;
+               } else {
+                       /* body is non-continuous */
+                       m_copydata(s, sn, blocklen, (caddr_t) sbuf);
+                       sp = sbuf;
+               }
 
-       return 0;
-}
+               /* destination */
+               if (!d || dn + blocklen > d->m_len) {
+                       if (d)
+                               dp = d;
+                       MGET(d, M_DONTWAIT, MT_DATA);
+                       i = m->m_pkthdr.len - (soff + sn);
+                       if (d && i > MLEN) {
+                               MCLGET(d, M_DONTWAIT);
+                               if ((d->m_flags & M_EXT) == 0) {
+                                       m_free(d);
+                                       d = NULL;
+                               }
+                       }
+                       if (!d) {
+                               m_freem(m);
+                               if (d0)
+                                       m_freem(d0);
+                               result = ENOBUFS;
+                               goto end;
+                       }
+                       if (!d0)
+                               d0 = d;
+                       if (dp)
+                               dp->m_next = d;
+
+                       // try to make mbuf data aligned
+                       if (!IPSEC_IS_P2ALIGNED(d->m_data)) {
+                               m_adj(d, IPSEC_GET_P2UNALIGNED_OFS(d->m_data));
+                       }
+
+                       d->m_len = 0;
+                       d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen;
+                       if (d->m_len > i)
+                               d->m_len = i;
+                       dn = 0;
+               }
 
-static int
-esp_3descbc_encrypt(m, off, plen, sav, algo, ivlen)
-       struct mbuf *m;
-       size_t off;
-       size_t plen;
-       struct secasvar *sav;
-       struct esp_algorithm *algo;
-       int ivlen;
-{
-       size_t ivoff;
-       size_t bodyoff;
-       u_int8_t *iv;
-
-       /* sanity check */
-       if (plen % 8) {
-               ipseclog((LOG_ERR, "esp_3descbc_encrypt: "
-                   "payload length must be multiple of 8\n"));
-               return EINVAL;
-       }
-       if (sav->ivlen != ivlen) {
-               ipseclog((LOG_ERR, "esp_3descbc_encrypt: bad ivlen %d/%d\n",
-                   ivlen, sav->ivlen));
-               return EINVAL;
-       }
-       if (_KEYBITS(sav->key_enc) < algo->keymin
-        || algo->keymax < _KEYBITS(sav->key_enc)) {
-               ipseclog((LOG_ERR, "esp_3descbc_encrypt: bad keylen %d\n",
-                   _KEYBITS(sav->key_enc)));
-               return EINVAL;
-       }
-       if (sav->flags & SADB_X_EXT_OLD) {
-               ipseclog((LOG_ERR,
-                   "esp_3descbc_encrypt: unsupported ESP version\n"));
-               return EINVAL;
-       }
-       if (ivlen != 8) {
-               ipseclog((LOG_ERR,
-                   "esp_3descbc_encrypt: unsupported ivlen %d\n", ivlen));
-               return EINVAL;
-       }
+               /* decrypt */
+               // check input pointer alignment and use a separate aligned buffer (if sp is unaligned on 4-byte boundary).
+               if (IPSEC_IS_P2ALIGNED(sp)) {
+                       sp_unaligned = NULL;
+               } else {
+                       sp_unaligned = sp;
+                       sp = sbuf;
+                       memcpy(sp, sp_unaligned, blocklen);
+               }
+               // no need to check output pointer alignment
+               (*algo->blockdecrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn);
 
-       ivoff = off + sizeof(struct newesp);
-       bodyoff = off + sizeof(struct newesp) + ivlen;
+               // update unaligned pointers
+               if (!IPSEC_IS_P2ALIGNED(sp_unaligned)) {
+                       sp = sp_unaligned;
+               }
 
-       if (m->m_pkthdr.len < bodyoff)
-               panic("assumption failed: mbuf too short");
-       iv = mbuf_find_offset(m, ivoff, ivlen);
-       if (!iv)
-               panic("assumption failed: bad mbuf chain");
+               /* xor */
+               p = ivp ? ivp : iv;
+               q = mtod(d, u_int8_t *) + dn;
+               for (i = 0; i < blocklen; i++)
+                       q[i] ^= p[i];
 
-       bcopy((caddr_t)sav->iv, (caddr_t)iv, ivlen);
+               /* next iv */
+               if (sp == sbuf) {
+                       bcopy(sbuf, iv, blocklen);
+                       ivp = NULL;
+               } else
+                       ivp = sp;
 
-       /* encrypt packet */
-    {
-       int deserr[3];
-       des_key_schedule ks[3];
+               sn += blocklen;
+               dn += blocklen;
 
-       deserr[0] = des_key_sched((C_Block *)_KEYBUF(sav->key_enc),     ks[0]);
-       deserr[1] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 8), ks[1]);
-       deserr[2] = des_key_sched((C_Block *)(_KEYBUF(sav->key_enc) + 16), ks[2]);
-       if ((deserr[0] != 0) || (deserr[1] != 0) || (deserr[2] != 0)) {
-               ipseclog((LOG_ERR, "esp_3descbc_encrypt: key error %d/%d/%d\n",
-                   deserr[0], deserr[1], deserr[2]));
-               return EINVAL;
+               /* find the next source block */
+               while (s && sn >= s->m_len) {
+                       sn -= s->m_len;
+                       soff += s->m_len;
+                       s = s->m_next;
+               }
        }
 
-       des_3cbc_process(m, bodyoff, plen, ks, (C_Block *)iv, DES_ENCRYPT);
-
-       /* for safety */
-       bzero(ks[0], sizeof(des_key_schedule)*3);
-    }
+       m_freem(scut->m_next);
+       scut->m_len = scutoff;
+       scut->m_next = d0;
 
-       esp_increment_iv(sav);
-
-       return 0;
+       /* just in case */
+       bzero(iv, sizeof(iv));
+       bzero(sbuf, blocklen);
+end:
+       if (sbuf != NULL)
+               FREE(sbuf, M_SECA);
+       return result;
 }
 
 static int
-esp_rc5cbc_ivlen(sav)
-       struct secasvar *sav;
+esp_cbc_encrypt(
+       struct mbuf *m,
+       size_t off,
+       __unused size_t plen,
+       struct secasvar *sav,
+       const struct esp_algorithm *algo,
+       int ivlen)
 {
-       return 8;
-}
+       struct mbuf *s;
+       struct mbuf *d, *d0, *dp;
+       int soff, doff; /* offset from the head of chain, to head of this mbuf */
+       int sn, dn;     /* offset from the head of the mbuf, to meat */
+       size_t ivoff, bodyoff;
+       u_int8_t iv[MAXIVLEN] __attribute__((aligned(4))), *ivp;
+       u_int8_t *sbuf = NULL, *sp, *sp_unaligned;
+       u_int8_t *p, *q;
+       struct mbuf *scut;
+       int scutoff;
+       int i, result = 0;
+       int blocklen;
+       int derived;
 
-static int
-esp_rc5cbc_decrypt(m, off, sav, algo, ivlen)
-       struct mbuf *m;
-       size_t off;
-       struct secasvar *sav;
-       struct esp_algorithm *algo;
-       int ivlen;
-{
-       size_t ivoff;
-       size_t bodyoff;
-       u_int8_t iv[8];
-       size_t plen;
-
-       /* sanity check */
-       if (sav->ivlen != ivlen) {
-               ipseclog((LOG_ERR, "esp_rc5cbc_decrypt: bad ivlen %d/%d\n",
-                   ivlen, sav->ivlen));
-               return EINVAL;
-       }
-       if ((_KEYBITS(sav->key_enc) < 40) || (_KEYBITS(sav->key_enc) > 2040)) {
-               ipseclog((LOG_ERR,
-                   "esp_rc5cbc_decrypt: unsupported key length %d: "
-                   "need 40 to 2040 bit\n", _KEYBITS(sav->key_enc)));
+       if (ivlen != sav->ivlen || ivlen > sizeof(iv)) {
+               ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
+                   "unsupported ivlen %d\n", algo->name, ivlen));
+               m_freem(m);
                return EINVAL;
        }
-       if (sav->flags & SADB_X_EXT_OLD) {
-               ipseclog((LOG_ERR,
-                   "esp_rc5cbc_decrypt: unsupported ESP version\n"));
-               return EINVAL;
-       }
-       if (ivlen != 8) {
-               ipseclog((LOG_ERR, "esp_rc5cbc_decrypt: unsupported ivlen %d\n",
-                   ivlen));
-               return EINVAL;
-       }
-
-       ivoff = off + sizeof(struct newesp);
-       bodyoff = off + sizeof(struct newesp) + ivlen;
 
-       /* copy mbuf's IV into iv */
-       m_copydata(m, ivoff, 8, iv);
+       /* assumes blocklen == padbound */
+       blocklen = algo->padbound;
 
-       plen = m->m_pkthdr.len;
-       if (plen < bodyoff) {
-               panic("esp_rc5cbc_decrypt: too short packet: len=%lu",
-                       (u_long)plen);
-       }
-       plen -= bodyoff;
-
-       if (plen % 8) {
-               ipseclog((LOG_ERR, "esp_rc5cbc_decrypt: "
-                   "payload length must be multiple of 8\n"));
+#if DIAGNOSTIC
+       if (blocklen > sizeof(iv)) {
+               ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
+                   "unsupported blocklen %d\n", algo->name, blocklen));
+               m_freem(m);
                return EINVAL;
        }
+#endif
 
-       /* decrypt */
-    {
-       RC5_WORD e_key[34];
-
-       set_rc5_expandkey(e_key, _KEYBUF(sav->key_enc),
-                       _KEYBITS(sav->key_enc) / 8, 16);
-       rc5_cbc_process(m, bodyoff, plen, e_key, iv, RC5_DECRYPT);
-
-       /* for safety */
-       bzero(e_key, sizeof(e_key));
-    }
-
-       return 0;
-}
-
-static int
-esp_rc5cbc_encrypt(m, off, plen, sav, algo, ivlen)
-       struct mbuf *m;
-       size_t off;
-       size_t plen;
-       struct secasvar *sav;
-       struct esp_algorithm *algo;
-       int ivlen;
-{
-       size_t ivoff;
-       size_t bodyoff;
-       u_int8_t *iv;
-
-       /* sanity check */
-       if (plen % 8) {
-               ipseclog((LOG_ERR, "esp_rc5cbc_encrypt: "
-                   "payload length must be multiple of 8\n"));
-               return EINVAL;
-       }
-       if (sav->ivlen != ivlen) {
-               ipseclog((LOG_ERR, "esp_rc5cbc_encrypt: bad ivlen %d/%d\n",
-                   ivlen, sav->ivlen));
-               return EINVAL;
+       if (sav->flags & SADB_X_EXT_OLD) {
+               /* RFC 1827 */
+               ivoff = off + sizeof(struct esp);
+               bodyoff = off + sizeof(struct esp) + ivlen;
+               derived = 0;
+       } else {
+               /* RFC 2406 */
+               if (sav->flags & SADB_X_EXT_DERIV) {
+                       /*
+                        * draft-ietf-ipsec-ciph-des-derived-00.txt
+                        * uses sequence number field as IV field.
+                        */
+                       ivoff = off + sizeof(struct esp);
+                       bodyoff = off + sizeof(struct esp) + sizeof(u_int32_t);
+                       ivlen = sizeof(u_int32_t);
+                       derived = 1;
+               } else {
+                       ivoff = off + sizeof(struct newesp);
+                       bodyoff = off + sizeof(struct newesp) + ivlen;
+                       derived = 0;
+               }
        }
-       if (_KEYBITS(sav->key_enc) < algo->keymin
-        || _KEYBITS(sav->key_enc) > algo->keymax) {
-               ipseclog((LOG_ERR,
-                   "esp_rc5cbc_encrypt: unsupported key length %d: "
-                   "need %d to %d bits\n", _KEYBITS(sav->key_enc),
-                   algo->keymin, algo->keymax));
+
+       /* put iv into the packet.  if we are in derived mode, use seqno. */
+       if (derived)
+               m_copydata(m, ivoff, ivlen, (caddr_t) iv);
+       else {
+               bcopy(sav->iv, iv, ivlen);
+               /* maybe it is better to overwrite dest, not source */
+               m_copyback(m, ivoff, ivlen, (caddr_t) iv);
+       }
+
+       /* extend iv */
+       if (ivlen == blocklen)
+               ;
+       else if (ivlen == 4 && blocklen == 8) {
+               bcopy(&iv[0], &iv[4], 4);
+               iv[4] ^= 0xff;
+               iv[5] ^= 0xff;
+               iv[6] ^= 0xff;
+               iv[7] ^= 0xff;
+       } else {
+               ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
+                   "unsupported ivlen/blocklen: %d %d\n",
+                   algo->name, ivlen, blocklen));
+               m_freem(m);
                return EINVAL;
        }
-       if (sav->flags & SADB_X_EXT_OLD) {
-               ipseclog((LOG_ERR,
-                   "esp_rc5cbc_encrypt: unsupported ESP version\n"));
+
+       if (m->m_pkthdr.len < bodyoff) {
+               ipseclog((LOG_ERR, "esp_cbc_encrypt %s: bad len %d/%lu\n",
+                   algo->name, m->m_pkthdr.len, (u_int32_t)bodyoff));
+               m_freem(m);
                return EINVAL;
        }
-       if (ivlen != 8) {
-               ipseclog((LOG_ERR, "esp_rc5cbc_encrypt: unsupported ivlen %d\n",
-                   ivlen));
+       if ((m->m_pkthdr.len - bodyoff) % blocklen) {
+               ipseclog((LOG_ERR, "esp_cbc_encrypt %s: "
+                   "payload length must be multiple of %lu\n",
+                   algo->name, (u_int32_t)algo->padbound));
+               m_freem(m);
                return EINVAL;
        }
 
-       ivoff = off + sizeof(struct newesp);
-       bodyoff = off + sizeof(struct newesp) + ivlen;
+       s = m;
+       d = d0 = dp = NULL;
+       soff = doff = sn = dn = 0;
+       ivp = sp = NULL;
 
-       if (m->m_pkthdr.len < bodyoff)
-               panic("assumption failed: mbuf too short");
-       iv = mbuf_find_offset(m, ivoff, ivlen);
-       if (!iv)
-               panic("assumption failed: bad mbuf chain");
+       /* skip bodyoff */
+       while (soff < bodyoff) {
+               if (soff + s->m_len > bodyoff) {
+                       sn = bodyoff - soff;
+                       break;
+               }
 
-       bcopy(sav->iv, iv, ivlen);
+               soff += s->m_len;
+               s = s->m_next;
+       }
+       scut = s;
+       scutoff = sn;
+
+       /* skip over empty mbuf */
+       while (s && s->m_len == 0)
+               s = s->m_next;
+
+       // Allocate blocksized buffer for unaligned or non-contiguous access
+        sbuf = (u_int8_t *)_MALLOC(blocklen, M_SECA, M_DONTWAIT);
+        if (sbuf == NULL)
+                return ENOBUFS;
+       while (soff < m->m_pkthdr.len) {
+               /* source */
+               if (sn + blocklen <= s->m_len) {
+                       /* body is continuous */
+                       sp = mtod(s, u_int8_t *) + sn;
+               } else {
+                       /* body is non-continuous */
+                       m_copydata(s, sn, blocklen, (caddr_t) sbuf);
+                       sp = sbuf;
+               }
 
-       /* encrypt */
-    {
-       RC5_WORD e_key[34];
+               /* destination */
+               if (!d || dn + blocklen > d->m_len) {
+                       if (d)
+                               dp = d;
+                       MGET(d, M_DONTWAIT, MT_DATA);
+                       i = m->m_pkthdr.len - (soff + sn);
+                       if (d && i > MLEN) {
+                               MCLGET(d, M_DONTWAIT);
+                               if ((d->m_flags & M_EXT) == 0) {
+                                       m_free(d);
+                                       d = NULL;
+                               }
+                       }
+                       if (!d) {
+                               m_freem(m);
+                               if (d0)
+                                       m_freem(d0);
+                               result = ENOBUFS;
+                               goto end;
+                       }
+                       if (!d0)
+                               d0 = d;
+                       if (dp)
+                               dp->m_next = d;
+
+                       // try to make mbuf data aligned
+                       if (!IPSEC_IS_P2ALIGNED(d->m_data)) {
+                               m_adj(d, IPSEC_GET_P2UNALIGNED_OFS(d->m_data));
+                       }
+
+                       d->m_len = 0;
+                       d->m_len = (M_TRAILINGSPACE(d) / blocklen) * blocklen;
+                       if (d->m_len > i)
+                               d->m_len = i;
+                       dn = 0;
+               }
 
-       set_rc5_expandkey(e_key, _KEYBUF(sav->key_enc),
-                       _KEYBITS(sav->key_enc) / 8, 16);
-       rc5_cbc_process(m, bodyoff, plen, e_key, iv, RC5_ENCRYPT);
+               /* xor */
+               p = ivp ? ivp : iv;
+               q = sp;
+               for (i = 0; i < blocklen; i++)
+                       q[i] ^= p[i];
 
-       /* for safety */
-       bzero(e_key, sizeof(e_key));
-    }
+               /* encrypt */
+               // check input pointer alignment and use a separate aligned buffer (if sp is not aligned on 4-byte boundary).
+               if (IPSEC_IS_P2ALIGNED(sp)) {
+                       sp_unaligned = NULL;
+               } else {
+                       sp_unaligned = sp;
+                       sp = sbuf;
+                       memcpy(sp, sp_unaligned, blocklen);
+               }
+               // no need to check output pointer alignment
+               (*algo->blockencrypt)(algo, sav, sp, mtod(d, u_int8_t *) + dn);
 
-       esp_increment_iv(sav);
+               // update unaligned pointers
+               if (!IPSEC_IS_P2ALIGNED(sp_unaligned)) {
+                       sp = sp_unaligned;
+               }
 
-       return 0;
-}
+               /* next iv */
+               ivp = mtod(d, u_int8_t *) + dn;
 
-/*
- * increment iv.
- */
-static void
-esp_increment_iv(sav)
-       struct secasvar *sav;
-{
-       u_int8_t *x;
-       u_int8_t y;
-       int i;
-
-#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
-       y = time.tv_sec & 0xff;
-#else
-       y = time_second & 0xff;
-#endif
-       if (!y) y++;
-       x = (u_int8_t *)sav->iv;
-       for (i = 0; i < sav->ivlen; i++) {
-               *x = (*x + y) & 0xff;
-               x++;
-       }
-}
+               sn += blocklen;
+               dn += blocklen;
 
-static caddr_t
-mbuf_find_offset(m, off, len)
-       struct mbuf *m;
-       size_t off;
-       size_t len;
-{
-       struct mbuf *n;
-       size_t cnt;
-
-       if (m->m_pkthdr.len < off || m->m_pkthdr.len < off + len)
-               return (caddr_t)NULL;
-       cnt = 0;
-       for (n = m; n; n = n->m_next) {
-               if (cnt + n->m_len <= off) {
-                       cnt += n->m_len;
-                       continue;
+               /* find the next source block */
+               while (s && sn >= s->m_len) {
+                       sn -= s->m_len;
+                       soff += s->m_len;
+                       s = s->m_next;
                }
-               if (cnt <= off && off < cnt + n->m_len
-                && cnt <= off + len && off + len <= cnt + n->m_len) {
-                       return mtod(n, caddr_t) + off - cnt;
-               } else
-                       return (caddr_t)NULL;
        }
-       return (caddr_t)NULL;
+
+       m_freem(scut->m_next);
+       scut->m_len = scutoff;
+       scut->m_next = d0;
+
+       /* just in case */
+       bzero(iv, sizeof(iv));
+       bzero(sbuf, blocklen);
+
+       key_sa_stir_iv(sav);
+end:
+       if (sbuf != NULL)
+               FREE(sbuf, M_SECA);
+       return result;
 }
 
 /*------------------------------------------------------------*/
 
+/* does not free m0 on error */
 int
 esp_auth(m0, skip, length, sav, sum)
        struct mbuf *m0;
@@ -1189,9 +1000,10 @@ esp_auth(m0, skip, length, sav, sum)
        struct mbuf *m;
        size_t off;
        struct ah_algorithm_state s;
-       u_char sumbuf[AH_MAXSUMSIZE];
-       struct ah_algorithm *algo;
+       u_char sumbuf[AH_MAXSUMSIZE] __attribute__((aligned(4)));
+       const struct ah_algorithm *algo;
        size_t siz;
+       int error;
 
        /* sanity checks */
        if (m0->m_pkthdr.len < skip) {
@@ -1203,34 +1015,40 @@ esp_auth(m0, skip, length, sav, sum)
                    "esp_auth: mbuf length < skip + length\n"));
                return EINVAL;
        }
+
+       KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_START, skip,length,0,0,0);
        /*
         * length of esp part (excluding authentication data) must be 4n,
         * since nexthdr must be at offset 4n+3.
         */
        if (length % 4) {
                ipseclog((LOG_ERR, "esp_auth: length is not multiple of 4\n"));
+               KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 1,0,0,0,0);
                return EINVAL;
        }
        if (!sav) {
                ipseclog((LOG_DEBUG, "esp_auth: NULL SA passed\n"));
+               KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 2,0,0,0,0);
                return EINVAL;
        }
-       if (!sav->alg_auth) {
+       algo = ah_algorithm_lookup(sav->alg_auth);
+       if (!algo) {
                ipseclog((LOG_ERR,
                    "esp_auth: bad ESP auth algorithm passed: %d\n",
                    sav->alg_auth));
+               KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 3,0,0,0,0);
                return EINVAL;
        }
 
        m = m0;
        off = 0;
 
-       algo = &ah_algorithms[sav->alg_auth];
        siz = (((*algo->sumsiz)(sav) + 3) & ~(4 - 1));
        if (sizeof(sumbuf) < siz) {
                ipseclog((LOG_DEBUG,
                    "esp_auth: AH_MAXSUMSIZE is too small: siz=%lu\n",
-                   (u_long)siz));
+                   (u_int32_t)siz));
+               KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 4,0,0,0,0);
                return EINVAL;
        }
 
@@ -1248,24 +1066,28 @@ esp_auth(m0, skip, length, sav, sum)
                }
        }
 
-       (*algo->init)(&s, sav);
+       error = (*algo->init)(&s, sav);
+       if (error) {
+               KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 5,0,0,0,0);
+               return error;
+       }
        while (0 < length) {
                if (!m)
                        panic("mbuf chain?");
 
                if (m->m_len - off < length) {
-                       (*algo->update)(&s, mtod(m, u_char *) + off,
+                       (*algo->update)(&s, (caddr_t)(mtod(m, u_char *) + off),
                                m->m_len - off);
                        length -= m->m_len - off;
                        m = m->m_next;
                        off = 0;
                } else {
-                       (*algo->update)(&s, mtod(m, u_char *) + off, length);
+                       (*algo->update)(&s, (caddr_t)(mtod(m, u_char *) + off), length);
                        break;
                }
        }
-       (*algo->result)(&s, sumbuf);
+       (*algo->result)(&s, (caddr_t) sumbuf, sizeof(sumbuf));
        bcopy(sumbuf, sum, siz);        /*XXX*/
-       
+       KERNEL_DEBUG(DBG_FNC_ESPAUTH | DBG_FUNC_END, 6,0,0,0,0);
        return 0;
 }