diff options
author | Greg Hudson <ghudson@mit.edu> | 2010-09-30 21:57:42 +0000 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 2010-09-30 21:57:42 +0000 |
commit | 267657197005c84ec8af9a030b23d14f3be68f32 (patch) | |
tree | d927e631ca038c256159e50835bcec5d87135be9 /src/lib/crypto/krb/dk | |
parent | a787dec7564f865343ed511cd1710d3847d8778b (diff) | |
download | krb5-267657197005c84ec8af9a030b23d14f3be68f32.zip krb5-267657197005c84ec8af9a030b23d14f3be68f32.tar.gz krb5-267657197005c84ec8af9a030b23d14f3be68f32.tar.bz2 |
Merge r24242:24397 from trunk to branches/nss. This will break the
nss branch build temporarily due to Camellia changes.
git-svn-id: svn://anonsvn.mit.edu/krb5/branches/nss@24398 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib/crypto/krb/dk')
-rw-r--r-- | src/lib/crypto/krb/dk/Makefile.in | 12 | ||||
-rw-r--r-- | src/lib/crypto/krb/dk/checksum_cmac.c | 66 | ||||
-rw-r--r-- | src/lib/crypto/krb/dk/checksum_hmac.c (renamed from src/lib/crypto/krb/dk/checksum.c) | 2 | ||||
-rw-r--r-- | src/lib/crypto/krb/dk/deps | 48 | ||||
-rw-r--r-- | src/lib/crypto/krb/dk/derive.c | 128 | ||||
-rw-r--r-- | src/lib/crypto/krb/dk/dk.h | 60 | ||||
-rw-r--r-- | src/lib/crypto/krb/dk/dk_aead.c | 8 | ||||
-rw-r--r-- | src/lib/crypto/krb/dk/dk_ccm.c | 614 | ||||
-rw-r--r-- | src/lib/crypto/krb/dk/stringtokey.c | 57 |
9 files changed, 944 insertions, 51 deletions
diff --git a/src/lib/crypto/krb/dk/Makefile.in b/src/lib/crypto/krb/dk/Makefile.in index 8d65857..09df6c3 100644 --- a/src/lib/crypto/krb/dk/Makefile.in +++ b/src/lib/crypto/krb/dk/Makefile.in @@ -11,20 +11,26 @@ PROG_LIBPATH=-L$(TOPLIBD) PROG_RPATH=$(KRB5_LIBDIR) STLIBOBJS=\ - checksum.o \ + checksum_hmac.o \ + checksum_cmac.o \ dk_aead.o \ + dk_ccm.o \ derive.o \ stringtokey.o OBJS=\ - $(OUTPRE)checksum.$(OBJEXT) \ + $(OUTPRE)checksum_hmac.$(OBJEXT)\ + $(OUTPRE)checksum_cmac.$(OBJEXT)\ $(OUTPRE)dk_aead.$(OBJEXT) \ + $(OUTPRE)dk_ccm.$(OBJEXT) \ $(OUTPRE)derive.$(OBJEXT) \ $(OUTPRE)stringtokey.$(OBJEXT) SRCS=\ - $(srcdir)/checksum.c \ + $(srcdir)/checksum_hmac.c \ + $(srcdir)/checksum_cmac.c \ $(srcdir)/dk_aead.c \ + $(srcdir)/dk_ccm.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 new file mode 100644 index 0000000..c2309b7 --- /dev/null +++ b/src/lib/crypto/krb/dk/checksum_cmac.c @@ -0,0 +1,66 @@ +/* + * lib/crypto/krb/dk/checksum_cmac.c + * + * Copyright 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 "etypes.h" +#include "dk.h" +#include "aead.h" +#include "cksumtypes.h" + +#define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */ + +#ifdef CAMELLIA_CCM + +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) +{ + const struct krb5_enc_provider *enc = ctp->enc; + krb5_error_code ret; + unsigned char constantdata[K5CLENGTH]; + krb5_data datain; + krb5_key kc; + + /* Derive the key. */ + datain = make_data(constantdata, K5CLENGTH); + store_32_be(usage, constantdata); + constantdata[4] = (char) 0x99; + ret = krb5int_derive_key(enc, key, &kc, &datain, DERIVE_SP800_108_CMAC); + if (ret != 0) + return ret; + + /* Hash the data. */ + ret = krb5int_cmac_checksum(enc, kc, data, num_data, output); + if (ret != 0) + memset(output->data, 0, output->length); + + krb5_k_free_key(NULL, kc); + return ret; +} + +#endif /* CAMELLIA_CCM */ diff --git a/src/lib/crypto/krb/dk/checksum.c b/src/lib/crypto/krb/dk/checksum_hmac.c index 3dbde10..ae51aa3 100644 --- a/src/lib/crypto/krb/dk/checksum.c +++ b/src/lib/crypto/krb/dk/checksum_hmac.c @@ -57,7 +57,7 @@ krb5int_dk_checksum(const struct krb5_cksumtypes *ctp, datain = make_data(constantdata, K5CLENGTH); store_32_be(usage, constantdata); constantdata[4] = (char) 0x99; - ret = krb5int_derive_key(enc, key, &kc, &datain); + ret = krb5int_derive_key(enc, key, &kc, &datain, DERIVE_RFC3961); if (ret) return ret; diff --git a/src/lib/crypto/krb/dk/deps b/src/lib/crypto/krb/dk/deps index 947b73a..a7b610f 100644 --- a/src/lib/crypto/krb/dk/deps +++ b/src/lib/crypto/krb/dk/deps @@ -1,7 +1,7 @@ # # Generated makefile dependencies follow. # -checksum.so checksum.po $(OUTPRE)checksum.$(OBJEXT): \ +checksum_hmac.so checksum_hmac.po $(OUTPRE)checksum_hmac.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ $(COM_ERR_DEPS) $(srcdir)/../cksumtypes.h $(srcdir)/../etypes.h \ @@ -11,8 +11,23 @@ checksum.so checksum.po $(OUTPRE)checksum.$(OBJEXT): \ $(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/locate_plugin.h \ + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \ + $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ + checksum_hmac.c dk.h +checksum_cmac.so checksum_cmac.po $(OUTPRE)checksum_cmac.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(srcdir)/../aead.h $(srcdir)/../cksumtypes.h \ + $(srcdir)/../etypes.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/locate_plugin.h $(top_srcdir)/include/krb5/plugin.h \ $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/port-sockets.h \ - $(top_srcdir)/include/socket-utils.h checksum.c dk.h + $(top_srcdir)/include/socket-utils.h checksum_cmac.c \ + dk.h dk_aead.so dk_aead.po $(OUTPRE)dk_aead.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../aead.h \ @@ -22,9 +37,21 @@ dk_aead.so dk_aead.po $(OUTPRE)dk_aead.$(OBJEXT): $(BUILDTOP)/include/autoconf.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/locate_plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \ - $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ - dk.h dk_aead.c + $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/plugin.h \ + $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h dk.h dk_aead.c +dk_ccm.so dk_ccm.po $(OUTPRE)dk_ccm.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../aead.h \ + $(srcdir)/../cksumtypes.h $(srcdir)/../etypes.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/locate_plugin.h $(top_srcdir)/include/krb5/plugin.h \ + $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h dk.h dk_ccm.c derive.so derive.po $(OUTPRE)derive.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../cksumtypes.h \ @@ -34,9 +61,9 @@ derive.so derive.po $(OUTPRE)derive.$(OBJEXT): $(BUILDTOP)/include/autoconf.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/locate_plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \ - $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ - derive.c dk.h + $(top_srcdir)/include/krb5/locate_plugin.h $(top_srcdir)/include/krb5/plugin.h \ + $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h derive.c dk.h stringtokey.so stringtokey.po $(OUTPRE)stringtokey.$(OBJEXT): \ $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ @@ -47,5 +74,6 @@ stringtokey.so stringtokey.po $(OUTPRE)stringtokey.$(OBJEXT): \ $(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/locate_plugin.h \ - $(top_srcdir)/include/krb5/preauth_plugin.h $(top_srcdir)/include/port-sockets.h \ - $(top_srcdir)/include/socket-utils.h dk.h stringtokey.c + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/krb5/preauth_plugin.h \ + $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ + dk.h stringtokey.c diff --git a/src/lib/crypto/krb/dk/derive.c b/src/lib/crypto/krb/dk/derive.c index 5fd8876..a7ad2e3 100644 --- a/src/lib/crypto/krb/dk/derive.c +++ b/src/lib/crypto/krb/dk/derive.c @@ -79,14 +79,14 @@ cleanup: return ENOMEM; } -krb5_error_code -krb5int_derive_random(const struct krb5_enc_provider *enc, +static krb5_error_code +derive_random_rfc3961(const struct krb5_enc_provider *enc, krb5_key inkey, krb5_data *outrnd, const krb5_data *in_constant) { size_t blocksize, keybytes, n; - krb5_crypto_iov iov; krb5_error_code ret; + krb5_data block = empty_data(); blocksize = enc->block_size; keybytes = enc->keybytes; @@ -95,41 +95,136 @@ krb5int_derive_random(const struct krb5_enc_provider *enc, return KRB5_CRYPTO_INTERNAL; /* Allocate encryption data buffer. */ - iov.flags = KRB5_CRYPTO_TYPE_DATA; - ret = alloc_data(&iov.data, blocksize); + ret = alloc_data(&block, blocksize); if (ret) return ret; /* Initialize the input block. */ if (in_constant->length == blocksize) { - memcpy(iov.data.data, in_constant->data, blocksize); + memcpy(block.data, in_constant->data, blocksize); } else { krb5int_nfold(in_constant->length * 8, (unsigned char *) in_constant->data, - blocksize * 8, (unsigned char *) iov.data.data); + blocksize * 8, (unsigned char *) block.data); } /* Loop encrypting the blocks until enough key bytes are generated. */ n = 0; while (n < keybytes) { - ret = enc->encrypt(inkey, 0, &iov, 1); + ret = encrypt_block(enc, inkey, &block); if (ret) goto cleanup; if ((keybytes - n) <= blocksize) { - memcpy(outrnd->data + n, iov.data.data, (keybytes - n)); + memcpy(outrnd->data + n, block.data, (keybytes - n)); break; } - memcpy(outrnd->data + n, iov.data.data, blocksize); + memcpy(outrnd->data + n, block.data, blocksize); n += blocksize; } cleanup: - zapfree(iov.data.data, blocksize); + zapfree(block.data, blocksize); return ret; } +#ifdef CAMELLIA_CCM + +/* + * NIST SP800-108 KDF in feedback mode (section 5.2). + * Parameters: + * - CMAC (with enc as the enc provider) is the PRF. + * - A block counter of four bytes is used. + * - Label is the key derivation constant. + * - Context is empty. + * - Four bytes are used to encode the output length in the PRF input. + */ +static krb5_error_code +derive_random_sp800_108_cmac(const struct krb5_enc_provider *enc, + krb5_key inkey, krb5_data *outrnd, + const krb5_data *in_constant) +{ + size_t blocksize, keybytes, n; + krb5_crypto_iov iov[6]; + krb5_error_code ret; + krb5_data prf; + unsigned int i; + unsigned char ibuf[4], Lbuf[4]; + + blocksize = enc->block_size; + keybytes = enc->keybytes; + + if (inkey->keyblock.length != enc->keylength || outrnd->length != keybytes) + return KRB5_CRYPTO_INTERNAL; + + /* Allocate encryption data buffer. */ + ret = alloc_data(&prf, blocksize); + if (ret) + return ret; + + /* K(i-1): the previous block of PRF output, initially all-zeros. */ + iov[0].flags = KRB5_CRYPTO_TYPE_DATA; + iov[0].data = prf; + /* [i]2: four-byte big-endian binary string giving the block counter */ + iov[1].flags = KRB5_CRYPTO_TYPE_DATA; + iov[1].data = make_data(ibuf, sizeof(ibuf)); + /* Label: the fixed derived-key input */ + iov[2].flags = KRB5_CRYPTO_TYPE_DATA; + iov[2].data = *in_constant; + /* 0x00: separator byte */ + iov[3].flags = KRB5_CRYPTO_TYPE_DATA; + iov[3].data = make_data("", 1); + /* Context: (unused) */ + iov[4].flags = KRB5_CRYPTO_TYPE_DATA; + iov[4].data = empty_data(); + /* [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); + + for (i = 1, n = 0; n < keybytes; i++) { + /* Update the block counter. */ + store_32_be(i, ibuf); + + /* Compute a CMAC checksum, storing the result into K(i-1). */ + ret = krb5int_cmac_checksum(enc, inkey, iov, 6, &prf); + if (ret) + goto cleanup; + + /* Copy the result into the appropriate part of the output buffer. */ + if (keybytes - n <= blocksize) { + memcpy(outrnd->data + n, prf.data, keybytes - n); + break; + } + memcpy(outrnd->data + n, prf.data, blocksize); + n += blocksize; + } + +cleanup: + zapfree(prf.data, blocksize); + return ret; +} + +#endif /* CAMELLIA_CCM */ + +krb5_error_code +krb5int_derive_random(const struct krb5_enc_provider *enc, + krb5_key inkey, krb5_data *outrnd, + const krb5_data *in_constant, enum deriv_alg alg) +{ + switch (alg) { + case DERIVE_RFC3961: + return derive_random_rfc3961(enc, inkey, outrnd, in_constant); +#ifdef CAMELLIA_CCM + case DERIVE_SP800_108_CMAC: + return derive_random_sp800_108_cmac(enc, inkey, outrnd, in_constant); +#endif + default: + return EINVAL; + } +} + /* * Compute a derived key into the keyblock outkey. This variation on * krb5int_derive_key does not cache the result, as it is only used @@ -139,7 +234,7 @@ cleanup: krb5_error_code krb5int_derive_keyblock(const struct krb5_enc_provider *enc, krb5_key inkey, krb5_keyblock *outkey, - const krb5_data *in_constant) + const krb5_data *in_constant, enum deriv_alg alg) { krb5_error_code ret; krb5_data rawkey = empty_data(); @@ -150,7 +245,7 @@ krb5int_derive_keyblock(const struct krb5_enc_provider *enc, goto cleanup; /* Derive pseudo-random data for the key bytes. */ - ret = krb5int_derive_random(enc, inkey, &rawkey, in_constant); + ret = krb5int_derive_random(enc, inkey, &rawkey, in_constant, alg); if (ret) goto cleanup; @@ -165,7 +260,7 @@ cleanup: krb5_error_code krb5int_derive_key(const struct krb5_enc_provider *enc, krb5_key inkey, krb5_key *outkey, - const krb5_data *in_constant) + const krb5_data *in_constant, enum deriv_alg alg) { krb5_keyblock keyblock; krb5_error_code ret; @@ -183,13 +278,10 @@ krb5int_derive_key(const struct krb5_enc_provider *enc, /* Derive into a temporary keyblock. */ keyblock.length = enc->keylength; keyblock.contents = malloc(keyblock.length); - /* Set the enctype as the krb5_k_free_key will iterate over list - or derived keys and invoke krb5_k_free_key which will lookup - the enctype for key_cleanup handler */ keyblock.enctype = inkey->keyblock.enctype; if (keyblock.contents == NULL) return ENOMEM; - ret = krb5int_derive_keyblock(enc, inkey, &keyblock, in_constant); + ret = krb5int_derive_keyblock(enc, inkey, &keyblock, in_constant, alg); if (ret) goto cleanup; diff --git a/src/lib/crypto/krb/dk/dk.h b/src/lib/crypto/krb/dk/dk.h index 0fdd984..fb6df88 100644 --- a/src/lib/crypto/krb/dk/dk.h +++ b/src/lib/crypto/krb/dk/dk.h @@ -58,16 +58,28 @@ 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); + +enum deriv_alg { + DERIVE_RFC3961, /* RFC 3961 section 5.1 */ +#ifdef CAMELLIA_CCM + DERIVE_SP800_108_CMAC /* NIST SP 800-108 with CMAC as PRF */ +#endif +}; + +krb5_error_code krb5int_derive_keyblock(const struct krb5_enc_provider *enc, - krb5_key inkey, - krb5_keyblock *outkey, - const krb5_data *in_constant); + krb5_key inkey, krb5_keyblock *outkey, + const krb5_data *in_constant, enum deriv_alg alg); krb5_error_code krb5int_derive_key(const struct krb5_enc_provider *enc, - krb5_key inkey, - krb5_key *outkey, - const krb5_data *in_constant); + krb5_key inkey, krb5_key *outkey, + const krb5_data *in_constant, enum deriv_alg alg); krb5_error_code krb5int_dk_checksum(const struct krb5_cksumtypes *ctp, @@ -78,4 +90,38 @@ krb5int_dk_checksum(const struct krb5_cksumtypes *ctp, krb5_error_code krb5int_derive_random(const struct krb5_enc_provider *enc, krb5_key inkey, krb5_data *outrnd, - const krb5_data *in_constant); + 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); + +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); + +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_aead.c b/src/lib/crypto/krb/dk/dk_aead.c index f44ae84..4e9a7c4 100644 --- a/src/lib/crypto/krb/dk/dk_aead.c +++ b/src/lib/crypto/krb/dk/dk_aead.c @@ -134,13 +134,13 @@ krb5int_dk_encrypt(const struct krb5_keytypes *ktp, krb5_key key, d1.data[4] = 0xAA; - ret = krb5int_derive_key(enc, key, &ke, &d1); + ret = krb5int_derive_key(enc, key, &ke, &d1, DERIVE_RFC3961); if (ret != 0) goto cleanup; d1.data[4] = 0x55; - ret = krb5int_derive_key(enc, key, &ki, &d1); + ret = krb5int_derive_key(enc, key, &ki, &d1, DERIVE_RFC3961); if (ret != 0) goto cleanup; @@ -235,13 +235,13 @@ krb5int_dk_decrypt(const struct krb5_keytypes *ktp, krb5_key key, d1.data[4] = 0xAA; - ret = krb5int_derive_key(enc, key, &ke, &d1); + ret = krb5int_derive_key(enc, key, &ke, &d1, DERIVE_RFC3961); if (ret != 0) goto cleanup; d1.data[4] = 0x55; - ret = krb5int_derive_key(enc, key, &ki, &d1); + ret = krb5int_derive_key(enc, key, &ki, &d1, DERIVE_RFC3961); if (ret != 0) goto cleanup; diff --git a/src/lib/crypto/krb/dk/dk_ccm.c b/src/lib/crypto/krb/dk/dk_ccm.c new file mode 100644 index 0000000..284e362 --- /dev/null +++ b/src/lib/crypto/krb/dk/dk_ccm.c @@ -0,0 +1,614 @@ +/* + * 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/stringtokey.c b/src/lib/crypto/krb/dk/stringtokey.c index 4c7206c..12ef67a 100644 --- a/src/lib/crypto/krb/dk/stringtokey.c +++ b/src/lib/crypto/krb/dk/stringtokey.c @@ -87,7 +87,8 @@ krb5int_dk_string_to_key(const struct krb5_keytypes *ktp, indata.length = kerberos_len; indata.data = (char *) kerberos; - ret = krb5int_derive_keyblock(enc, foldkey, keyblock, &indata); + ret = krb5int_derive_keyblock(enc, foldkey, keyblock, &indata, + DERIVE_RFC3961); if (ret != 0) memset(keyblock->contents, 0, keyblock->length); @@ -103,18 +104,18 @@ cleanup: #define DEFAULT_ITERATION_COUNT 4096 /* was 0xb000L in earlier drafts */ #define MAX_ITERATION_COUNT 0x1000000L -krb5_error_code -krb5int_aes_string_to_key(const struct krb5_keytypes *ktp, - const krb5_data *string, - const krb5_data *salt, - const krb5_data *params, - krb5_keyblock *key) +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) { unsigned long iter_count; krb5_data out; static const krb5_data usage = { KV5M_DATA, 8, "kerberos" }; krb5_key tempkey = NULL; krb5_error_code err; + krb5_data sandp = empty_data(); if (params) { unsigned char *p = (unsigned char *) params->data; @@ -142,6 +143,18 @@ krb5int_aes_string_to_key(const struct krb5_keytypes *ktp, if (out.length != 16 && out.length != 32) return KRB5_CRYPTO_INTERNAL; + if (pepper != NULL) { + err = alloc_data(&sandp, pepper->length + 1 + salt->length); + if (err) + return err; + + memcpy(sandp.data, pepper->data, pepper->length); + sandp.data[pepper->length] = '\0'; + memcpy(&sandp.data[pepper->length + 1], salt->data, salt->length); + + salt = &sandp; + } + err = krb5int_pbkdf2_hmac_sha1 (&out, iter_count, string, salt); if (err) goto cleanup; @@ -150,11 +163,39 @@ krb5int_aes_string_to_key(const struct krb5_keytypes *ktp, if (err) goto cleanup; - err = krb5int_derive_keyblock(ktp->enc, tempkey, key, &usage); + err = krb5int_derive_keyblock(ktp->enc, tempkey, key, &usage, deriv_alg); cleanup: + if (sandp.data) + free(sandp.data); if (err) memset (out.data, 0, out.length); krb5_k_free_key (NULL, tempkey); return err; } + +krb5_error_code +krb5int_aes_string_to_key(const struct krb5_keytypes *ktp, + const krb5_data *string, + const krb5_data *salt, + const krb5_data *params, + krb5_keyblock *key) +{ + return pbkdf2_string_to_key(ktp, string, salt, NULL, params, key, + DERIVE_RFC3961); +} + +#ifdef CAMELLIA_CCM +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) +{ + krb5_data pepper = string2data(ktp->name); + + return pbkdf2_string_to_key(ktp, string, salt, &pepper, params, key, + DERIVE_SP800_108_CMAC); +} +#endif |