2 * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3 * Authors: Doug Rabson <dfr@rabson.org>
4 * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
32 #include <sys/malloc.h>
36 #include <kgssapi/gssapi.h>
37 #include <kgssapi/gssapi_impl.h>
41 static struct krb5_encryption_class *krb5_encryption_classes[] = {
42 &krb5_des_encryption_class,
43 &krb5_des3_encryption_class,
44 &krb5_aes128_encryption_class,
45 &krb5_aes256_encryption_class,
46 &krb5_arcfour_encryption_class,
47 &krb5_arcfour_56_encryption_class,
51 struct krb5_encryption_class *
52 krb5_find_encryption_class(int etype)
56 for (i = 0; krb5_encryption_classes[i]; i++) {
57 if (krb5_encryption_classes[i]->ec_type == etype)
58 return (krb5_encryption_classes[i]);
63 struct krb5_key_state *
64 krb5_create_key(const struct krb5_encryption_class *ec)
66 struct krb5_key_state *ks;
68 ks = malloc(sizeof(struct krb5_key_state), M_GSSAPI, M_WAITOK);
70 refcount_init(&ks->ks_refs, 1);
71 ks->ks_key = malloc(ec->ec_keylen, M_GSSAPI, M_WAITOK);
78 krb5_free_key(struct krb5_key_state *ks)
81 if (refcount_release(&ks->ks_refs)) {
82 ks->ks_class->ec_destroy(ks);
83 bzero(ks->ks_key, ks->ks_class->ec_keylen);
84 free(ks->ks_key, M_GSSAPI);
90 gcd(size_t a, size_t b)
99 lcm(size_t a, size_t b)
101 return ((a * b) / gcd(a, b));
105 * Rotate right 13 of a variable precision number in 'in', storing the
106 * result in 'out'. The number is assumed to be big-endian in memory
110 krb5_rotate_right_13(uint8_t *out, uint8_t *in, size_t numlen)
116 * Special case when numlen == 1. A rotate right 13 of a
117 * single byte number changes to a rotate right 5.
121 out[0] = (in[0] << 3) | carry;
125 carry = ((in[numlen - 2] & 31) << 8) | in[numlen - 1];
126 for (i = 2; i < numlen; i++) {
127 out[i] = ((in[i - 2] & 31) << 3) | (in[i - 1] >> 5);
129 out[1] = ((carry & 31) << 3) | (in[0] >> 5);
134 * Add two variable precision numbers in big-endian representation
135 * using ones-complement arithmetic.
138 krb5_ones_complement_add(uint8_t *out, const uint8_t *in, size_t len)
143 * First calculate the 2s complement sum, remembering the
147 for (i = len - 1; i >= 0; i--) {
148 n = out[i] + in[i] + n;
153 * Then add back the carry.
155 for (i = len - 1; n && i >= 0; i--) {
163 krb5_n_fold(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen)
170 tmplen = lcm(inlen, outlen);
171 tmp = malloc(tmplen, M_GSSAPI, M_WAITOK);
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);
178 for (i = 0, p = tmp; i < tmplen; i += outlen, p += outlen) {
179 krb5_ones_complement_add(out, p, outlen);
184 struct krb5_key_state *
185 krb5_derive_key(struct krb5_key_state *inkey,
186 void *constant, size_t constantlen)
188 struct krb5_key_state *dk;
189 const struct krb5_encryption_class *ec = inkey->ks_class;
191 uint8_t *bytes, *p, *q;
196 * Expand the constant to blocklen bytes.
198 folded = malloc(ec->ec_blocklen, M_GSSAPI, M_WAITOK);
199 krb5_n_fold(folded, ec->ec_blocklen, constant, constantlen);
202 * Generate enough bytes for keybits rounded up to a multiple
205 randomlen = ((ec->ec_keybits/8 + ec->ec_blocklen - 1) / 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);
218 dk = krb5_create_key(ec);
219 krb5_random_to_key(dk, bytes);
221 free(folded, M_GSSAPI);
222 free(bytes, M_GSSAPI);
227 static struct krb5_key_state *
228 krb5_get_usage_key(struct krb5_key_state *basekey, int usage, int which)
230 const struct krb5_encryption_class *ec = basekey->ks_class;
232 if (ec->ec_flags & EC_DERIVED_KEYS) {
235 constant[0] = usage >> 24;
236 constant[1] = usage >> 16;
237 constant[2] = usage >> 8;
240 return (krb5_derive_key(basekey, constant, 5));
242 refcount_acquire(&basekey->ks_refs);
247 struct krb5_key_state *
248 krb5_get_encryption_key(struct krb5_key_state *basekey, int usage)
251 return (krb5_get_usage_key(basekey, usage, 0xaa));
254 struct krb5_key_state *
255 krb5_get_integrity_key(struct krb5_key_state *basekey, int usage)
258 return (krb5_get_usage_key(basekey, usage, 0x55));
261 struct krb5_key_state *
262 krb5_get_checksum_key(struct krb5_key_state *basekey, int usage)
265 return (krb5_get_usage_key(basekey, usage, 0x99));