From: Paul Park Date: Fri, 7 Jul 1995 21:01:10 +0000 (+0000) Subject: Correct implementation of RSA-MD4-DES checksums and add verifier procedure/dispatch X-Git-Tag: krb5-1.0-beta6~1564 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=a993a6baad58f2e5ba383b76ade7c0fc0bebd6e5;p=krb5.git Correct implementation of RSA-MD4-DES checksums and add verifier procedure/dispatch git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@6252 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/lib/crypto/md4/md4crypto.c b/src/lib/crypto/md4/md4crypto.c index 40ad9bd80..248f17683 100644 --- a/src/lib/crypto/md4/md4crypto.c +++ b/src/lib/crypto/md4/md4crypto.c @@ -28,12 +28,42 @@ #include "rsa-md4.h" #include "des_int.h" /* we cheat a bit and call it directly... */ -krb5_error_code -md4_crypto_sum_func KRB5_NPROTOTYPE((krb5_pointer in, size_t in_length, - krb5_pointer seed, size_t seed_length, krb5_checksum *outcksum)); +/* + * In Kerberos V5 Beta 5 and previous releases the RSA-MD4-DES implementation + * did not follow RFC1510. The folowing definitions control the compatibility + * with these releases. + * + * If MD4_K5BETA_COMPAT is defined, then compatability mode is enabled. That + * means that both checksum functions are compiled and available for use and + * the additional interface md4_crypto_compat_ctl() is defined. + * + * If MD4_K5BETA_COMPAT_DEF is defined and compatability mode is enabled, then + * the compatible behaviour becomes the default. + * + */ +static void +md4_calculate_cksum(md4ctx, in, in_length, confound, confound_length) + MD4_CTX *md4ctx; + krb5_pointer in; + size_t in_length; + krb5_pointer confound; + size_t confound_length; +{ + MD4Init(md4ctx); + if (confound && confound_length) + MD4Update(md4ctx, confound, confound_length); + MD4Update(md4ctx, in, in_length); + MD4Final(md4ctx); +} + +#ifdef MD4_K5BETA_COMPAT +/* + * Generate the RSA-MD4-DES checksum in a manner which is compatible with + * K5 Beta implementations. Sigh... + */ krb5_error_code -md4_crypto_sum_func(in, in_length, seed, seed_length, outcksum) +md4_crypto_compat_sum_func(in, in_length, seed, seed_length, outcksum) krb5_pointer in; size_t in_length; krb5_pointer seed; @@ -78,12 +108,252 @@ krb5_checksum FAR *outcksum; } return mit_des_finish_key(&eblock); } +#endif /* MD4_K5BETA_COMPAT */ + +/* + * Generate the RSA-MD4-DES checksum correctly. + */ +krb5_error_code +md4_crypto_sum_func(in, in_length, seed, seed_length, outcksum) +krb5_pointer in; +size_t in_length; +krb5_pointer seed; +size_t seed_length; +krb5_checksum FAR *outcksum; +{ + krb5_octet outtmp[RSA_MD4_DES_CKSUM_LENGTH+ + RSA_MD4_DES_CONFOUND_LENGTH]; + mit_des_cblock tmpkey; + krb5_octet *input = (krb5_octet *)in; + krb5_encrypt_block eblock; + krb5_keyblock keyblock; + krb5_error_code retval; + int i; + + MD4_CTX working; + + /* Generate the confounder in place */ + if (retval = krb5_random_confounder(RSA_MD4_DES_CONFOUND_LENGTH, + outtmp)) + return(retval); + + /* Calculate the checksum */ + md4_calculate_cksum(&working, + (krb5_pointer) outtmp, + (size_t) RSA_MD4_DES_CONFOUND_LENGTH, + in, + in_length); + + outcksum->checksum_type = CKSUMTYPE_RSA_MD4_DES; + outcksum->length = RSA_MD4_DES_CKSUM_LENGTH + RSA_MD4_DES_CONFOUND_LENGTH; + + /* Now blast in the digest */ + memcpy((char *) &outtmp[RSA_MD4_DES_CONFOUND_LENGTH], + (char *) &working.digest[0], + RSA_MD4_DES_CKSUM_LENGTH); + + /* Clean up droppings */ + memset((char *)&working, 0, sizeof(working)); + /* Set up the temporary copy of the key (see RFC 1510 section 6.4.3) */ + memset((char *) tmpkey, 0, sizeof(mit_des_cblock)); + for (i=0; (icontents, + RSA_MD4_DES_CKSUM_LENGTH + + RSA_MD4_DES_CONFOUND_LENGTH, + (struct mit_des_ks_struct *)eblock.priv, + keyblock.contents, + MIT_DES_ENCRYPT); + if (retval) { + (void) mit_des_finish_key(&eblock); + return retval; + } + return mit_des_finish_key(&eblock); +} + +krb5_error_code +md4_crypto_verify_func(cksum, in, in_length, seed, seed_length) +krb5_checksum FAR *cksum; +krb5_pointer in; +size_t in_length; +krb5_pointer seed; +size_t seed_length; +{ + krb5_octet outtmp[RSA_MD4_DES_CKSUM_LENGTH+ + RSA_MD4_DES_CONFOUND_LENGTH]; + krb5_octet outtmp1[RSA_MD4_DES_CKSUM_LENGTH+ + RSA_MD4_DES_CONFOUND_LENGTH]; + mit_des_cblock tmpkey; + krb5_octet *input = (krb5_octet *)in; + krb5_encrypt_block eblock; + krb5_keyblock keyblock; + krb5_error_code retval; + int i; + + MD4_CTX working; + + retval = 0; + if (cksum->checksum_type == CKSUMTYPE_RSA_MD4_DES) { +#ifdef MD4_K5BETA_COMPAT + /* + * We have a backwards compatibility problem here. Kerberos version 5 + * Beta 5 and previous releases did not correctly generate RSA-MD4-DES + * checksums. The way that we can differentiate is by the length of + * the provided checksum. If it's only RSA_MD4_DES_CKSUM_LENGTH, then + * it's the old style, otherwise it's the correct implementation. + */ + if (cksum->length == RSA_MD4_DES_CKSUM_LENGTH) { + /* + * If we're verifying the Old Style (tm) checksum, then we can just + * recalculate the checksum and encrypt it and see if it's the + * same. + */ + + /* Recalculate the checksum with no confounder */ + md4_calculate_cksum(&working, + (krb5_pointer) NULL, + (size_t) 0, + in, + in_length); + + /* Use the key "as-is" */ + keyblock.length = seed_length; + keyblock.contents = (krb5_octet *) seed; + keyblock.keytype = KEYTYPE_DES; + + if ((retval = mit_des_process_key(&eblock, &keyblock))) + return retval; + /* now encrypt the checksum */ + retval = mit_des_cbc_encrypt((mit_des_cblock *)&working.digest[0], + (mit_des_cblock *)&outtmp[0], + RSA_MD4_DES_CKSUM_LENGTH, + (struct mit_des_ks_struct *) + eblock.priv, + keyblock.contents, + MIT_DES_ENCRYPT); + if (retval) { + (void) mit_des_finish_key(&eblock); + return retval; + } + if (retval = mit_des_finish_key(&eblock)) + return(retval); + + /* Compare the encrypted checksums */ + if (memcmp((char *) &outtmp[0], + (char *) cksum->contents, + RSA_MD4_DES_CKSUM_LENGTH)) + retval = KRB5KRB_AP_ERR_BAD_INTEGRITY; + } + else +#endif /* MD4_K5BETA_COMPAT */ + if (cksum->length == (RSA_MD4_DES_CKSUM_LENGTH + + RSA_MD4_DES_CONFOUND_LENGTH)) { + /* + * If we're verifying the correct implementation, then we have + * to do a little more work because we must decrypt the checksum + * because it contains the confounder in it. So, figure out + * what our key variant is and then do it! + */ + + /* Set up the variant of the key (see RFC 1510 section 6.4.3) */ + memset((char *) tmpkey, 0, sizeof(mit_des_cblock)); + for (i=0; (icontents, + (mit_des_cblock *)&outtmp[0], + RSA_MD4_DES_CKSUM_LENGTH + + RSA_MD4_DES_CONFOUND_LENGTH, + (struct mit_des_ks_struct *) + eblock.priv, + keyblock.contents, + MIT_DES_DECRYPT); + if (retval) { + (void) mit_des_finish_key(&eblock); + return retval; + } + if (retval = mit_des_finish_key(&eblock)) + return(retval); + + /* Now that we have the decrypted checksum, try to regenerate it */ + md4_calculate_cksum(&working, + (krb5_pointer) outtmp, + (size_t) RSA_MD4_DES_CONFOUND_LENGTH, + in, + in_length); + + /* Compare the checksums */ + if (memcmp((char *) &outtmp[RSA_MD4_DES_CONFOUND_LENGTH], + (char *) &working.digest[0], + RSA_MD4_DES_CKSUM_LENGTH)) + retval = KRB5KRB_AP_ERR_BAD_INTEGRITY; + } + else + retval = KRB5KRB_AP_ERR_BAD_INTEGRITY; + } + else + retval = KRB5KRB_AP_ERR_INAPP_CKSUM; + + /* Clean up droppings */ + memset((char *)&working, 0, sizeof(working)); + return(retval); +} + +krb5_checksum_entry rsa_md4_des_cksumtable_entry = +#if defined(MD4_K5BETA_COMPAT) && defined(MD4_K5BETA_COMPAT_DEF) +{ 0, - md4_crypto_sum_func, + md4_crypto_compat_sum_func, + md4_crypto_verify_func, RSA_MD4_DES_CKSUM_LENGTH, 1, /* is collision proof */ 1, /* uses key */ }; +#else /* MD4_K5BETA_COMPAT && MD4_K5BETA_COMPAT_DEF */ +{ + 0, + md4_crypto_sum_func, + md4_crypto_verify_func, + RSA_MD4_DES_CKSUM_LENGTH+RSA_MD4_DES_CONFOUND_LENGTH, + 1, /* is collision proof */ + 1, /* uses key */ +}; +#endif /* MD4_K5BETA_COMPAT && MD4_K5BETA_COMPAT_DEF */ + +#ifdef MD4_K5BETA_COMPAT +/* + * Turn on/off compatible checksum generation. + */ +void +md4_crypto_compat_ctl(scompat) + krb5_boolean scompat; +{ + if (scompat) { + rsa_md4_des_cksumtable_entry.sum_func = md4_crypto_compat_sum_func; + rsa_md4_des_cksumtable_entry.checksum_length = + RSA_MD4_DES_CKSUM_LENGTH; + } + else { + rsa_md4_des_cksumtable_entry.sum_func = md4_crypto_sum_func; + rsa_md4_des_cksumtable_entry.checksum_length = + RSA_MD4_DES_CKSUM_LENGTH + RSA_MD4_DES_CONFOUND_LENGTH; + } +} +#endif /* MD4_K5BETA_COMPAT */