diff options
author | Cy Schubert <cy@FreeBSD.org> | 2017-07-07 17:03:42 +0000 |
---|---|---|
committer | Cy Schubert <cy@FreeBSD.org> | 2017-07-07 17:03:42 +0000 |
commit | 33a9b234e7087f573ef08cd7318c6497ba08b439 (patch) | |
tree | d0ea40ad3bf5463a3c55795977c71bcb7d781b4b /src/lib/crypto/builtin/enc_provider | |
download | src-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.in | 45 | ||||
-rw-r--r-- | src/lib/crypto/builtin/enc_provider/aes.c | 406 | ||||
-rw-r--r-- | src/lib/crypto/builtin/enc_provider/camellia.c | 315 | ||||
-rw-r--r-- | src/lib/crypto/builtin/enc_provider/deps | 64 | ||||
-rw-r--r-- | src/lib/crypto/builtin/enc_provider/des.c | 120 | ||||
-rw-r--r-- | src/lib/crypto/builtin/enc_provider/des3.c | 105 | ||||
-rw-r--r-- | src/lib/crypto/builtin/enc_provider/rc4.c | 190 |
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 +}; |