#include "crypto_int.h"
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
krb5_error_code KRB5_CALLCONV
krb5_c_prfplus(krb5_context context, const krb5_keyblock *k,
const krb5_data *input, krb5_data *output)
{
krb5_error_code ret;
krb5_data prf_in = empty_data(), prf_out = empty_data();
size_t prflen, nblocks, i;
ret = krb5_c_prf_length(context, k->enctype, &prflen);
if (ret)
return ret;
nblocks = (output->length + prflen - 1)/ prflen;
if (nblocks > 255)
return E2BIG;
ret = alloc_data(&prf_in, input->length + 1);
if (ret)
goto cleanup;
ret = alloc_data(&prf_out, prflen);
if (ret)
goto cleanup;
memcpy(&prf_in.data[1], input->data, input->length);
for (i = 0; i < nblocks; i++) {
prf_in.data[0] = i + 1;
ret = krb5_c_prf(context, k, &prf_in, &prf_out);
if (ret)
goto cleanup;
memcpy(&output->data[i * prflen], prf_out.data,
MIN(prflen, output->length - i * prflen));
}
cleanup:
zapfree(prf_out.data, prf_out.length);
zapfree(prf_in.data, prf_in.length);
return ret;
}
krb5_error_code KRB5_CALLCONV
krb5_c_derive_prfplus(krb5_context context, const krb5_keyblock *k,
const krb5_data *input, krb5_enctype enctype,
krb5_keyblock **out)
{
krb5_error_code ret;
const struct krb5_keytypes *ktp;
krb5_data rnd = empty_data();
krb5_keyblock *kb = NULL;
*out = NULL;
ktp = find_enctype((enctype == ENCTYPE_NULL) ? k->enctype : enctype);
if (ktp == NULL)
return KRB5_BAD_ENCTYPE;
ret = alloc_data(&rnd, ktp->enc->keybytes);
if (ret)
goto cleanup;
ret = krb5_c_prfplus(context, k, input, &rnd);
if (ret)
goto cleanup;
ret = krb5int_c_init_keyblock(context, ktp->etype, ktp->enc->keylength,
&kb);
if (ret)
goto cleanup;
ret = (*ktp->rand2key)(&rnd, kb);
if (ret)
goto cleanup;
*out = kb;
kb = NULL;
cleanup:
zapfree(rnd.data, rnd.length);
krb5int_c_free_keyblock(context, kb);
return ret;
}
krb5_error_code KRB5_CALLCONV
krb5_c_fx_cf2_simple(krb5_context context,
const krb5_keyblock *k1, const char *pepper1,
const krb5_keyblock *k2, const char *pepper2,
krb5_keyblock **out)
{
krb5_error_code ret;
const struct krb5_keytypes *ktp = NULL;
const krb5_data pepper1_data = string2data((char *)pepper1);
const krb5_data pepper2_data = string2data((char *)pepper2);
krb5_data prf1 = empty_data(), prf2 = empty_data();
unsigned int i;
krb5_keyblock *kb = NULL;
*out = NULL;
ktp = find_enctype(k1->enctype);
if (ktp == NULL)
return KRB5_BAD_ENCTYPE;
ret = alloc_data(&prf1, ktp->enc->keybytes);
if (ret)
goto cleanup;
ret = krb5_c_prfplus(context, k1, &pepper1_data, &prf1);
if (ret)
goto cleanup;
ret = alloc_data(&prf2, ktp->enc->keybytes);
if (ret)
goto cleanup;
ret = krb5_c_prfplus(context, k2, &pepper2_data, &prf2);
if (ret)
goto cleanup;
for (i = 0; i < prf1.length; i++)
prf1.data[i] ^= prf2.data[i];
ret = krb5int_c_init_keyblock(context, ktp->etype, ktp->enc->keylength,
&kb);
if (ret)
goto cleanup;
ret = (*ktp->rand2key)(&prf1, kb);
if (ret)
goto cleanup;
*out = kb;
kb = NULL;
cleanup:
zapfree(prf2.data, prf2.length);
zapfree(prf1.data, prf1.length);
krb5int_c_free_keyblock(context, kb);
return ret;
}