From 84bdfcb1d871bdb5477790245209d8409186ff84 Mon Sep 17 00:00:00 2001 From: Johan Danielsson Date: Mon, 22 Sep 1997 16:08:10 +0000 Subject: [PATCH] Some cleanup, and added: - rsa-md5-des3 - hmac-sha1-des3 - keyed and collision proof flags to each checksum method - checksum<->string functions. git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@3522 ec53bebd-3082-4978-b11e-865c3cabbd6b --- lib/krb5/checksum.c | 188 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 180 insertions(+), 8 deletions(-) diff --git a/lib/krb5/checksum.c b/lib/krb5/checksum.c index 919b826cd..daf28b76d 100644 --- a/lib/krb5/checksum.c +++ b/lib/krb5/checksum.c @@ -43,12 +43,22 @@ RCSID("$Id$"); struct checksum_type { int type; + size_t blocksize; size_t checksumsize; krb5_keytype keytype; void (*checksum)(void *, size_t, const krb5_keyblock *, void *); int (*verify)(void *, size_t, const krb5_keyblock *, void *); + int flags; + const char *name; }; +/* values for `flags' */ +#define F_KEYED 1 +#define F_CPROOF 2 + +static struct checksum_type* find_checksum_type(krb5_cksumtype); + + static void NULL_checksum(void *p, size_t len, const krb5_keyblock *k, void *result) { @@ -229,22 +239,143 @@ MD5_DES_verify (void *p, size_t len, const krb5_keyblock *keyblock, return memcmp (res, (u_char *)other + 8, 16); } +static void +fix_des3_key(const krb5_keyblock *keyblock, des_key_schedule *sched) +{ + unsigned char *orig_key = keyblock->keyvalue.data; + des_cblock key[3]; + int i; + for (i = 0; i < 8; ++i){ + key[0][i] = orig_key[i] ^ 0xF0; + key[1][i] = orig_key[i+8] ^ 0xF0; + key[2][i] = orig_key[i+16] ^ 0xF0; + } + for(i = 0; i < 3; i++) + des_set_key(&key[i], sched[i]); + memset(key, 0, sizeof(key)); +} + +static void +MD5_DES3_checksum (void *p, size_t len, const krb5_keyblock *keyblock, + void *result) +{ + struct md5 md5; + des_cblock ivec; + des_key_schedule sched[3]; + unsigned char *r = result; + + md5_init(&md5); + krb5_generate_random_block(r, 8); + md5_update(&md5, r, 8); + md5_update(&md5, p, len); + md5_finito(&md5, r + 8); + fix_des3_key(keyblock, sched); + memset (&ivec, 0, sizeof(ivec)); + des_ede3_cbc_encrypt(result, result, 24, sched[0], sched[1], sched[2], + &ivec, DES_ENCRYPT); + memset(sched, 0, sizeof(sched)); +} + +static int +MD5_DES3_verify (void *p, size_t len, const krb5_keyblock *keyblock, + void *other) +{ + des_cblock ivec; + des_key_schedule sched[3]; + unsigned char res[16]; + unsigned char *orig_key = (unsigned char *)keyblock->keyvalue.data; + struct md5 md5; + + fix_des3_key(keyblock, sched); + memset (&ivec, 0, sizeof(ivec)); + des_ede3_cbc_encrypt(other, other, 24, sched[0], sched[1], sched[2], + &ivec, DES_DECRYPT); + + memset(sched, 0, sizeof(sched)); + md5_init(&md5); + md5_update(&md5, other, 8); + md5_update(&md5, p, len); + md5_finito(&md5, res); + + return memcmp (res, (unsigned char*)other + 8, 16); +} + + +/* HMAC according to RFC2104 */ +static void +hmac(struct checksum_type *cm, void *data, size_t len, + const krb5_keyblock *keyblock, void *result) +{ + unsigned char *ipad, *opad; + unsigned char *key, *tmp_key = NULL; + size_t key_len; + int i; + + key = keyblock->keyvalue.data; + key_len = keyblock->keyvalue.length; + if(key_len > cm->blocksize){ + tmp_key = malloc(cm->checksumsize); + (*cm->checksum)(key, key_len, keyblock, tmp_key); + key = tmp_key; + key_len = cm->checksumsize; + } + ipad = malloc(cm->blocksize + len); + opad = malloc(cm->blocksize + cm->checksumsize); + memset(ipad, 0x36, cm->blocksize); + memset(opad, 0x5c, cm->blocksize); + for(i = 0; i < key_len; i++){ + ipad[i] ^= key[i]; + opad[i] ^= key[i]; + } + memcpy(ipad + cm->blocksize, data, len); + (*cm->checksum)(ipad, cm->blocksize + len, keyblock, result); + memcpy(opad + cm->blocksize, result, cm->checksumsize); + (*cm->checksum)(opad, cm->blocksize + cm->checksumsize, keyblock, result); + if(tmp_key) + free(tmp_key); + free(ipad); + free(opad); +} + +/* this is used for HMAC-SHA1-DES3, but we make no checks that it + actually is a DES3 key that is passed */ +static void +HMAC_SHA1_checksum(void *data, size_t len, const krb5_keyblock *key, + void *result) +{ + struct checksum_type *c = find_checksum_type(CKSUMTYPE_SHA1); + hmac(c, data, len, key, result); +} + static struct checksum_type cm[] = { - { CKSUMTYPE_NONE, 0, KEYTYPE_NULL, NULL_checksum, NULL}, - { CKSUMTYPE_CRC32, 4, KEYTYPE_NULL, CRC_checksum, NULL}, - { CKSUMTYPE_RSA_MD4, 16, KEYTYPE_NULL, MD4_checksum, NULL}, - { CKSUMTYPE_RSA_MD5, 16, KEYTYPE_NULL, MD5_checksum, NULL}, - { CKSUMTYPE_RSA_MD4_DES, 24, KEYTYPE_DES, MD4_DES_checksum, MD4_DES_verify}, + { CKSUMTYPE_NONE, 1, 0, KEYTYPE_NULL, + NULL_checksum, NULL, 0, "none" }, + { CKSUMTYPE_CRC32, 1, 4, KEYTYPE_NULL, + CRC_checksum, NULL, 0, "crc32" }, + { CKSUMTYPE_RSA_MD4, 64, 16, KEYTYPE_NULL, + MD4_checksum, NULL, F_CPROOF, "md4" }, + { CKSUMTYPE_RSA_MD5, 64, 16, KEYTYPE_NULL, + MD5_checksum, NULL, F_CPROOF, "md5" }, + { CKSUMTYPE_RSA_MD4_DES, 64, 24, KEYTYPE_DES, + MD4_DES_checksum, MD4_DES_verify, F_KEYED|F_CPROOF, "md4-des" }, #if 0 - { CKSUMTYPE_RSA_MD4_DES, 16, KEYTYPE_DES, MD4_DES_broken_checksum, MD4_DES_broken_verify}, + { CKSUMTYPE_RSA_MD4_DES, 64, 16, KEYTYPE_DES, + MD4_DES_broken_checksum, MD4_DES_broken_verify, F_KEYED|F_CPROOF, "md4-des" }, #endif - { CKSUMTYPE_RSA_MD5_DES, 24, KEYTYPE_DES, MD5_DES_checksum, MD5_DES_verify} + { CKSUMTYPE_RSA_MD5_DES, 64, 24, KEYTYPE_DES, + MD5_DES_checksum, MD5_DES_verify, F_KEYED|F_CPROOF, "md5-des" }, + { CKSUMTYPE_RSA_MD5_DES3, 64, 24, KEYTYPE_DES3, + MD5_DES3_checksum, MD5_DES3_verify, F_KEYED|F_CPROOF, "md5-des3" }, + { CKSUMTYPE_SHA1, 80, 20, KEYTYPE_NULL, + SHA1_checksum, NULL, F_CPROOF, "sha1" }, + { CKSUMTYPE_HMAC_SHA1_DES3, 80, 20, KEYTYPE_DES3, + HMAC_SHA1_checksum, NULL, F_KEYED|F_CPROOF, "hmac-sha1-des3" } }; static int num_ctypes = sizeof(cm) / sizeof(cm[0]); static struct checksum_type * -find_checksum_type(int ctype) +find_checksum_type(krb5_cksumtype ctype) { struct checksum_type *c; for(c = cm; c < cm + num_ctypes; c++) @@ -253,6 +384,47 @@ find_checksum_type(int ctype) return NULL; } +krb5_boolean +krb5_checksum_is_keyed(krb5_cksumtype ctype) +{ + struct checksum_type *c; + c = find_checksum_type(ctype); + return (c->flags & F_KEYED) != 0; +} + +krb5_boolean +krb5_checksum_is_collision_proof(krb5_cksumtype ctype) +{ + struct checksum_type *c = find_checksum_type(ctype); + if(c == NULL) + return FALSE; /* XXX */ + return (c->flags & F_CPROOF) != 0; +} + +krb5_error_code +krb5_checksum_to_string(krb5_context context, krb5_cksumtype ctype, + char **string) +{ + struct checksum_type *c = find_checksum_type(ctype); + if(c == NULL) + return KRB5_PROG_SUMTYPE_NOSUPP; + *string = strdup(c->name); + return 0; +} + +krb5_error_code +krb5_string_to_checksum(krb5_context context, const char *string, + krb5_cksumtype *ctype) +{ + int i; + for(i = 0; i < num_ctypes; i++) + if(strcasecmp(cm[i].name, string) == 0){ + *ctype = cm[i].type; + return 0; + } + return KRB5_PROG_SUMTYPE_NOSUPP; +} + krb5_error_code krb5_cksumsize(krb5_context context, krb5_cksumtype type,