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