xref: /freebsd/crypto/krb5/src/lib/crypto/krb/cf2.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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