]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kgssapi/krb5/kcrypto.c
MFV r336851:
[FreeBSD/FreeBSD.git] / sys / kgssapi / krb5 / kcrypto.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
5  * Authors: Doug Rabson <dfr@rabson.org>
6  * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/malloc.h>
35 #include <sys/kobj.h>
36 #include <sys/mbuf.h>
37
38 #include <kgssapi/gssapi.h>
39 #include <kgssapi/gssapi_impl.h>
40
41 #include "kcrypto.h"
42
43 static struct krb5_encryption_class *krb5_encryption_classes[] = {
44         &krb5_des_encryption_class,
45         &krb5_des3_encryption_class,
46         &krb5_aes128_encryption_class,
47         &krb5_aes256_encryption_class,
48         &krb5_arcfour_encryption_class,
49         &krb5_arcfour_56_encryption_class,
50         NULL
51 };
52
53 struct krb5_encryption_class *
54 krb5_find_encryption_class(int etype)
55 {
56         int i;
57
58         for (i = 0; krb5_encryption_classes[i]; i++) {
59                 if (krb5_encryption_classes[i]->ec_type == etype)
60                         return (krb5_encryption_classes[i]);
61         }
62         return (NULL);
63 }
64
65 struct krb5_key_state *
66 krb5_create_key(const struct krb5_encryption_class *ec)
67 {
68         struct krb5_key_state *ks;
69
70         ks = malloc(sizeof(struct krb5_key_state), M_GSSAPI, M_WAITOK);
71         ks->ks_class = ec;
72         refcount_init(&ks->ks_refs, 1);
73         ks->ks_key = malloc(ec->ec_keylen, M_GSSAPI, M_WAITOK);
74         ec->ec_init(ks);
75
76         return (ks);
77 }
78
79 void
80 krb5_free_key(struct krb5_key_state *ks)
81 {
82
83         if (refcount_release(&ks->ks_refs)) {
84                 ks->ks_class->ec_destroy(ks);
85                 bzero(ks->ks_key, ks->ks_class->ec_keylen);
86                 free(ks->ks_key, M_GSSAPI);
87                 free(ks, M_GSSAPI);
88         }
89 }
90
91 static size_t
92 gcd(size_t a, size_t b)
93 {
94
95         if (b == 0)
96                 return (a);
97         return gcd(b, a % b);
98 }
99
100 static size_t
101 lcm(size_t a, size_t b)
102 {
103         return ((a * b) / gcd(a, b));
104 }
105
106 /*
107  * Rotate right 13 of a variable precision number in 'in', storing the
108  * result in 'out'. The number is assumed to be big-endian in memory
109  * representation.
110  */
111 static void
112 krb5_rotate_right_13(uint8_t *out, uint8_t *in, size_t numlen)
113 {
114         uint32_t carry;
115         size_t i;
116
117         /*
118          * Special case when numlen == 1. A rotate right 13 of a
119          * single byte number changes to a rotate right 5.
120          */
121         if (numlen == 1) {
122                 carry = in[0] >> 5;
123                 out[0] = (in[0] << 3) | carry;
124                 return;
125         }
126
127         carry = ((in[numlen - 2] & 31) << 8) | in[numlen - 1];
128         for (i = 2; i < numlen; i++) {
129                 out[i] = ((in[i - 2] & 31) << 3) | (in[i - 1] >> 5);
130         }
131         out[1] = ((carry & 31) << 3) | (in[0] >> 5);
132         out[0] = carry >> 5;
133 }
134
135 /*
136  * Add two variable precision numbers in big-endian representation
137  * using ones-complement arithmetic.
138  */
139 static void
140 krb5_ones_complement_add(uint8_t *out, const uint8_t *in, size_t len)
141 {
142         int n, i;
143
144         /*
145          * First calculate the 2s complement sum, remembering the
146          * carry.
147          */
148         n = 0;
149         for (i = len - 1; i >= 0; i--) {
150                 n = out[i] + in[i] + n;
151                 out[i] = n;
152                 n >>= 8;
153         }
154         /*
155          * Then add back the carry.
156          */
157         for (i = len - 1; n && i >= 0; i--) {
158                 n = out[i] + n;
159                 out[i] = n;
160                 n >>= 8;
161         }
162 }
163
164 static void
165 krb5_n_fold(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen)
166 {
167         size_t tmplen;
168         uint8_t *tmp;
169         size_t i;
170         uint8_t *p;
171
172         tmplen = lcm(inlen, outlen);
173         tmp = malloc(tmplen, M_GSSAPI, M_WAITOK);
174
175         bcopy(in, tmp, inlen);
176         for (i = inlen, p = tmp; i < tmplen; i += inlen, p += inlen) {
177                 krb5_rotate_right_13(p + inlen, p, inlen);
178         }
179         bzero(out, outlen);
180         for (i = 0, p = tmp; i < tmplen; i += outlen, p += outlen) {
181                 krb5_ones_complement_add(out, p, outlen);
182         }
183         free(tmp, M_GSSAPI);
184 }
185
186 struct krb5_key_state *
187 krb5_derive_key(struct krb5_key_state *inkey,
188     void *constant, size_t constantlen)
189 {
190         struct krb5_key_state *dk;
191         const struct krb5_encryption_class *ec = inkey->ks_class;
192         uint8_t *folded;
193         uint8_t *bytes, *p, *q;
194         struct mbuf *m;
195         int randomlen, i;
196
197         /*
198          * Expand the constant to blocklen bytes.
199          */
200         folded = malloc(ec->ec_blocklen, M_GSSAPI, M_WAITOK);
201         krb5_n_fold(folded, ec->ec_blocklen, constant, constantlen);
202
203         /*
204          * Generate enough bytes for keybits rounded up to a multiple
205          * of blocklen.
206          */
207         randomlen = roundup(ec->ec_keybits / 8, ec->ec_blocklen);
208         bytes = malloc(randomlen, M_GSSAPI, M_WAITOK);
209         MGET(m, M_WAITOK, MT_DATA);
210         m->m_len = ec->ec_blocklen;
211         for (i = 0, p = bytes, q = folded; i < randomlen;
212              q = p, i += ec->ec_blocklen, p += ec->ec_blocklen) {
213                 bcopy(q, m->m_data, ec->ec_blocklen);
214                 krb5_encrypt(inkey, m, 0, ec->ec_blocklen, NULL, 0);
215                 bcopy(m->m_data, p, ec->ec_blocklen);
216         }
217         m_free(m);
218
219         dk = krb5_create_key(ec);
220         krb5_random_to_key(dk, bytes);
221
222         free(folded, M_GSSAPI);
223         free(bytes, M_GSSAPI);
224
225         return (dk);
226 }
227
228 static struct krb5_key_state *
229 krb5_get_usage_key(struct krb5_key_state *basekey, int usage, int which)
230 {
231         const struct krb5_encryption_class *ec = basekey->ks_class;
232
233         if (ec->ec_flags & EC_DERIVED_KEYS) {
234                 uint8_t constant[5];
235
236                 constant[0] = usage >> 24;
237                 constant[1] = usage >> 16;
238                 constant[2] = usage >> 8;
239                 constant[3] = usage;
240                 constant[4] = which;
241                 return (krb5_derive_key(basekey, constant, 5));
242         } else {
243                 refcount_acquire(&basekey->ks_refs);
244                 return (basekey);
245         }
246 }
247
248 struct krb5_key_state *
249 krb5_get_encryption_key(struct krb5_key_state *basekey, int usage)
250 {
251
252         return (krb5_get_usage_key(basekey, usage, 0xaa));
253 }
254
255 struct krb5_key_state *
256 krb5_get_integrity_key(struct krb5_key_state *basekey, int usage)
257 {
258
259         return (krb5_get_usage_key(basekey, usage, 0x55));
260 }
261
262 struct krb5_key_state *
263 krb5_get_checksum_key(struct krb5_key_state *basekey, int usage)
264 {
265
266         return (krb5_get_usage_key(basekey, usage, 0x99));
267 }