14891f2d0SKevin Coffman /* 24891f2d0SKevin Coffman * COPYRIGHT (c) 2008 34891f2d0SKevin Coffman * The Regents of the University of Michigan 44891f2d0SKevin Coffman * ALL RIGHTS RESERVED 54891f2d0SKevin Coffman * 64891f2d0SKevin Coffman * Permission is granted to use, copy, create derivative works 74891f2d0SKevin Coffman * and redistribute this software and such derivative works 84891f2d0SKevin Coffman * for any purpose, so long as the name of The University of 94891f2d0SKevin Coffman * Michigan is not used in any advertising or publicity 104891f2d0SKevin Coffman * pertaining to the use of distribution of this software 114891f2d0SKevin Coffman * without specific, written prior authorization. If the 124891f2d0SKevin Coffman * above copyright notice or any other identification of the 134891f2d0SKevin Coffman * University of Michigan is included in any copy of any 144891f2d0SKevin Coffman * portion of this software, then the disclaimer below must 154891f2d0SKevin Coffman * also be included. 164891f2d0SKevin Coffman * 174891f2d0SKevin Coffman * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION 184891f2d0SKevin Coffman * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY 194891f2d0SKevin Coffman * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF 204891f2d0SKevin Coffman * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING 214891f2d0SKevin Coffman * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF 224891f2d0SKevin Coffman * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE 234891f2d0SKevin Coffman * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE 244891f2d0SKevin Coffman * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR 254891f2d0SKevin Coffman * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING 264891f2d0SKevin Coffman * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN 274891f2d0SKevin Coffman * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF 284891f2d0SKevin Coffman * SUCH DAMAGES. 294891f2d0SKevin Coffman */ 304891f2d0SKevin Coffman 314891f2d0SKevin Coffman /* 324891f2d0SKevin Coffman * Copyright (C) 1998 by the FundsXpress, INC. 334891f2d0SKevin Coffman * 344891f2d0SKevin Coffman * All rights reserved. 354891f2d0SKevin Coffman * 364891f2d0SKevin Coffman * Export of this software from the United States of America may require 374891f2d0SKevin Coffman * a specific license from the United States Government. It is the 384891f2d0SKevin Coffman * responsibility of any person or organization contemplating export to 394891f2d0SKevin Coffman * obtain such a license before exporting. 404891f2d0SKevin Coffman * 414891f2d0SKevin Coffman * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 424891f2d0SKevin Coffman * distribute this software and its documentation for any purpose and 434891f2d0SKevin Coffman * without fee is hereby granted, provided that the above copyright 444891f2d0SKevin Coffman * notice appear in all copies and that both that copyright notice and 454891f2d0SKevin Coffman * this permission notice appear in supporting documentation, and that 464891f2d0SKevin Coffman * the name of FundsXpress. not be used in advertising or publicity pertaining 474891f2d0SKevin Coffman * to distribution of the software without specific, written prior 484891f2d0SKevin Coffman * permission. FundsXpress makes no representations about the suitability of 494891f2d0SKevin Coffman * this software for any purpose. It is provided "as is" without express 504891f2d0SKevin Coffman * or implied warranty. 514891f2d0SKevin Coffman * 524891f2d0SKevin Coffman * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 534891f2d0SKevin Coffman * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 544891f2d0SKevin Coffman * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 554891f2d0SKevin Coffman */ 564891f2d0SKevin Coffman 574891f2d0SKevin Coffman #include <linux/err.h> 584891f2d0SKevin Coffman #include <linux/types.h> 594891f2d0SKevin Coffman #include <linux/crypto.h> 604891f2d0SKevin Coffman #include <linux/sunrpc/gss_krb5.h> 614891f2d0SKevin Coffman #include <linux/sunrpc/xdr.h> 62c692554bSLuis Henriques #include <linux/lcm.h> 634891f2d0SKevin Coffman 644891f2d0SKevin Coffman #ifdef RPC_DEBUG 654891f2d0SKevin Coffman # define RPCDBG_FACILITY RPCDBG_AUTH 664891f2d0SKevin Coffman #endif 674891f2d0SKevin Coffman 684891f2d0SKevin Coffman /* 694891f2d0SKevin Coffman * This is the n-fold function as described in rfc3961, sec 5.1 704891f2d0SKevin Coffman * Taken from MIT Kerberos and modified. 714891f2d0SKevin Coffman */ 724891f2d0SKevin Coffman 734891f2d0SKevin Coffman static void krb5_nfold(u32 inbits, const u8 *in, 744891f2d0SKevin Coffman u32 outbits, u8 *out) 754891f2d0SKevin Coffman { 76c692554bSLuis Henriques unsigned long ulcm; 774891f2d0SKevin Coffman int byte, i, msbit; 784891f2d0SKevin Coffman 794891f2d0SKevin Coffman /* the code below is more readable if I make these bytes 804891f2d0SKevin Coffman instead of bits */ 814891f2d0SKevin Coffman 824891f2d0SKevin Coffman inbits >>= 3; 834891f2d0SKevin Coffman outbits >>= 3; 844891f2d0SKevin Coffman 854891f2d0SKevin Coffman /* first compute lcm(n,k) */ 86c692554bSLuis Henriques ulcm = lcm(inbits, outbits); 874891f2d0SKevin Coffman 884891f2d0SKevin Coffman /* now do the real work */ 894891f2d0SKevin Coffman 904891f2d0SKevin Coffman memset(out, 0, outbits); 914891f2d0SKevin Coffman byte = 0; 924891f2d0SKevin Coffman 934891f2d0SKevin Coffman /* this will end up cycling through k lcm(k,n)/k times, which 944891f2d0SKevin Coffman is correct */ 95c692554bSLuis Henriques for (i = ulcm-1; i >= 0; i--) { 964891f2d0SKevin Coffman /* compute the msbit in k which gets added into this byte */ 974891f2d0SKevin Coffman msbit = ( 984891f2d0SKevin Coffman /* first, start with the msbit in the first, 994891f2d0SKevin Coffman * unrotated byte */ 1004891f2d0SKevin Coffman ((inbits << 3) - 1) 1014891f2d0SKevin Coffman /* then, for each byte, shift to the right 1024891f2d0SKevin Coffman * for each repetition */ 1034891f2d0SKevin Coffman + (((inbits << 3) + 13) * (i/inbits)) 1044891f2d0SKevin Coffman /* last, pick out the correct byte within 1054891f2d0SKevin Coffman * that shifted repetition */ 1064891f2d0SKevin Coffman + ((inbits - (i % inbits)) << 3) 1074891f2d0SKevin Coffman ) % (inbits << 3); 1084891f2d0SKevin Coffman 1094891f2d0SKevin Coffman /* pull out the byte value itself */ 1104891f2d0SKevin Coffman byte += (((in[((inbits - 1) - (msbit >> 3)) % inbits] << 8)| 1114891f2d0SKevin Coffman (in[((inbits) - (msbit >> 3)) % inbits])) 1124891f2d0SKevin Coffman >> ((msbit & 7) + 1)) & 0xff; 1134891f2d0SKevin Coffman 1144891f2d0SKevin Coffman /* do the addition */ 1154891f2d0SKevin Coffman byte += out[i % outbits]; 1164891f2d0SKevin Coffman out[i % outbits] = byte & 0xff; 1174891f2d0SKevin Coffman 1184891f2d0SKevin Coffman /* keep around the carry bit, if any */ 1194891f2d0SKevin Coffman byte >>= 8; 1204891f2d0SKevin Coffman 1214891f2d0SKevin Coffman } 1224891f2d0SKevin Coffman 1234891f2d0SKevin Coffman /* if there's a carry bit left over, add it back in */ 1244891f2d0SKevin Coffman if (byte) { 1254891f2d0SKevin Coffman for (i = outbits - 1; i >= 0; i--) { 1264891f2d0SKevin Coffman /* do the addition */ 1274891f2d0SKevin Coffman byte += out[i]; 1284891f2d0SKevin Coffman out[i] = byte & 0xff; 1294891f2d0SKevin Coffman 1304891f2d0SKevin Coffman /* keep around the carry bit, if any */ 1314891f2d0SKevin Coffman byte >>= 8; 1324891f2d0SKevin Coffman } 1334891f2d0SKevin Coffman } 1344891f2d0SKevin Coffman } 1354891f2d0SKevin Coffman 1364891f2d0SKevin Coffman /* 1374891f2d0SKevin Coffman * This is the DK (derive_key) function as described in rfc3961, sec 5.1 1384891f2d0SKevin Coffman * Taken from MIT Kerberos and modified. 1394891f2d0SKevin Coffman */ 1404891f2d0SKevin Coffman 14147d84807SKevin Coffman u32 krb5_derive_key(const struct gss_krb5_enctype *gk5e, 1424891f2d0SKevin Coffman const struct xdr_netobj *inkey, 1434891f2d0SKevin Coffman struct xdr_netobj *outkey, 1441f4c86c0STrond Myklebust const struct xdr_netobj *in_constant, 1451f4c86c0STrond Myklebust gfp_t gfp_mask) 1464891f2d0SKevin Coffman { 1474891f2d0SKevin Coffman size_t blocksize, keybytes, keylength, n; 1484891f2d0SKevin Coffman unsigned char *inblockdata, *outblockdata, *rawkey; 1494891f2d0SKevin Coffman struct xdr_netobj inblock, outblock; 1504891f2d0SKevin Coffman struct crypto_blkcipher *cipher; 1514891f2d0SKevin Coffman u32 ret = EINVAL; 1524891f2d0SKevin Coffman 1534891f2d0SKevin Coffman blocksize = gk5e->blocksize; 1544891f2d0SKevin Coffman keybytes = gk5e->keybytes; 1554891f2d0SKevin Coffman keylength = gk5e->keylength; 1564891f2d0SKevin Coffman 1574891f2d0SKevin Coffman if ((inkey->len != keylength) || (outkey->len != keylength)) 1584891f2d0SKevin Coffman goto err_return; 1594891f2d0SKevin Coffman 1604891f2d0SKevin Coffman cipher = crypto_alloc_blkcipher(gk5e->encrypt_name, 0, 1614891f2d0SKevin Coffman CRYPTO_ALG_ASYNC); 1624891f2d0SKevin Coffman if (IS_ERR(cipher)) 1634891f2d0SKevin Coffman goto err_return; 1644891f2d0SKevin Coffman if (crypto_blkcipher_setkey(cipher, inkey->data, inkey->len)) 1654891f2d0SKevin Coffman goto err_return; 1664891f2d0SKevin Coffman 1674891f2d0SKevin Coffman /* allocate and set up buffers */ 1684891f2d0SKevin Coffman 1694891f2d0SKevin Coffman ret = ENOMEM; 1701f4c86c0STrond Myklebust inblockdata = kmalloc(blocksize, gfp_mask); 1714891f2d0SKevin Coffman if (inblockdata == NULL) 1724891f2d0SKevin Coffman goto err_free_cipher; 1734891f2d0SKevin Coffman 1741f4c86c0STrond Myklebust outblockdata = kmalloc(blocksize, gfp_mask); 1754891f2d0SKevin Coffman if (outblockdata == NULL) 1764891f2d0SKevin Coffman goto err_free_in; 1774891f2d0SKevin Coffman 1781f4c86c0STrond Myklebust rawkey = kmalloc(keybytes, gfp_mask); 1794891f2d0SKevin Coffman if (rawkey == NULL) 1804891f2d0SKevin Coffman goto err_free_out; 1814891f2d0SKevin Coffman 1824891f2d0SKevin Coffman inblock.data = (char *) inblockdata; 1834891f2d0SKevin Coffman inblock.len = blocksize; 1844891f2d0SKevin Coffman 1854891f2d0SKevin Coffman outblock.data = (char *) outblockdata; 1864891f2d0SKevin Coffman outblock.len = blocksize; 1874891f2d0SKevin Coffman 1884891f2d0SKevin Coffman /* initialize the input block */ 1894891f2d0SKevin Coffman 1904891f2d0SKevin Coffman if (in_constant->len == inblock.len) { 1914891f2d0SKevin Coffman memcpy(inblock.data, in_constant->data, inblock.len); 1924891f2d0SKevin Coffman } else { 1934891f2d0SKevin Coffman krb5_nfold(in_constant->len * 8, in_constant->data, 1944891f2d0SKevin Coffman inblock.len * 8, inblock.data); 1954891f2d0SKevin Coffman } 1964891f2d0SKevin Coffman 1974891f2d0SKevin Coffman /* loop encrypting the blocks until enough key bytes are generated */ 1984891f2d0SKevin Coffman 1994891f2d0SKevin Coffman n = 0; 2004891f2d0SKevin Coffman while (n < keybytes) { 2014891f2d0SKevin Coffman (*(gk5e->encrypt))(cipher, NULL, inblock.data, 2024891f2d0SKevin Coffman outblock.data, inblock.len); 2034891f2d0SKevin Coffman 2044891f2d0SKevin Coffman if ((keybytes - n) <= outblock.len) { 2054891f2d0SKevin Coffman memcpy(rawkey + n, outblock.data, (keybytes - n)); 2064891f2d0SKevin Coffman break; 2074891f2d0SKevin Coffman } 2084891f2d0SKevin Coffman 2094891f2d0SKevin Coffman memcpy(rawkey + n, outblock.data, outblock.len); 2104891f2d0SKevin Coffman memcpy(inblock.data, outblock.data, outblock.len); 2114891f2d0SKevin Coffman n += outblock.len; 2124891f2d0SKevin Coffman } 2134891f2d0SKevin Coffman 2144891f2d0SKevin Coffman /* postprocess the key */ 2154891f2d0SKevin Coffman 2164891f2d0SKevin Coffman inblock.data = (char *) rawkey; 2174891f2d0SKevin Coffman inblock.len = keybytes; 2184891f2d0SKevin Coffman 2194891f2d0SKevin Coffman BUG_ON(gk5e->mk_key == NULL); 2204891f2d0SKevin Coffman ret = (*(gk5e->mk_key))(gk5e, &inblock, outkey); 2214891f2d0SKevin Coffman if (ret) { 2224891f2d0SKevin Coffman dprintk("%s: got %d from mk_key function for '%s'\n", 2234891f2d0SKevin Coffman __func__, ret, gk5e->encrypt_name); 2244891f2d0SKevin Coffman goto err_free_raw; 2254891f2d0SKevin Coffman } 2264891f2d0SKevin Coffman 2274891f2d0SKevin Coffman /* clean memory, free resources and exit */ 2284891f2d0SKevin Coffman 2294891f2d0SKevin Coffman ret = 0; 2304891f2d0SKevin Coffman 2314891f2d0SKevin Coffman err_free_raw: 2324891f2d0SKevin Coffman memset(rawkey, 0, keybytes); 2334891f2d0SKevin Coffman kfree(rawkey); 2344891f2d0SKevin Coffman err_free_out: 2354891f2d0SKevin Coffman memset(outblockdata, 0, blocksize); 2364891f2d0SKevin Coffman kfree(outblockdata); 2374891f2d0SKevin Coffman err_free_in: 2384891f2d0SKevin Coffman memset(inblockdata, 0, blocksize); 2394891f2d0SKevin Coffman kfree(inblockdata); 2404891f2d0SKevin Coffman err_free_cipher: 2414891f2d0SKevin Coffman crypto_free_blkcipher(cipher); 2424891f2d0SKevin Coffman err_return: 2434891f2d0SKevin Coffman return ret; 2444891f2d0SKevin Coffman } 245958142e9SKevin Coffman 246958142e9SKevin Coffman #define smask(step) ((1<<step)-1) 247958142e9SKevin Coffman #define pstep(x, step) (((x)&smask(step))^(((x)>>step)&smask(step))) 248958142e9SKevin Coffman #define parity_char(x) pstep(pstep(pstep((x), 4), 2), 1) 249958142e9SKevin Coffman 250958142e9SKevin Coffman static void mit_des_fixup_key_parity(u8 key[8]) 251958142e9SKevin Coffman { 252958142e9SKevin Coffman int i; 253958142e9SKevin Coffman for (i = 0; i < 8; i++) { 254958142e9SKevin Coffman key[i] &= 0xfe; 255958142e9SKevin Coffman key[i] |= 1^parity_char(key[i]); 256958142e9SKevin Coffman } 257958142e9SKevin Coffman } 258958142e9SKevin Coffman 259958142e9SKevin Coffman /* 260958142e9SKevin Coffman * This is the des3 key derivation postprocess function 261958142e9SKevin Coffman */ 262958142e9SKevin Coffman u32 gss_krb5_des3_make_key(const struct gss_krb5_enctype *gk5e, 263958142e9SKevin Coffman struct xdr_netobj *randombits, 264958142e9SKevin Coffman struct xdr_netobj *key) 265958142e9SKevin Coffman { 266958142e9SKevin Coffman int i; 267958142e9SKevin Coffman u32 ret = EINVAL; 268958142e9SKevin Coffman 269958142e9SKevin Coffman if (key->len != 24) { 270958142e9SKevin Coffman dprintk("%s: key->len is %d\n", __func__, key->len); 271958142e9SKevin Coffman goto err_out; 272958142e9SKevin Coffman } 273958142e9SKevin Coffman if (randombits->len != 21) { 274958142e9SKevin Coffman dprintk("%s: randombits->len is %d\n", 275958142e9SKevin Coffman __func__, randombits->len); 276958142e9SKevin Coffman goto err_out; 277958142e9SKevin Coffman } 278958142e9SKevin Coffman 279958142e9SKevin Coffman /* take the seven bytes, move them around into the top 7 bits of the 280958142e9SKevin Coffman 8 key bytes, then compute the parity bits. Do this three times. */ 281958142e9SKevin Coffman 282958142e9SKevin Coffman for (i = 0; i < 3; i++) { 283958142e9SKevin Coffman memcpy(key->data + i*8, randombits->data + i*7, 7); 284958142e9SKevin Coffman key->data[i*8+7] = (((key->data[i*8]&1)<<1) | 285958142e9SKevin Coffman ((key->data[i*8+1]&1)<<2) | 286958142e9SKevin Coffman ((key->data[i*8+2]&1)<<3) | 287958142e9SKevin Coffman ((key->data[i*8+3]&1)<<4) | 288958142e9SKevin Coffman ((key->data[i*8+4]&1)<<5) | 289958142e9SKevin Coffman ((key->data[i*8+5]&1)<<6) | 290958142e9SKevin Coffman ((key->data[i*8+6]&1)<<7)); 291958142e9SKevin Coffman 292958142e9SKevin Coffman mit_des_fixup_key_parity(key->data + i*8); 293958142e9SKevin Coffman } 294958142e9SKevin Coffman ret = 0; 295958142e9SKevin Coffman err_out: 296958142e9SKevin Coffman return ret; 297958142e9SKevin Coffman } 298934a95aaSKevin Coffman 299934a95aaSKevin Coffman /* 300934a95aaSKevin Coffman * This is the aes key derivation postprocess function 301934a95aaSKevin Coffman */ 302934a95aaSKevin Coffman u32 gss_krb5_aes_make_key(const struct gss_krb5_enctype *gk5e, 303934a95aaSKevin Coffman struct xdr_netobj *randombits, 304934a95aaSKevin Coffman struct xdr_netobj *key) 305934a95aaSKevin Coffman { 306934a95aaSKevin Coffman u32 ret = EINVAL; 307934a95aaSKevin Coffman 308934a95aaSKevin Coffman if (key->len != 16 && key->len != 32) { 309934a95aaSKevin Coffman dprintk("%s: key->len is %d\n", __func__, key->len); 310934a95aaSKevin Coffman goto err_out; 311934a95aaSKevin Coffman } 312934a95aaSKevin Coffman if (randombits->len != 16 && randombits->len != 32) { 313934a95aaSKevin Coffman dprintk("%s: randombits->len is %d\n", 314934a95aaSKevin Coffman __func__, randombits->len); 315934a95aaSKevin Coffman goto err_out; 316934a95aaSKevin Coffman } 317934a95aaSKevin Coffman if (randombits->len != key->len) { 318934a95aaSKevin Coffman dprintk("%s: randombits->len is %d, key->len is %d\n", 319934a95aaSKevin Coffman __func__, randombits->len, key->len); 320934a95aaSKevin Coffman goto err_out; 321934a95aaSKevin Coffman } 322934a95aaSKevin Coffman memcpy(key->data, randombits->data, key->len); 323934a95aaSKevin Coffman ret = 0; 324934a95aaSKevin Coffman err_out: 325934a95aaSKevin Coffman return ret; 326934a95aaSKevin Coffman } 327934a95aaSKevin Coffman 328