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