diff options
author | Zhanna Tsitkov <tsitkova@mit.edu> | 2009-08-03 14:19:16 +0000 |
---|---|---|
committer | Zhanna Tsitkov <tsitkova@mit.edu> | 2009-08-03 14:19:16 +0000 |
commit | 3c40c7f134b4e87baa43b0cacb435b6f96245e2f (patch) | |
tree | 2b1014db60c1d3941f17a4d00221e07cc5cece62 /src/lib/crypto/krb/dk | |
parent | ab7ffb919b4ee5ee5bc07f987d9163202a632e6a (diff) | |
download | krb5-3c40c7f134b4e87baa43b0cacb435b6f96245e2f.zip krb5-3c40c7f134b4e87baa43b0cacb435b6f96245e2f.tar.gz krb5-3c40c7f134b4e87baa43b0cacb435b6f96245e2f.tar.bz2 |
Crypto modularity proj: Separate files under crypto directory based on their functionality. Move Kerberos specific files into krb subdir and MIT specific - into builtin subdir. Place all tests into crypto_tests subfolder.
bigredbutton: whitespace
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@22477 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib/crypto/krb/dk')
-rw-r--r-- | src/lib/crypto/krb/dk/Makefile.in | 53 | ||||
-rw-r--r-- | src/lib/crypto/krb/dk/checksum.c | 168 | ||||
-rw-r--r-- | src/lib/crypto/krb/dk/deps | 79 | ||||
-rw-r--r-- | src/lib/crypto/krb/dk/derive.c | 217 | ||||
-rw-r--r-- | src/lib/crypto/krb/dk/dk.h | 124 | ||||
-rw-r--r-- | src/lib/crypto/krb/dk/dk_aead.c | 386 | ||||
-rw-r--r-- | src/lib/crypto/krb/dk/dk_decrypt.c | 200 | ||||
-rw-r--r-- | src/lib/crypto/krb/dk/dk_encrypt.c | 358 | ||||
-rw-r--r-- | src/lib/crypto/krb/dk/dk_prf.c | 64 | ||||
-rw-r--r-- | src/lib/crypto/krb/dk/stringtokey.c | 96 |
10 files changed, 1745 insertions, 0 deletions
diff --git a/src/lib/crypto/krb/dk/Makefile.in b/src/lib/crypto/krb/dk/Makefile.in new file mode 100644 index 0000000..b254523 --- /dev/null +++ b/src/lib/crypto/krb/dk/Makefile.in @@ -0,0 +1,53 @@ +thisconfigdir=../../../.. +myfulldir=lib/crypto/krb/dk +mydir=lib/crypto/dk +BUILDTOP=$(REL)..$(S)..$(S)..$(S).. +LOCALINCLUDES = -I$(srcdir)/.. -I$(srcdir)/../../@CRYPTO_IMPL@ +DEFS= + +##DOS##BUILDTOP = ..\..\..\.. +##DOS##PREFIXDIR=dk +##DOS##OBJFILE=..\$(OUTPRE)dk.lst + +PROG_LIBPATH=-L$(TOPLIBD) +PROG_RPATH=$(KRB5_LIBDIR) + +STLIBOBJS=\ + checksum.o \ + dk_aead.o \ + dk_decrypt.o \ + dk_encrypt.o \ + derive.o \ + dk_prf.o \ + stringtokey.o + +OBJS=\ + $(OUTPRE)checksum.$(OBJEXT) \ + $(OUTPRE)dk_aead.$(OBJEXT) \ + $(OUTPRE)dk_decrypt.$(OBJEXT) \ + $(OUTPRE)dk_encrypt.$(OBJEXT) \ + $(OUTPRE)derive.$(OBJEXT) \ + $(OUTPRE)dk_prf.$(OBJEXT) \ + $(OUTPRE)stringtokey.$(OBJEXT) + +SRCS=\ + $(srcdir)/checksum.c \ + $(srcdir)/dk_aead.c \ + $(srcdir)/dk_decrypt.c \ + $(srcdir)/dk_encrypt.c \ + $(srcdir)/dk_prf.c \ + $(srcdir)/derive.c \ + $(srcdir)/stringtokey.c + +##DOS##LIBOBJS = $(OBJS) + +all-unix:: all-libobjs + +includes:: depend + +depend:: $(SRCS) + +clean-unix:: clean-libobjs + +@libobj_frag@ + diff --git a/src/lib/crypto/krb/dk/checksum.c b/src/lib/crypto/krb/dk/checksum.c new file mode 100644 index 0000000..f4b18bf --- /dev/null +++ b/src/lib/crypto/krb/dk/checksum.c @@ -0,0 +1,168 @@ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "k5-int.h" +#include "etypes.h" +#include "dk.h" +#include "aead.h" + +#define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */ + +krb5_error_code +krb5_dk_make_checksum(const struct krb5_hash_provider *hash, + const krb5_keyblock *key, krb5_keyusage usage, + const krb5_data *input, krb5_data *output) +{ + int i; + const struct krb5_enc_provider *enc; + size_t blocksize, keybytes, keylength; + krb5_error_code ret; + unsigned char constantdata[K5CLENGTH]; + krb5_data datain; + unsigned char *kcdata; + krb5_keyblock kc; + + for (i=0; i<krb5_enctypes_length; i++) { + if (krb5_enctypes_list[i].etype == key->enctype) + break; + } + + if (i == krb5_enctypes_length) + return(KRB5_BAD_ENCTYPE); + + enc = krb5_enctypes_list[i].enc; + + /* allocate and set to-be-derived keys */ + + blocksize = enc->block_size; + keybytes = enc->keybytes; + keylength = enc->keylength; + + /* key->length will be tested in enc->encrypt + output->length will be tested in krb5_hmac */ + + if ((kcdata = (unsigned char *) malloc(keylength)) == NULL) + return(ENOMEM); + + kc.contents = kcdata; + kc.length = keylength; + + /* derive the key */ + + datain.data = (char *) constantdata; + datain.length = K5CLENGTH; + + store_32_be(usage, constantdata); + + datain.data[4] = (char) 0x99; + + if ((ret = krb5_derive_key(enc, key, &kc, &datain)) != 0) + goto cleanup; + + /* hash the data */ + + datain = *input; + + if ((ret = krb5_hmac(hash, &kc, 1, &datain, output)) != 0) + memset(output->data, 0, output->length); + + /* ret is set correctly by the prior call */ + +cleanup: + memset(kcdata, 0, keylength); + + free(kcdata); + + return(ret); +} + +krb5_error_code +krb5int_dk_make_checksum_iov(const struct krb5_hash_provider *hash, + const krb5_keyblock *key, krb5_keyusage usage, + const krb5_crypto_iov *data, size_t num_data, + krb5_data *output) +{ + int i; + const struct krb5_enc_provider *enc; + size_t blocksize, keybytes, keylength; + krb5_error_code ret; + unsigned char constantdata[K5CLENGTH]; + krb5_data datain; + unsigned char *kcdata; + krb5_keyblock kc; + + for (i=0; i<krb5_enctypes_length; i++) { + if (krb5_enctypes_list[i].etype == key->enctype) + break; + } + + if (i == krb5_enctypes_length) + return(KRB5_BAD_ENCTYPE); + + enc = krb5_enctypes_list[i].enc; + + /* allocate and set to-be-derived keys */ + + blocksize = enc->block_size; + keybytes = enc->keybytes; + keylength = enc->keylength; + + /* key->length will be tested in enc->encrypt + output->length will be tested in krb5_hmac */ + + if ((kcdata = (unsigned char *) malloc(keylength)) == NULL) + return(ENOMEM); + + kc.contents = kcdata; + kc.length = keylength; + + /* derive the key */ + + datain.data = (char *) constantdata; + datain.length = K5CLENGTH; + + store_32_be(usage, constantdata); + + datain.data[4] = (char) 0x99; + + if ((ret = krb5_derive_key(enc, key, &kc, &datain)) != 0) + goto cleanup; + + /* hash the data */ + + if ((ret = krb5int_hmac_iov(hash, &kc, data, num_data, output)) != 0) + memset(output->data, 0, output->length); + + /* ret is set correctly by the prior call */ + +cleanup: + memset(kcdata, 0, keylength); + + free(kcdata); + + return(ret); +} + diff --git a/src/lib/crypto/krb/dk/deps b/src/lib/crypto/krb/dk/deps new file mode 100644 index 0000000..28e8a08 --- /dev/null +++ b/src/lib/crypto/krb/dk/deps @@ -0,0 +1,79 @@ +# +# Generated makefile dependencies follow. +# +checksum.so checksum.po $(OUTPRE)checksum.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h $(SRCTOP)/include/k5-buf.h \ + $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-gmt_mktime.h \ + $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \ + $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(srcdir)/../aead.h $(srcdir)/../cksumtypes.h $(srcdir)/../etypes.h \ + checksum.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) $(SRCTOP)/include/autoconf.h \ + $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \ + $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \ + $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \ + $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \ + $(SRCTOP)/include/socket-utils.h $(srcdir)/../aead.h \ + $(srcdir)/../cksumtypes.h dk.h dk_aead.c +dk_decrypt.so dk_decrypt.po $(OUTPRE)dk_decrypt.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h $(SRCTOP)/include/k5-buf.h \ + $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-gmt_mktime.h \ + $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \ + $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + dk.h dk_decrypt.c +dk_encrypt.so dk_encrypt.po $(OUTPRE)dk_encrypt.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h $(SRCTOP)/include/k5-buf.h \ + $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-gmt_mktime.h \ + $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \ + $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + dk.h dk_encrypt.c +dk_prf.so dk_prf.po $(OUTPRE)dk_prf.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h \ + $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \ + $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \ + $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \ + $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \ + $(SRCTOP)/include/socket-utils.h dk.h dk_prf.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) $(SRCTOP)/include/autoconf.h \ + $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \ + $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \ + $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \ + $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \ + $(SRCTOP)/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 \ + $(COM_ERR_DEPS) $(SRCTOP)/include/autoconf.h $(SRCTOP)/include/k5-buf.h \ + $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-gmt_mktime.h \ + $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \ + $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/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 new file mode 100644 index 0000000..77b05fa --- /dev/null +++ b/src/lib/crypto/krb/dk/derive.c @@ -0,0 +1,217 @@ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "k5-int.h" +#include "dk.h" + +krb5_error_code +krb5_derive_key(const struct krb5_enc_provider *enc, + const krb5_keyblock *inkey, krb5_keyblock *outkey, + const krb5_data *in_constant) +{ + size_t blocksize, keybytes, keylength, n; + unsigned char *inblockdata, *outblockdata, *rawkey; + krb5_data inblock, outblock; + + blocksize = enc->block_size; + keybytes = enc->keybytes; + keylength = enc->keylength; + + if ((inkey->length != keylength) || + (outkey->length != keylength)) + return(KRB5_CRYPTO_INTERNAL); + + /* allocate and set up buffers */ + + if ((inblockdata = (unsigned char *) malloc(blocksize)) == NULL) + return(ENOMEM); + + if ((outblockdata = (unsigned char *) malloc(blocksize)) == NULL) { + free(inblockdata); + return(ENOMEM); + } + + if ((rawkey = (unsigned char *) malloc(keybytes)) == NULL) { + free(outblockdata); + free(inblockdata); + return(ENOMEM); + } + + inblock.data = (char *) inblockdata; + inblock.length = blocksize; + + outblock.data = (char *) outblockdata; + outblock.length = blocksize; + + /* initialize the input block */ + + if (in_constant->length == inblock.length) { + memcpy(inblock.data, in_constant->data, inblock.length); + } else { + krb5_nfold(in_constant->length*8, (unsigned char *) in_constant->data, + inblock.length*8, (unsigned char *) inblock.data); + } + + /* loop encrypting the blocks until enough key bytes are generated */ + + n = 0; + while (n < keybytes) { + (*(enc->encrypt))(inkey, 0, &inblock, &outblock); + + if ((keybytes - n) <= outblock.length) { + memcpy(rawkey+n, outblock.data, (keybytes - n)); + break; + } + + memcpy(rawkey+n, outblock.data, outblock.length); + memcpy(inblock.data, outblock.data, outblock.length); + n += outblock.length; + } + + /* postprocess the key */ + + inblock.data = (char *) rawkey; + inblock.length = keybytes; + + (*(enc->make_key))(&inblock, outkey); + + /* clean memory, free resources and exit */ + + memset(inblockdata, 0, blocksize); + memset(outblockdata, 0, blocksize); + memset(rawkey, 0, keybytes); + + free(rawkey); + free(outblockdata); + free(inblockdata); + + return(0); +} + + +krb5_error_code +krb5_derive_random(const struct krb5_enc_provider *enc, + const krb5_keyblock *inkey, krb5_data *outrnd, + const krb5_data *in_constant) +{ + size_t blocksize, keybytes, keylength, n; + unsigned char *inblockdata, *outblockdata, *rawkey; + krb5_data inblock, outblock; + + blocksize = enc->block_size; + keybytes = enc->keybytes; + keylength = enc->keylength; + + if ((inkey->length != keylength) || + (outrnd->length != keybytes)) + return(KRB5_CRYPTO_INTERNAL); + + /* allocate and set up buffers */ + + if ((inblockdata = (unsigned char *) malloc(blocksize)) == NULL) + return(ENOMEM); + + if ((outblockdata = (unsigned char *) malloc(blocksize)) == NULL) { + free(inblockdata); + return(ENOMEM); + } + + if ((rawkey = (unsigned char *) malloc(keybytes)) == NULL) { + free(outblockdata); + free(inblockdata); + return(ENOMEM); + } + + inblock.data = (char *) inblockdata; + inblock.length = blocksize; + + outblock.data = (char *) outblockdata; + outblock.length = blocksize; + + /* initialize the input block */ + + if (in_constant->length == inblock.length) { + memcpy(inblock.data, in_constant->data, inblock.length); + } else { + krb5_nfold(in_constant->length*8, (unsigned char *) in_constant->data, + inblock.length*8, (unsigned char *) inblock.data); + } + + /* loop encrypting the blocks until enough key bytes are generated */ + + n = 0; + while (n < keybytes) { + (*(enc->encrypt))(inkey, 0, &inblock, &outblock); + + if ((keybytes - n) <= outblock.length) { + memcpy(rawkey+n, outblock.data, (keybytes - n)); + break; + } + + memcpy(rawkey+n, outblock.data, outblock.length); + memcpy(inblock.data, outblock.data, outblock.length); + n += outblock.length; + } + + /* postprocess the key */ + + memcpy (outrnd->data, rawkey, keybytes); + + /* clean memory, free resources and exit */ + + memset(inblockdata, 0, blocksize); + memset(outblockdata, 0, blocksize); + memset(rawkey, 0, keybytes); + + free(rawkey); + free(outblockdata); + free(inblockdata); + + return(0); +} + +#if 0 +#include "etypes.h" +void +krb5_random2key (krb5_enctype enctype, krb5_data *inblock, + krb5_keyblock *outkey) +{ + int i; + const struct krb5_enc_provider *enc; + + for (i=0; i<krb5_enctypes_length; i++) { + if (krb5_enctypes_list[i].etype == enctype) + break; + } + + if (i == krb5_enctypes_length) + abort (); + + enc = krb5_enctypes_list[i].enc; + + enc->make_key (inblock, outkey); +} +#endif diff --git a/src/lib/crypto/krb/dk/dk.h b/src/lib/crypto/krb/dk/dk.h new file mode 100644 index 0000000..bc40134 --- /dev/null +++ b/src/lib/crypto/krb/dk/dk.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "k5-int.h" + +void krb5_dk_encrypt_length +(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + size_t input, size_t *length); + +krb5_error_code krb5_dk_encrypt +(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, krb5_keyusage usage, + const krb5_data *ivec, + const krb5_data *input, krb5_data *output); + +void krb5int_aes_encrypt_length +(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + size_t input, size_t *length); + +krb5_error_code krb5int_aes_dk_encrypt +(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, krb5_keyusage usage, + const krb5_data *ivec, + const krb5_data *input, krb5_data *output); + +krb5_error_code krb5_dk_decrypt +(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, krb5_keyusage usage, + const krb5_data *ivec, const krb5_data *input, + krb5_data *arg_output); + +krb5_error_code krb5int_aes_dk_decrypt +(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, krb5_keyusage usage, + const krb5_data *ivec, const krb5_data *input, + krb5_data *arg_output); + +krb5_error_code krb5int_dk_string_to_key +(const struct krb5_enc_provider *enc, + const krb5_data *string, const krb5_data *salt, + const krb5_data *params, krb5_keyblock *key); + +krb5_error_code +krb5int_dk_prf(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, const krb5_data *in, krb5_data *out); + +krb5_error_code krb5_derive_key +(const struct krb5_enc_provider *enc, + const krb5_keyblock *inkey, + krb5_keyblock *outkey, const krb5_data *in_constant); + +krb5_error_code krb5_dk_make_checksum +(const struct krb5_hash_provider *hash, + const krb5_keyblock *key, krb5_keyusage usage, + const krb5_data *input, krb5_data *output); + +krb5_error_code +krb5int_dk_make_checksum_iov(const struct krb5_hash_provider *hash, + const krb5_keyblock *key, krb5_keyusage usage, + const krb5_crypto_iov *data, size_t num_data, + krb5_data *output); + +krb5_error_code +krb5_derive_random(const struct krb5_enc_provider *enc, + const krb5_keyblock *inkey, krb5_data *outrnd, + const krb5_data *in_constant); + +/* AEAD */ + +extern const struct krb5_aead_provider krb5int_aead_dk; +extern const struct krb5_aead_provider krb5int_aead_aes; + +/* CCM */ + +void +krb5int_ccm_encrypt_length(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + size_t inputlen, size_t *length); + +extern const struct krb5_aead_provider krb5int_aead_ccm; + +krb5_error_code krb5int_ccm_encrypt +(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, krb5_keyusage usage, + const krb5_data *ivec, const krb5_data *input, + krb5_data *arg_output); + +krb5_error_code krb5int_ccm_decrypt +(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, krb5_keyusage usage, + const krb5_data *ivec, const krb5_data *input, + krb5_data *arg_output); diff --git a/src/lib/crypto/krb/dk/dk_aead.c b/src/lib/crypto/krb/dk/dk_aead.c new file mode 100644 index 0000000..e995f9a --- /dev/null +++ b/src/lib/crypto/krb/dk/dk_aead.c @@ -0,0 +1,386 @@ +/* + * lib/crypto/dk/dk_aead.c + * + * Copyright 2008, 2009 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" + +#define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */ + +/* AEAD */ + +static krb5_error_code +krb5int_dk_crypto_length(const struct krb5_aead_provider *aead, + const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + krb5_cryptotype type, + unsigned int *length) +{ + switch (type) { + case KRB5_CRYPTO_TYPE_HEADER: + case KRB5_CRYPTO_TYPE_PADDING: + *length = enc->block_size; + break; + case KRB5_CRYPTO_TYPE_TRAILER: + case KRB5_CRYPTO_TYPE_CHECKSUM: + *length = hash->hashsize; + break; + default: + assert(0 && "invalid cryptotype passed to krb5int_dk_crypto_length"); + break; + } + + return 0; +} + +static krb5_error_code +krb5int_dk_encrypt_iov(const struct krb5_aead_provider *aead, + const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, + krb5_keyusage usage, + const krb5_data *ivec, + krb5_crypto_iov *data, + size_t num_data) +{ + krb5_error_code ret; + unsigned char constantdata[K5CLENGTH]; + krb5_data d1, d2; + krb5_crypto_iov *header, *trailer, *padding; + krb5_keyblock ke, ki; + size_t i; + unsigned int blocksize = 0; + unsigned int plainlen = 0; + unsigned int hmacsize = 0; + unsigned int padsize = 0; + unsigned char *cksum = NULL; + + ke.contents = ki.contents = NULL; + ke.length = ki.length = 0; + + /* E(Confounder | Plaintext | Pad) | Checksum */ + + ret = aead->crypto_length(aead, enc, hash, KRB5_CRYPTO_TYPE_PADDING, &blocksize); + if (ret != 0) + return ret; + + ret = aead->crypto_length(aead, enc, hash, KRB5_CRYPTO_TYPE_TRAILER, &hmacsize); + if (ret != 0) + return ret; + + for (i = 0; i < num_data; i++) { + krb5_crypto_iov *iov = &data[i]; + + if (iov->flags == KRB5_CRYPTO_TYPE_DATA) + plainlen += iov->data.length; + } + + /* 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 < hmacsize) + return KRB5_BAD_MSIZE; + + if (blocksize != 0) { + /* Check that the input data is correctly padded */ + if (plainlen % blocksize) + padsize = blocksize - (plainlen % blocksize); + } + + padding = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_PADDING); + if (padsize && (padding == NULL || padding->data.length < padsize)) + return KRB5_BAD_MSIZE; + + if (padding != NULL) { + memset(padding->data.data, 0, padsize); + padding->data.length = padsize; + } + + ke.length = enc->keylength; + ke.contents = malloc(ke.length); + if (ke.contents == NULL) { + ret = ENOMEM; + goto cleanup; + } + ki.length = enc->keylength; + ki.contents = malloc(ki.length); + if (ki.contents == NULL) { + ret = ENOMEM; + goto cleanup; + } + cksum = (unsigned char *)malloc(hash->hashsize); + if (cksum == NULL) { + ret = ENOMEM; + goto cleanup; + } + + /* derive the keys */ + + d1.data = (char *)constantdata; + d1.length = K5CLENGTH; + + store_32_be(usage, constantdata); + + d1.data[4] = 0xAA; + + ret = krb5_derive_key(enc, key, &ke, &d1); + if (ret != 0) + goto cleanup; + + d1.data[4] = 0x55; + + ret = krb5_derive_key(enc, key, &ki, &d1); + if (ret != 0) + goto cleanup; + + /* generate confounder */ + + header->data.length = enc->block_size; + + ret = krb5_c_random_make_octets(/* XXX */ NULL, &header->data); + if (ret != 0) + goto cleanup; + + /* hash the plaintext */ + d2.length = hash->hashsize; + d2.data = (char *)cksum; + + ret = krb5int_hmac_iov(hash, &ki, data, num_data, &d2); + if (ret != 0) + goto cleanup; + + /* encrypt the plaintext (header | data | padding) */ + assert(enc->encrypt_iov != NULL); + + ret = enc->encrypt_iov(&ke, ivec, data, num_data); /* will update ivec */ + if (ret != 0) + goto cleanup; + + /* possibly truncate the hash */ + assert(hmacsize <= d2.length); + + memcpy(trailer->data.data, cksum, hmacsize); + trailer->data.length = hmacsize; + +cleanup: + if (ke.contents != NULL) { + memset(ke.contents, 0, ke.length); + free(ke.contents); + } + if (ki.contents != NULL) { + memset(ki.contents, 0, ki.length); + free(ki.contents); + } + if (cksum != NULL) { + free(cksum); + } + + return ret; +} + +static krb5_error_code +krb5int_dk_decrypt_iov(const struct krb5_aead_provider *aead, + const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, + krb5_keyusage usage, + const krb5_data *ivec, + krb5_crypto_iov *data, + size_t num_data) +{ + krb5_error_code ret; + unsigned char constantdata[K5CLENGTH]; + krb5_data d1; + krb5_crypto_iov *header, *trailer; + krb5_keyblock ke, ki; + size_t i; + unsigned int blocksize = 0; /* careful, this is enc block size not confounder len */ + unsigned int cipherlen = 0; + unsigned int hmacsize = 0; + unsigned char *cksum = NULL; + + if (krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_STREAM) != NULL) { + return krb5int_c_iov_decrypt_stream(aead, enc, hash, key, + usage, ivec, data, num_data); + } + + ke.contents = ki.contents = NULL; + ke.length = ki.length = 0; + + /* E(Confounder | Plaintext | Pad) | Checksum */ + + ret = aead->crypto_length(aead, enc, hash, KRB5_CRYPTO_TYPE_PADDING, &blocksize); + if (ret != 0) + return ret; + + ret = aead->crypto_length(aead, enc, hash, KRB5_CRYPTO_TYPE_TRAILER, &hmacsize); + if (ret != 0) + return ret; + + for (i = 0; i < num_data; i++) { + const krb5_crypto_iov *iov = &data[i]; + + if (ENCRYPT_DATA_IOV(iov)) + cipherlen += iov->data.length; + } + + if (blocksize == 0) { + /* Check for correct input length in CTS mode */ + if (enc->block_size != 0 && cipherlen < enc->block_size) + return KRB5_BAD_MSIZE; + } else { + /* Check that the input data is correctly padded */ + if ((cipherlen % blocksize) != 0) + return KRB5_BAD_MSIZE; + } + + /* 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 != hmacsize) + return KRB5_BAD_MSIZE; + + ke.length = enc->keylength; + ke.contents = malloc(ke.length); + if (ke.contents == NULL) { + ret = ENOMEM; + goto cleanup; + } + ki.length = enc->keylength; + ki.contents = malloc(ki.length); + if (ki.contents == NULL) { + ret = ENOMEM; + goto cleanup; + } + cksum = (unsigned char *)malloc(hash->hashsize); + if (cksum == NULL) { + ret = ENOMEM; + goto cleanup; + } + + /* derive the keys */ + + d1.data = (char *)constantdata; + d1.length = K5CLENGTH; + + store_32_be(usage, constantdata); + + d1.data[4] = 0xAA; + + ret = krb5_derive_key(enc, key, &ke, &d1); + if (ret != 0) + goto cleanup; + + d1.data[4] = 0x55; + + ret = krb5_derive_key(enc, key, &ki, &d1); + if (ret != 0) + goto cleanup; + + /* decrypt the plaintext (header | data | padding) */ + assert(enc->decrypt_iov != NULL); + + ret = enc->decrypt_iov(&ke, ivec, data, num_data); /* will update ivec */ + if (ret != 0) + goto cleanup; + + /* verify the hash */ + d1.length = hash->hashsize; /* non-truncated length */ + d1.data = (char *)cksum; + + ret = krb5int_hmac_iov(hash, &ki, data, num_data, &d1); + if (ret != 0) + goto cleanup; + + /* compare only the possibly truncated length */ + if (memcmp(cksum, trailer->data.data, hmacsize) != 0) { + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + goto cleanup; + } + +cleanup: + if (ke.contents != NULL) { + memset(ke.contents, 0, ke.length); + free(ke.contents); + } + if (ki.contents != NULL) { + memset(ki.contents, 0, ki.length); + free(ki.contents); + } + if (cksum != NULL) { + free(cksum); + } + + return ret; +} + +const struct krb5_aead_provider krb5int_aead_dk = { + krb5int_dk_crypto_length, + krb5int_dk_encrypt_iov, + krb5int_dk_decrypt_iov +}; + +static krb5_error_code +krb5int_aes_crypto_length(const struct krb5_aead_provider *aead, + const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + krb5_cryptotype type, + unsigned int *length) +{ + switch (type) { + case KRB5_CRYPTO_TYPE_HEADER: + *length = enc->block_size; + break; + case KRB5_CRYPTO_TYPE_PADDING: + *length = 0; + break; + case KRB5_CRYPTO_TYPE_TRAILER: + case KRB5_CRYPTO_TYPE_CHECKSUM: + *length = 96 / 8; + break; + default: + assert(0 && "invalid cryptotype passed to krb5int_aes_crypto_length"); + break; + } + + return 0; +} + +const struct krb5_aead_provider krb5int_aead_aes = { + krb5int_aes_crypto_length, + krb5int_dk_encrypt_iov, + krb5int_dk_decrypt_iov +}; + diff --git a/src/lib/crypto/krb/dk/dk_decrypt.c b/src/lib/crypto/krb/dk/dk_decrypt.c new file mode 100644 index 0000000..c38c4d5 --- /dev/null +++ b/src/lib/crypto/krb/dk/dk_decrypt.c @@ -0,0 +1,200 @@ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "k5-int.h" +#include "dk.h" + +#define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */ + +static krb5_error_code +krb5_dk_decrypt_maybe_trunc_hmac(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, + krb5_keyusage usage, + const krb5_data *ivec, + const krb5_data *input, + krb5_data *output, + size_t hmacsize, + int ivec_mode); + +krb5_error_code +krb5_dk_decrypt(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, krb5_keyusage usage, + const krb5_data *ivec, const krb5_data *input, + krb5_data *output) +{ + return krb5_dk_decrypt_maybe_trunc_hmac(enc, hash, key, usage, + ivec, input, output, 0, 0); +} + +krb5_error_code +krb5int_aes_dk_decrypt(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, krb5_keyusage usage, + const krb5_data *ivec, const krb5_data *input, + krb5_data *output) +{ + return krb5_dk_decrypt_maybe_trunc_hmac(enc, hash, key, usage, + ivec, input, output, 96 / 8, 1); +} + +static krb5_error_code +krb5_dk_decrypt_maybe_trunc_hmac(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, krb5_keyusage usage, + const krb5_data *ivec, const krb5_data *input, + krb5_data *output, size_t hmacsize, + int ivec_mode) +{ + krb5_error_code ret; + size_t hashsize, blocksize, keybytes, keylength, enclen, plainlen; + unsigned char *plaindata, *kedata, *kidata, *cksum, *cn; + krb5_keyblock ke, ki; + krb5_data d1, d2; + unsigned char constantdata[K5CLENGTH]; + + /* allocate and set up ciphertext and to-be-derived keys */ + + hashsize = hash->hashsize; + blocksize = enc->block_size; + keybytes = enc->keybytes; + keylength = enc->keylength; + + if (hmacsize == 0) + hmacsize = hashsize; + else if (hmacsize > hashsize) + return KRB5KRB_AP_ERR_BAD_INTEGRITY; + + enclen = input->length - hmacsize; + + if ((kedata = (unsigned char *) malloc(keylength)) == NULL) + return(ENOMEM); + if ((kidata = (unsigned char *) malloc(keylength)) == NULL) { + free(kedata); + return(ENOMEM); + } + if ((plaindata = (unsigned char *) malloc(enclen)) == NULL) { + free(kidata); + free(kedata); + return(ENOMEM); + } + if ((cksum = (unsigned char *) malloc(hashsize)) == NULL) { + free(plaindata); + free(kidata); + free(kedata); + return(ENOMEM); + } + + ke.contents = kedata; + ke.length = keylength; + ki.contents = kidata; + ki.length = keylength; + + /* derive the keys */ + + d1.data = (char *) constantdata; + d1.length = K5CLENGTH; + + store_32_be(usage, constantdata); + + d1.data[4] = (char) 0xAA; + + if ((ret = krb5_derive_key(enc, key, &ke, &d1)) != 0) + goto cleanup; + + d1.data[4] = 0x55; + + if ((ret = krb5_derive_key(enc, key, &ki, &d1)) != 0) + goto cleanup; + + /* decrypt the ciphertext */ + + d1.length = enclen; + d1.data = input->data; + + d2.length = enclen; + d2.data = (char *) plaindata; + + if ((ret = ((*(enc->decrypt))(&ke, ivec, &d1, &d2))) != 0) + goto cleanup; + + if (ivec != NULL && ivec->length == blocksize) { + if (ivec_mode == 0) + cn = (unsigned char *) d1.data + d1.length - blocksize; + else if (ivec_mode == 1) { + int nblocks = (d1.length + blocksize - 1) / blocksize; + cn = d1.data + blocksize * (nblocks - 2); + } else + abort(); + } else + cn = NULL; + + /* verify the hash */ + + d1.length = hashsize; + d1.data = (char *) cksum; + + if ((ret = krb5_hmac(hash, &ki, 1, &d2, &d1)) != 0) + goto cleanup; + + if (memcmp(cksum, input->data+enclen, hmacsize) != 0) { + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + goto cleanup; + } + + /* because this encoding isn't self-describing wrt length, the + best we can do here is to compute the length minus the + confounder. */ + + plainlen = enclen - blocksize; + + if (output->length < plainlen) + return(KRB5_BAD_MSIZE); + + output->length = plainlen; + + memcpy(output->data, d2.data+blocksize, output->length); + + if (cn != NULL) + memcpy(ivec->data, cn, blocksize); + + ret = 0; + +cleanup: + memset(kedata, 0, keylength); + memset(kidata, 0, keylength); + memset(plaindata, 0, enclen); + memset(cksum, 0, hashsize); + + free(cksum); + free(plaindata); + free(kidata); + free(kedata); + + return(ret); +} + diff --git a/src/lib/crypto/krb/dk/dk_encrypt.c b/src/lib/crypto/krb/dk/dk_encrypt.c new file mode 100644 index 0000000..6596e53 --- /dev/null +++ b/src/lib/crypto/krb/dk/dk_encrypt.c @@ -0,0 +1,358 @@ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "k5-int.h" +#include "dk.h" + +#define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */ + +/* the spec says that the confounder size and padding are specific to + the encryption algorithm. This code (dk_encrypt_length and + dk_encrypt) assume the confounder is always the blocksize, and the + padding is always zero bytes up to the blocksize. If these + assumptions ever fails, the keytype table should be extended to + include these bits of info. */ + +void +krb5_dk_encrypt_length(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + size_t inputlen, size_t *length) +{ + size_t blocksize, hashsize; + + blocksize = enc->block_size; + hashsize = hash->hashsize; + *length = krb5_roundup(blocksize+inputlen, blocksize) + hashsize; +} + +krb5_error_code +krb5_dk_encrypt(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, krb5_keyusage usage, + const krb5_data *ivec, const krb5_data *input, + krb5_data *output) +{ + size_t blocksize, keybytes, keylength, plainlen, enclen; + krb5_error_code ret; + unsigned char constantdata[K5CLENGTH]; + krb5_data d1, d2; + unsigned char *plaintext, *kedata, *kidata; + char *cn; + krb5_keyblock ke, ki; + + /* allocate and set up plaintext and to-be-derived keys */ + + blocksize = enc->block_size; + keybytes = enc->keybytes; + keylength = enc->keylength; + plainlen = krb5_roundup(blocksize+input->length, blocksize); + + krb5_dk_encrypt_length(enc, hash, input->length, &enclen); + + /* key->length, ivec will be tested in enc->encrypt */ + + if (output->length < enclen) + return(KRB5_BAD_MSIZE); + + if ((kedata = (unsigned char *) malloc(keylength)) == NULL) + return(ENOMEM); + if ((kidata = (unsigned char *) malloc(keylength)) == NULL) { + free(kedata); + return(ENOMEM); + } + if ((plaintext = (unsigned char *) malloc(plainlen)) == NULL) { + free(kidata); + free(kedata); + return(ENOMEM); + } + + ke.contents = kedata; + ke.length = keylength; + ki.contents = kidata; + ki.length = keylength; + + /* derive the keys */ + + d1.data = (char *) constantdata; + d1.length = K5CLENGTH; + + store_32_be(usage, constantdata); + + d1.data[4] = (char) 0xAA; + + if ((ret = krb5_derive_key(enc, key, &ke, &d1))) + goto cleanup; + + d1.data[4] = 0x55; + + if ((ret = krb5_derive_key(enc, key, &ki, &d1))) + goto cleanup; + + /* put together the plaintext */ + + d1.length = blocksize; + d1.data = (char *) plaintext; + + if ((ret = krb5_c_random_make_octets(/* XXX */ 0, &d1))) + goto cleanup; + + memcpy(plaintext+blocksize, input->data, input->length); + + memset(plaintext+blocksize+input->length, 0, + plainlen - (blocksize+input->length)); + + /* encrypt the plaintext */ + + d1.length = plainlen; + d1.data = (char *) plaintext; + + d2.length = plainlen; + d2.data = output->data; + + if ((ret = ((*(enc->encrypt))(&ke, ivec, &d1, &d2)))) + goto cleanup; + + if (ivec != NULL && ivec->length == blocksize) + cn = d2.data + d2.length - blocksize; + else + cn = NULL; + + /* hash the plaintext */ + + d2.length = enclen - plainlen; + d2.data = output->data+plainlen; + + output->length = enclen; + + if ((ret = krb5_hmac(hash, &ki, 1, &d1, &d2))) { + memset(d2.data, 0, d2.length); + goto cleanup; + } + + /* update ivec */ + if (cn != NULL) + memcpy(ivec->data, cn, blocksize); + + /* ret is set correctly by the prior call */ + +cleanup: + memset(kedata, 0, keylength); + memset(kidata, 0, keylength); + memset(plaintext, 0, plainlen); + + free(plaintext); + free(kidata); + free(kedata); + + return(ret); +} + +/* Not necessarily "AES", per se, but "a CBC+CTS mode block cipher + with a 96-bit truncated HMAC". */ +void +krb5int_aes_encrypt_length(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + size_t inputlen, size_t *length) +{ + size_t blocksize, hashsize; + + blocksize = enc->block_size; + hashsize = 96 / 8; + + /* No roundup, since CTS requires no padding once we've hit the + block size. */ + *length = blocksize+inputlen + hashsize; +} + +static krb5_error_code +trunc_hmac (const struct krb5_hash_provider *hash, + const krb5_keyblock *ki, unsigned int num, + const krb5_data *input, const krb5_data *output) +{ + size_t hashsize; + krb5_data tmp; + krb5_error_code ret; + + hashsize = hash->hashsize; + if (hashsize < output->length) + return KRB5_CRYPTO_INTERNAL; + tmp.length = hashsize; + tmp.data = malloc(hashsize); + if (tmp.data == NULL) + return ENOMEM; + ret = krb5_hmac(hash, ki, num, input, &tmp); + if (ret == 0) + memcpy(output->data, tmp.data, output->length); + memset(tmp.data, 0, hashsize); + free(tmp.data); + return ret; +} + +krb5_error_code +krb5int_aes_dk_encrypt(const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, krb5_keyusage usage, + const krb5_data *ivec, const krb5_data *input, + krb5_data *output) +{ + size_t blocksize, keybytes, keylength, plainlen, enclen; + krb5_error_code ret; + unsigned char constantdata[K5CLENGTH]; + krb5_data d1, d2; + unsigned char *plaintext, *kedata, *kidata; + char *cn; + krb5_keyblock ke, ki; + + /* allocate and set up plaintext and to-be-derived keys */ + + blocksize = enc->block_size; + keybytes = enc->keybytes; + keylength = enc->keylength; + plainlen = blocksize+input->length; + + krb5int_aes_encrypt_length(enc, hash, input->length, &enclen); + + /* key->length, ivec will be tested in enc->encrypt */ + + if (output->length < enclen) + return(KRB5_BAD_MSIZE); + + if ((kedata = (unsigned char *) malloc(keylength)) == NULL) + return(ENOMEM); + if ((kidata = (unsigned char *) malloc(keylength)) == NULL) { + free(kedata); + return(ENOMEM); + } + if ((plaintext = (unsigned char *) malloc(plainlen)) == NULL) { + free(kidata); + free(kedata); + return(ENOMEM); + } + + ke.contents = kedata; + ke.length = keylength; + ki.contents = kidata; + ki.length = keylength; + + /* derive the keys */ + + d1.data = (char *) constantdata; + d1.length = K5CLENGTH; + + store_32_be(usage, constantdata); + + d1.data[4] = (char) 0xAA; + + if ((ret = krb5_derive_key(enc, key, &ke, &d1))) + goto cleanup; + + d1.data[4] = 0x55; + + if ((ret = krb5_derive_key(enc, key, &ki, &d1))) + goto cleanup; + + /* put together the plaintext */ + + d1.length = blocksize; + d1.data = (char *) plaintext; + + if ((ret = krb5_c_random_make_octets(/* XXX */ 0, &d1))) + goto cleanup; + + memcpy(plaintext+blocksize, input->data, input->length); + + /* Ciphertext stealing; there should be no more. */ + if (plainlen != blocksize + input->length) + abort(); + + /* encrypt the plaintext */ + + d1.length = plainlen; + d1.data = (char *) plaintext; + + d2.length = plainlen; + d2.data = output->data; + + if ((ret = ((*(enc->encrypt))(&ke, ivec, &d1, &d2)))) + goto cleanup; + + if (ivec != NULL && ivec->length == blocksize) { + int nblocks = (d2.length + blocksize - 1) / blocksize; + cn = d2.data + blocksize * (nblocks - 2); + } else + cn = NULL; + + /* hash the plaintext */ + + d2.length = enclen - plainlen; + d2.data = output->data+plainlen; + if (d2.length != 96 / 8) + abort(); + + if ((ret = trunc_hmac(hash, &ki, 1, &d1, &d2))) { + memset(d2.data, 0, d2.length); + goto cleanup; + } + + output->length = enclen; + + /* update ivec */ + if (cn != NULL) { + memcpy(ivec->data, cn, blocksize); +#if 0 + { + int i; + printf("\n%s: output:", __func__); + for (i = 0; i < output->length; i++) { + if (i % 16 == 0) + printf("\n%s: ", __func__); + printf(" %02x", i[(unsigned char *)output->data]); + } + printf("\n%s: outputIV:", __func__); + for (i = 0; i < ivec->length; i++) { + if (i % 16 == 0) + printf("\n%s: ", __func__); + printf(" %02x", i[(unsigned char *)ivec->data]); + } + printf("\n"); fflush(stdout); + } +#endif + } + + /* ret is set correctly by the prior call */ + +cleanup: + memset(kedata, 0, keylength); + memset(kidata, 0, keylength); + memset(plaintext, 0, plainlen); + + free(plaintext); + free(kidata); + free(kedata); + + return(ret); +} + diff --git a/src/lib/crypto/krb/dk/dk_prf.c b/src/lib/crypto/krb/dk/dk_prf.c new file mode 100644 index 0000000..ec64caf --- /dev/null +++ b/src/lib/crypto/krb/dk/dk_prf.c @@ -0,0 +1,64 @@ +/* + * lib/crypto/dk/prf.c + * + * Copyright (C) 2004 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. + * + * + * + * This file contains an implementation of the RFC 3961 PRF for + *simplified profile enctypes. + */ + +#include "k5-int.h" +#include "dk.h" + +krb5_error_code +krb5int_dk_prf (const struct krb5_enc_provider *enc, + const struct krb5_hash_provider *hash, + const krb5_keyblock *key, + const krb5_data *in, krb5_data *out) +{ + krb5_data tmp; + krb5_data prfconst; + krb5_keyblock *kp = NULL; + krb5_error_code ret = 0; + + prfconst.data = (char *) "prf"; + prfconst.length = 3; + tmp.length = hash->hashsize; + tmp.data = malloc(hash->hashsize); + if (tmp.data == NULL) + return ENOMEM; + hash->hash(1, in, &tmp); + tmp.length = (tmp.length/enc->block_size)*enc->block_size; /*truncate to block size*/ + ret = krb5int_c_init_keyblock(0, key->enctype, + key->length, &kp); + if (ret == 0) + ret = krb5_derive_key(enc, key, kp, &prfconst); + if (ret == 0) + ret = enc->encrypt(kp, NULL, &tmp, out); + if (kp) + krb5int_c_free_keyblock(0, kp); + free (tmp.data); + return ret; +} diff --git a/src/lib/crypto/krb/dk/stringtokey.c b/src/lib/crypto/krb/dk/stringtokey.c new file mode 100644 index 0000000..0e54b84 --- /dev/null +++ b/src/lib/crypto/krb/dk/stringtokey.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 1998 by the FundsXpress, INC. + * + * All rights reserved. + * + * Export of this software from the United States of America may require + * a specific license from the United States Government. It is the + * responsibility of any person or organization contemplating export to + * obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of FundsXpress. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. FundsXpress makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "dk.h" + +static const unsigned char kerberos[] = "kerberos"; +#define kerberos_len (sizeof(kerberos)-1) + +krb5_error_code +krb5int_dk_string_to_key(const struct krb5_enc_provider *enc, + const krb5_data *string, const krb5_data *salt, + const krb5_data *parms, krb5_keyblock *key) +{ + krb5_error_code ret; + size_t keybytes, keylength, concatlen; + unsigned char *concat, *foldstring, *foldkeydata; + krb5_data indata; + krb5_keyblock foldkey; + + /* key->length is checked by krb5_derive_key */ + + keybytes = enc->keybytes; + keylength = enc->keylength; + + concatlen = string->length+(salt?salt->length:0); + + if ((concat = (unsigned char *) malloc(concatlen)) == NULL) + return(ENOMEM); + if ((foldstring = (unsigned char *) malloc(keybytes)) == NULL) { + free(concat); + return(ENOMEM); + } + if ((foldkeydata = (unsigned char *) malloc(keylength)) == NULL) { + free(foldstring); + free(concat); + return(ENOMEM); + } + + /* construct input string ( = string + salt), fold it, make_key it */ + + memcpy(concat, string->data, string->length); + if (salt) + memcpy(concat+string->length, salt->data, salt->length); + + krb5_nfold(concatlen*8, concat, keybytes*8, foldstring); + + indata.length = keybytes; + indata.data = (char *) foldstring; + foldkey.length = keylength; + foldkey.contents = foldkeydata; + + (*(enc->make_key))(&indata, &foldkey); + + /* now derive the key from this one */ + + indata.length = kerberos_len; + indata.data = (char *) kerberos; + + if ((ret = krb5_derive_key(enc, &foldkey, key, &indata))) + memset(key->contents, 0, key->length); + + /* ret is set correctly by the prior call */ + + memset(concat, 0, concatlen); + memset(foldstring, 0, keybytes); + memset(foldkeydata, 0, keylength); + + free(foldkeydata); + free(foldstring); + free(concat); + + return(ret); +} |