aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2010-07-30 20:13:20 +0000
committerGreg Hudson <ghudson@mit.edu>2010-07-30 20:13:20 +0000
commit96a16ea265ebd03c32c1ac4d9c923d6873c20056 (patch)
tree627f945906705767638dbcfcb5ec77ea3933c2f7 /src
parent1ac070880d81a541735986eede6a37a5e60073c5 (diff)
downloadkrb5-96a16ea265ebd03c32c1ac4d9c923d6873c20056.zip
krb5-96a16ea265ebd03c32c1ac4d9c923d6873c20056.tar.gz
krb5-96a16ea265ebd03c32c1ac4d9c923d6873c20056.tar.bz2
Add comments to the CMAC implementation relating it to specific steps
in the RFC 4493 algorithm description, and adjust the code to make it clearer what we're doing with the ivecs we're passing to the enc provider cbc_mac method. Add a test program for CMAC with Camellia-128, using the RFC 4493 test vector inputs. git-svn-id: svn://anonsvn.mit.edu/krb5/branches/camellia-ccm@24221 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src')
-rw-r--r--src/lib/crypto/crypto_tests/Makefile.in11
-rw-r--r--src/lib/crypto/crypto_tests/t_cmac.c142
-rw-r--r--src/lib/crypto/krb/checksum/cmac.c27
-rw-r--r--src/lib/crypto/libk5crypto.exports2
4 files changed, 168 insertions, 14 deletions
diff --git a/src/lib/crypto/crypto_tests/Makefile.in b/src/lib/crypto/crypto_tests/Makefile.in
index f8460f6..38a6aea 100644
--- a/src/lib/crypto/crypto_tests/Makefile.in
+++ b/src/lib/crypto/crypto_tests/Makefile.in
@@ -19,6 +19,7 @@ EXTRADEPSRCS=\
$(srcdir)/t_encrypt.c \
$(srcdir)/t_prf.c \
$(srcdir)/t_prng.c \
+ $(srcdir)/t_cmac.c \
$(srcdir)/t_hmac.c \
$(srcdir)/t_pkcs5.c \
$(srcdir)/t_cts.c \
@@ -43,7 +44,7 @@ EXTRADEPSRCS=\
# NOTE: The t_cksum known checksum values are primarily for regression
# testing. They are not derived a priori, but are known to produce
# checksums that interoperate.
-check-unix:: t_nfold t_encrypt t_prf t_prng t_hmac \
+check-unix:: t_nfold t_encrypt t_prf t_prng t_cmac t_hmac \
t_cksum4 t_cksum5 \
aes-test \
camellia-test \
@@ -53,6 +54,7 @@ check-unix:: t_nfold t_encrypt t_prf t_prng t_hmac \
$(RUN_SETUP) $(VALGRIND) ./t_encrypt
$(RUN_SETUP) $(VALGRIND) ./t_prng <$(srcdir)/t_prng.seed >t_prng.output && \
diff t_prng.output $(srcdir)/t_prng.expected
+ $(RUN_SETUP) $(VALGRIND) ./t_cmac
$(RUN_SETUP) $(VALGRIND) ./t_hmac
$(RUN_SETUP) $(VALGRIND) ./t_prf <$(srcdir)/t_prf.in >t_prf.output
diff t_prf.output $(srcdir)/t_prf.expected
@@ -90,6 +92,9 @@ t_prf$(EXEEXT): t_prf.$(OBJEXT) $(SUPPORT_DEPLIB)
t_prng$(EXEEXT): t_prng.$(OBJEXT) $(SUPPORT_DEPLIB)
$(CC_LINK) -o $@ t_prng.$(OBJEXT) -lk5crypto -lcom_err $(SUPPORT_LIB)
+t_cmac$(EXEEXT): t_cmac.$(OBJEXT) $(CRYPTO_DEPLIB) $(SUPPORT_DEPLIB)
+ $(CC_LINK) -o $@ t_cmac.$(OBJEXT) $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB)
+
t_hmac$(EXEEXT): t_hmac.$(OBJEXT) $(CRYPTO_DEPLIB) $(SUPPORT_DEPLIB)
$(CC_LINK) -o $@ t_hmac.$(OBJEXT) $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB)
@@ -147,8 +152,8 @@ ytest: ytest.o shs.o $(SUPPORT_DEPLIB) $(CRYPTO_DEPLIB)
clean::
$(RM) t_nfold.o t_nfold nfold.$(OBJEXT) t_encrypt t_encrypt.o \
- t_prng.o t_prng t_hmac.o t_hmac t_pkcs5.o t_pkcs5 pbkdf2.o \
- t_prf t_prf.o \
+ t_prng.o t_prng t_cmac.o t_cmac t_hmac.o t_hmac \
+ t_pkcs5.o t_pkcs5 pbkdf2.o t_prf t_prf.o \
aes-test.o aes-test vt.txt vk.txt kresults.out \
t_cksum.o t_cksum \
t_crc.o t_crc t_cts.o t_cts \
diff --git a/src/lib/crypto/crypto_tests/t_cmac.c b/src/lib/crypto/crypto_tests/t_cmac.c
new file mode 100644
index 0000000..05ac012
--- /dev/null
+++ b/src/lib/crypto/crypto_tests/t_cmac.c
@@ -0,0 +1,142 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * lib/crypto/t_hmac.c
+ *
+ * Copyright 2001,2002 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.
+ *
+ *
+ * Test vectors for CMAC. Inputs are taken from RFC 4493 section 4. Outputs
+ * are changed for the use of Camellia-128 in place of AES-128.
+ *
+ * Ideally we would double-check subkey values, but we have no easy way to see
+ * them.
+ *
+ * Ideally we would test AES-CMAC against the expected results in RFC 4493,
+ * instead of results we generated ourselves. This was done manually, but is
+ * not convenient to do automatically since the AES-128 enc provider has no
+ * cbc_mac method and therefore cannot be used with krb5int_cmac_checksum.
+ */
+
+#include "k5-int.h"
+#include "enc_provider.h"
+#include "cksumtypes.h"
+
+/* All examples use the following Camellia-128 key. */
+static unsigned char keybytes[] = {
+ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+};
+
+/* Example inputs are this message truncated to 0, 16, 40, and 64 bytes. */
+unsigned char input[] = {
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
+};
+
+/* Expected result of CMAC on empty input. */
+static unsigned char cmac1[] = {
+ 0xba, 0x92, 0x57, 0x82, 0xaa, 0xa1, 0xf5, 0xd9,
+ 0xa0, 0x0f, 0x89, 0x64, 0x80, 0x94, 0xfc, 0x71
+};
+
+/* Expected result of CMAC on first 16 bytes of input. */
+static unsigned char cmac2[] = {
+ 0x6d, 0x96, 0x28, 0x54, 0xa3, 0xb9, 0xfd, 0xa5,
+ 0x6d, 0x7d, 0x45, 0xa9, 0x5e, 0xe1, 0x79, 0x93
+};
+
+/* Expected result of CMAC on first 40 bytes of input. */
+static unsigned char cmac3[] = {
+ 0x5c, 0x18, 0xd1, 0x19, 0xcc, 0xd6, 0x76, 0x61,
+ 0x44, 0xac, 0x18, 0x66, 0x13, 0x1d, 0x9f, 0x22
+};
+
+/* Expected result of CMAC on all 64 bytes of input. */
+static unsigned char cmac4[] = {
+ 0xc2, 0x69, 0x9a, 0x6e, 0xba, 0x55, 0xce, 0x9d,
+ 0x93, 0x9a, 0x8a, 0x4e, 0x19, 0x46, 0x6e, 0xe9
+};
+
+static void
+check_result(const char *name, const unsigned char *result,
+ const unsigned char *expected)
+{
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ if (result[i] != expected[i]) {
+ fprintf(stderr, "CMAC test vector failure: %s\n", name);
+ exit(1);
+ }
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ krb5_context context = NULL;
+ krb5_keyblock keyblock;
+ krb5_key key;
+ const struct krb5_enc_provider *enc = &krb5int_enc_camellia128_ctr;
+ krb5_crypto_iov iov;
+ unsigned char resultbuf[16];
+ krb5_data result = make_data(resultbuf, 16);
+
+ /* Create the example key. */
+ keyblock.magic = KV5M_KEYBLOCK;
+ keyblock.enctype = ENCTYPE_CAMELLIA128_CCM_128;
+ keyblock.length = 16;
+ keyblock.contents = keybytes;
+ assert(krb5_k_create_key(context, &keyblock, &key) == 0);
+
+ /* Example 1. */
+ iov.flags = KRB5_CRYPTO_TYPE_DATA;
+ iov.data = make_data(input, 0);
+ assert(krb5int_cmac_checksum(enc, key, &iov, 1, &result) == 0);
+ check_result("example 1", resultbuf, cmac1);
+
+ /* Example 2. */
+ iov.data.length = 16;
+ assert(krb5int_cmac_checksum(enc, key, &iov, 1, &result) == 0);
+ check_result("example 2", resultbuf, cmac2);
+
+ /* Example 1. */
+ iov.data.length = 40;
+ assert(krb5int_cmac_checksum(enc, key, &iov, 1, &result) == 0);
+ check_result("example 3", resultbuf, cmac3);
+
+ /* Example 1. */
+ iov.data.length = 64;
+ assert(krb5int_cmac_checksum(enc, key, &iov, 1, &result) == 0);
+ check_result("example 4", resultbuf, cmac4);
+
+ printf("All CMAC tests passed.\n");
+ krb5_k_free_key(context, key);
+ return 0;
+}
diff --git a/src/lib/crypto/krb/checksum/cmac.c b/src/lib/crypto/krb/checksum/cmac.c
index 5f4aefb..d660911 100644
--- a/src/lib/crypto/krb/checksum/cmac.c
+++ b/src/lib/crypto/krb/checksum/cmac.c
@@ -79,6 +79,7 @@ leftshift_onebit(unsigned char *input, unsigned char *output)
}
}
+/* Generate subkeys K1 and K2 as described in RFC 4493 figure 2.2. */
static krb5_error_code
generate_subkey(const struct krb5_enc_provider *enc,
krb5_key key,
@@ -92,16 +93,17 @@ generate_subkey(const struct krb5_enc_provider *enc,
krb5_data d;
krb5_error_code ret;
+ /* L := encrypt(K, const_Zero) */
memset(Z, 0, sizeof(Z));
iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
iov[0].data = make_data(Z, sizeof(Z));
-
d = make_data(L, BLOCK_SIZE);
-
+ /* cbc-mac is the same as block encrypt if invoked on a single block. */
ret = enc->cbc_mac(key, iov, 1, NULL, &d);
if (ret != 0)
return ret;
+ /* K1 := (MSB(L) == 0) ? L << 1 : (L << 1) XOR const_Rb */
if ((L[0] & 0x80) == 0) {
leftshift_onebit(L, K1);
} else {
@@ -109,6 +111,7 @@ generate_subkey(const struct krb5_enc_provider *enc,
xor_128(tmp, const_Rb, K1);
}
+ /* K2 := (MSB(K1) == 0) ? K1 << 1 : (K1 << 1) XOR const_Rb */
if ((K1[0] & 0x80) == 0) {
leftshift_onebit(K1, K2);
} else {
@@ -119,6 +122,7 @@ generate_subkey(const struct krb5_enc_provider *enc,
return 0;
}
+/* Pad out lastb with a 1 bit followed by 0 bits, placing the result in pad. */
static void
padding(unsigned char *lastb, unsigned char *pad, int length)
{
@@ -138,7 +142,7 @@ padding(unsigned char *lastb, unsigned char *pad, int length)
/*
* Implementation of CMAC algorithm. When used with AES, this function
- * is compatible with RFC 4493.
+ * is compatible with RFC 4493 figure 2.3.
*/
krb5_error_code
krb5int_cmac_checksum(const struct krb5_enc_provider *enc, krb5_key key,
@@ -152,7 +156,6 @@ krb5int_cmac_checksum(const struct krb5_enc_provider *enc, krb5_key key,
krb5_error_code ret;
struct iov_block_state iov_state;
unsigned int length;
- krb5_data ivec;
krb5_crypto_iov iov[1];
krb5_data d;
@@ -168,12 +171,15 @@ krb5int_cmac_checksum(const struct krb5_enc_provider *enc, krb5_key key,
length += piov->data.length;
}
+ /* Step 1. */
ret = generate_subkey(enc, key, K1, K2);
if (ret != 0)
return ret;
+ /* Step 2. */
n = (length + BLOCK_SIZE - 1) / BLOCK_SIZE;
+ /* Step 3. */
if (n == 0) {
n = 1;
flag = 0;
@@ -184,24 +190,23 @@ krb5int_cmac_checksum(const struct krb5_enc_provider *enc, krb5_key key,
iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
iov[0].data = make_data(input, BLOCK_SIZE);
+ /* Step 5 (we'll do step 4 in a bit). */
memset(Y, 0, BLOCK_SIZE);
-
- ivec = make_data(Y, BLOCK_SIZE);
d = make_data(Y, BLOCK_SIZE);
+ /* Step 6 (all but last block). */
IOV_BLOCK_STATE_INIT(&iov_state);
iov_state.include_sign_only = 1;
-
for (i = 0; i < n - 1; i++) {
krb5int_c_iov_get_block(input, BLOCK_SIZE, data, num_data, &iov_state);
- ret = enc->cbc_mac(key, iov, 1, &ivec, &d);
+ ret = enc->cbc_mac(key, iov, 1, &d, &d);
if (ret != 0)
return ret;
}
+ /* Step 4. */
krb5int_c_iov_get_block(input, BLOCK_SIZE, data, num_data, &iov_state);
-
if (flag) {
/* last block is complete block */
xor_128(input, K1, M_last);
@@ -210,9 +215,9 @@ krb5int_cmac_checksum(const struct krb5_enc_provider *enc, krb5_key key,
xor_128(padded, K2, M_last);
}
+ /* Step 6 (last block). */
iov[0].data = make_data(M_last, BLOCK_SIZE);
-
- ret = enc->cbc_mac(key, iov, 1, &ivec, &d);
+ ret = enc->cbc_mac(key, iov, 1, &d, &d);
if (ret != 0)
return ret;
diff --git a/src/lib/crypto/libk5crypto.exports b/src/lib/crypto/libk5crypto.exports
index 4160db6..114b6c9 100644
--- a/src/lib/crypto/libk5crypto.exports
+++ b/src/lib/crypto/libk5crypto.exports
@@ -96,3 +96,5 @@ krb5int_aes_decrypt
krb5int_enc_des3
krb5int_arcfour_gsscrypt
krb5int_camellia_cbc_mac
+krb5int_cmac_checksum
+krb5int_enc_camellia128_ctr