aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/crypto/builtin/enc_provider
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2017-07-07 17:03:42 +0000
committerCy Schubert <cy@FreeBSD.org>2017-07-07 17:03:42 +0000
commit33a9b234e7087f573ef08cd7318c6497ba08b439 (patch)
treed0ea40ad3bf5463a3c55795977c71bcb7d781b4b /src/lib/crypto/builtin/enc_provider
downloadsrc-33a9b234e7087f573ef08cd7318c6497ba08b439.tar.gz
src-33a9b234e7087f573ef08cd7318c6497ba08b439.zip
Import MIT KRB5 1.15.1, which will gracefully replace KTH Heimdal.vendor/krb5/1.15.1
The tarball used in this import is the same tarball used in ports/krb5-115 r435378. Obtained from: http://web.mit.edu/kerberos/dist/ Thanks to: pfg (for all your tireless behind-the-scenes effort)
Notes
Notes: svn path=/vendor-crypto/krb5/dist/; revision=320790 svn path=/vendor-crypto/krb5/1.15.1/; revision=320791; tag=vendor/krb5/1.15.1
Diffstat (limited to 'src/lib/crypto/builtin/enc_provider')
-rw-r--r--src/lib/crypto/builtin/enc_provider/Makefile.in45
-rw-r--r--src/lib/crypto/builtin/enc_provider/aes.c406
-rw-r--r--src/lib/crypto/builtin/enc_provider/camellia.c315
-rw-r--r--src/lib/crypto/builtin/enc_provider/deps64
-rw-r--r--src/lib/crypto/builtin/enc_provider/des.c120
-rw-r--r--src/lib/crypto/builtin/enc_provider/des3.c105
-rw-r--r--src/lib/crypto/builtin/enc_provider/rc4.c190
7 files changed, 1245 insertions, 0 deletions
diff --git a/src/lib/crypto/builtin/enc_provider/Makefile.in b/src/lib/crypto/builtin/enc_provider/Makefile.in
new file mode 100644
index 000000000000..4fd3311b4fb1
--- /dev/null
+++ b/src/lib/crypto/builtin/enc_provider/Makefile.in
@@ -0,0 +1,45 @@
+mydir=lib$(S)crypto$(S)builtin$(S)enc_provider
+BUILDTOP=$(REL)..$(S)..$(S)..$(S)..
+LOCALINCLUDES = -I$(srcdir)/../des \
+ -I$(srcdir)/../aes \
+ -I$(srcdir)/../camellia \
+ -I$(srcdir)/../../krb \
+ -I$(srcdir)/..
+
+##DOS##BUILDTOP = ..\..\..\..
+##DOS##PREFIXDIR = builtin\enc_provider
+##DOS##OBJFILE = ..\..\$(OUTPRE)enc_provider.lst
+
+STLIBOBJS= \
+ des.o \
+ des3.o \
+ rc4.o \
+ aes.o \
+ camellia.o
+
+OBJS= \
+ $(OUTPRE)des.$(OBJEXT) \
+ $(OUTPRE)des3.$(OBJEXT) \
+ $(OUTPRE)aes.$(OBJEXT) \
+ $(OUTPRE)camellia.$(OBJEXT) \
+ $(OUTPRE)rc4.$(OBJEXT)
+
+SRCS= \
+ $(srcdir)/des.c \
+ $(srcdir)/des3.c \
+ $(srcdir)/aes.c \
+ $(srcdir)/camellia.c \
+ $(srcdir)/rc4.c
+
+##DOS##LIBOBJS = $(OBJS)
+
+all-unix: all-libobjs
+
+includes: depend
+
+depend: $(SRCS)
+
+clean-unix:: clean-libobjs
+
+@libobj_frag@
+
diff --git a/src/lib/crypto/builtin/enc_provider/aes.c b/src/lib/crypto/builtin/enc_provider/aes.c
new file mode 100644
index 000000000000..2a5d8e39775d
--- /dev/null
+++ b/src/lib/crypto/builtin/enc_provider/aes.c
@@ -0,0 +1,406 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/crypto/builtin/enc_provider/aes.c */
+/*
+ * Copyright (C) 2003, 2007, 2008 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "crypto_int.h"
+#include "aes.h"
+
+/*
+ * Private per-key data to cache after first generation. We don't
+ * want to mess with the imported AES implementation too much, so
+ * we'll just use two copies of its context, one for encryption and
+ * one for decryption, and use the #rounds field as a flag for whether
+ * we've initialized each half.
+ */
+struct aes_key_info_cache {
+ aes_ctx enc_ctx, dec_ctx;
+ krb5_boolean aesni;
+};
+#define CACHE(X) ((struct aes_key_info_cache *)((X)->cache))
+
+#ifdef AESNI
+
+/* Use AES-NI instructions (via assembly functions) when possible. */
+
+#include <cpuid.h>
+
+struct aes_data
+{
+ unsigned char *in_block;
+ unsigned char *out_block;
+ uint32_t *expanded_key;
+ unsigned char *iv;
+ size_t num_blocks;
+};
+
+void k5_iEncExpandKey128(unsigned char *key, uint32_t *expanded_key);
+void k5_iEncExpandKey256(unsigned char *key, uint32_t *expanded_key);
+void k5_iDecExpandKey256(unsigned char *key, uint32_t *expanded_key);
+void k5_iDecExpandKey128(unsigned char *key, uint32_t *expanded_key);
+
+void k5_iEnc128_CBC(struct aes_data *data);
+void k5_iDec128_CBC(struct aes_data *data);
+void k5_iEnc256_CBC(struct aes_data *data);
+void k5_iDec256_CBC(struct aes_data *data);
+
+static krb5_boolean
+aesni_supported_by_cpu()
+{
+ unsigned int a, b, c, d;
+
+ return __get_cpuid(1, &a, &b, &c, &d) && (c & (1 << 25));
+}
+
+static inline krb5_boolean
+aesni_supported(krb5_key key)
+{
+ return CACHE(key)->aesni;
+}
+
+static void
+aesni_expand_enc_key(krb5_key key)
+{
+ struct aes_key_info_cache *cache = CACHE(key);
+
+ if (key->keyblock.length == 16)
+ k5_iEncExpandKey128(key->keyblock.contents, cache->enc_ctx.k_sch);
+ else
+ k5_iEncExpandKey256(key->keyblock.contents, cache->enc_ctx.k_sch);
+ cache->enc_ctx.n_rnd = 1;
+}
+
+static void
+aesni_expand_dec_key(krb5_key key)
+{
+ struct aes_key_info_cache *cache = CACHE(key);
+
+ if (key->keyblock.length == 16)
+ k5_iDecExpandKey128(key->keyblock.contents, cache->dec_ctx.k_sch);
+ else
+ k5_iDecExpandKey256(key->keyblock.contents, cache->dec_ctx.k_sch);
+ cache->dec_ctx.n_rnd = 1;
+}
+
+static inline void
+aesni_enc(krb5_key key, unsigned char *data, size_t nblocks, unsigned char *iv)
+{
+ struct aes_key_info_cache *cache = CACHE(key);
+ struct aes_data d;
+
+ d.in_block = data;
+ d.out_block = data;
+ d.expanded_key = cache->enc_ctx.k_sch;
+ d.iv = iv;
+ d.num_blocks = nblocks;
+ if (key->keyblock.length == 16)
+ k5_iEnc128_CBC(&d);
+ else
+ k5_iEnc256_CBC(&d);
+}
+
+static inline void
+aesni_dec(krb5_key key, unsigned char *data, size_t nblocks, unsigned char *iv)
+{
+ struct aes_key_info_cache *cache = CACHE(key);
+ struct aes_data d;
+
+ d.in_block = data;
+ d.out_block = data;
+ d.expanded_key = cache->dec_ctx.k_sch;
+ d.iv = iv;
+ d.num_blocks = nblocks;
+ if (key->keyblock.length == 16)
+ k5_iDec128_CBC(&d);
+ else
+ k5_iDec256_CBC(&d);
+}
+
+#else /* not AESNI */
+
+#define aesni_supported_by_cpu() FALSE
+#define aesni_supported(key) FALSE
+#define aesni_expand_enc_key(key)
+#define aesni_expand_dec_key(key)
+#define aesni_enc(key, data, nblocks, iv)
+#define aesni_dec(key, data, nblocks, iv)
+
+#endif
+
+/* out = out ^ in */
+static inline void
+xorblock(const unsigned char *in, unsigned char *out)
+{
+ size_t q;
+
+ for (q = 0; q < BLOCK_SIZE; q += 4)
+ store_32_n(load_32_n(out + q) ^ load_32_n(in + q), out + q);
+}
+
+static inline krb5_error_code
+init_key_cache(krb5_key key)
+{
+ if (key->cache != NULL)
+ return 0;
+ key->cache = malloc(sizeof(struct aes_key_info_cache));
+ if (key->cache == NULL)
+ return ENOMEM;
+ CACHE(key)->enc_ctx.n_rnd = CACHE(key)->dec_ctx.n_rnd = 0;
+ CACHE(key)->aesni = aesni_supported_by_cpu();
+ return 0;
+}
+
+static inline void
+expand_enc_key(krb5_key key)
+{
+ if (CACHE(key)->enc_ctx.n_rnd)
+ return;
+ if (aesni_supported(key))
+ aesni_expand_enc_key(key);
+ else if (aes_enc_key(key->keyblock.contents, key->keyblock.length,
+ &CACHE(key)->enc_ctx) != aes_good)
+ abort();
+}
+
+static inline void
+expand_dec_key(krb5_key key)
+{
+ if (CACHE(key)->dec_ctx.n_rnd)
+ return;
+ if (aesni_supported(key))
+ aesni_expand_dec_key(key);
+ else if (aes_dec_key(key->keyblock.contents, key->keyblock.length,
+ &CACHE(key)->dec_ctx) != aes_good)
+ abort();
+}
+
+/* CBC encrypt nblocks blocks of data in place, using and updating iv. */
+static inline void
+cbc_enc(krb5_key key, unsigned char *data, size_t nblocks, unsigned char *iv)
+{
+ if (aesni_supported(key)) {
+ aesni_enc(key, data, nblocks, iv);
+ return;
+ }
+ for (; nblocks > 0; nblocks--, data += BLOCK_SIZE) {
+ xorblock(iv, data);
+ if (aes_enc_blk(data, data, &CACHE(key)->enc_ctx) != aes_good)
+ abort();
+ memcpy(iv, data, BLOCK_SIZE);
+ }
+}
+
+/* CBC decrypt nblocks blocks of data in place, using and updating iv. */
+static inline void
+cbc_dec(krb5_key key, unsigned char *data, size_t nblocks, unsigned char *iv)
+{
+ unsigned char last_cipherblock[BLOCK_SIZE];
+
+ if (aesni_supported(key)) {
+ aesni_dec(key, data, nblocks, iv);
+ return;
+ }
+ assert(nblocks > 0);
+ data += (nblocks - 1) * BLOCK_SIZE;
+ memcpy(last_cipherblock, data, BLOCK_SIZE);
+ for (; nblocks > 0; nblocks--, data -= BLOCK_SIZE) {
+ if (aes_dec_blk(data, data, &CACHE(key)->dec_ctx) != aes_good)
+ abort();
+ xorblock(nblocks == 1 ? iv : data - BLOCK_SIZE, data);
+ }
+ memcpy(iv, last_cipherblock, BLOCK_SIZE);
+}
+
+krb5_error_code
+krb5int_aes_encrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
+ size_t num_data)
+{
+ unsigned char iv[BLOCK_SIZE], block[BLOCK_SIZE];
+ unsigned char blockN2[BLOCK_SIZE], blockN1[BLOCK_SIZE];
+ size_t input_length, nblocks, ncontig;
+ struct iov_cursor cursor;
+
+ if (init_key_cache(key))
+ return ENOMEM;
+ expand_enc_key(key);
+
+ k5_iov_cursor_init(&cursor, data, num_data, BLOCK_SIZE, FALSE);
+
+ input_length = iov_total_length(data, num_data, FALSE);
+ nblocks = (input_length + BLOCK_SIZE - 1) / BLOCK_SIZE;
+ if (nblocks == 1) {
+ k5_iov_cursor_get(&cursor, block);
+ memset(iv, 0, BLOCK_SIZE);
+ cbc_enc(key, block, 1, iv);
+ k5_iov_cursor_put(&cursor, block);
+ return 0;
+ }
+
+ if (ivec != NULL)
+ memcpy(iv, ivec->data, BLOCK_SIZE);
+ else
+ memset(iv, 0, BLOCK_SIZE);
+
+ while (nblocks > 2) {
+ ncontig = iov_cursor_contig_blocks(&cursor);
+ if (ncontig > 0) {
+ /* Encrypt a series of contiguous blocks in place if we can, but
+ * don't touch the last two blocks. */
+ ncontig = (ncontig > nblocks - 2) ? nblocks - 2 : ncontig;
+ cbc_enc(key, iov_cursor_ptr(&cursor), ncontig, iv);
+ iov_cursor_advance(&cursor, ncontig);
+ nblocks -= ncontig;
+ } else {
+ k5_iov_cursor_get(&cursor, block);
+ cbc_enc(key, block, 1, iv);
+ k5_iov_cursor_put(&cursor, block);
+ nblocks--;
+ }
+ }
+
+ /* Encrypt the last two blocks and put them back in reverse order, possibly
+ * truncating the encrypted second-to-last block. */
+ k5_iov_cursor_get(&cursor, blockN2);
+ k5_iov_cursor_get(&cursor, blockN1);
+ cbc_enc(key, blockN2, 1, iv);
+ cbc_enc(key, blockN1, 1, iv);
+ k5_iov_cursor_put(&cursor, blockN1);
+ k5_iov_cursor_put(&cursor, blockN2);
+
+ if (ivec != NULL)
+ memcpy(ivec->data, iv, BLOCK_SIZE);
+
+ return 0;
+}
+
+krb5_error_code
+krb5int_aes_decrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
+ size_t num_data)
+{
+ unsigned char iv[BLOCK_SIZE], dummy_iv[BLOCK_SIZE], block[BLOCK_SIZE];
+ unsigned char blockN2[BLOCK_SIZE], blockN1[BLOCK_SIZE];
+ size_t input_length, last_len, nblocks, ncontig;
+ struct iov_cursor cursor;
+
+ if (init_key_cache(key))
+ return ENOMEM;
+ expand_dec_key(key);
+
+ k5_iov_cursor_init(&cursor, data, num_data, BLOCK_SIZE, FALSE);
+
+ input_length = iov_total_length(data, num_data, FALSE);
+ nblocks = (input_length + BLOCK_SIZE - 1) / BLOCK_SIZE;
+ last_len = input_length - (nblocks - 1) * BLOCK_SIZE;
+ if (nblocks == 1) {
+ k5_iov_cursor_get(&cursor, block);
+ memset(iv, 0, BLOCK_SIZE);
+ cbc_dec(key, block, 1, iv);
+ k5_iov_cursor_put(&cursor, block);
+ return 0;
+ }
+
+ if (ivec != NULL)
+ memcpy(iv, ivec->data, BLOCK_SIZE);
+ else
+ memset(iv, 0, BLOCK_SIZE);
+
+ while (nblocks > 2) {
+ ncontig = iov_cursor_contig_blocks(&cursor);
+ if (ncontig > 0) {
+ /* Decrypt a series of contiguous blocks in place if we can, but
+ * don't touch the last two blocks. */
+ ncontig = (ncontig > nblocks - 2) ? nblocks - 2 : ncontig;
+ cbc_dec(key, iov_cursor_ptr(&cursor), ncontig, iv);
+ iov_cursor_advance(&cursor, ncontig);
+ nblocks -= ncontig;
+ } else {
+ k5_iov_cursor_get(&cursor, block);
+ cbc_dec(key, block, 1, iv);
+ k5_iov_cursor_put(&cursor, block);
+ nblocks--;
+ }
+ }
+
+ /* Get the last two ciphertext blocks. Save the first as the new iv. */
+ k5_iov_cursor_get(&cursor, blockN2);
+ k5_iov_cursor_get(&cursor, blockN1);
+ if (ivec != NULL)
+ memcpy(ivec->data, blockN2, BLOCK_SIZE);
+
+ /* Decrypt the second-to-last ciphertext block, using the final ciphertext
+ * block as the CBC IV. This produces the final plaintext block. */
+ memcpy(dummy_iv, blockN1, sizeof(dummy_iv));
+ cbc_dec(key, blockN2, 1, dummy_iv);
+
+ /* Use the final bits of the decrypted plaintext to pad the last ciphertext
+ * block, and decrypt it to produce the second-to-last plaintext block. */
+ memcpy(blockN1 + last_len, blockN2 + last_len, BLOCK_SIZE - last_len);
+ cbc_dec(key, blockN1, 1, iv);
+
+ /* Put the last two plaintext blocks back into the iovec. */
+ k5_iov_cursor_put(&cursor, blockN1);
+ k5_iov_cursor_put(&cursor, blockN2);
+
+ return 0;
+}
+
+static krb5_error_code
+aes_init_state(const krb5_keyblock *key, krb5_keyusage usage,
+ krb5_data *state)
+{
+ state->length = 16;
+ state->data = malloc(16);
+ if (state->data == NULL)
+ return ENOMEM;
+ memset(state->data, 0, state->length);
+ return 0;
+}
+
+static void
+aes_key_cleanup(krb5_key key)
+{
+ zapfree(key->cache, sizeof(struct aes_key_info_cache));
+}
+
+const struct krb5_enc_provider krb5int_enc_aes128 = {
+ 16,
+ 16, 16,
+ krb5int_aes_encrypt,
+ krb5int_aes_decrypt,
+ NULL,
+ aes_init_state,
+ krb5int_default_free_state,
+ aes_key_cleanup
+};
+
+const struct krb5_enc_provider krb5int_enc_aes256 = {
+ 16,
+ 32, 32,
+ krb5int_aes_encrypt,
+ krb5int_aes_decrypt,
+ NULL,
+ aes_init_state,
+ krb5int_default_free_state,
+ aes_key_cleanup
+};
diff --git a/src/lib/crypto/builtin/enc_provider/camellia.c b/src/lib/crypto/builtin/enc_provider/camellia.c
new file mode 100644
index 000000000000..db1258086798
--- /dev/null
+++ b/src/lib/crypto/builtin/enc_provider/camellia.c
@@ -0,0 +1,315 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/crypto/builtin/enc_provider/camellia.c - Camellia enc provider */
+/*
+ * Copyright (C) 2009, 2010 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "crypto_int.h"
+#include "camellia.h"
+
+/*
+ * Private per-key data to cache after first generation. We don't want to mess
+ * with the imported Camellia implementation too much, so we'll just use two
+ * copies of its context, one for encryption and one for decryption, and use
+ * the keybitlen field as a flag for whether we've initialized each half.
+ */
+struct camellia_key_info_cache {
+ camellia_ctx enc_ctx, dec_ctx;
+};
+#define CACHE(X) ((struct camellia_key_info_cache *)((X)->cache))
+
+/* out = out ^ in */
+static inline void
+xorblock(const unsigned char *in, unsigned char *out)
+{
+ size_t q;
+
+ for (q = 0; q < BLOCK_SIZE; q += 4)
+ store_32_n(load_32_n(out + q) ^ load_32_n(in + q), out + q);
+}
+
+static inline krb5_error_code
+init_key_cache(krb5_key key)
+{
+ if (key->cache != NULL)
+ return 0;
+ key->cache = malloc(sizeof(struct camellia_key_info_cache));
+ if (key->cache == NULL)
+ return ENOMEM;
+ CACHE(key)->enc_ctx.keybitlen = CACHE(key)->dec_ctx.keybitlen = 0;
+ return 0;
+}
+
+static inline void
+expand_enc_key(krb5_key key)
+{
+ if (CACHE(key)->enc_ctx.keybitlen)
+ return;
+ if (camellia_enc_key(key->keyblock.contents, key->keyblock.length,
+ &CACHE(key)->enc_ctx) != camellia_good)
+ abort();
+}
+
+static inline void
+expand_dec_key(krb5_key key)
+{
+ if (CACHE(key)->dec_ctx.keybitlen)
+ return;
+ if (camellia_dec_key(key->keyblock.contents, key->keyblock.length,
+ &CACHE(key)->dec_ctx) != camellia_good)
+ abort();
+}
+
+/* CBC encrypt nblocks blocks of data in place, using and updating iv. */
+static inline void
+cbc_enc(krb5_key key, unsigned char *data, size_t nblocks, unsigned char *iv)
+{
+ for (; nblocks > 0; nblocks--, data += BLOCK_SIZE) {
+ xorblock(iv, data);
+ if (camellia_enc_blk(data, data, &CACHE(key)->enc_ctx) !=
+ camellia_good)
+ abort();
+ memcpy(iv, data, BLOCK_SIZE);
+ }
+}
+
+/* CBC decrypt nblocks blocks of data in place, using and updating iv. */
+static inline void
+cbc_dec(krb5_key key, unsigned char *data, size_t nblocks, unsigned char *iv)
+{
+ unsigned char last_cipherblock[BLOCK_SIZE];
+
+ assert(nblocks > 0);
+ data += (nblocks - 1) * BLOCK_SIZE;
+ memcpy(last_cipherblock, data, BLOCK_SIZE);
+ for (; nblocks > 0; nblocks--, data -= BLOCK_SIZE) {
+ if (camellia_dec_blk(data, data, &CACHE(key)->dec_ctx) !=
+ camellia_good)
+ abort();
+ xorblock(nblocks == 1 ? iv : data - BLOCK_SIZE, data);
+ }
+ memcpy(iv, last_cipherblock, BLOCK_SIZE);
+}
+
+static krb5_error_code
+krb5int_camellia_encrypt(krb5_key key, const krb5_data *ivec,
+ krb5_crypto_iov *data, size_t num_data)
+{
+ unsigned char iv[BLOCK_SIZE], block[BLOCK_SIZE];
+ unsigned char blockN2[BLOCK_SIZE], blockN1[BLOCK_SIZE];
+ size_t input_length, nblocks, ncontig;
+ struct iov_cursor cursor;
+
+ if (init_key_cache(key))
+ return ENOMEM;
+ expand_enc_key(key);
+
+ k5_iov_cursor_init(&cursor, data, num_data, BLOCK_SIZE, FALSE);
+
+ input_length = iov_total_length(data, num_data, FALSE);
+ nblocks = (input_length + BLOCK_SIZE - 1) / BLOCK_SIZE;
+ if (nblocks == 1) {
+ k5_iov_cursor_get(&cursor, block);
+ memset(iv, 0, BLOCK_SIZE);
+ cbc_enc(key, block, 1, iv);
+ k5_iov_cursor_put(&cursor, block);
+ return 0;
+ }
+
+ if (ivec != NULL)
+ memcpy(iv, ivec->data, BLOCK_SIZE);
+ else
+ memset(iv, 0, BLOCK_SIZE);
+
+ while (nblocks > 2) {
+ ncontig = iov_cursor_contig_blocks(&cursor);
+ if (ncontig > 0) {
+ /* Encrypt a series of contiguous blocks in place if we can, but
+ * don't touch the last two blocks. */
+ ncontig = (ncontig > nblocks - 2) ? nblocks - 2 : ncontig;
+ cbc_enc(key, iov_cursor_ptr(&cursor), ncontig, iv);
+ iov_cursor_advance(&cursor, ncontig);
+ nblocks -= ncontig;
+ } else {
+ k5_iov_cursor_get(&cursor, block);
+ cbc_enc(key, block, 1, iv);
+ k5_iov_cursor_put(&cursor, block);
+ nblocks--;
+ }
+ }
+
+ /* Encrypt the last two blocks and put them back in reverse order, possibly
+ * truncating the encrypted second-to-last block. */
+ k5_iov_cursor_get(&cursor, blockN2);
+ k5_iov_cursor_get(&cursor, blockN1);
+ cbc_enc(key, blockN2, 1, iv);
+ cbc_enc(key, blockN1, 1, iv);
+ k5_iov_cursor_put(&cursor, blockN1);
+ k5_iov_cursor_put(&cursor, blockN2);
+
+ if (ivec != NULL)
+ memcpy(ivec->data, iv, BLOCK_SIZE);
+
+ return 0;
+}
+
+static krb5_error_code
+krb5int_camellia_decrypt(krb5_key key, const krb5_data *ivec,
+ krb5_crypto_iov *data, size_t num_data)
+{
+ unsigned char iv[BLOCK_SIZE], dummy_iv[BLOCK_SIZE], block[BLOCK_SIZE];
+ unsigned char blockN2[BLOCK_SIZE], blockN1[BLOCK_SIZE];
+ size_t input_length, last_len, nblocks, ncontig;
+ struct iov_cursor cursor;
+
+ if (init_key_cache(key))
+ return ENOMEM;
+ expand_dec_key(key);
+
+ k5_iov_cursor_init(&cursor, data, num_data, BLOCK_SIZE, FALSE);
+
+ input_length = iov_total_length(data, num_data, FALSE);
+ nblocks = (input_length + BLOCK_SIZE - 1) / BLOCK_SIZE;
+ last_len = input_length - (nblocks - 1) * BLOCK_SIZE;
+ if (nblocks == 1) {
+ k5_iov_cursor_get(&cursor, block);
+ memset(iv, 0, BLOCK_SIZE);
+ cbc_dec(key, block, 1, iv);
+ k5_iov_cursor_put(&cursor, block);
+ return 0;
+ }
+
+ if (ivec != NULL)
+ memcpy(iv, ivec->data, BLOCK_SIZE);
+ else
+ memset(iv, 0, BLOCK_SIZE);
+
+ while (nblocks > 2) {
+ ncontig = iov_cursor_contig_blocks(&cursor);
+ if (ncontig > 0) {
+ /* Encrypt a series of contiguous blocks in place if we can, but
+ * don't touch the last two blocks. */
+ ncontig = (ncontig > nblocks - 2) ? nblocks - 2 : ncontig;
+ cbc_dec(key, iov_cursor_ptr(&cursor), ncontig, iv);
+ iov_cursor_advance(&cursor, ncontig);
+ nblocks -= ncontig;
+ } else {
+ k5_iov_cursor_get(&cursor, block);
+ cbc_dec(key, block, 1, iv);
+ k5_iov_cursor_put(&cursor, block);
+ nblocks--;
+ }
+ }
+
+ /* Get the last two ciphertext blocks. Save the first as the new iv. */
+ k5_iov_cursor_get(&cursor, blockN2);
+ k5_iov_cursor_get(&cursor, blockN1);
+ if (ivec != NULL)
+ memcpy(ivec->data, blockN2, BLOCK_SIZE);
+
+ /* Decrypt the second-to-last ciphertext block, using the final ciphertext
+ * block as the CBC IV. This produces the final plaintext block. */
+ memcpy(dummy_iv, blockN1, sizeof(dummy_iv));
+ cbc_dec(key, blockN2, 1, dummy_iv);
+
+ /* Use the final bits of the decrypted plaintext to pad the last ciphertext
+ * block, and decrypt it to produce the second-to-last plaintext block. */
+ memcpy(blockN1 + last_len, blockN2 + last_len, BLOCK_SIZE - last_len);
+ cbc_dec(key, blockN1, 1, iv);
+
+ /* Put the last two plaintext blocks back into the iovec. */
+ k5_iov_cursor_put(&cursor, blockN1);
+ k5_iov_cursor_put(&cursor, blockN2);
+
+ return 0;
+}
+
+krb5_error_code
+krb5int_camellia_cbc_mac(krb5_key key, const krb5_crypto_iov *data,
+ size_t num_data, const krb5_data *ivec,
+ krb5_data *output)
+{
+ unsigned char iv[BLOCK_SIZE], block[BLOCK_SIZE];
+ struct iov_cursor cursor;
+
+ if (output->length < BLOCK_SIZE)
+ return KRB5_BAD_MSIZE;
+
+ if (init_key_cache(key))
+ return ENOMEM;
+ expand_enc_key(key);
+
+ if (ivec != NULL)
+ memcpy(iv, ivec->data, BLOCK_SIZE);
+ else
+ memset(iv, 0, BLOCK_SIZE);
+
+ k5_iov_cursor_init(&cursor, data, num_data, BLOCK_SIZE, FALSE);
+ while (k5_iov_cursor_get(&cursor, block))
+ cbc_enc(key, block, 1, iv);
+
+ output->length = BLOCK_SIZE;
+ memcpy(output->data, iv, BLOCK_SIZE);
+
+ return 0;
+}
+
+static krb5_error_code
+camellia_init_state(const krb5_keyblock *key, krb5_keyusage usage,
+ krb5_data *state)
+{
+ state->length = 16;
+ state->data = malloc(16);
+ if (state->data == NULL)
+ return ENOMEM;
+ memset(state->data, 0, state->length);
+ return 0;
+}
+
+static void
+camellia_key_cleanup(krb5_key key)
+{
+ zapfree(key->cache, sizeof(struct camellia_key_info_cache));
+}
+
+const struct krb5_enc_provider krb5int_enc_camellia128 = {
+ 16,
+ 16, 16,
+ krb5int_camellia_encrypt,
+ krb5int_camellia_decrypt,
+ krb5int_camellia_cbc_mac,
+ camellia_init_state,
+ krb5int_default_free_state,
+ camellia_key_cleanup
+};
+
+const struct krb5_enc_provider krb5int_enc_camellia256 = {
+ 16,
+ 32, 32,
+ krb5int_camellia_encrypt,
+ krb5int_camellia_decrypt,
+ krb5int_camellia_cbc_mac,
+ camellia_init_state,
+ krb5int_default_free_state,
+ camellia_key_cleanup
+};
diff --git a/src/lib/crypto/builtin/enc_provider/deps b/src/lib/crypto/builtin/enc_provider/deps
new file mode 100644
index 000000000000..72e34076684c
--- /dev/null
+++ b/src/lib/crypto/builtin/enc_provider/deps
@@ -0,0 +1,64 @@
+#
+# Generated makefile dependencies follow.
+#
+des.so des.po $(OUTPRE)des.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h \
+ $(srcdir)/../aes/aes.h $(srcdir)/../crypto_mod.h $(srcdir)/../des/des_int.h \
+ $(srcdir)/../sha2/sha2.h $(top_srcdir)/include/k5-buf.h \
+ $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
+ $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
+ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
+ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
+ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
+ $(top_srcdir)/include/socket-utils.h des.c
+des3.so des3.po $(OUTPRE)des3.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h \
+ $(srcdir)/../aes/aes.h $(srcdir)/../crypto_mod.h $(srcdir)/../des/des_int.h \
+ $(srcdir)/../sha2/sha2.h $(top_srcdir)/include/k5-buf.h \
+ $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
+ $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
+ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
+ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
+ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
+ $(top_srcdir)/include/socket-utils.h des3.c
+aes.so aes.po $(OUTPRE)aes.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h \
+ $(srcdir)/../aes/aes.h $(srcdir)/../crypto_mod.h $(srcdir)/../sha2/sha2.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ aes.c
+camellia.so camellia.po $(OUTPRE)camellia.$(OBJEXT): \
+ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h $(srcdir)/../aes/aes.h \
+ $(srcdir)/../camellia/camellia.h $(srcdir)/../crypto_mod.h \
+ $(srcdir)/../sha2/sha2.h $(top_srcdir)/include/k5-buf.h \
+ $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
+ $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
+ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
+ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
+ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
+ $(top_srcdir)/include/socket-utils.h camellia.c
+rc4.so rc4.po $(OUTPRE)rc4.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h \
+ $(srcdir)/../aes/aes.h $(srcdir)/../crypto_mod.h $(srcdir)/../sha2/sha2.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
+ $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
+ $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
+ rc4.c
diff --git a/src/lib/crypto/builtin/enc_provider/des.c b/src/lib/crypto/builtin/enc_provider/des.c
new file mode 100644
index 000000000000..30b8229f8c6f
--- /dev/null
+++ b/src/lib/crypto/builtin/enc_provider/des.c
@@ -0,0 +1,120 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "crypto_int.h"
+#include "des_int.h"
+
+static krb5_error_code
+validate_and_schedule(krb5_key key, const krb5_data *ivec,
+ const krb5_crypto_iov *data, size_t num_data,
+ mit_des_key_schedule schedule)
+{
+ if (key->keyblock.length != 8)
+ return KRB5_BAD_KEYSIZE;
+ if (iov_total_length(data, num_data, FALSE) % 8 != 0)
+ return KRB5_BAD_MSIZE;
+ if (ivec != NULL && ivec->length != 8)
+ return KRB5_BAD_MSIZE;
+
+ switch (mit_des_key_sched(key->keyblock.contents, schedule)) {
+ case -1:
+ return(KRB5DES_BAD_KEYPAR);
+ case -2:
+ return(KRB5DES_WEAK_KEY);
+ }
+ return 0;
+}
+
+static krb5_error_code
+des_encrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
+ size_t num_data)
+{
+ mit_des_key_schedule schedule;
+ krb5_error_code err;
+
+ err = validate_and_schedule(key, ivec, data, num_data, schedule);
+ if (err)
+ return err;
+
+ krb5int_des_cbc_encrypt(data, num_data, schedule,
+ ivec != NULL ? (unsigned char *) ivec->data :
+ NULL);
+
+ zap(schedule, sizeof(schedule));
+ return 0;
+}
+
+static krb5_error_code
+des_decrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
+ size_t num_data)
+{
+ mit_des_key_schedule schedule;
+ krb5_error_code err;
+
+ err = validate_and_schedule(key, ivec, data, num_data, schedule);
+ if (err)
+ return err;
+
+ krb5int_des_cbc_decrypt(data, num_data, schedule,
+ ivec != NULL ? (unsigned char *) ivec->data :
+ NULL);
+
+ zap(schedule, sizeof(schedule));
+ return 0;
+}
+
+static krb5_error_code
+des_cbc_mac(krb5_key key, const krb5_crypto_iov *data, size_t num_data,
+ const krb5_data *ivec, krb5_data *output)
+{
+ mit_des_key_schedule schedule;
+ krb5_error_code err;
+
+ err = validate_and_schedule(key, ivec, data, num_data, schedule);
+ if (err)
+ return err;
+
+ if (output->length != 8)
+ return KRB5_CRYPTO_INTERNAL;
+
+ krb5int_des_cbc_mac(data, num_data, schedule,
+ ivec != NULL ? (unsigned char *) ivec->data : NULL,
+ (unsigned char *) output->data);
+
+ zap(schedule, sizeof(schedule));
+ return 0;
+}
+
+const struct krb5_enc_provider krb5int_enc_des = {
+ 8,
+ 7, 8,
+ des_encrypt,
+ des_decrypt,
+ des_cbc_mac,
+ krb5int_des_init_state,
+ krb5int_default_free_state
+};
diff --git a/src/lib/crypto/builtin/enc_provider/des3.c b/src/lib/crypto/builtin/enc_provider/des3.c
new file mode 100644
index 000000000000..9b82442236f8
--- /dev/null
+++ b/src/lib/crypto/builtin/enc_provider/des3.c
@@ -0,0 +1,105 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 1998 by the FundsXpress, INC.
+ *
+ * All rights reserved.
+ *
+ * Export of this software from the United States of America may require
+ * a specific license from the United States Government. It is the
+ * responsibility of any person or organization contemplating export to
+ * obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of FundsXpress. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. FundsXpress makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include "crypto_int.h"
+#include "des_int.h"
+
+static krb5_error_code
+validate_and_schedule(krb5_key key, const krb5_data *ivec,
+ const krb5_crypto_iov *data, size_t num_data,
+ mit_des3_key_schedule *schedule)
+{
+ if (key->keyblock.length != 24)
+ return(KRB5_BAD_KEYSIZE);
+ if (iov_total_length(data, num_data, FALSE) % 8 != 0)
+ return(KRB5_BAD_MSIZE);
+ if (ivec && (ivec->length != 8))
+ return(KRB5_BAD_MSIZE);
+
+ switch (mit_des3_key_sched(*(mit_des3_cblock *)key->keyblock.contents,
+ *schedule)) {
+ case -1:
+ return(KRB5DES_BAD_KEYPAR);
+ case -2:
+ return(KRB5DES_WEAK_KEY);
+ }
+ return 0;
+}
+
+static krb5_error_code
+k5_des3_encrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
+ size_t num_data)
+{
+ mit_des3_key_schedule schedule;
+ krb5_error_code err;
+
+ err = validate_and_schedule(key, ivec, data, num_data, &schedule);
+ if (err)
+ return err;
+
+ /* this has a return value, but the code always returns zero */
+ krb5int_des3_cbc_encrypt(data, num_data,
+ schedule[0], schedule[1], schedule[2],
+ ivec != NULL ? (unsigned char *) ivec->data :
+ NULL);
+
+ zap(schedule, sizeof(schedule));
+
+ return(0);
+}
+
+static krb5_error_code
+k5_des3_decrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
+ size_t num_data)
+{
+ mit_des3_key_schedule schedule;
+ krb5_error_code err;
+
+ err = validate_and_schedule(key, ivec, data, num_data, &schedule);
+ if (err)
+ return err;
+
+ /* this has a return value, but the code always returns zero */
+ krb5int_des3_cbc_decrypt(data, num_data,
+ schedule[0], schedule[1], schedule[2],
+ ivec != NULL ? (unsigned char *) ivec->data :
+ NULL);
+
+ zap(schedule, sizeof(schedule));
+
+ return 0;
+}
+
+const struct krb5_enc_provider krb5int_enc_des3 = {
+ 8,
+ 21, 24,
+ k5_des3_encrypt,
+ k5_des3_decrypt,
+ NULL,
+ krb5int_des_init_state,
+ krb5int_default_free_state
+};
diff --git a/src/lib/crypto/builtin/enc_provider/rc4.c b/src/lib/crypto/builtin/enc_provider/rc4.c
new file mode 100644
index 000000000000..3776f80715ab
--- /dev/null
+++ b/src/lib/crypto/builtin/enc_provider/rc4.c
@@ -0,0 +1,190 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/crypto/builtin/enc_provider/rc4.c */
+/*
+ * Copyright (c) 2000 by Computer Science Laboratory,
+ * Rensselaer Polytechnic Institute
+ *
+ * #include STD_DISCLAIMER
+ */
+
+#include "crypto_int.h"
+
+typedef struct
+{
+ unsigned int x;
+ unsigned int y;
+ unsigned char state[256];
+} ArcfourContext;
+
+typedef struct {
+ int initialized;
+ ArcfourContext ctx;
+} ArcFourCipherState;
+
+/* gets the next byte from the PRNG */
+#if ((__GNUC__ >= 2) )
+static __inline__ unsigned int k5_arcfour_byte(ArcfourContext *);
+#else
+static unsigned int k5_arcfour_byte(ArcfourContext *);
+#endif /* gcc inlines*/
+
+/* Initializes the context and sets the key. */
+static krb5_error_code k5_arcfour_init(ArcfourContext *ctx, const unsigned char *key,
+ unsigned int keylen);
+
+/* Encrypts/decrypts data. */
+static void k5_arcfour_crypt(ArcfourContext *ctx, unsigned char *dest,
+ const unsigned char *src, unsigned int len);
+
+static inline unsigned int k5_arcfour_byte(ArcfourContext * ctx)
+{
+ unsigned int x;
+ unsigned int y;
+ unsigned int sx, sy;
+ unsigned char *state;
+
+ state = ctx->state;
+ x = (ctx->x + 1) & 0xff;
+ sx = state[x];
+ y = (sx + ctx->y) & 0xff;
+ sy = state[y];
+ ctx->x = x;
+ ctx->y = y;
+ state[y] = sx;
+ state[x] = sy;
+ return state[(sx + sy) & 0xff];
+}
+
+static void k5_arcfour_crypt(ArcfourContext *ctx, unsigned char *dest,
+ const unsigned char *src, unsigned int len)
+{
+ unsigned int i;
+ for (i = 0; i < len; i++)
+ dest[i] = src[i] ^ k5_arcfour_byte(ctx);
+}
+
+
+static krb5_error_code
+k5_arcfour_init(ArcfourContext *ctx, const unsigned char *key,
+ unsigned int key_len)
+{
+ unsigned int t, u;
+ unsigned int keyindex;
+ unsigned int stateindex;
+ unsigned char* state;
+ unsigned int counter;
+
+ if (key_len != 16)
+ return KRB5_BAD_MSIZE; /*this is probably not the correct error code
+ to return */
+ state = &ctx->state[0];
+ ctx->x = 0;
+ ctx->y = 0;
+ for (counter = 0; counter < 256; counter++)
+ state[counter] = counter;
+ keyindex = 0;
+ stateindex = 0;
+ for (counter = 0; counter < 256; counter++)
+ {
+ t = state[counter];
+ stateindex = (stateindex + key[keyindex] + t) & 0xff;
+ u = state[stateindex];
+ state[stateindex] = t;
+ state[counter] = u;
+ if (++keyindex >= key_len)
+ keyindex = 0;
+ }
+ return 0;
+}
+
+
+static krb5_error_code
+k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
+ size_t num_data)
+{
+ ArcfourContext *arcfour_ctx = NULL;
+ ArcFourCipherState *cipher_state = NULL;
+ krb5_error_code ret;
+ size_t i;
+
+ if (key->keyblock.length != 16)
+ return KRB5_BAD_KEYSIZE;
+ if (state != NULL && (state->length != sizeof(ArcFourCipherState)))
+ return KRB5_BAD_MSIZE;
+
+ if (state != NULL) {
+ cipher_state = (ArcFourCipherState *)state->data;
+ arcfour_ctx = &cipher_state->ctx;
+ if (cipher_state->initialized == 0) {
+ ret = k5_arcfour_init(arcfour_ctx, key->keyblock.contents,
+ key->keyblock.length);
+ if (ret != 0)
+ return ret;
+
+ cipher_state->initialized = 1;
+ }
+ } else {
+ arcfour_ctx = (ArcfourContext *)malloc(sizeof(ArcfourContext));
+ if (arcfour_ctx == NULL)
+ return ENOMEM;
+
+ ret = k5_arcfour_init(arcfour_ctx, key->keyblock.contents,
+ key->keyblock.length);
+ if (ret != 0) {
+ free(arcfour_ctx);
+ return ret;
+ }
+ }
+
+ for (i = 0; i < num_data; i++) {
+ krb5_crypto_iov *iov = &data[i];
+
+ if (ENCRYPT_IOV(iov))
+ k5_arcfour_crypt(arcfour_ctx, (unsigned char *)iov->data.data,
+ (const unsigned char *)iov->data.data, iov->data.length);
+ }
+
+ if (state == NULL)
+ zapfree(arcfour_ctx, sizeof(ArcfourContext));
+
+ return 0;
+}
+
+static krb5_error_code
+k5_arcfour_init_state (const krb5_keyblock *key,
+ krb5_keyusage keyusage, krb5_data *new_state)
+{
+ /* Note that we can't actually set up the state here because the key
+ * will change between now and when encrypt is called
+ * because it is data dependent. Yeah, this has strange
+ * properties. --SDH
+ */
+ new_state->length = sizeof (ArcFourCipherState);
+ new_state->data = malloc (new_state->length);
+ if (new_state->data) {
+ memset (new_state->data, 0 , new_state->length);
+ /* That will set initialized to zero*/
+ }else {
+ return (ENOMEM);
+ }
+ return 0;
+}
+
+/* Since the arcfour cipher is identical going forwards and backwards,
+ we just call "docrypt" directly
+*/
+const struct krb5_enc_provider krb5int_enc_arcfour = {
+ /* This seems to work... although I am not sure what the
+ implications are in other places in the kerberos library */
+ 1,
+ /* Keysize is arbitrary in arcfour, but the constraints of the
+ system, and to attempt to work with the MSFT system forces us
+ to 16byte/128bit. Since there is no parity in the key, the
+ byte and length are the same. */
+ 16, 16,
+ k5_arcfour_docrypt,
+ k5_arcfour_docrypt,
+ NULL,
+ k5_arcfour_init_state, /*xxx not implemented yet*/
+ krb5int_default_free_state
+};