diff options
| author | Greg Hudson <ghudson@mit.edu> | 2010-11-20 00:31:46 +0000 |
|---|---|---|
| committer | Greg Hudson <ghudson@mit.edu> | 2010-11-20 00:31:46 +0000 |
| commit | 41acda8ebd3517c3d0f2184c09741cd10d061182 (patch) | |
| tree | dcc9695ff569763cfa96eff1c895d88d27721d12 /src/lib/crypto/krb | |
| parent | 52bae3736c1835b8d7ba6b2e8bda370fe58f044b (diff) | |
| download | krb5-41acda8ebd3517c3d0f2184c09741cd10d061182.tar.gz krb5-41acda8ebd3517c3d0f2184c09741cd10d061182.tar.xz krb5-41acda8ebd3517c3d0f2184c09741cd10d061182.zip | |
Implement Camellia-CTS-CMAC instead of Camellia-CCM
Replace the Camellia-CCM enctypes with Camellia-CTS-CMAC. Still not
compiled in by default since we don't have enctype assignments yet.
ticket: 6822
target_verion: 1.9
tags: pullup
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@24524 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib/crypto/krb')
| -rw-r--r-- | src/lib/crypto/krb/checksum/cmac.c | 6 | ||||
| -rw-r--r-- | src/lib/crypto/krb/cksumtypes.c | 16 | ||||
| -rw-r--r-- | src/lib/crypto/krb/dk/Makefile.in | 6 | ||||
| -rw-r--r-- | src/lib/crypto/krb/dk/checksum_cmac.c | 4 | ||||
| -rw-r--r-- | src/lib/crypto/krb/dk/derive.c | 8 | ||||
| -rw-r--r-- | src/lib/crypto/krb/dk/dk.h | 47 | ||||
| -rw-r--r-- | src/lib/crypto/krb/dk/dk_ccm.c | 614 | ||||
| -rw-r--r-- | src/lib/crypto/krb/dk/dk_cmac.c | 188 | ||||
| -rw-r--r-- | src/lib/crypto/krb/dk/stringtokey.c | 21 | ||||
| -rw-r--r-- | src/lib/crypto/krb/etypes.c | 38 | ||||
| -rw-r--r-- | src/lib/crypto/krb/prf/cmac_prf.c | 4 |
11 files changed, 257 insertions, 695 deletions
diff --git a/src/lib/crypto/krb/checksum/cmac.c b/src/lib/crypto/krb/checksum/cmac.c index a0e249ffd..ec4d65ff6 100644 --- a/src/lib/crypto/krb/checksum/cmac.c +++ b/src/lib/crypto/krb/checksum/cmac.c @@ -45,7 +45,7 @@ #include "etypes.h" #include "cksumtypes.h" -#ifdef CAMELLIA_CCM +#ifdef CAMELLIA #define BLOCK_SIZE 16 @@ -226,7 +226,7 @@ krb5int_cmac_checksum(const struct krb5_enc_provider *enc, krb5_key key, return 0; } -#else /* CAMELLIA_CCM */ +#else /* CAMELLIA */ /* This won't be used, but is still in the export table. */ @@ -238,4 +238,4 @@ krb5int_cmac_checksum(const struct krb5_enc_provider *enc, krb5_key key, return EINVAL; } -#endif /* CAMELLIA_CCM */ +#endif /* CAMELLIA */ diff --git a/src/lib/crypto/krb/cksumtypes.c b/src/lib/crypto/krb/cksumtypes.c index 6744775bc..bcd514011 100644 --- a/src/lib/crypto/krb/cksumtypes.c +++ b/src/lib/crypto/krb/cksumtypes.c @@ -105,19 +105,19 @@ const struct krb5_cksumtypes krb5int_cksumtypes_list[] = { krb5int_hmacmd5_checksum, NULL, 16, 16, 0 }, -#ifdef CAMELLIA_CCM - { CKSUMTYPE_CMAC_128_CAMELLIA128, - "cmac-128-camellia128", { 0 }, "CMAC Camellia128 key", - &krb5int_enc_camellia128_ctr, NULL, +#ifdef CAMELLIA + { CKSUMTYPE_CMAC_CAMELLIA128, + "cmac-camellia128", { 0 }, "CMAC Camellia128 key", + &krb5int_enc_camellia128, NULL, krb5int_dk_cmac_checksum, NULL, 16, 16, 0 }, - { CKSUMTYPE_CMAC_128_CAMELLIA256, - "cmac-128-camellia256", { 0 }, "CMAC Camellia256 key", - &krb5int_enc_camellia256_ctr, NULL, + { CKSUMTYPE_CMAC_CAMELLIA256, + "cmac-camellia256", { 0 }, "CMAC Camellia256 key", + &krb5int_enc_camellia256, NULL, krb5int_dk_cmac_checksum, NULL, 16, 16, 0 }, -#endif /* CAMELLIA_CCM */ +#endif /* CAMELLIA */ }; const size_t krb5int_cksumtypes_length = diff --git a/src/lib/crypto/krb/dk/Makefile.in b/src/lib/crypto/krb/dk/Makefile.in index 09df6c38d..cd804bc6d 100644 --- a/src/lib/crypto/krb/dk/Makefile.in +++ b/src/lib/crypto/krb/dk/Makefile.in @@ -14,7 +14,7 @@ STLIBOBJS=\ checksum_hmac.o \ checksum_cmac.o \ dk_aead.o \ - dk_ccm.o \ + dk_cmac.o \ derive.o \ stringtokey.o @@ -22,7 +22,7 @@ OBJS=\ $(OUTPRE)checksum_hmac.$(OBJEXT)\ $(OUTPRE)checksum_cmac.$(OBJEXT)\ $(OUTPRE)dk_aead.$(OBJEXT) \ - $(OUTPRE)dk_ccm.$(OBJEXT) \ + $(OUTPRE)dk_cmac.$(OBJEXT) \ $(OUTPRE)derive.$(OBJEXT) \ $(OUTPRE)stringtokey.$(OBJEXT) @@ -30,7 +30,7 @@ SRCS=\ $(srcdir)/checksum_hmac.c \ $(srcdir)/checksum_cmac.c \ $(srcdir)/dk_aead.c \ - $(srcdir)/dk_ccm.c \ + $(srcdir)/dk_cmac.c \ $(srcdir)/derive.c \ $(srcdir)/stringtokey.c diff --git a/src/lib/crypto/krb/dk/checksum_cmac.c b/src/lib/crypto/krb/dk/checksum_cmac.c index c2309b7cd..ac3e4e998 100644 --- a/src/lib/crypto/krb/dk/checksum_cmac.c +++ b/src/lib/crypto/krb/dk/checksum_cmac.c @@ -32,7 +32,7 @@ #define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */ -#ifdef CAMELLIA_CCM +#ifdef CAMELLIA krb5_error_code krb5int_dk_cmac_checksum(const struct krb5_cksumtypes *ctp, @@ -63,4 +63,4 @@ krb5int_dk_cmac_checksum(const struct krb5_cksumtypes *ctp, return ret; } -#endif /* CAMELLIA_CCM */ +#endif /* CAMELLIA */ diff --git a/src/lib/crypto/krb/dk/derive.c b/src/lib/crypto/krb/dk/derive.c index a7ad2e344..d309206f1 100644 --- a/src/lib/crypto/krb/dk/derive.c +++ b/src/lib/crypto/krb/dk/derive.c @@ -129,7 +129,7 @@ cleanup: return ret; } -#ifdef CAMELLIA_CCM +#ifdef CAMELLIA /* * NIST SP800-108 KDF in feedback mode (section 5.2). @@ -181,7 +181,7 @@ derive_random_sp800_108_cmac(const struct krb5_enc_provider *enc, /* [L]2: four-byte big-endian binary string giving the output length */ iov[5].flags = KRB5_CRYPTO_TYPE_DATA; iov[5].data = make_data(Lbuf, sizeof(Lbuf)); - store_32_be(outrnd->length, Lbuf); + store_32_be(outrnd->length * 8, Lbuf); for (i = 1, n = 0; n < keybytes; i++) { /* Update the block counter. */ @@ -206,7 +206,7 @@ cleanup: return ret; } -#endif /* CAMELLIA_CCM */ +#endif /* CAMELLIA */ krb5_error_code krb5int_derive_random(const struct krb5_enc_provider *enc, @@ -216,7 +216,7 @@ krb5int_derive_random(const struct krb5_enc_provider *enc, switch (alg) { case DERIVE_RFC3961: return derive_random_rfc3961(enc, inkey, outrnd, in_constant); -#ifdef CAMELLIA_CCM +#ifdef CAMELLIA case DERIVE_SP800_108_CMAC: return derive_random_sp800_108_cmac(enc, inkey, outrnd, in_constant); #endif diff --git a/src/lib/crypto/krb/dk/dk.h b/src/lib/crypto/krb/dk/dk.h index fb6df88fa..079977847 100644 --- a/src/lib/crypto/krb/dk/dk.h +++ b/src/lib/crypto/krb/dk/dk.h @@ -37,6 +37,9 @@ unsigned int krb5int_aes_crypto_length(const struct krb5_keytypes *ktp, krb5_cryptotype type); +unsigned int +krb5int_camellia_crypto_length(const struct krb5_keytypes *ktp, + krb5_cryptotype type); krb5_error_code krb5int_dk_encrypt(const struct krb5_keytypes *ktp, krb5_key key, krb5_keyusage usage, const krb5_data *ivec, @@ -58,15 +61,15 @@ krb5int_aes_string_to_key(const struct krb5_keytypes *enc, const krb5_data *params, krb5_keyblock *key); krb5_error_code -krb5int_camellia_ccm_string_to_key(const struct krb5_keytypes *enc, - const krb5_data *string, - const krb5_data *salt, - const krb5_data *params, - krb5_keyblock *key); +krb5int_camellia_string_to_key(const struct krb5_keytypes *enc, + const krb5_data *string, + const krb5_data *salt, + const krb5_data *params, + krb5_keyblock *key); enum deriv_alg { DERIVE_RFC3961, /* RFC 3961 section 5.1 */ -#ifdef CAMELLIA_CCM +#ifdef CAMELLIA DERIVE_SP800_108_CMAC /* NIST SP 800-108 with CMAC as PRF */ #endif }; @@ -92,36 +95,20 @@ krb5int_derive_random(const struct krb5_enc_provider *enc, krb5_key inkey, krb5_data *outrnd, const krb5_data *in_constant, enum deriv_alg alg); -unsigned int -krb5int_dk_ccm_crypto_length(const struct krb5_keytypes *ktp, - krb5_cryptotype type); - krb5_error_code -krb5int_dk_ccm_encrypt(const struct krb5_keytypes *ktp, - krb5_key key, - krb5_keyusage usage, - const krb5_data *ivec, - krb5_crypto_iov *data, - size_t num_data); +krb5int_dk_cmac_encrypt(const struct krb5_keytypes *ktp, + krb5_key key, krb5_keyusage usage, + const krb5_data *ivec, krb5_crypto_iov *data, + size_t num_data); krb5_error_code -krb5int_dk_ccm_decrypt(const struct krb5_keytypes *ktp, - krb5_key key, - krb5_keyusage usage, - const krb5_data *ivec, - krb5_crypto_iov *data, - size_t num_data); +krb5int_dk_cmac_decrypt(const struct krb5_keytypes *ktp, + krb5_key key, krb5_keyusage usage, + const krb5_data *ivec, krb5_crypto_iov *data, + size_t num_data); krb5_error_code krb5int_dk_cmac_checksum(const struct krb5_cksumtypes *ctp, krb5_key key, krb5_keyusage usage, const krb5_crypto_iov *data, size_t num_data, krb5_data *output); - -krb5_error_code -krb5int_dk_ccm_init_state(const struct krb5_keytypes *ktp, - const krb5_keyblock *key, krb5_keyusage usage, - krb5_data *out_state); - -void -krb5int_dk_ccm_free_state(const struct krb5_keytypes *ktp, krb5_data *state); diff --git a/src/lib/crypto/krb/dk/dk_ccm.c b/src/lib/crypto/krb/dk/dk_ccm.c deleted file mode 100644 index 284e36215..000000000 --- a/src/lib/crypto/krb/dk/dk_ccm.c +++ /dev/null @@ -1,614 +0,0 @@ -/* - * lib/crypto/krb/dk/dk_ccm.c - * - * Copyright 2008-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 "k5-int.h" -#include "dk.h" -#include "aead.h" - -#ifdef CAMELLIA_CCM - -/* - * Implement CCM-mode AEAD as described in section 5.3 and 5.4 of RFC 5116. - * This is the CCM mode as described in NIST SP800-38C, with a 12 byte nonce - * and 16 byte checksum. Multiple buffers of the same type are logically - * concatenated. The underlying enc provider must have a 16-byte block size, - * must have a counter-mode encrypt method, and must have a cbc_mac method. - * - * The IOV should be laid out as follows: - * - * HEADER | SIGN_DATA | DATA | PADDING | TRAILER - * - * SIGN_DATA and PADDING may be absent. - * - * Upon decryption, one can pass in explicit buffers as for encryption, or one - * can pass in STREAM, being the concatenation of HEADER | DATA | TRAILER. - * - * STREAM | SIGN_DATA | DATA - * - * Upon output, DATA will contain a pointer into the STREAM buffer with the - * decrypted payload. SIGN_DATA should be ordered relative to the output DATA - * buffer as it was upon encryption. - * - * For compatibility with RFC 5116, a single key is used both for encryption - * and checksumming. The key derivation function is as follows: - * - * Kc = DK(base-key, usage | 0xCC) - * - * Again as required by the CCM specification, SIGN_DATA is processed before - * DATA for the purpose of checksumming. - */ - -#define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */ - -unsigned int -krb5int_dk_ccm_crypto_length(const struct krb5_keytypes *ktp, - krb5_cryptotype type) -{ - unsigned int length; - - switch (type) { - case KRB5_CRYPTO_TYPE_HEADER: - length = 12; /* RFC 5116 5.3 */ - break; - case KRB5_CRYPTO_TYPE_PADDING: - length = 0; /* CTR mode requires no padding */ - break; - case KRB5_CRYPTO_TYPE_TRAILER: - case KRB5_CRYPTO_TYPE_CHECKSUM: - length = ktp->enc->block_size; - break; - default: - assert(0 && "invalid cryptotype passed to ccm_crypto_length"); - length = ~0; - break; - } - - return length; -} - -/* - * Encode the length of the additional data according to NIST SP800-38C section - * A.2.2. The size of the encoding will be 0, 2, 6, or 10 bytes depending on - * the length value. - */ -static krb5_error_code -encode_a_len(krb5_data *a, krb5_ui_8 adata_len) -{ - size_t len; - unsigned char *p; - - if (adata_len > (1LL << 32)) - len = 10; - else if (adata_len > (1LL << 16) - (1LL << 8)) - len = 6; - else if (adata_len) - len = 2; - else - len = 0; - - if (a->length < len) - return KRB5_BAD_MSIZE; - - p = (unsigned char *)a->data; - - switch (len) { - case 2: - /* Two raw bytes; first byte will not be 0xFF. */ - p[0] = (adata_len >> 8) & 0xFF; - p[1] = (adata_len ) & 0xFF; - break; - case 6: - /* FF FE followed by four bytes. */ - p[0] = 0xFF; - p[1] = 0xFE; - p[2] = (adata_len >> 24) & 0xFF; - p[3] = (adata_len >> 16) & 0xFF; - p[4] = (adata_len >> 8 ) & 0xFF; - p[5] = (adata_len ) & 0xFF; - break; - case 10: - /* FF FF followed by eight bytes. */ - p[0] = 0xFF; - p[1] = 0xFF; - p[2] = (adata_len >> 56) & 0xFF; - p[3] = (adata_len >> 48) & 0xFF; - p[4] = (adata_len >> 40) & 0xFF; - p[5] = (adata_len >> 32) & 0xFF; - p[6] = (adata_len >> 24) & 0xFF; - p[7] = (adata_len >> 16) & 0xFF; - p[8] = (adata_len >> 8 ) & 0xFF; - p[9] = (adata_len ) & 0xFF; - break; - } - - a->length = len; - - return 0; -} - -/* - * Encode the first 16-byte block of CBC-MAC input according to NIST SP800-38C - * section A.2.1. n (the nonce length) is given by nonce->length. - */ -static krb5_error_code -format_B0(krb5_data *B0, /* B0 */ - krb5_data *nonce, /* N */ - size_t trailer_len, /* t */ - krb5_ui_8 adata_len, /* a */ - krb5_ui_8 payload_len) /* Q */ -{ - unsigned char flags; - unsigned char *p; - krb5_octet q, i = 0; - - if (B0->length != 16) - return KRB5_BAD_MSIZE; - - /* Section A.1: Length Requirements */ - - /* t is an element of {4, 6, 8, 10, 12, 14, 16}. */ - if (trailer_len % 2 || - (trailer_len < 4 || trailer_len > 16)) - return KRB5_BAD_MSIZE; - - /* n is an element of {7, 8, 9, 10, 11, 12, 13}. */ - if (nonce->length < 7 || nonce->length > 13) - return KRB5_BAD_MSIZE; - - q = 15 - nonce->length; - - /* P consists of fewer than 2^(8q) octets. */ - if (payload_len >= (1UL << (8 * q))) - return KRB5_BAD_MSIZE; - - /* Encode the flags octet. */ - flags = q - 1; - flags |= (((trailer_len - 2) / 2) << 3); - if (adata_len != 0) - flags |= (1 << 6); - - p = (unsigned char *)B0->data; - p[i++] = flags; - - /* Next comes the nonce (n bytes). */ - memcpy(&p[i], nonce->data, nonce->length); - i += nonce->length; - - /* The final q bytes are the payload length. */ - for (; i < B0->length; i++) { - register krb5_octet s; - - s = (q - (i - nonce->length)) * 8; - - p[i] = (payload_len >> s) & 0xFF; - } - - return 0; -} - -/* - * Encode the initial counter block according to NIST SP800-38C section A.3. - * The counter value may be chained across krb5_k_encrypt invocations via the - * cipher_state parameter; otherwise it begins at 0. - */ -static krb5_error_code -format_Ctr0(krb5_data *counter, const krb5_data *nonce, const krb5_data *state, - unsigned int n) -{ - krb5_octet q; /* counter length */ - - assert(n >= 7 && n <= 13); - - /* First byte is q-1 in the lowest three bits. */ - q = 15 - n; - counter->data[0] = q - 1; - /* Next comes the nonce (n bytes). */ - memcpy(&counter->data[1], nonce->data, n); - - /* Finally, the counter value. */ - if (state != NULL) - memcpy(&counter->data[1 + n], state->data, q); - else - memset(&counter->data[1 + n], 0, q); - - return 0; -} - -/* Return true if the payload length is valid given the nonce length n. */ -static krb5_boolean -valid_payload_length_p(const struct krb5_keytypes *ktp, unsigned int n, - unsigned int payload_len) -{ - unsigned int block_size = ktp->enc->block_size; - unsigned int nblocks, maxblocks; - krb5_octet q; - - assert(n >= 7 && n <= 13); - - q = 15 - n; - - maxblocks = (1U << (8 * q)) - 1 /* tag */; - - nblocks = (payload_len + block_size - 1) / block_size; - - return (nblocks <= maxblocks); -} - -/* Encrypt and authenticate data according to NIST SP800-38C section 6.1. */ -static krb5_error_code -ccm_encrypt(const struct krb5_keytypes *ktp, krb5_key kc, - const krb5_data *state, krb5_crypto_iov *data, size_t num_data) -{ - krb5_error_code ret; - krb5_crypto_iov *header, *trailer, *sign_data = NULL, cksum; - size_t i, num_sign_data = 0; - unsigned int header_len; - unsigned int trailer_len; - size_t payload_len = 0; - size_t adata_len = 0; - char adata_len_buf[6]; - unsigned char B0[16], Ctr[16]; - krb5_data counter = make_data(Ctr, sizeof(Ctr)); - - header_len = ktp->crypto_length(ktp, KRB5_CRYPTO_TYPE_HEADER); - - header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER); - if (header == NULL || header->data.length < header_len) { - ret = KRB5_BAD_MSIZE; - goto cleanup; - } - - trailer_len = ktp->crypto_length(ktp, KRB5_CRYPTO_TYPE_TRAILER); - - trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); - if (trailer == NULL || trailer->data.length < trailer_len) { - ret = KRB5_BAD_MSIZE; - goto cleanup; - } - - for (i = 0; i < num_data; i++) { - krb5_crypto_iov *iov = &data[i]; - - switch (iov->flags) { - case KRB5_CRYPTO_TYPE_DATA: - payload_len += iov->data.length; - break; - case KRB5_CRYPTO_TYPE_SIGN_ONLY: - adata_len += iov->data.length; - break; - case KRB5_CRYPTO_TYPE_PADDING: - iov->data.length = 0; - break; - default: - break; - } - } - - if (!valid_payload_length_p(ktp, header_len, payload_len)) { - ret = KRB5_BAD_MSIZE; - goto cleanup; - } - - header->data.length = header_len; - trailer->data.length = trailer_len; - - /* Choose a random nonce. */ - ret = krb5_c_random_make_octets(NULL, &header->data); - if (ret != 0) - goto cleanup; - - /* Encode the first counter block. */ - ret = format_Ctr0(&counter, &header->data, state, header_len); - if (ret != 0) - goto cleanup; - - /* Create a list of CBC-MAC input blocks. */ - sign_data = k5alloc((num_data + 1) * sizeof(krb5_crypto_iov), &ret); - if (sign_data == NULL) - goto cleanup; - - /* Format the initial control/nonce block. */ - sign_data[0].flags = KRB5_CRYPTO_TYPE_HEADER; - sign_data[0].data = make_data(B0, sizeof(B0)); - ret = format_B0(&sign_data[0].data, &header->data, trailer_len, - (krb5_ui_8)adata_len, (krb5_ui_8)payload_len); - if (ret != 0) - goto cleanup; - - /* Format the length of associated data. */ - sign_data[1].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; - sign_data[1].data = make_data(adata_len_buf, sizeof(adata_len_buf)); - ret = encode_a_len(&sign_data[1].data, (krb5_ui_8)adata_len); - if (ret != 0) - goto cleanup; - num_sign_data = 2; - - /* Reorder input IOV so SIGN_ONLY data is before DATA. */ - for (i = 0; i < num_data; i++) { - if (data[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) - sign_data[num_sign_data++] = data[i]; - } - for (i = 0; i < num_data; i++) { - if (data[i].flags == KRB5_CRYPTO_TYPE_DATA) - sign_data[num_sign_data++] = data[i]; - } - - assert(ktp->enc->encrypt != NULL); - assert(ktp->enc->cbc_mac != NULL); - - /* Make checksum and place in trailer. */ - ret = ktp->enc->cbc_mac(kc, sign_data, num_sign_data, NULL, - &trailer->data); - if (ret != 0) - goto cleanup; - - /* Encrypt checksum in trailer using the first counter block. */ - cksum.flags = KRB5_CRYPTO_TYPE_DATA; - cksum.data = trailer->data; - ret = ktp->enc->encrypt(kc, &counter, &cksum, 1); - if (ret != 0) - goto cleanup; - - /* Encrypt everything but B0 (header) in subsequent counter blocks. */ - ret = ktp->enc->encrypt(kc, &counter, data, num_data); - if (ret != 0) - goto cleanup; - - /* Store the counter value as cipher state. Subsequent encryptions will - * generate a fresh nonce. */ - if (state != NULL) - memcpy(state->data, counter.data + 1 + header_len, 15 - header_len); - -cleanup: - free(sign_data); - return ret; -} - -/* Derive an encryption key based on usage and CCM-encrypt data. */ -krb5_error_code -krb5int_dk_ccm_encrypt(const struct krb5_keytypes *ktp, krb5_key key, - krb5_keyusage usage, const krb5_data *state, - krb5_crypto_iov *data, size_t num_data) -{ - unsigned char constantdata[K5CLENGTH]; - krb5_error_code ret; - krb5_key kc; - krb5_data d1; - - d1.data = (char *)constantdata; - d1.length = K5CLENGTH; - - d1.data[0] = (usage >> 24) & 0xFF; - d1.data[1] = (usage >> 16) & 0xFF; - d1.data[2] = (usage >> 8 ) & 0xFF; - d1.data[3] = (usage ) & 0xFF; - - d1.data[4] = 0xCC; - - ret = krb5int_derive_key(ktp->enc, key, &kc, &d1, DERIVE_SP800_108_CMAC); - if (ret != 0) - return ret; - - ret = ccm_encrypt(ktp, kc, state, data, num_data); - - krb5_k_free_key(NULL, kc); - - return ret; -} - -/* Decrypt and verify data according to NIST SP800-38C section 6.2. */ -static krb5_error_code -ccm_decrypt(const struct krb5_keytypes *ktp, krb5_key kc, - const krb5_data *state, krb5_crypto_iov *data, size_t num_data) -{ - krb5_error_code ret; - krb5_crypto_iov *header, *trailer, *sign_data = NULL, got_cksum; - size_t i, num_sign_data = 0; - unsigned int header_len; - unsigned int trailer_len; - size_t adata_len = 0; - size_t payload_len = 0; - char adata_len_buf[6]; - unsigned char B0[16], Ctr[16]; - krb5_data made_cksum = empty_data(); - krb5_data counter = make_data(Ctr, sizeof(Ctr)); - - header_len = ktp->crypto_length(ktp, KRB5_CRYPTO_TYPE_HEADER); - - header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER); - if (header == NULL || header->data.length != header_len) { - ret = KRB5_BAD_MSIZE; - goto cleanup; - } - - trailer_len = ktp->crypto_length(ktp, KRB5_CRYPTO_TYPE_TRAILER); - - trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); - if (trailer == NULL || trailer->data.length != trailer_len) { - ret = KRB5_BAD_MSIZE; - goto cleanup; - } - - for (i = 0; i < num_data; i++) { - krb5_crypto_iov *iov = &data[i]; - - switch (iov->flags) { - case KRB5_CRYPTO_TYPE_DATA: - payload_len += iov->data.length; - break; - case KRB5_CRYPTO_TYPE_SIGN_ONLY: - adata_len += iov->data.length; - break; - case KRB5_CRYPTO_TYPE_PADDING: - if (iov->data.length != 0) { - ret = KRB5_BAD_MSIZE; - goto cleanup; - } - break; - default: - break; - } - } - - if (!valid_payload_length_p(ktp, header_len, payload_len)) { - ret = KRB5_BAD_MSIZE; - goto cleanup; - } - - /* Encode the first counter block. */ - ret = format_Ctr0(&counter, &header->data, state, header_len); - if (ret != 0) - goto cleanup; - - /* Create a list of CBC-MAC input blocks. */ - sign_data = k5alloc((num_data + 1) * sizeof(krb5_crypto_iov), &ret); - if (sign_data == NULL) - goto cleanup; - - /* Format the initial control/nonce block. */ - sign_data[0].flags = KRB5_CRYPTO_TYPE_HEADER; - sign_data[0].data = make_data(B0, sizeof(B0)); - ret = format_B0(&sign_data[0].data, &header->data, trailer_len, - (krb5_ui_8)adata_len, (krb5_ui_8)payload_len); - if (ret != 0) - goto cleanup; - - /* Format the length of associated data. */ - sign_data[1].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; - sign_data[1].data = make_data(adata_len_buf, sizeof(adata_len_buf)); - ret = encode_a_len(&sign_data[1].data, (krb5_ui_8)adata_len); - if (ret != 0) - goto cleanup; - num_sign_data = 2; - - assert(ktp->enc->decrypt != NULL); - assert(ktp->enc->cbc_mac != NULL); - - made_cksum.data = k5alloc(trailer_len, &ret); - if (made_cksum.data == NULL) - goto cleanup; - made_cksum.length = trailer_len; - - /* Decrypt checksum from trailer using the first counter block. */ - got_cksum.flags = KRB5_CRYPTO_TYPE_DATA; - got_cksum.data = trailer->data; - ret = ktp->enc->decrypt(kc, &counter, &got_cksum, 1); - if (ret != 0) - goto cleanup; - - /* Decrypt everything but B0 (header) in subsequent counter blocks. */ - ret = ktp->enc->decrypt(kc, &counter, data, num_data); - if (ret != 0) - goto cleanup; - - /* Reorder input IOV so SIGN_ONLY data is before DATA */ - for (i = 0; i < num_data; i++) { - if (data[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) - sign_data[num_sign_data++] = data[i]; - } - for (i = 0; i < num_data; i++) { - if (data[i].flags == KRB5_CRYPTO_TYPE_DATA) - sign_data[num_sign_data++] = data[i]; - } - - /* Calculate CBC-MAC for comparison (including B0). */ - ret = ktp->enc->cbc_mac(kc, sign_data, num_sign_data, NULL, &made_cksum); - if (ret != 0) - goto cleanup; - - if (made_cksum.length != trailer->data.length || - memcmp(made_cksum.data, trailer->data.data, - trailer->data.length) != 0) { - ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; - goto cleanup; - } - - /* Store the counter value as cipher state. Subsequent encryptions will - * generate a fresh nonce. */ - if (state != NULL) - memcpy(state->data, counter.data + 1 + header_len, 15 - header_len); - -cleanup: - free(made_cksum.data); - free(sign_data); - - return ret; -} - -/* Derive an encryption key based on usage and CCM-decrypt data. */ -krb5_error_code -krb5int_dk_ccm_decrypt(const struct krb5_keytypes *ktp, krb5_key key, - krb5_keyusage usage, const krb5_data *state, - krb5_crypto_iov *data, size_t num_data) -{ - unsigned char constantdata[K5CLENGTH]; - krb5_error_code ret; - krb5_key kc; - krb5_data d1; - - d1.data = (char *)constantdata; - d1.length = K5CLENGTH; - - d1.data[0] = (usage >> 24) & 0xFF; - d1.data[1] = (usage >> 16) & 0xFF; - d1.data[2] = (usage >> 8 ) & 0xFF; - d1.data[3] = (usage ) & 0xFF; - - d1.data[4] = 0xCC; - - ret = krb5int_derive_key(ktp->enc, key, &kc, &d1, DERIVE_SP800_108_CMAC); - if (ret != 0) - return ret; - - ret = ccm_decrypt(ktp, kc, state, data, num_data); - - krb5_k_free_key(NULL, kc); - - return ret; -} - -krb5_error_code -krb5int_dk_ccm_init_state(const struct krb5_keytypes *ktp, - const krb5_keyblock *key, krb5_keyusage usage, - krb5_data *out_state) -{ - unsigned int header_len; - - /* The cipher state is the q-byte block counter value. */ - header_len = ktp->crypto_length(ktp, KRB5_CRYPTO_TYPE_HEADER); - return alloc_data(out_state, 15 - header_len); -} - -void -krb5int_dk_ccm_free_state(const struct krb5_keytypes *ktp, - krb5_data *state) -{ - free(state->data); - state->data = NULL; - state->length = 0; -} - -#endif /* CAMELLIA_CCM */ diff --git a/src/lib/crypto/krb/dk/dk_cmac.c b/src/lib/crypto/krb/dk/dk_cmac.c new file mode 100644 index 000000000..9ac5bee8f --- /dev/null +++ b/src/lib/crypto/krb/dk/dk_cmac.c @@ -0,0 +1,188 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* lib/crypto/dk/dk_cmac.c - Derived-key enctype functions using CMAC */ +/* + * Copyright 2008, 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 "k5-int.h" +#include "dk.h" +#include "aead.h" + +#ifdef CAMELLIA + +#define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */ + +/* AEAD */ + +unsigned int +krb5int_camellia_crypto_length(const struct krb5_keytypes *ktp, + krb5_cryptotype type) +{ + switch (type) { + case KRB5_CRYPTO_TYPE_HEADER: + return ktp->enc->block_size; + case KRB5_CRYPTO_TYPE_PADDING: + return 0; + case KRB5_CRYPTO_TYPE_TRAILER: + case KRB5_CRYPTO_TYPE_CHECKSUM: + return ktp->enc->block_size; + default: + assert(0 && "bad type passed to krb5int_camellia_crypto_length"); + return 0; + } +} + +/* Derive encryption and integrity keys for CMAC-using enctypes. */ +static krb5_error_code +derive_keys(const struct krb5_enc_provider *enc, krb5_key key, + krb5_keyusage usage, krb5_key *ke_out, krb5_key *ki_out) +{ + krb5_error_code ret; + unsigned char buf[K5CLENGTH]; + krb5_data constant = make_data(buf, K5CLENGTH); + krb5_key ke, ki; + + *ke_out = *ki_out = NULL; + + /* Derive the encryption key. */ + store_32_be(usage, buf); + buf[4] = 0xAA; + ret = krb5int_derive_key(enc, key, &ke, &constant, DERIVE_SP800_108_CMAC); + if (ret != 0) + return ret; + + /* Derive the integrity key. */ + buf[4] = 0x55; + ret = krb5int_derive_key(enc, key, &ki, &constant, DERIVE_SP800_108_CMAC); + if (ret != 0) { + krb5_k_free_key(NULL, ke); + return ret; + } + + *ke_out = ke; + *ki_out = ki; + return 0; +} + +krb5_error_code +krb5int_dk_cmac_encrypt(const struct krb5_keytypes *ktp, krb5_key key, + krb5_keyusage usage, const krb5_data *ivec, + krb5_crypto_iov *data, size_t num_data) +{ + const struct krb5_enc_provider *enc = ktp->enc; + krb5_error_code ret; + krb5_crypto_iov *header, *trailer, *padding; + krb5_data cksum = empty_data(); + krb5_key ke = NULL, ki = NULL; + + /* E(Confounder | Plaintext | Pad) | Checksum */ + + /* Validate header and trailer lengths, and zero out padding length. */ + header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER); + if (header == NULL || header->data.length < enc->block_size) + return KRB5_BAD_MSIZE; + trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); + if (trailer == NULL || trailer->data.length < enc->block_size) + return KRB5_BAD_MSIZE; + padding = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_PADDING); + if (padding != NULL) + padding->data.length = 0; + + /* Derive the encryption and integrity keys. */ + ret = derive_keys(enc, key, usage, &ke, &ki); + if (ret != 0) + goto cleanup; + + /* Generate confounder. */ + header->data.length = enc->block_size; + ret = krb5_c_random_make_octets(NULL, &header->data); + if (ret != 0) + goto cleanup; + + /* Checksum the plaintext. */ + ret = krb5int_cmac_checksum(enc, ki, data, num_data, &trailer->data); + if (ret != 0) + goto cleanup; + + /* Encrypt the plaintext (header | data | padding) */ + ret = enc->encrypt(ke, ivec, data, num_data); + if (ret != 0) + goto cleanup; + +cleanup: + krb5_k_free_key(NULL, ke); + krb5_k_free_key(NULL, ki); + zapfree(cksum.data, cksum.length); + return ret; +} + +krb5_error_code +krb5int_dk_cmac_decrypt(const struct krb5_keytypes *ktp, krb5_key key, + krb5_keyusage usage, const krb5_data *ivec, + krb5_crypto_iov *data, size_t num_data) +{ + const struct krb5_enc_provider *enc = ktp->enc; + krb5_error_code ret; + krb5_crypto_iov *header, *trailer; + krb5_data cksum; + krb5_key ke = NULL, ki = NULL; + + /* E(Confounder | Plaintext | Pad) | Checksum */ + + /* Validate header and trailer lengths. */ + header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER); + if (header == NULL || header->data.length != enc->block_size) + return KRB5_BAD_MSIZE; + trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); + if (trailer == NULL || trailer->data.length != enc->block_size) + return KRB5_BAD_MSIZE; + + /* Derive the encryption and integrity keys. */ + ret = derive_keys(enc, key, usage, &ke, &ki); + if (ret != 0) + goto cleanup; + + /* Decrypt the plaintext (header | data | padding). */ + ret = enc->decrypt(ke, ivec, data, num_data); + if (ret != 0) + goto cleanup; + + /* Verify the hash. */ + ret = alloc_data(&cksum, enc->block_size); + if (ret != 0) + goto cleanup; + ret = krb5int_cmac_checksum(enc, ki, data, num_data, &cksum); + if (ret != 0) + goto cleanup; + if (!data_eq(cksum, trailer->data)) + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + +cleanup: + krb5_k_free_key(NULL, ke); + krb5_k_free_key(NULL, ki); + zapfree(cksum.data, cksum.length); + return ret; +} + +#endif /* CAMELLIA */ diff --git a/src/lib/crypto/krb/dk/stringtokey.c b/src/lib/crypto/krb/dk/stringtokey.c index 12ef67a01..779f51bdf 100644 --- a/src/lib/crypto/krb/dk/stringtokey.c +++ b/src/lib/crypto/krb/dk/stringtokey.c @@ -101,14 +101,13 @@ cleanup: } -#define DEFAULT_ITERATION_COUNT 4096 /* was 0xb000L in earlier drafts */ #define MAX_ITERATION_COUNT 0x1000000L static krb5_error_code pbkdf2_string_to_key(const struct krb5_keytypes *ktp, const krb5_data *string, const krb5_data *salt, const krb5_data *pepper, const krb5_data *params, krb5_keyblock *key, - enum deriv_alg deriv_alg) + enum deriv_alg deriv_alg, unsigned long def_iter_count) { unsigned long iter_count; krb5_data out; @@ -129,7 +128,7 @@ pbkdf2_string_to_key(const struct krb5_keytypes *ktp, const krb5_data *string, return KRB5_ERR_BAD_S2K_PARAMS; } } else - iter_count = DEFAULT_ITERATION_COUNT; + iter_count = def_iter_count; /* This is not a protocol specification constraint; this is an implementation limit, which should eventually be controlled by @@ -182,20 +181,20 @@ krb5int_aes_string_to_key(const struct krb5_keytypes *ktp, krb5_keyblock *key) { return pbkdf2_string_to_key(ktp, string, salt, NULL, params, key, - DERIVE_RFC3961); + DERIVE_RFC3961, 4096); } -#ifdef CAMELLIA_CCM +#ifdef CAMELLIA krb5_error_code -krb5int_camellia_ccm_string_to_key(const struct krb5_keytypes *ktp, - const krb5_data *string, - const krb5_data *salt, - const krb5_data *params, - krb5_keyblock *key) +krb5int_camellia_string_to_key(const struct krb5_keytypes *ktp, + const krb5_data *string, + const krb5_data *salt, + const krb5_data *params, + krb5_keyblock *key) { krb5_data pepper = string2data(ktp->name); return pbkdf2_string_to_key(ktp, string, salt, &pepper, params, key, - DERIVE_SP800_108_CMAC); + DERIVE_SP800_108_CMAC, 32768); } #endif diff --git a/src/lib/crypto/krb/etypes.c b/src/lib/crypto/krb/etypes.c index 7a8d6f198..9703a939b 100644 --- a/src/lib/crypto/krb/etypes.c +++ b/src/lib/crypto/krb/etypes.c @@ -164,30 +164,32 @@ const struct krb5_keytypes krb5int_enctypes_list[] = { krb5int_init_state_enc, krb5int_free_state_enc, CKSUMTYPE_HMAC_SHA1_96_AES256, 0 /*flags*/ }, -#ifdef CAMELLIA_CCM - { ENCTYPE_CAMELLIA128_CCM_128, - "camellia128-ccm-128", { "camellia128-ccm" }, - "Camellia-128 CCM mode with 128-bit MAC", - &krb5int_enc_camellia128_ctr, NULL, +#ifdef CAMELLIA + { ENCTYPE_CAMELLIA128_CTS_CMAC, + "camellia128-cts-cmac", { "camellia128-cts" }, + "Camellia-128 CTS mode with CMAC", + &krb5int_enc_camellia128, NULL, 16, - krb5int_dk_ccm_crypto_length, krb5int_dk_ccm_encrypt, krb5int_dk_ccm_decrypt, - krb5int_camellia_ccm_string_to_key, + krb5int_camellia_crypto_length, + krb5int_dk_cmac_encrypt, krb5int_dk_cmac_decrypt, + krb5int_camellia_string_to_key, krb5int_dk_cmac_prf, - krb5int_dk_ccm_init_state, krb5int_dk_ccm_free_state, - CKSUMTYPE_CMAC_128_CAMELLIA128, + krb5int_init_state_enc, krb5int_free_state_enc, + CKSUMTYPE_CMAC_CAMELLIA128, 0 /*flags*/ }, - { ENCTYPE_CAMELLIA256_CCM_128, - "camellia256-ccm-128", { "camellia256-ccm" }, - "Camellia-256 CCM mode with 128-bit MAC", - &krb5int_enc_camellia256_ctr, NULL, + { ENCTYPE_CAMELLIA256_CTS_CMAC, + "camellia256-cts-cmac", { "camellia256-cts" }, + "Camellia-256 CTS mode with CMAC", + &krb5int_enc_camellia256, NULL, 16, - krb5int_dk_ccm_crypto_length, krb5int_dk_ccm_encrypt, krb5int_dk_ccm_decrypt, - krb5int_camellia_ccm_string_to_key, + krb5int_camellia_crypto_length, + krb5int_dk_cmac_encrypt, krb5int_dk_cmac_decrypt, + krb5int_camellia_string_to_key, krb5int_dk_cmac_prf, - krb5int_dk_ccm_init_state, krb5int_dk_ccm_free_state, - CKSUMTYPE_CMAC_128_CAMELLIA256, + krb5int_init_state_enc, krb5int_free_state_enc, + CKSUMTYPE_CMAC_CAMELLIA256, 0 /*flags */ }, -#endif /* CAMELLIA_CCM */ +#endif /* CAMELLIA */ }; const int krb5int_enctypes_length = diff --git a/src/lib/crypto/krb/prf/cmac_prf.c b/src/lib/crypto/krb/prf/cmac_prf.c index a9ad09ab2..78d11641c 100644 --- a/src/lib/crypto/krb/prf/cmac_prf.c +++ b/src/lib/crypto/krb/prf/cmac_prf.c @@ -33,7 +33,7 @@ #include "prf_int.h" #include <dk.h> -#ifdef CAMELLIA_CCM +#ifdef CAMELLIA krb5_error_code krb5int_dk_cmac_prf(const struct krb5_keytypes *ktp, krb5_key key, @@ -66,4 +66,4 @@ cleanup: return ret; } -#endif /* CAMELLIA_CCM */ +#endif /* CAMELLIA */ |
