#include "k5-int.h"
#include "arcfour-int.h"
static const char *const l40 = "fortybits";
void
krb5_arcfour_encrypt_length(const struct krb5_enc_provider *enc,
const struct krb5_hash_provider *hash,
size_t inputlen, size_t *length)
{
size_t blocksize, hashsize;
blocksize = enc->block_size;
hashsize = hash->hashsize;
*length = hashsize + krb5_roundup(8 + inputlen, blocksize);
}
krb5_keyusage
krb5int_arcfour_translate_usage(krb5_keyusage usage)
{
switch (usage) {
case 1:
return 1;
case 2:
return 2;
case 3:
return 8;
case 4:
return 4;
case 5:
return 5;
case 6:
return 6;
case 7:
return 7;
case 8:
return 8;
case 9:
return 8;
case 10:
return 10;
case 11:
return 11;
case 12:
return 12;
case 23:
return 13;
default:
return usage;
}
}
krb5_error_code
krb5_arcfour_encrypt(const struct krb5_enc_provider *enc,
const struct krb5_hash_provider *hash,
const krb5_keyblock *key, krb5_keyusage usage,
const krb5_data *ivec, const krb5_data *input,
krb5_data *output)
{
krb5_keyblock k1, k2, k3;
krb5_data d1, d2, d3, salt, plaintext, checksum, ciphertext, confounder;
krb5_keyusage ms_usage;
size_t keylength, keybytes, blocksize, hashsize;
krb5_error_code ret;
blocksize = enc->block_size;
keybytes = enc->keybytes;
keylength = enc->keylength;
hashsize = hash->hashsize;
d1.length=keybytes;
d1.data=malloc(d1.length);
if (d1.data == NULL)
return (ENOMEM);
memcpy(&k1, key, sizeof (krb5_keyblock));
k1.length=d1.length;
k1.contents= (void *) d1.data;
d2.length=keybytes;
d2.data=malloc(d2.length);
if (d2.data == NULL) {
free(d1.data);
return (ENOMEM);
}
memcpy(&k2, key, sizeof (krb5_keyblock));
k2.length=d2.length;
k2.contents=(void *) d2.data;
d3.length=keybytes;
d3.data=malloc(d3.length);
if (d3.data == NULL) {
free(d1.data);
free(d2.data);
return (ENOMEM);
}
memcpy(&k3, key, sizeof (krb5_keyblock));
k3.length=d3.length;
k3.contents= (void *) d3.data;
salt.length=14;
salt.data=malloc(salt.length);
if (salt.data == NULL) {
free(d1.data);
free(d2.data);
free(d3.data);
return (ENOMEM);
}
plaintext.length=krb5_roundup(input->length+CONFOUNDERLENGTH,blocksize);
plaintext.data=malloc(plaintext.length);
if (plaintext.data == NULL) {
free(d1.data);
free(d2.data);
free(d3.data);
free(salt.data);
return(ENOMEM);
}
checksum.length=hashsize;
checksum.data=output->data;
ciphertext.length=krb5_roundup(input->length+CONFOUNDERLENGTH,blocksize);
ciphertext.data=output->data+hashsize;
confounder.length=CONFOUNDERLENGTH;
confounder.data=plaintext.data;
output->length = plaintext.length+hashsize;
ms_usage=krb5int_arcfour_translate_usage(usage);
if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
strncpy(salt.data, l40, salt.length);
salt.data[10]=ms_usage & 0xff;
salt.data[11]=(ms_usage >> 8) & 0xff;
salt.data[12]=(ms_usage >> 16) & 0xff;
salt.data[13]=(ms_usage >> 24) & 0xff;
} else {
salt.length=4;
salt.data[0]=ms_usage & 0xff;
salt.data[1]=(ms_usage >> 8) & 0xff;
salt.data[2]=(ms_usage >> 16) & 0xff;
salt.data[3]=(ms_usage >> 24) & 0xff;
}
krb5_hmac(hash, key, 1, &salt, &d1);
memcpy(k2.contents, k1.contents, k2.length);
if (key->enctype==ENCTYPE_ARCFOUR_HMAC_EXP)
memset(k1.contents+7, 0xab, 9);
ret=krb5_c_random_make_octets( 0, &confounder);
memcpy(plaintext.data+confounder.length, input->data, input->length);
if (ret)
goto cleanup;
krb5_hmac(hash, &k2, 1, &plaintext, &checksum);
krb5_hmac(hash, &k1, 1, &checksum, &d3);
ret=(*(enc->encrypt))(&k3, ivec, &plaintext, &ciphertext);
cleanup:
memset(d1.data, 0, d1.length);
memset(d2.data, 0, d2.length);
memset(d3.data, 0, d3.length);
memset(salt.data, 0, salt.length);
memset(plaintext.data, 0, plaintext.length);
free(d1.data);
free(d2.data);
free(d3.data);
free(salt.data);
free(plaintext.data);
return (ret);
}
krb5_error_code
krb5_arcfour_decrypt(const struct krb5_enc_provider *enc,
const struct krb5_hash_provider *hash,
const krb5_keyblock *key, krb5_keyusage usage,
const krb5_data *ivec, const krb5_data *input,
krb5_data *output)
{
krb5_keyblock k1,k2,k3;
krb5_data d1,d2,d3,salt,ciphertext,plaintext,checksum;
krb5_keyusage ms_usage;
size_t keybytes, keylength, hashsize, blocksize;
krb5_error_code ret;
blocksize = enc->block_size;
keybytes = enc->keybytes;
keylength = enc->keylength;
hashsize = hash->hashsize;
d1.length=keybytes;
d1.data=malloc(d1.length);
if (d1.data == NULL)
return (ENOMEM);
memcpy(&k1, key, sizeof (krb5_keyblock));
k1.length=d1.length;
k1.contents= (void *) d1.data;
d2.length=keybytes;
d2.data=malloc(d2.length);
if (d2.data == NULL) {
free(d1.data);
return (ENOMEM);
}
memcpy(&k2, key, sizeof(krb5_keyblock));
k2.length=d2.length;
k2.contents= (void *) d2.data;
d3.length=keybytes;
d3.data=malloc(d3.length);
if (d3.data == NULL) {
free(d1.data);
free(d2.data);
return (ENOMEM);
}
memcpy(&k3, key, sizeof(krb5_keyblock));
k3.length=d3.length;
k3.contents= (void *) d3.data;
salt.length=14;
salt.data=malloc(salt.length);
if(salt.data==NULL) {
free(d1.data);
free(d2.data);
free(d3.data);
return (ENOMEM);
}
ciphertext.length=input->length-hashsize;
ciphertext.data=input->data+hashsize;
plaintext.length=ciphertext.length;
plaintext.data=malloc(plaintext.length);
if (plaintext.data == NULL) {
free(d1.data);
free(d2.data);
free(d3.data);
free(salt.data);
return (ENOMEM);
}
checksum.length=hashsize;
checksum.data=input->data;
ms_usage=krb5int_arcfour_translate_usage(usage);
if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
strncpy(salt.data, l40, salt.length);
salt.data[10]=ms_usage & 0xff;
salt.data[11]=(ms_usage>>8) & 0xff;
salt.data[12]=(ms_usage>>16) & 0xff;
salt.data[13]=(ms_usage>>24) & 0xff;
} else {
salt.length=4;
salt.data[0]=ms_usage & 0xff;
salt.data[1]=(ms_usage>>8) & 0xff;
salt.data[2]=(ms_usage>>16) & 0xff;
salt.data[3]=(ms_usage>>24) & 0xff;
}
ret=krb5_hmac(hash, key, 1, &salt, &d1);
if (ret)
goto cleanup;
memcpy(k2.contents, k1.contents, k2.length);
if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP)
memset(k1.contents+7, 0xab, 9);
ret = krb5_hmac(hash, &k1, 1, &checksum, &d3);
if (ret)
goto cleanup;
ret=(*(enc->decrypt))(&k3, ivec, &ciphertext, &plaintext);
if (ret)
goto cleanup;
ret=krb5_hmac(hash, &k2, 1, &plaintext, &d1);
if (ret)
goto cleanup;
if (memcmp(checksum.data, d1.data, hashsize) != 0) {
ret=KRB5KRB_AP_ERR_BAD_INTEGRITY;
goto cleanup;
}
memcpy(output->data, plaintext.data+CONFOUNDERLENGTH,
(plaintext.length-CONFOUNDERLENGTH));
output->length=plaintext.length-CONFOUNDERLENGTH;
cleanup:
memset(d1.data, 0, d1.length);
memset(d2.data, 0, d2.length);
memset(d3.data, 0, d2.length);
memset(salt.data, 0, salt.length);
memset(plaintext.data, 0, plaintext.length);
free(d1.data);
free(d2.data);
free(d3.data);
free(salt.data);
free(plaintext.data);
return (ret);
}