summaryrefslogtreecommitdiffstats
path: root/src/lib/crypto/md4
diff options
context:
space:
mode:
authorPaul Park <pjpark@mit.edu>1995-07-07 21:01:10 +0000
committerPaul Park <pjpark@mit.edu>1995-07-07 21:01:10 +0000
commita993a6baad58f2e5ba383b76ade7c0fc0bebd6e5 (patch)
tree05bd8e3459bc0129006b63941e0290204f79d1c6 /src/lib/crypto/md4
parent9993244e1697c30543f513c206e1194cda739b0d (diff)
downloadkrb5-a993a6baad58f2e5ba383b76ade7c0fc0bebd6e5.tar.gz
krb5-a993a6baad58f2e5ba383b76ade7c0fc0bebd6e5.tar.xz
krb5-a993a6baad58f2e5ba383b76ade7c0fc0bebd6e5.zip
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
Diffstat (limited to 'src/lib/crypto/md4')
-rw-r--r--src/lib/crypto/md4/md4crypto.c282
1 files changed, 276 insertions, 6 deletions
diff --git a/src/lib/crypto/md4/md4crypto.c b/src/lib/crypto/md4/md4crypto.c
index 40ad9bd804..248f17683a 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; (i<seed_length) && (i<sizeof(mit_des_cblock)); i++)
+ tmpkey[i] = (((krb5_octet *) seed)[i]) ^ 0xf0;
-krb5_checksum_entry rsa_md4_des_cksumtable_entry = {
+ keyblock.length = sizeof(mit_des_cblock);
+ keyblock.contents = (krb5_octet *) tmpkey;
+ keyblock.keytype = KEYTYPE_DES;
+
+ if ((retval = mit_des_process_key(&eblock, &keyblock)))
+ return retval;
+ /* now encrypt it */
+ retval = mit_des_cbc_encrypt((mit_des_cblock *)&outtmp[0],
+ (mit_des_cblock *)outcksum->contents,
+ 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; (i<seed_length) && (i<sizeof(mit_des_cblock)); i++)
+ tmpkey[i] = (((krb5_octet *) seed)[i]) ^ 0xf0;
+
+ keyblock.length = sizeof(mit_des_cblock);
+ keyblock.contents = (krb5_octet *) tmpkey;
+ keyblock.keytype = KEYTYPE_DES;
+
+ if ((retval = mit_des_process_key(&eblock, &keyblock)))
+ return retval;
+ /* now decrypt it */
+ retval = mit_des_cbc_encrypt((mit_des_cblock *)cksum->contents,
+ (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 */