2N/A/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2N/A/*
2N/A * lib/crypto/cf2.c
2N/A *
2N/A * Copyright (C) 2009 by the Massachusetts Institute of Technology.
2N/A * All rights reserved.
2N/A *
2N/A * Export of this software from the United States of America may
2N/A * require a specific license from the United States Government.
2N/A * It is the responsibility of any person or organization contemplating
2N/A * export to obtain such a license before exporting.
2N/A *
2N/A * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
2N/A * distribute this software and its documentation for any purpose and
2N/A * without fee is hereby granted, provided that the above copyright
2N/A * notice appear in all copies and that both that copyright notice and
2N/A * this permission notice appear in supporting documentation, and that
2N/A * the name of M.I.T. not be used in advertising or publicity pertaining
2N/A * to distribution of the software without specific, written prior
2N/A * permission. Furthermore if you modify this software you must label
2N/A * your software as modified software and not distribute it in such a
2N/A * fashion that it might be confused with the original M.I.T. software.
2N/A * M.I.T. makes no representations about the suitability of
2N/A * this software for any purpose. It is provided "as is" without express
2N/A * or implied warranty.
2N/A *
2N/A *
2N/A *
2N/A * Implement KRB_FX_CF2 function per
2N/A *draft-ietf-krb-wg-preauth-framework-09. Take two keys and two
2N/A *pepper strings as input and return a combined key.
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <k5-int.h>
2N/A#include <assert.h>
2N/A#include "etypes.h"
2N/A
2N/A
2N/A/*
2N/A * Call the PRF function multiple times with the pepper prefixed with
2N/A * a count byte to get enough bits of output.
2N/A */
2N/Astatic krb5_error_code
2N/Aprf_plus(krb5_context context, krb5_keyblock *k, const char *pepper,
2N/A size_t keybytes, char **out)
2N/A{
2N/A krb5_error_code retval = 0;
2N/A size_t prflen, iterations;
2N/A krb5_data out_data;
2N/A krb5_data in_data;
2N/A char *buffer = NULL;
2N/A struct k5buf prf_inbuf;
2N/A
2N/A krb5int_buf_init_dynamic(&prf_inbuf);
2N/A krb5int_buf_add_len(&prf_inbuf, "\001", 1);
2N/A krb5int_buf_add(&prf_inbuf, pepper);
2N/A retval = krb5_c_prf_length( context, k->enctype, &prflen);
2N/A if (retval)
2N/A goto cleanup;
2N/A iterations = keybytes / prflen;
2N/A if (keybytes % prflen != 0)
2N/A iterations++;
2N/A assert(iterations <= 254);
2N/A buffer = k5alloc(iterations * prflen, &retval);
2N/A if (retval)
2N/A goto cleanup;
2N/A if (krb5int_buf_len(&prf_inbuf) == -1) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A in_data.length = (krb5_int32) krb5int_buf_len(&prf_inbuf);
2N/A in_data.data = krb5int_buf_data(&prf_inbuf);
2N/A out_data.length = prflen;
2N/A out_data.data = buffer;
2N/A
2N/A while (iterations > 0) {
2N/A retval = krb5_c_prf(context, k, &in_data, &out_data);
2N/A if (retval)
2N/A goto cleanup;
2N/A out_data.data += prflen;
2N/A in_data.data[0]++;
2N/A iterations--;
2N/A }
2N/A
2N/A *out = buffer;
2N/A buffer = NULL;
2N/A
2N/Acleanup:
2N/A free(buffer);
2N/A krb5int_free_buf(&prf_inbuf);
2N/A return retval;
2N/A}
2N/A
2N/A
2N/Akrb5_error_code KRB5_CALLCONV
2N/Akrb5_c_fx_cf2_simple(krb5_context context,
2N/A krb5_keyblock *k1, const char *pepper1,
2N/A krb5_keyblock *k2, const char *pepper2,
2N/A krb5_keyblock **out)
2N/A{
2N/A const struct krb5_keytypes *out_enctype;
2N/A size_t keybytes, keylength, i;
2N/A char *prf1 = NULL, *prf2 = NULL;
2N/A krb5_data keydata;
2N/A krb5_enctype out_enctype_num;
2N/A krb5_error_code retval = 0;
2N/A krb5_keyblock *out_key = NULL;
2N/A
2N/A if (k1 == NULL || !krb5_c_valid_enctype(k1->enctype))
2N/A return KRB5_BAD_ENCTYPE;
2N/A if (k2 == NULL || !krb5_c_valid_enctype(k2->enctype))
2N/A return KRB5_BAD_ENCTYPE;
2N/A out_enctype_num = k1->enctype;
2N/A assert(out != NULL);
2N/A
2N/A /* Solaris Kerberos - Move the assignment out of the assert */
2N/A out_enctype = find_enctype(out_enctype_num);
2N/A assert(out_enctype != NULL);
2N/A
2N/A if (out_enctype->prf == NULL) {
2N/A if (context)
2N/A krb5int_set_error(&(context->err), KRB5_CRYPTO_INTERNAL,
2N/A "Enctype %d has no PRF", out_enctype_num);
2N/A return KRB5_CRYPTO_INTERNAL;
2N/A }
2N/A keybytes = out_enctype->enc->keybytes;
2N/A keylength = out_enctype->enc->keylength;
2N/A
2N/A retval = prf_plus(context, k1, pepper1, keybytes, &prf1);
2N/A if (retval)
2N/A goto cleanup;
2N/A retval = prf_plus(context, k2, pepper2, keybytes, &prf2);
2N/A if (retval)
2N/A goto cleanup;
2N/A for (i = 0; i < keybytes; i++)
2N/A prf1[i] ^= prf2[i];
2N/A retval = krb5int_c_init_keyblock(context, out_enctype_num, keylength,
2N/A &out_key);
2N/A if (retval)
2N/A goto cleanup;
2N/A keydata.data = prf1;
2N/A keydata.length = keybytes;
2N/A /* Solaris Kerberos - tmp added 1st arg */
2N/A retval = (*out_enctype->enc->make_key)(context, &keydata, out_key);
2N/A if (retval)
2N/A goto cleanup;
2N/A
2N/A *out = out_key;
2N/A out_key = NULL;
2N/A
2N/Acleanup:
2N/A krb5int_c_free_keyblock( context, out_key);
2N/A zapfree(prf1, keybytes);
2N/A zapfree(prf2, keybytes);
2N/A return retval;
2N/A}