#include "k5-int.h"
#include <CommonCrypto/CommonCryptor.h>
#include <CommonCrypto/CommonDigest.h>
#include "des_int.h"
#include "keyhash_provider.h"
#define CONFLENGTH 8
#define KRB5_MD4DES_BETA5_COMPAT
static krb5_error_code
k5_md4des_hash(const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *ivec,
const krb5_data *input, krb5_data *output)
{
krb5_error_code ret;
krb5_data data;
CC_MD4_CTX ctx;
unsigned char conf[CONFLENGTH];
unsigned char xorkey[8];
unsigned int i;
if (key->length != 8)
return(KRB5_BAD_KEYSIZE);
if (ivec)
return(KRB5_CRYPTO_INTERNAL);
if (output->length != (CONFLENGTH+CC_MD4_DIGEST_LENGTH))
return(KRB5_CRYPTO_INTERNAL);
data.length = CONFLENGTH;
data.data = (char *) conf;
if ((ret = krb5_c_random_make_octets( 0, &data)))
return(ret);
memcpy(xorkey, key->contents, sizeof(xorkey));
for (i=0; i<sizeof(xorkey); i++)
xorkey[i] ^= 0xf0;
CC_MD4_Init(&ctx);
CC_MD4_Update(&ctx, conf, CONFLENGTH);
CC_MD4_Update(&ctx, (unsigned char *) input->data,
(unsigned int) input->length);
CC_MD4_Final(output->data+CONFLENGTH, &ctx);
memcpy(output->data, conf, CONFLENGTH);
{
CCCryptorStatus cret;
size_t movedData;
cret = CCCrypt(kCCEncrypt,
kCCAlgorithmDES,
0,
xorkey,
sizeof(xorkey),
mit_des_zeroblock,
output->data,
output->length,
output->data,
output->length,
&movedData);
if (cret)
return(KRB5_CRYPTO_INTERNAL);
}
return(0);
}
static krb5_error_code
k5_md4des_verify(const krb5_keyblock *key, krb5_keyusage usage,
const krb5_data *ivec,
const krb5_data *input, const krb5_data *hash,
krb5_boolean *valid)
{
CC_MD4_CTX ctx;
unsigned char plaintext[CONFLENGTH+CC_MD4_DIGEST_LENGTH];
unsigned char xorkey[8];
unsigned char digest[CC_MD4_DIGEST_LENGTH];
unsigned int i;
int compathash = 0;
if (key->length != 8)
return(KRB5_BAD_KEYSIZE);
if (ivec)
return(KRB5_CRYPTO_INTERNAL);
if (hash->length != (CONFLENGTH+CC_MD4_DIGEST_LENGTH)) {
#ifdef KRB5_MD4DES_BETA5_COMPAT
if (hash->length != CC_MD4_DIGEST_LENGTH)
return(KRB5_CRYPTO_INTERNAL);
else
compathash = 1;
#else
return(KRB5_CRYPTO_INTERNAL);
#endif
return(KRB5_CRYPTO_INTERNAL);
}
memcpy(xorkey, key->contents, sizeof(xorkey));
if (!compathash) {
for (i=0; i<sizeof(xorkey); i++)
xorkey[i] ^= 0xf0;
}
{
CCCryptorStatus ret;
size_t movedData;
ret = CCCrypt(kCCEncrypt,
kCCAlgorithmDES,
0,
xorkey,
sizeof(xorkey),
compathash ? xorkey : mit_des_zeroblock,
hash->data,
hash->length,
plaintext,
sizeof(plaintext),
&movedData);
if (ret)
return(KRB5_CRYPTO_INTERNAL);
}
CC_MD4_Init(&ctx);
if (!compathash) {
CC_MD4_Update(&ctx, plaintext, CONFLENGTH);
}
CC_MD4_Update(&ctx, (unsigned char *) input->data,
(unsigned int) input->length);
CC_MD4_Final(digest, &ctx);
if (!compathash) {
*valid =
(memcmp(plaintext+CONFLENGTH, digest, CC_MD4_DIGEST_LENGTH)
== 0);
} else {
*valid =
(memcmp(plaintext, digest, CC_MD4_DIGEST_LENGTH) == 0);
}
memset(plaintext, 0, sizeof(plaintext));
return(0);
}
const struct krb5_keyhash_provider krb5int_keyhash_md4des = {
CONFLENGTH+CC_MD4_DIGEST_LENGTH,
k5_md4des_hash,
k5_md4des_verify
};