From: Sam Hartman Date: Thu, 18 Oct 2001 19:38:48 +0000 (+0000) Subject: Patches contributed by David E. Cross" to add X-Git-Tag: krb5-1.3-alpha1~1029 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=0642372c8ce6283554babcdbf922054643d0612f;p=krb5.git Patches contributed by David E. Cross" to add RC4-hmac support. This directory is taken from a diff at a url posted to krbdev with krb5int_hash_md5 substituted for krb5_hash_md5 so that the code would compile. krb5int_enc_arcfour has been substituted for krb5_enc_arcfour as well. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@13818 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/lib/crypto/arcfour/Makefile.in b/src/lib/crypto/arcfour/Makefile.in new file mode 100644 index 000000000..1fb2806b6 --- /dev/null +++ b/src/lib/crypto/arcfour/Makefile.in @@ -0,0 +1,37 @@ +thisconfigdir=./.. +myfulldir=lib/crypto/arcfour +mydir=arcfour +BUILDTOP=$(REL)$(U)$(S)$(U)$(S)$(U) +LOCALINCLUDES = -I$(srcdir)/.. -I$(srcdir)/../md4 + +##DOS##BUILDTOP = ..\..\.. +##DOS##PREFIXDIR=arcfour +##DOS##OBJFILE=..\$(OUTPRE)arcfour.lst +##WIN16##LIBNAME=..\crypto.lib + +PROG_LIBPATH=-L$(TOPLIBD) +PROG_RPATH=$(KRB5_LIBDIR) + +RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf + +STLIBOBJS=\ + arcfour.o \ + string_to_key.o + +OBJS=\ + $(OUTPRE)arcfour.$(OBJEXT) \ + $(OUTPRE)string_to_key.$(OBJEXT) + +SRCS=\ + $(srcdir)/arcfour.c \ + $(srcdir)/string_to_key.c + +##DOS##LIBOBJS = $(OBJS) + +all-unix:: all-libobjs + +includes:: depend + +depend:: $(SRCS) + +clean-unix:: clean-libobjs diff --git a/src/lib/crypto/arcfour/arcfour-int.h b/src/lib/crypto/arcfour/arcfour-int.h new file mode 100644 index 000000000..2b2557634 --- /dev/null +++ b/src/lib/crypto/arcfour/arcfour-int.h @@ -0,0 +1,50 @@ +/* + +ARCFOUR cipher (based on a cipher posted on the Usenet in Spring-95). +This cipher is widely believed and has been tested to be equivalent +with the RC4 cipher from RSA Data Security, Inc. (RC4 is a trademark +of RSA Data Security) + +*/ +#ifndef ARCFOUR_INT_H +#define ARCFOUR_INT_H + +#include "arcfour.h" + +#define CONFOUNDERLENGTH 8 + +typedef struct +{ + unsigned int x; + unsigned int y; + unsigned char state[256]; +} ArcfourContext; + +/* gets the next byte from the PRNG */ +static inline unsigned int k5_arcfour_byte(ArcfourContext *); + +/* Initializes the context and sets the key. */ +static krb5_error_code k5_arcfour_init(ArcfourContext *ctx, const unsigned char *key, + unsigned int keylen); + +/* Encrypts/decrypts data. */ +static void k5_arcfour_crypt(ArcfourContext *ctx, unsigned char *dest, + const unsigned char *src, unsigned int len); + +/* Interface layer to kerb5 crypto layer */ +static krb5_error_code +k5_arcfour_docrypt(krb5_const krb5_keyblock *, krb5_const krb5_data *, + krb5_const krb5_data *, krb5_data *); + + +/* The blocksize for the enctype */ +static void k5_arcfour_blocksize(size_t *); + +/* keysize for the enctype (number of bytes, and length of key (parity/etc) */ +static void k5_arcfour_keysize(size_t *, size_t *); + +/* from a random bitstrem, construct a key */ +static krb5_error_code +k5_arcfour_make_key(krb5_const krb5_data *, krb5_keyblock *); + +#endif /* ARCFOUR_INT_H */ diff --git a/src/lib/crypto/arcfour/arcfour.c b/src/lib/crypto/arcfour/arcfour.c new file mode 100644 index 000000000..d96a6518d --- /dev/null +++ b/src/lib/crypto/arcfour/arcfour.c @@ -0,0 +1,291 @@ +/* + +ARCFOUR cipher (based on a cipher posted on the Usenet in Spring-95). +This cipher is widely believed and has been tested to be equivalent +with the RC4 cipher from RSA Data Security, Inc. (RC4 is a trademark +of RSA Data Security) + +*/ +#include "k5-int.h" +#include "arcfour-int.h" +const unsigned char *l40 = "fortybits"; + +void +krb5_arcfour_encrypt_length(enc, hash, inputlen, length) + krb5_const struct krb5_enc_provider *enc; + krb5_const struct krb5_hash_provider *hash; + size_t inputlen; + size_t *length; +{ + size_t blocksize, hashsize; + + (*(enc->block_size))(&blocksize); + (*(hash->hash_size))(&hashsize); + + + /* checksum + (confounder + inputlen, in even blocksize) */ + *length = hashsize + krb5_roundup(8 + inputlen, blocksize); +} + +static krb5_keyusage arcfour_translate_usage(krb5_keyusage usage) +{ + return usage; +} + +krb5_error_code +krb5_arcfour_encrypt(enc, hash, key, usage, ivec, input, output) + krb5_const struct krb5_enc_provider *enc; + krb5_const struct krb5_hash_provider *hash; + krb5_const krb5_keyblock *key; + krb5_keyusage usage; + krb5_const krb5_data *ivec; + krb5_const krb5_data *input; + krb5_data *output; +{ + krb5_keyblock k1, k2, k3; + krb5_data d1, d2, d3, salt, plaintext, checksum, ciphertext, confounder; + krb5_keyusage ms_usage; + size_t keylength, keybytes, blocksize, hashsize; + krb5_error_code ret; + + (*(enc->block_size))(&blocksize); + (*(enc->keysize))(&keybytes, &keylength); + (*(hash->hash_size))(&hashsize); + + d1.length=keybytes; + d1.data=malloc(d1.length); + if (d1.data == NULL) + return (ENOMEM); + memcpy(&k1, key, sizeof (krb5_keyblock)); + k1.length=d1.length; + k1.contents=d1.data; + + d2.length=keybytes; + d2.data=malloc(d2.length); + if (d2.data == NULL) { + free(d1.data); + return (ENOMEM); + } + memcpy(&k2, key, sizeof (krb5_keyblock)); + k2.length=d2.length; + k2.contents=d2.data; + + d3.length=keybytes; + d3.data=malloc(d3.length); + if (d3.data == NULL) { + free(d1.data); + free(d2.data); + return (ENOMEM); + } + memcpy(&k3, key, sizeof (krb5_keyblock)); + k3.length=d3.length; + k3.contents=d3.data; + + salt.length=14; + salt.data=malloc(salt.length); + if (salt.data == NULL) { + free(d1.data); + free(d2.data); + free(d3.data); + return (ENOMEM); + } + + /* is "input" already blocksize aligned? if it is, then we need this + step, otherwise we do not */ + plaintext.length=krb5_roundup(input->length+CONFOUNDERLENGTH,blocksize); + plaintext.data=malloc(plaintext.length); + if (plaintext.data == NULL) { + free(d1.data); + free(d2.data); + free(d3.data); + free(salt.data); + return(ENOMEM); + } + + /* setup convienient pointers into the allocated data */ + checksum.length=hashsize; + checksum.data=output->data; + ciphertext.length=krb5_roundup(input->length+CONFOUNDERLENGTH,blocksize); + ciphertext.data=output->data+hashsize; + confounder.length=CONFOUNDERLENGTH; + confounder.data=plaintext.data; + + /* begin the encryption, computer K1 */ + ms_usage=arcfour_translate_usage(usage); + if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) { + strncpy(salt.data, l40, salt.length); + salt.data[10]=ms_usage & 0xff; + salt.data[11]=(ms_usage >> 8) & 0xff; + salt.data[12]=(ms_usage >> 16) & 0xff; + salt.data[13]=(ms_usage >> 24) & 0xff; + } else { + salt.length=4; + salt.data[0]=ms_usage & 0xff; + salt.data[1]=(ms_usage >> 8) & 0xff; + salt.data[2]=(ms_usage >> 16) & 0xff; + salt.data[3]=(ms_usage >> 24) & 0xff; + } + krb5_hmac(hash, key, 1, &salt, &d1); + + memcpy(k2.contents, k1.contents, k2.length); + + if (key->enctype==ENCTYPE_ARCFOUR_HMAC) + memset(k1.contents+7, 0xab, 9); + + ret=krb5_c_random_make_octets(/* XXX */ 0, &confounder); + memcpy(plaintext.data+confounder.length, input->data, input->length); + if (ret) + goto cleanup; + + krb5_hmac(hash, &k2, 1, &plaintext, &checksum); + + krb5_hmac(hash, &k1, 1, &checksum, &d3); + + ret=(*(enc->encrypt))(&k3, ivec, &plaintext, &ciphertext); + + cleanup: + memset(d1.data, 0, d1.length); + memset(d2.data, 0, d2.length); + memset(d3.data, 0, d3.length); + memset(salt.data, 0, salt.length); + memset(plaintext.data, 0, plaintext.length); + + free(d1.data); + free(d2.data); + free(d3.data); + free(salt.data); + free(plaintext.data); + return (ret); +} + +/* This is the arcfour-hmac decryption routine */ +krb5_error_code +krb5_arcfour_decrypt(enc, hash, key, usage, ivec, input, output) + krb5_const struct krb5_enc_provider *enc; + krb5_const struct krb5_hash_provider *hash; + krb5_const krb5_keyblock *key; + krb5_keyusage usage; + krb5_const krb5_data *ivec; + krb5_const krb5_data *input; + krb5_data *output; +{ + krb5_keyblock k1,k2,k3; + krb5_data d1,d2,d3,salt,ciphertext,plaintext,checksum; + krb5_keyusage ms_usage; + size_t keybytes, keylength, hashsize, blocksize; + krb5_error_code ret; + + (*(enc->block_size))(&blocksize); + (*(enc->keysize))(&keybytes, &keylength); + (*(hash->hash_size))(&hashsize); + + d1.length=keybytes; + d1.data=malloc(d1.length); + if (d1.data == NULL) + return (ENOMEM); + memcpy(&k1, key, sizeof (krb5_keyblock)); + k1.length=d1.length; + k1.contents=d1.data; + + d2.length=keybytes; + d2.data=malloc(d2.length); + if (d2.data == NULL) { + free(d1.data); + return (ENOMEM); + } + memcpy(&k2, key, sizeof(krb5_keyblock)); + k2.length=d2.length; + k2.contents=d2.data; + + d3.length=keybytes; + d3.data=malloc(d3.length); + if (d3.data == NULL) { + free(d1.data); + free(d2.data); + return (ENOMEM); + } + memcpy(&k3, key, sizeof(krb5_keyblock)); + k3.length=d3.length; + k3.contents=d3.data; + + salt.length=14; + salt.data=malloc(salt.length); + if(salt.data==NULL) { + free(d1.data); + free(d2.data); + free(d3.data); + } + + ciphertext.length=input->length-hashsize; + ciphertext.data=input->data+hashsize; + plaintext.length=ciphertext.length; + plaintext.data=malloc(plaintext.length); + if (plaintext.data == NULL) { + free(d1.data); + free(d2.data); + free(d3.data); + free(salt.data); + } + + checksum.length=hashsize; + checksum.data=input->data; + + /* compute the salt */ + ms_usage=arcfour_translate_usage(usage); + if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) { + strncpy(salt.data, l40, salt.length); + salt.data[10]=ms_usage & 0xff; + salt.data[11]=(ms_usage>>8) & 0xff; + salt.data[12]=(ms_usage>>16) & 0xff; + salt.data[13]=(ms_usage>>24) & 0xff; + } else { + salt.length=4; + salt.data[0]=ms_usage & 0xff; + salt.data[1]=(ms_usage>>8) & 0xff; + salt.data[2]=(ms_usage>>16) & 0xff; + salt.data[3]=(ms_usage>>24) & 0xff; + } + ret=krb5_hmac(hash, key, 1, &salt, &d1); + if (ret) + goto cleanup; + + memcpy(k2.contents, k1.contents, k2.length); + + if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) + memset(k1.contents+7, 0xab, 9); + + ret = krb5_hmac(hash, &k1, 1, &checksum, &d3); + if (ret) + goto cleanup; + + ret=(*(enc->decrypt))(&k3, ivec, &ciphertext, &plaintext); + if (ret) + goto cleanup; + + ret=krb5_hmac(hash, &k2, 1, &plaintext, &d1); + if (ret) + goto cleanup; + + if (memcmp(checksum.data, d1.data, hashsize) != 0) { + ret=KRB5KRB_AP_ERR_BAD_INTEGRITY; + goto cleanup; + } + + memcpy(output->data, plaintext.data+CONFOUNDERLENGTH, + (plaintext.length-CONFOUNDERLENGTH)); + output->length=plaintext.length-CONFOUNDERLENGTH; + + cleanup: + memset(d1.data, 0, d1.length); + memset(d2.data, 0, d2.length); + memset(d3.data, 0, d2.length); + memset(salt.data, 0, salt.length); + memset(plaintext.data, 0, plaintext.length); + + free(d1.data); + free(d2.data); + free(d3.data); + free(salt.data); + free(plaintext.data); + return (ret); +} diff --git a/src/lib/crypto/arcfour/arcfour.h b/src/lib/crypto/arcfour/arcfour.h new file mode 100644 index 000000000..2b04680e5 --- /dev/null +++ b/src/lib/crypto/arcfour/arcfour.h @@ -0,0 +1,33 @@ +#ifndef ARCFOUR_H +#define ARCFOUR_H + +void +krb5_arcfour_encrypt_length(krb5_const struct krb5_enc_provider *, + krb5_const struct krb5_hash_provider *, + size_t, + size_t *); + +krb5_error_code krb5_arcfour_encrypt(krb5_const struct krb5_enc_provider *, + krb5_const struct krb5_hash_provider *, + krb5_const krb5_keyblock *, + krb5_keyusage, + krb5_const krb5_data *, + krb5_const krb5_data *, + krb5_data *); + +krb5_error_code krb5_arcfour_decrypt(krb5_const struct krb5_enc_provider *, + krb5_const struct krb5_hash_provider *, + krb5_const krb5_keyblock *, + krb5_keyusage, + krb5_const krb5_data *, + krb5_const krb5_data *, + krb5_data *); + +krb5_error_code krb5_arcfour_string_to_key( + krb5_const struct krb5_enc_provider *, + krb5_const krb5_data *, + krb5_const krb5_data *, + krb5_keyblock *); + +const struct krb5_enc_provider krb5int_enc_arcfour; +#endif /* ARCFOUR_H */ diff --git a/src/lib/crypto/arcfour/string_to_key.c b/src/lib/crypto/arcfour/string_to_key.c new file mode 100644 index 000000000..d41bc2585 --- /dev/null +++ b/src/lib/crypto/arcfour/string_to_key.c @@ -0,0 +1,71 @@ +#include "k5-int.h" +#include "rsa-md4.h" +#include "arcfour-int.h" + +static void asctouni(unsigned char *unicode, unsigned char *ascii, int len) +{ + int counter; + for (counter=0;counterlength != 16) + return (KRB5_BAD_MSIZE); + + /* handle the salt... + We really don't salt our key, else it won't work with MSFT, but + handle it anyway + */ + saltlen=salt?salt->length:0; + + /* compute the space needed for the new string. + Since the password must be stored in unicode, we need to increase + that number by 2x. + + This should be re-evauated in the future, it makes the assumption that + thes user's password is in ascii. + */ + slen = ((string->length)>128)?128:string->length; + len=(slen)*2 + saltlen; + + copystr = malloc((size_t) len); + if (copystr == NULL) + return ENOMEM; + + /* make the string. start by creating the unicode version of the password + then copy the salt to the end of the string */ + asctouni(copystr, string->data, slen ); + memcpy(copystr+(slen*2), salt->data, saltlen); + + /* the actual MD4 hash of the data */ + krb5_MD4Init(&md4_context); + krb5_MD4Update(&md4_context, (unsigned char *)copystr, len); + krb5_MD4Final(&md4_context); + memcpy(key->contents, md4_context.digest, 16); + +#if 0 + /* test the string_to_key function */ + printf("Hash="); + for(counter=0;counter<16;counter++) + printf("%02x", md4_context.digest[counter]); + printf("\n"); +#endif /* 0 */ + + /* Zero out the data behind us */ + bzero(copystr, len); + bzero(&md4_context, sizeof(md4_context)); + return 0; +}