diff options
author | Sam Hartman <hartmans@mit.edu> | 2008-12-01 16:41:26 +0000 |
---|---|---|
committer | Sam Hartman <hartmans@mit.edu> | 2008-12-01 16:41:26 +0000 |
commit | 26df99363f4b42f68c00b2f76470b3ab1c62a354 (patch) | |
tree | 666d5ea43d1c2bf9b707c53ccf68472f1c8358d5 | |
parent | 087199ae03c946635458a9833e2fd4e3d4dcd119 (diff) | |
download | krb5-26df99363f4b42f68c00b2f76470b3ab1c62a354.zip krb5-26df99363f4b42f68c00b2f76470b3ab1c62a354.tar.gz krb5-26df99363f4b42f68c00b2f76470b3ab1c62a354.tar.bz2 |
Some work on checksum code for AEAD
git-svn-id: svn://anonsvn.mit.edu/krb5/branches/mskrb-integ-crypto-iov@21212 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r-- | src/include/k5-int.h | 21 | ||||
-rw-r--r-- | src/include/krb5/krb5.hin | 1 | ||||
-rw-r--r-- | src/lib/crypto/aead.c | 104 | ||||
-rw-r--r-- | src/lib/crypto/aead.h | 8 | ||||
-rw-r--r-- | src/lib/crypto/arcfour/arcfour_aead.c | 30 | ||||
-rw-r--r-- | src/lib/crypto/dk/checksum.c | 72 | ||||
-rw-r--r-- | src/lib/crypto/dk/dk.h | 6 | ||||
-rw-r--r-- | src/lib/crypto/hmac.c | 40 | ||||
-rw-r--r-- | src/lib/crypto/make_checksum_iov.c | 32 | ||||
-rw-r--r-- | src/lib/crypto/verify_checksum_iov.c | 57 |
10 files changed, 340 insertions, 31 deletions
diff --git a/src/include/k5-int.h b/src/include/k5-int.h index 588ba8d..03092bf 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -600,6 +600,21 @@ struct krb5_keyhash_provider { const krb5_data *input, const krb5_data *hash, krb5_boolean *valid); + + krb5_error_code (*hash_iov) (const krb5_keyblock *key, + krb5_keyusage keyusage, + const krb5_data *ivec, + const krb5_crypto_iov *data, + size_t num_data, + krb5_data *output); + + krb5_error_code (*verify_iov) (const krb5_keyblock *key, + krb5_keyusage keyusage, + const krb5_data *ivec, + const krb5_data *input, + const krb5_crypto_iov *data, + size_t num_data, + krb5_boolean *valid); }; struct krb5_aead_provider { @@ -702,6 +717,12 @@ krb5_error_code krb5_hmac const krb5_keyblock *key, unsigned int icount, const krb5_data *input, krb5_data *output); +krb5_error_code krb5_hmac_iov +(const struct krb5_hash_provider *hash, + const krb5_keyblock *key, + const krb5_crypto_iov *data, size_t num_data, + krb5_data *output); + krb5_error_code krb5int_pbkdf2_hmac_sha1 (const krb5_data *, unsigned long, const krb5_data *, const krb5_data *); diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin index 1c88673..9755dc2 100644 --- a/src/include/krb5/krb5.hin +++ b/src/include/krb5/krb5.hin @@ -630,6 +630,7 @@ krb5_error_code KRB5_CALLCONV krb5_error_code KRB5_CALLCONV krb5_c_verify_checksum_iov (krb5_context context, + krb5_cksumtype cksumtype, const krb5_keyblock *key, krb5_keyusage usage, const krb5_crypto_iov *data, size_t num_data, krb5_boolean *valid); diff --git a/src/lib/crypto/aead.c b/src/lib/crypto/aead.c index 58f1aee..8c1a735 100644 --- a/src/lib/crypto/aead.c +++ b/src/lib/crypto/aead.c @@ -25,6 +25,9 @@ */ #include "k5-int.h" +#include "etypes.h" +#include "cksumtypes.h" +#include "dk.h" #include "aead.h" krb5_crypto_iov * KRB5_CALLCONV @@ -50,3 +53,104 @@ krb5int_c_locate_iov(krb5_crypto_iov *data, return iov; } +static krb5_error_code +make_unkeyed_checksum_iov(const struct krb5_hash_provider *hash_provider, + const krb5_crypto_iov *data, + size_t num_data, + krb5_data *output) +{ + krb5_data *sign_data; + size_t num_sign_data; + krb5_error_code ret; + size_t i, j; + + /* Create a checksum over all the data to be signed */ + for (i = 0, num_sign_data = 0; i < num_data; i++) { + const krb5_crypto_iov *iov = &data[i]; + + if (iov->flags == KRB5_CRYPTO_TYPE_DATA || + iov->flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) + num_sign_data++; + } + + /* XXX cleanup to avoid alloc */ + sign_data = (krb5_data *)calloc(num_sign_data, sizeof(krb5_data)); + if (sign_data == NULL) + return ENOMEM; + + for (i = 0, j = 0; i < num_data; i++) { + const krb5_crypto_iov *iov = &data[i]; + + if (iov->flags == KRB5_CRYPTO_TYPE_DATA || + iov->flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) { + sign_data[j++] = iov[i].data; + } + } + + ret = hash_provider->hash(num_sign_data, sign_data, output); + + free(sign_data); + + return ret; +} + +krb5_error_code KRB5_CALLCONV +krb5int_c_make_checksum_iov(const struct krb5_cksumtypes *cksum_type, + const krb5_keyblock *key, + krb5_keyusage usage, + const krb5_crypto_iov *data, + size_t num_data, + krb5_data *cksum_data) +{ + int e1, e2; + krb5_error_code ret; + + if (cksum_type->keyhash) { + /* check if key is compatible */ + + if (cksum_type->keyed_etype) { + for (e1=0; e1<krb5_enctypes_length; e1++) + if (krb5_enctypes_list[e1].etype == + cksum_type->keyed_etype) + break; + + for (e2=0; e2<krb5_enctypes_length; e2++) + if (krb5_enctypes_list[e2].etype == key->enctype) + break; + + if ((e1 == krb5_enctypes_length) || + (e2 == krb5_enctypes_length) || + (krb5_enctypes_list[e1].enc != krb5_enctypes_list[e2].enc)) { + ret = KRB5_BAD_ENCTYPE; + goto cleanup; + } + } + + if (cksum_type->keyhash->hash_iov == NULL) { + return KRB5_BAD_ENCTYPE; + } + + ret = (*(cksum_type->keyhash->hash_iov))(key, usage, 0, + data, num_data, cksum_data); + } else if (cksum_type->flags & KRB5_CKSUMFLAG_DERIVE) { + ret = krb5_dk_make_checksum_iov(cksum_type->hash, + key, usage, data, num_data, + cksum_data); + } else { + ret = make_unkeyed_checksum_iov(cksum_type->hash, data, num_data, + cksum_data); + } + + if (!ret) { + if (cksum_type->trunc_size) { + cksum_data->length = cksum_type->trunc_size; + } + } + +cleanup: + if (ret) { + memset(cksum_data->data, 0, cksum_data->length); + } + + return(ret); +} diff --git a/src/lib/crypto/aead.h b/src/lib/crypto/aead.h index 83e4de8..29f97ae 100644 --- a/src/lib/crypto/aead.h +++ b/src/lib/crypto/aead.h @@ -33,3 +33,11 @@ krb5int_c_locate_iov(krb5_crypto_iov *data, size_t num_data, krb5_cryptotype type); +krb5_error_code KRB5_CALLCONV +krb5int_c_make_checksum_iov(const struct krb5_cksumtypes *cksum, + const krb5_keyblock *key, + krb5_keyusage usage, + const krb5_crypto_iov *data, + size_t num_data, + krb5_data *cksum_data); + diff --git a/src/lib/crypto/arcfour/arcfour_aead.c b/src/lib/crypto/arcfour/arcfour_aead.c index b64e93b..0c51937 100644 --- a/src/lib/crypto/arcfour/arcfour_aead.c +++ b/src/lib/crypto/arcfour/arcfour_aead.c @@ -88,13 +88,11 @@ krb5int_arcfour_encrypt_iov(const struct krb5_aead_provider *aead, { krb5_error_code ret; krb5_crypto_iov *header, *trailer, *padding; - size_t i, j, num_sign_data; krb5_keyblock k1, k2, k3; krb5_data d1, d2, d3; krb5_keyusage ms_usage; char salt_data[14]; krb5_data salt; - krb5_data *sign_data = NULL; d1.length = d2.length = d3.length = 0; d1.data = d2.data = d3.data = NULL; @@ -156,32 +154,11 @@ krb5int_arcfour_encrypt_iov(const struct krb5_aead_provider *aead, if (ret != 0) goto cleanup; - /* Create a checksum over all the data to be signed */ - for (i = 0, num_sign_data = 0; i < num_data; i++) { - krb5_crypto_iov *iov = &data[i]; - - if (iov->flags == KRB5_CRYPTO_TYPE_DATA || - iov->flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) - num_sign_data++; - } - sign_data = (krb5_data *)calloc(num_sign_data, sizeof(krb5_data)); - if (sign_data == NULL) - goto cleanup; - - for (i = 0, j = 0; i < num_data; i++) { - krb5_crypto_iov *iov = &data[i]; - - if (iov->flags == KRB5_CRYPTO_TYPE_DATA || - iov->flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) { - sign_data[j++] = iov[i].data; - } - } - - krb5_hmac(hash, &k2, 1, sign_data, &trailer->data); + krb5_hmac_iov(hash, &k2, data, num_data, &trailer->data); krb5_hmac(hash, &k1, 1, &trailer->data, &d3); - ret = enc->encrypt_iov(&k3, ivec, data); + ret = enc->encrypt_iov(&k3, ivec, data, num_data); cleanup: if (d1.data != NULL) { @@ -196,9 +173,6 @@ cleanup: memset(d3.data, 0, d3.length); free(d3.data); } - if (sign_data != NULL) { - free(sign_data); - } return ret; } diff --git a/src/lib/crypto/dk/checksum.c b/src/lib/crypto/dk/checksum.c index 2f30cb7..ccef9df 100644 --- a/src/lib/crypto/dk/checksum.c +++ b/src/lib/crypto/dk/checksum.c @@ -27,6 +27,7 @@ #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 */ @@ -101,3 +102,74 @@ cleanup: return(ret); } +krb5_error_code +krb5_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; + krb5_crypto_iov *checksum; + + 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; + + datain.data[0] = (usage>>24)&0xff; + datain.data[1] = (usage>>16)&0xff; + datain.data[2] = (usage>>8)&0xff; + datain.data[3] = usage&0xff; + + datain.data[4] = (char) 0x99; + + if ((ret = krb5_derive_key(enc, key, &kc, &datain)) != 0) + goto cleanup; + + /* hash the data */ + + if ((ret = krb5_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/dk/dk.h b/src/lib/crypto/dk/dk.h index 9e5aab8..a8def7a 100644 --- a/src/lib/crypto/dk/dk.h +++ b/src/lib/crypto/dk/dk.h @@ -85,6 +85,12 @@ krb5_error_code krb5_dk_make_checksum const krb5_data *input, krb5_data *output); krb5_error_code +krb5_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); diff --git a/src/lib/crypto/hmac.c b/src/lib/crypto/hmac.c index 3c02726..d3fd968 100644 --- a/src/lib/crypto/hmac.c +++ b/src/lib/crypto/hmac.c @@ -125,3 +125,43 @@ cleanup: return(ret); } + +krb5_error_code +krb5_hmac_iov(const struct krb5_hash_provider *hash, const krb5_keyblock *key, + const krb5_crypto_iov *data, size_t num_data, krb5_data *output) +{ + krb5_data *sign_data; + size_t num_sign_data; + krb5_error_code ret; + size_t i, j; + + /* Create a checksum over all the data to be signed */ + for (i = 0, num_sign_data = 0; i < num_data; i++) { + const krb5_crypto_iov *iov = &data[i]; + + if (iov->flags == KRB5_CRYPTO_TYPE_DATA || + iov->flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) + num_sign_data++; + } + /* XXX cleanup to avoid alloc */ + sign_data = (krb5_data *)calloc(num_sign_data, sizeof(krb5_data)); + if (sign_data == NULL) + return ENOMEM; + + for (i = 0, j = 0; i < num_data; i++) { + const krb5_crypto_iov *iov = &data[i]; + + if (iov->flags == KRB5_CRYPTO_TYPE_DATA || + iov->flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) { + sign_data[j++] = iov[i].data; + } + } + + /* caller must store checksum in iov as it may be TYPE_TRAILER or TYPE_CHECKSUM */ + ret = krb5_hmac(hash, key, num_sign_data, sign_data, output); + + free(sign_data); + + return ret; +} + diff --git a/src/lib/crypto/make_checksum_iov.c b/src/lib/crypto/make_checksum_iov.c index 6e52481..0d862c8 100644 --- a/src/lib/crypto/make_checksum_iov.c +++ b/src/lib/crypto/make_checksum_iov.c @@ -25,7 +25,8 @@ */ #include "k5-int.h" -#include "etypes.h" +#include "cksumtypes.h" +#include "aead.h" krb5_error_code KRB5_CALLCONV krb5_c_make_checksum_iov(krb5_context context, @@ -35,4 +36,33 @@ krb5_c_make_checksum_iov(krb5_context context, krb5_crypto_iov *data, size_t num_data) { + krb5_error_code ret; + size_t cksumlen; + krb5_crypto_iov *checksum; + size_t i; + + for (i = 0; i < krb5_cksumtypes_length; i++) { + if (krb5_cksumtypes_list[i].ctype == cksumtype) + break; + } + + if (i == krb5_cksumtypes_length) + return(KRB5_BAD_ENCTYPE); + + if (krb5_cksumtypes_list[i].keyhash) + cksumlen = krb5_cksumtypes_list[i].keyhash->hashsize; + else + cksumlen = krb5_cksumtypes_list[i].hash->hashsize; + + checksum = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM); + if (checksum == NULL || checksum->data.length < cksumlen) + return(KRB5_BAD_MSIZE); + + checksum->data.length = cksumlen; + + ret = krb5int_c_make_checksum_iov(&krb5_cksumtypes_list[i], + key, usage, data, num_data, + &checksum->data); + + return(ret); } diff --git a/src/lib/crypto/verify_checksum_iov.c b/src/lib/crypto/verify_checksum_iov.c index 82672e8..5627188 100644 --- a/src/lib/crypto/verify_checksum_iov.c +++ b/src/lib/crypto/verify_checksum_iov.c @@ -25,15 +25,68 @@ */ #include "k5-int.h" -#include "etypes.h" +#include "cksumtypes.h" +#include "aead.h" krb5_error_code KRB5_CALLCONV krb5_c_verify_checksum_iov(krb5_context context, + krb5_cksumtype checksum_type, const krb5_keyblock *key, krb5_keyusage usage, const krb5_crypto_iov *data, size_t num_data, krb5_boolean *valid) { -} + unsigned int i; + size_t hashsize; + krb5_error_code ret; + krb5_data computed; + krb5_crypto_iov *checksum; + + for (i=0; i<krb5_cksumtypes_length; i++) { + if (krb5_cksumtypes_list[i].ctype == checksum_type) + break; + } + + if (i == krb5_cksumtypes_length) + return(KRB5_BAD_ENCTYPE); + + checksum = krb5int_c_locate_iov((krb5_crypto_iov *)data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM); + if (checksum == NULL) + return(KRB5_BAD_MSIZE); + + /* if there's actually a verify function, call it */ + + if (krb5_cksumtypes_list[i].keyhash && + krb5_cksumtypes_list[i].keyhash->verify_iov) + return((*(krb5_cksumtypes_list[i].keyhash->verify_iov))(key, usage, 0, + &checksum->data, + data, num_data, + valid)); + + /* otherwise, make the checksum again, and compare */ + if ((ret = krb5_c_checksum_length(context, checksum_type, &hashsize))) + return(ret); + + if (checksum->data.length != hashsize) + return(KRB5_BAD_MSIZE); + + computed.data = malloc(hashsize); + if (computed.data == NULL) { + return(ENOMEM); + } + computed.length = hashsize; + + if ((ret = krb5int_c_make_checksum_iov(&krb5_cksumtypes_list[i], key, usage, + data, num_data, &computed))) { + free(computed.data); + return(ret); + } + + *valid = (memcmp(computed.data, &checksum->data, hashsize) == 0); + + free(computed.data); + + return(0); +} |