1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/crypto/krb/cf2.c */
3 /*
4 * Copyright (C) 2009, 2015 by the Massachusetts Institute of Technology. All
5 * rights reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 /*
28 * Implement KRB_FX_CF2 function per draft-ietf-krb-wg-preauth-framework-09.
29 * Take two keys and two pepper strings as input and return a combined key.
30 */
31
32 #include "crypto_int.h"
33
34 #ifndef MIN
35 #define MIN(a,b) ((a) < (b) ? (a) : (b))
36 #endif
37
38 krb5_error_code KRB5_CALLCONV
krb5_c_prfplus(krb5_context context,const krb5_keyblock * k,const krb5_data * input,krb5_data * output)39 krb5_c_prfplus(krb5_context context, const krb5_keyblock *k,
40 const krb5_data *input, krb5_data *output)
41 {
42 krb5_error_code ret;
43 krb5_data prf_in = empty_data(), prf_out = empty_data();
44 size_t prflen, nblocks, i;
45
46 /* Calculate the number of PRF invocations we will need. */
47 ret = krb5_c_prf_length(context, k->enctype, &prflen);
48 if (ret)
49 return ret;
50 nblocks = (output->length + prflen - 1)/ prflen;
51 if (nblocks > 255)
52 return E2BIG;
53
54 /* Allocate PRF input and output buffers. */
55 ret = alloc_data(&prf_in, input->length + 1);
56 if (ret)
57 goto cleanup;
58 ret = alloc_data(&prf_out, prflen);
59 if (ret)
60 goto cleanup;
61
62 /* Concatenate PRF(k, 1||input) || PRF(k, 2||input) || ... to produce the
63 * desired number of bytes. */
64 memcpy(&prf_in.data[1], input->data, input->length);
65 for (i = 0; i < nblocks; i++) {
66 prf_in.data[0] = i + 1;
67 ret = krb5_c_prf(context, k, &prf_in, &prf_out);
68 if (ret)
69 goto cleanup;
70
71 memcpy(&output->data[i * prflen], prf_out.data,
72 MIN(prflen, output->length - i * prflen));
73 }
74
75 cleanup:
76 zapfree(prf_out.data, prf_out.length);
77 zapfree(prf_in.data, prf_in.length);
78 return ret;
79 }
80
81 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)82 krb5_c_derive_prfplus(krb5_context context, const krb5_keyblock *k,
83 const krb5_data *input, krb5_enctype enctype,
84 krb5_keyblock **out)
85 {
86 krb5_error_code ret;
87 const struct krb5_keytypes *ktp;
88 krb5_data rnd = empty_data();
89 krb5_keyblock *kb = NULL;
90
91 *out = NULL;
92
93 ktp = find_enctype((enctype == ENCTYPE_NULL) ? k->enctype : enctype);
94 if (ktp == NULL)
95 return KRB5_BAD_ENCTYPE;
96
97 /* Generate enough pseudo-random bytes for the random-to-key function. */
98 ret = alloc_data(&rnd, ktp->enc->keybytes);
99 if (ret)
100 goto cleanup;
101 ret = krb5_c_prfplus(context, k, input, &rnd);
102 if (ret)
103 goto cleanup;
104
105 /* Generate a key from the pseudo-random bytes. */
106 ret = krb5int_c_init_keyblock(context, ktp->etype, ktp->enc->keylength,
107 &kb);
108 if (ret)
109 goto cleanup;
110 ret = (*ktp->rand2key)(&rnd, kb);
111 if (ret)
112 goto cleanup;
113
114 *out = kb;
115 kb = NULL;
116
117 cleanup:
118 zapfree(rnd.data, rnd.length);
119 krb5int_c_free_keyblock(context, kb);
120 return ret;
121 }
122
123 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)124 krb5_c_fx_cf2_simple(krb5_context context,
125 const krb5_keyblock *k1, const char *pepper1,
126 const krb5_keyblock *k2, const char *pepper2,
127 krb5_keyblock **out)
128 {
129 krb5_error_code ret;
130 const struct krb5_keytypes *ktp = NULL;
131 const krb5_data pepper1_data = string2data((char *)pepper1);
132 const krb5_data pepper2_data = string2data((char *)pepper2);
133 krb5_data prf1 = empty_data(), prf2 = empty_data();
134 unsigned int i;
135 krb5_keyblock *kb = NULL;
136
137 *out = NULL;
138
139 ktp = find_enctype(k1->enctype);
140 if (ktp == NULL)
141 return KRB5_BAD_ENCTYPE;
142
143 /* Generate PRF+(k1, pepper1) and PRF+(k2, kepper2). */
144 ret = alloc_data(&prf1, ktp->enc->keybytes);
145 if (ret)
146 goto cleanup;
147 ret = krb5_c_prfplus(context, k1, &pepper1_data, &prf1);
148 if (ret)
149 goto cleanup;
150 ret = alloc_data(&prf2, ktp->enc->keybytes);
151 if (ret)
152 goto cleanup;
153 ret = krb5_c_prfplus(context, k2, &pepper2_data, &prf2);
154 if (ret)
155 goto cleanup;
156
157 /* Compute the XOR of the two PRF+ values and generate a key. */
158 for (i = 0; i < prf1.length; i++)
159 prf1.data[i] ^= prf2.data[i];
160 ret = krb5int_c_init_keyblock(context, ktp->etype, ktp->enc->keylength,
161 &kb);
162 if (ret)
163 goto cleanup;
164 ret = (*ktp->rand2key)(&prf1, kb);
165 if (ret)
166 goto cleanup;
167
168 *out = kb;
169 kb = NULL;
170
171 cleanup:
172 zapfree(prf2.data, prf2.length);
173 zapfree(prf1.data, prf1.length);
174 krb5int_c_free_keyblock(context, kb);
175 return ret;
176 }
177