1184588Sdfr/*- 2184588Sdfr * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ 3184588Sdfr * Authors: Doug Rabson <dfr@rabson.org> 4184588Sdfr * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> 5184588Sdfr * 6184588Sdfr * Redistribution and use in source and binary forms, with or without 7184588Sdfr * modification, are permitted provided that the following conditions 8184588Sdfr * are met: 9184588Sdfr * 1. Redistributions of source code must retain the above copyright 10184588Sdfr * notice, this list of conditions and the following disclaimer. 11184588Sdfr * 2. Redistributions in binary form must reproduce the above copyright 12184588Sdfr * notice, this list of conditions and the following disclaimer in the 13184588Sdfr * documentation and/or other materials provided with the distribution. 14184588Sdfr * 15184588Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16184588Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17184588Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18184588Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19184588Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20184588Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21184588Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22184588Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23184588Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24184588Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25184588Sdfr * SUCH DAMAGE. 26184588Sdfr */ 27184588Sdfr 28184588Sdfr#include <sys/cdefs.h> 29184588Sdfr__FBSDID("$FreeBSD$"); 30184588Sdfr 31184588Sdfr#include <sys/param.h> 32184588Sdfr#include <sys/malloc.h> 33184588Sdfr#include <sys/kobj.h> 34184588Sdfr#include <sys/mbuf.h> 35184588Sdfr 36184588Sdfr#include <kgssapi/gssapi.h> 37184588Sdfr#include <kgssapi/gssapi_impl.h> 38184588Sdfr 39184588Sdfr#include "kcrypto.h" 40184588Sdfr 41184588Sdfrstatic struct krb5_encryption_class *krb5_encryption_classes[] = { 42184588Sdfr &krb5_des_encryption_class, 43184588Sdfr &krb5_des3_encryption_class, 44184588Sdfr &krb5_aes128_encryption_class, 45184588Sdfr &krb5_aes256_encryption_class, 46184588Sdfr &krb5_arcfour_encryption_class, 47184588Sdfr &krb5_arcfour_56_encryption_class, 48184588Sdfr NULL 49184588Sdfr}; 50184588Sdfr 51184588Sdfrstruct krb5_encryption_class * 52184588Sdfrkrb5_find_encryption_class(int etype) 53184588Sdfr{ 54184588Sdfr int i; 55184588Sdfr 56184588Sdfr for (i = 0; krb5_encryption_classes[i]; i++) { 57184588Sdfr if (krb5_encryption_classes[i]->ec_type == etype) 58184588Sdfr return (krb5_encryption_classes[i]); 59184588Sdfr } 60184588Sdfr return (NULL); 61184588Sdfr} 62184588Sdfr 63184588Sdfrstruct krb5_key_state * 64184588Sdfrkrb5_create_key(const struct krb5_encryption_class *ec) 65184588Sdfr{ 66184588Sdfr struct krb5_key_state *ks; 67184588Sdfr 68184588Sdfr ks = malloc(sizeof(struct krb5_key_state), M_GSSAPI, M_WAITOK); 69184588Sdfr ks->ks_class = ec; 70184588Sdfr refcount_init(&ks->ks_refs, 1); 71184588Sdfr ks->ks_key = malloc(ec->ec_keylen, M_GSSAPI, M_WAITOK); 72184588Sdfr ec->ec_init(ks); 73184588Sdfr 74184588Sdfr return (ks); 75184588Sdfr} 76184588Sdfr 77184588Sdfrvoid 78184588Sdfrkrb5_free_key(struct krb5_key_state *ks) 79184588Sdfr{ 80184588Sdfr 81184588Sdfr if (refcount_release(&ks->ks_refs)) { 82184588Sdfr ks->ks_class->ec_destroy(ks); 83184588Sdfr bzero(ks->ks_key, ks->ks_class->ec_keylen); 84184588Sdfr free(ks->ks_key, M_GSSAPI); 85184588Sdfr free(ks, M_GSSAPI); 86184588Sdfr } 87184588Sdfr} 88184588Sdfr 89184588Sdfrstatic size_t 90184588Sdfrgcd(size_t a, size_t b) 91184588Sdfr{ 92184588Sdfr 93184588Sdfr if (b == 0) 94184588Sdfr return (a); 95184588Sdfr return gcd(b, a % b); 96184588Sdfr} 97184588Sdfr 98184588Sdfrstatic size_t 99184588Sdfrlcm(size_t a, size_t b) 100184588Sdfr{ 101184588Sdfr return ((a * b) / gcd(a, b)); 102184588Sdfr} 103184588Sdfr 104184588Sdfr/* 105184588Sdfr * Rotate right 13 of a variable precision number in 'in', storing the 106184588Sdfr * result in 'out'. The number is assumed to be big-endian in memory 107184588Sdfr * representation. 108184588Sdfr */ 109184588Sdfrstatic void 110184588Sdfrkrb5_rotate_right_13(uint8_t *out, uint8_t *in, size_t numlen) 111184588Sdfr{ 112184588Sdfr uint32_t carry; 113184588Sdfr size_t i; 114184588Sdfr 115184588Sdfr /* 116184588Sdfr * Special case when numlen == 1. A rotate right 13 of a 117184588Sdfr * single byte number changes to a rotate right 5. 118184588Sdfr */ 119184588Sdfr if (numlen == 1) { 120184588Sdfr carry = in[0] >> 5; 121184588Sdfr out[0] = (in[0] << 3) | carry; 122184588Sdfr return; 123184588Sdfr } 124184588Sdfr 125184588Sdfr carry = ((in[numlen - 2] & 31) << 8) | in[numlen - 1]; 126184588Sdfr for (i = 2; i < numlen; i++) { 127184588Sdfr out[i] = ((in[i - 2] & 31) << 3) | (in[i - 1] >> 5); 128184588Sdfr } 129184588Sdfr out[1] = ((carry & 31) << 3) | (in[0] >> 5); 130184588Sdfr out[0] = carry >> 5; 131184588Sdfr} 132184588Sdfr 133184588Sdfr/* 134184588Sdfr * Add two variable precision numbers in big-endian representation 135184588Sdfr * using ones-complement arithmetic. 136184588Sdfr */ 137184588Sdfrstatic void 138184588Sdfrkrb5_ones_complement_add(uint8_t *out, const uint8_t *in, size_t len) 139184588Sdfr{ 140184588Sdfr int n, i; 141184588Sdfr 142184588Sdfr /* 143184588Sdfr * First calculate the 2s complement sum, remembering the 144184588Sdfr * carry. 145184588Sdfr */ 146184588Sdfr n = 0; 147184588Sdfr for (i = len - 1; i >= 0; i--) { 148184588Sdfr n = out[i] + in[i] + n; 149184588Sdfr out[i] = n; 150184588Sdfr n >>= 8; 151184588Sdfr } 152184588Sdfr /* 153184588Sdfr * Then add back the carry. 154184588Sdfr */ 155184588Sdfr for (i = len - 1; n && i >= 0; i--) { 156184588Sdfr n = out[i] + n; 157184588Sdfr out[i] = n; 158184588Sdfr n >>= 8; 159184588Sdfr } 160184588Sdfr} 161184588Sdfr 162184588Sdfrstatic void 163184588Sdfrkrb5_n_fold(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) 164184588Sdfr{ 165184588Sdfr size_t tmplen; 166184588Sdfr uint8_t *tmp; 167184588Sdfr size_t i; 168184588Sdfr uint8_t *p; 169184588Sdfr 170184588Sdfr tmplen = lcm(inlen, outlen); 171184588Sdfr tmp = malloc(tmplen, M_GSSAPI, M_WAITOK); 172184588Sdfr 173184588Sdfr bcopy(in, tmp, inlen); 174184588Sdfr for (i = inlen, p = tmp; i < tmplen; i += inlen, p += inlen) { 175184588Sdfr krb5_rotate_right_13(p + inlen, p, inlen); 176184588Sdfr } 177184588Sdfr bzero(out, outlen); 178184588Sdfr for (i = 0, p = tmp; i < tmplen; i += outlen, p += outlen) { 179184588Sdfr krb5_ones_complement_add(out, p, outlen); 180184588Sdfr } 181184588Sdfr free(tmp, M_GSSAPI); 182184588Sdfr} 183184588Sdfr 184184588Sdfrstruct krb5_key_state * 185184588Sdfrkrb5_derive_key(struct krb5_key_state *inkey, 186184588Sdfr void *constant, size_t constantlen) 187184588Sdfr{ 188184588Sdfr struct krb5_key_state *dk; 189184588Sdfr const struct krb5_encryption_class *ec = inkey->ks_class; 190184588Sdfr uint8_t *folded; 191184588Sdfr uint8_t *bytes, *p, *q; 192184588Sdfr struct mbuf *m; 193184588Sdfr int randomlen, i; 194184588Sdfr 195184588Sdfr /* 196184588Sdfr * Expand the constant to blocklen bytes. 197184588Sdfr */ 198184588Sdfr folded = malloc(ec->ec_blocklen, M_GSSAPI, M_WAITOK); 199184588Sdfr krb5_n_fold(folded, ec->ec_blocklen, constant, constantlen); 200184588Sdfr 201184588Sdfr /* 202184588Sdfr * Generate enough bytes for keybits rounded up to a multiple 203184588Sdfr * of blocklen. 204184588Sdfr */ 205184588Sdfr randomlen = ((ec->ec_keybits/8 + ec->ec_blocklen - 1) / ec->ec_blocklen) 206184588Sdfr * ec->ec_blocklen; 207184588Sdfr bytes = malloc(randomlen, M_GSSAPI, M_WAITOK); 208184588Sdfr MGET(m, M_WAITOK, MT_DATA); 209184588Sdfr m->m_len = ec->ec_blocklen; 210184588Sdfr for (i = 0, p = bytes, q = folded; i < randomlen; 211184588Sdfr q = p, i += ec->ec_blocklen, p += ec->ec_blocklen) { 212184588Sdfr bcopy(q, m->m_data, ec->ec_blocklen); 213184588Sdfr krb5_encrypt(inkey, m, 0, ec->ec_blocklen, NULL, 0); 214184588Sdfr bcopy(m->m_data, p, ec->ec_blocklen); 215184588Sdfr } 216184588Sdfr m_free(m); 217184588Sdfr 218184588Sdfr dk = krb5_create_key(ec); 219184588Sdfr krb5_random_to_key(dk, bytes); 220184588Sdfr 221184588Sdfr free(folded, M_GSSAPI); 222184588Sdfr free(bytes, M_GSSAPI); 223184588Sdfr 224184588Sdfr return (dk); 225184588Sdfr} 226184588Sdfr 227184588Sdfrstatic struct krb5_key_state * 228184588Sdfrkrb5_get_usage_key(struct krb5_key_state *basekey, int usage, int which) 229184588Sdfr{ 230184588Sdfr const struct krb5_encryption_class *ec = basekey->ks_class; 231184588Sdfr 232184588Sdfr if (ec->ec_flags & EC_DERIVED_KEYS) { 233184588Sdfr uint8_t constant[5]; 234184588Sdfr 235184588Sdfr constant[0] = usage >> 24; 236184588Sdfr constant[1] = usage >> 16; 237184588Sdfr constant[2] = usage >> 8; 238184588Sdfr constant[3] = usage; 239184588Sdfr constant[4] = which; 240184588Sdfr return (krb5_derive_key(basekey, constant, 5)); 241184588Sdfr } else { 242184588Sdfr refcount_acquire(&basekey->ks_refs); 243184588Sdfr return (basekey); 244184588Sdfr } 245184588Sdfr} 246184588Sdfr 247184588Sdfrstruct krb5_key_state * 248184588Sdfrkrb5_get_encryption_key(struct krb5_key_state *basekey, int usage) 249184588Sdfr{ 250184588Sdfr 251184588Sdfr return (krb5_get_usage_key(basekey, usage, 0xaa)); 252184588Sdfr} 253184588Sdfr 254184588Sdfrstruct krb5_key_state * 255184588Sdfrkrb5_get_integrity_key(struct krb5_key_state *basekey, int usage) 256184588Sdfr{ 257184588Sdfr 258184588Sdfr return (krb5_get_usage_key(basekey, usage, 0x55)); 259184588Sdfr} 260184588Sdfr 261184588Sdfrstruct krb5_key_state * 262184588Sdfrkrb5_get_checksum_key(struct krb5_key_state *basekey, int usage) 263184588Sdfr{ 264184588Sdfr 265184588Sdfr return (krb5_get_usage_key(basekey, usage, 0x99)); 266184588Sdfr} 267