summaryrefslogtreecommitdiffstats
path: root/src/lib/crypto/krb
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2010-11-20 00:31:46 +0000
committerGreg Hudson <ghudson@mit.edu>2010-11-20 00:31:46 +0000
commit41acda8ebd3517c3d0f2184c09741cd10d061182 (patch)
treedcc9695ff569763cfa96eff1c895d88d27721d12 /src/lib/crypto/krb
parent52bae3736c1835b8d7ba6b2e8bda370fe58f044b (diff)
downloadkrb5-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.c6
-rw-r--r--src/lib/crypto/krb/cksumtypes.c16
-rw-r--r--src/lib/crypto/krb/dk/Makefile.in6
-rw-r--r--src/lib/crypto/krb/dk/checksum_cmac.c4
-rw-r--r--src/lib/crypto/krb/dk/derive.c8
-rw-r--r--src/lib/crypto/krb/dk/dk.h47
-rw-r--r--src/lib/crypto/krb/dk/dk_ccm.c614
-rw-r--r--src/lib/crypto/krb/dk/dk_cmac.c188
-rw-r--r--src/lib/crypto/krb/dk/stringtokey.c21
-rw-r--r--src/lib/crypto/krb/etypes.c38
-rw-r--r--src/lib/crypto/krb/prf/cmac_prf.c4
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 */