kcrypto.c revision 267654
11057Salm/*-
21057Salm * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
31057Salm * Authors: Doug Rabson <dfr@rabson.org>
41057Salm * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
51057Salm *
61057Salm * Redistribution and use in source and binary forms, with or without
71057Salm * modification, are permitted provided that the following conditions
81057Salm * are met:
91057Salm * 1. Redistributions of source code must retain the above copyright
101057Salm *    notice, this list of conditions and the following disclaimer.
111057Salm * 2. Redistributions in binary form must reproduce the above copyright
121057Salm *    notice, this list of conditions and the following disclaimer in the
131057Salm *    documentation and/or other materials provided with the distribution.
141057Salm *
151057Salm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
161057Salm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
171057Salm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
181057Salm * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
191057Salm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
201057Salm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
211057Salm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
221057Salm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
231057Salm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
241057Salm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
251057Salm * SUCH DAMAGE.
261057Salm */
271057Salm
281057Salm#include <sys/cdefs.h>
2927963Ssteve__FBSDID("$FreeBSD: releng/9.3/sys/kgssapi/krb5/kcrypto.c 184588 2008-11-03 10:38:00Z dfr $");
3020420Ssteve
3127963Ssteve#include <sys/param.h>
3227963Ssteve#include <sys/malloc.h>
3346684Skris#include <sys/kobj.h>
3427963Ssteve#include <sys/mbuf.h>
351057Salm
361057Salm#include <kgssapi/gssapi.h>
371057Salm#include <kgssapi/gssapi_impl.h>
381057Salm
391057Salm#include "kcrypto.h"
401057Salm
411057Salmstatic struct krb5_encryption_class *krb5_encryption_classes[] = {
421057Salm	&krb5_des_encryption_class,
431057Salm	&krb5_des3_encryption_class,
441057Salm	&krb5_aes128_encryption_class,
4546684Skris	&krb5_aes256_encryption_class,
461057Salm	&krb5_arcfour_encryption_class,
471057Salm	&krb5_arcfour_56_encryption_class,
481057Salm	NULL
491057Salm};
501057Salm
511057Salmstruct krb5_encryption_class *
521057Salmkrb5_find_encryption_class(int etype)
531057Salm{
541057Salm	int i;
551057Salm
561057Salm	for (i = 0; krb5_encryption_classes[i]; i++) {
571057Salm		if (krb5_encryption_classes[i]->ec_type == etype)
581057Salm			return (krb5_encryption_classes[i]);
591057Salm	}
601057Salm	return (NULL);
611057Salm}
621057Salm
631057Salmstruct krb5_key_state *
641057Salmkrb5_create_key(const struct krb5_encryption_class *ec)
651057Salm{
661057Salm	struct krb5_key_state *ks;
671057Salm
681057Salm	ks = malloc(sizeof(struct krb5_key_state), M_GSSAPI, M_WAITOK);
691057Salm	ks->ks_class = ec;
701057Salm	refcount_init(&ks->ks_refs, 1);
711057Salm	ks->ks_key = malloc(ec->ec_keylen, M_GSSAPI, M_WAITOK);
721057Salm	ec->ec_init(ks);
731057Salm
741057Salm	return (ks);
751057Salm}
761057Salm
771057Salmvoid
781057Salmkrb5_free_key(struct krb5_key_state *ks)
791057Salm{
801057Salm
811057Salm	if (refcount_release(&ks->ks_refs)) {
821057Salm		ks->ks_class->ec_destroy(ks);
831057Salm		bzero(ks->ks_key, ks->ks_class->ec_keylen);
841057Salm		free(ks->ks_key, M_GSSAPI);
851057Salm		free(ks, M_GSSAPI);
861057Salm	}
871057Salm}
881057Salm
891057Salmstatic size_t
901057Salmgcd(size_t a, size_t b)
911057Salm{
921057Salm
931057Salm	if (b == 0)
941057Salm		return (a);
951057Salm	return gcd(b, a % b);
961057Salm}
971057Salm
981057Salmstatic size_t
991057Salmlcm(size_t a, size_t b)
1001057Salm{
1011057Salm	return ((a * b) / gcd(a, b));
1021057Salm}
1031057Salm
1041057Salm/*
1051057Salm * Rotate right 13 of a variable precision number in 'in', storing the
1061057Salm * result in 'out'. The number is assumed to be big-endian in memory
1071057Salm * representation.
1081057Salm */
1091057Salmstatic void
1101057Salmkrb5_rotate_right_13(uint8_t *out, uint8_t *in, size_t numlen)
1111057Salm{
1121057Salm	uint32_t carry;
1131057Salm	size_t i;
1141057Salm
1151057Salm	/*
1161057Salm	 * Special case when numlen == 1. A rotate right 13 of a
1171057Salm	 * single byte number changes to a rotate right 5.
1181057Salm	 */
1191057Salm	if (numlen == 1) {
1201057Salm		carry = in[0] >> 5;
1211057Salm		out[0] = (in[0] << 3) | carry;
1221057Salm		return;
1231057Salm	}
1241057Salm
1251057Salm	carry = ((in[numlen - 2] & 31) << 8) | in[numlen - 1];
1261057Salm	for (i = 2; i < numlen; i++) {
1271057Salm		out[i] = ((in[i - 2] & 31) << 3) | (in[i - 1] >> 5);
1281057Salm	}
1291057Salm	out[1] = ((carry & 31) << 3) | (in[0] >> 5);
1301057Salm	out[0] = carry >> 5;
1311057Salm}
1321057Salm
1331057Salm/*
1341057Salm * Add two variable precision numbers in big-endian representation
1351057Salm * using ones-complement arithmetic.
1361057Salm */
1371057Salmstatic void
1381057Salmkrb5_ones_complement_add(uint8_t *out, const uint8_t *in, size_t len)
1391057Salm{
1401057Salm	int n, i;
1411057Salm
1421057Salm	/*
1431057Salm	 * First calculate the 2s complement sum, remembering the
1441057Salm	 * carry.
1451057Salm	 */
1461057Salm	n = 0;
1471057Salm	for (i = len - 1; i >= 0; i--) {
1481057Salm		n = out[i] + in[i] + n;
1491057Salm		out[i] = n;
1501057Salm		n >>= 8;
1511057Salm	}
1521057Salm	/*
1531057Salm	 * Then add back the carry.
1541057Salm	 */
1551057Salm	for (i = len - 1; n && i >= 0; i--) {
1561057Salm		n = out[i] + n;
1571057Salm		out[i] = n;
1581057Salm		n >>= 8;
1591057Salm	}
160}
161
162static void
163krb5_n_fold(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen)
164{
165	size_t tmplen;
166	uint8_t *tmp;
167	size_t i;
168	uint8_t *p;
169
170	tmplen = lcm(inlen, outlen);
171	tmp = malloc(tmplen, M_GSSAPI, M_WAITOK);
172
173	bcopy(in, tmp, inlen);
174	for (i = inlen, p = tmp; i < tmplen; i += inlen, p += inlen) {
175		krb5_rotate_right_13(p + inlen, p, inlen);
176	}
177	bzero(out, outlen);
178	for (i = 0, p = tmp; i < tmplen; i += outlen, p += outlen) {
179		krb5_ones_complement_add(out, p, outlen);
180	}
181	free(tmp, M_GSSAPI);
182}
183
184struct krb5_key_state *
185krb5_derive_key(struct krb5_key_state *inkey,
186    void *constant, size_t constantlen)
187{
188	struct krb5_key_state *dk;
189	const struct krb5_encryption_class *ec = inkey->ks_class;
190	uint8_t *folded;
191	uint8_t *bytes, *p, *q;
192	struct mbuf *m;
193	int randomlen, i;
194
195	/*
196	 * Expand the constant to blocklen bytes.
197	 */
198	folded = malloc(ec->ec_blocklen, M_GSSAPI, M_WAITOK);
199	krb5_n_fold(folded, ec->ec_blocklen, constant, constantlen);
200
201	/*
202	 * Generate enough bytes for keybits rounded up to a multiple
203	 * of blocklen.
204	 */
205	randomlen = ((ec->ec_keybits/8 + ec->ec_blocklen - 1) / ec->ec_blocklen)
206		* ec->ec_blocklen;
207	bytes = malloc(randomlen, M_GSSAPI, M_WAITOK);
208	MGET(m, M_WAITOK, MT_DATA);
209	m->m_len = ec->ec_blocklen;
210	for (i = 0, p = bytes, q = folded; i < randomlen;
211	     q = p, i += ec->ec_blocklen, p += ec->ec_blocklen) {
212		bcopy(q, m->m_data, ec->ec_blocklen);
213		krb5_encrypt(inkey, m, 0, ec->ec_blocklen, NULL, 0);
214		bcopy(m->m_data, p, ec->ec_blocklen);
215	}
216	m_free(m);
217
218	dk = krb5_create_key(ec);
219	krb5_random_to_key(dk, bytes);
220
221	free(folded, M_GSSAPI);
222	free(bytes, M_GSSAPI);
223
224	return (dk);
225}
226
227static struct krb5_key_state *
228krb5_get_usage_key(struct krb5_key_state *basekey, int usage, int which)
229{
230	const struct krb5_encryption_class *ec = basekey->ks_class;
231
232	if (ec->ec_flags & EC_DERIVED_KEYS) {
233		uint8_t constant[5];
234
235		constant[0] = usage >> 24;
236		constant[1] = usage >> 16;
237		constant[2] = usage >> 8;
238		constant[3] = usage;
239		constant[4] = which;
240		return (krb5_derive_key(basekey, constant, 5));
241	} else {
242		refcount_acquire(&basekey->ks_refs);
243		return (basekey);
244	}
245}
246
247struct krb5_key_state *
248krb5_get_encryption_key(struct krb5_key_state *basekey, int usage)
249{
250
251	return (krb5_get_usage_key(basekey, usage, 0xaa));
252}
253
254struct krb5_key_state *
255krb5_get_integrity_key(struct krb5_key_state *basekey, int usage)
256{
257
258	return (krb5_get_usage_key(basekey, usage, 0x55));
259}
260
261struct krb5_key_state *
262krb5_get_checksum_key(struct krb5_key_state *basekey, int usage)
263{
264
265	return (krb5_get_usage_key(basekey, usage, 0x99));
266}
267