xref: /freebsd/sys/kgssapi/krb5/kcrypto.c (revision b00ab754)
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 }
268