18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * COPYRIGHT (c) 2008 38c2ecf20Sopenharmony_ci * The Regents of the University of Michigan 48c2ecf20Sopenharmony_ci * ALL RIGHTS RESERVED 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Permission is granted to use, copy, create derivative works 78c2ecf20Sopenharmony_ci * and redistribute this software and such derivative works 88c2ecf20Sopenharmony_ci * for any purpose, so long as the name of The University of 98c2ecf20Sopenharmony_ci * Michigan is not used in any advertising or publicity 108c2ecf20Sopenharmony_ci * pertaining to the use of distribution of this software 118c2ecf20Sopenharmony_ci * without specific, written prior authorization. If the 128c2ecf20Sopenharmony_ci * above copyright notice or any other identification of the 138c2ecf20Sopenharmony_ci * University of Michigan is included in any copy of any 148c2ecf20Sopenharmony_ci * portion of this software, then the disclaimer below must 158c2ecf20Sopenharmony_ci * also be included. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION 188c2ecf20Sopenharmony_ci * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY 198c2ecf20Sopenharmony_ci * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF 208c2ecf20Sopenharmony_ci * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING 218c2ecf20Sopenharmony_ci * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF 228c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE 238c2ecf20Sopenharmony_ci * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE 248c2ecf20Sopenharmony_ci * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR 258c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING 268c2ecf20Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN 278c2ecf20Sopenharmony_ci * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF 288c2ecf20Sopenharmony_ci * SUCH DAMAGES. 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * Copyright (C) 1998 by the FundsXpress, INC. 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * All rights reserved. 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * Export of this software from the United States of America may require 378c2ecf20Sopenharmony_ci * a specific license from the United States Government. It is the 388c2ecf20Sopenharmony_ci * responsibility of any person or organization contemplating export to 398c2ecf20Sopenharmony_ci * obtain such a license before exporting. 408c2ecf20Sopenharmony_ci * 418c2ecf20Sopenharmony_ci * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 428c2ecf20Sopenharmony_ci * distribute this software and its documentation for any purpose and 438c2ecf20Sopenharmony_ci * without fee is hereby granted, provided that the above copyright 448c2ecf20Sopenharmony_ci * notice appear in all copies and that both that copyright notice and 458c2ecf20Sopenharmony_ci * this permission notice appear in supporting documentation, and that 468c2ecf20Sopenharmony_ci * the name of FundsXpress. not be used in advertising or publicity pertaining 478c2ecf20Sopenharmony_ci * to distribution of the software without specific, written prior 488c2ecf20Sopenharmony_ci * permission. FundsXpress makes no representations about the suitability of 498c2ecf20Sopenharmony_ci * this software for any purpose. It is provided "as is" without express 508c2ecf20Sopenharmony_ci * or implied warranty. 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 538c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 548c2ecf20Sopenharmony_ci * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#include <crypto/skcipher.h> 588c2ecf20Sopenharmony_ci#include <linux/err.h> 598c2ecf20Sopenharmony_ci#include <linux/types.h> 608c2ecf20Sopenharmony_ci#include <linux/sunrpc/gss_krb5.h> 618c2ecf20Sopenharmony_ci#include <linux/sunrpc/xdr.h> 628c2ecf20Sopenharmony_ci#include <linux/lcm.h> 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) 658c2ecf20Sopenharmony_ci# define RPCDBG_FACILITY RPCDBG_AUTH 668c2ecf20Sopenharmony_ci#endif 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* 698c2ecf20Sopenharmony_ci * This is the n-fold function as described in rfc3961, sec 5.1 708c2ecf20Sopenharmony_ci * Taken from MIT Kerberos and modified. 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic void krb5_nfold(u32 inbits, const u8 *in, 748c2ecf20Sopenharmony_ci u32 outbits, u8 *out) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci unsigned long ulcm; 778c2ecf20Sopenharmony_ci int byte, i, msbit; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* the code below is more readable if I make these bytes 808c2ecf20Sopenharmony_ci instead of bits */ 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci inbits >>= 3; 838c2ecf20Sopenharmony_ci outbits >>= 3; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* first compute lcm(n,k) */ 868c2ecf20Sopenharmony_ci ulcm = lcm(inbits, outbits); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* now do the real work */ 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci memset(out, 0, outbits); 918c2ecf20Sopenharmony_ci byte = 0; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* this will end up cycling through k lcm(k,n)/k times, which 948c2ecf20Sopenharmony_ci is correct */ 958c2ecf20Sopenharmony_ci for (i = ulcm-1; i >= 0; i--) { 968c2ecf20Sopenharmony_ci /* compute the msbit in k which gets added into this byte */ 978c2ecf20Sopenharmony_ci msbit = ( 988c2ecf20Sopenharmony_ci /* first, start with the msbit in the first, 998c2ecf20Sopenharmony_ci * unrotated byte */ 1008c2ecf20Sopenharmony_ci ((inbits << 3) - 1) 1018c2ecf20Sopenharmony_ci /* then, for each byte, shift to the right 1028c2ecf20Sopenharmony_ci * for each repetition */ 1038c2ecf20Sopenharmony_ci + (((inbits << 3) + 13) * (i/inbits)) 1048c2ecf20Sopenharmony_ci /* last, pick out the correct byte within 1058c2ecf20Sopenharmony_ci * that shifted repetition */ 1068c2ecf20Sopenharmony_ci + ((inbits - (i % inbits)) << 3) 1078c2ecf20Sopenharmony_ci ) % (inbits << 3); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* pull out the byte value itself */ 1108c2ecf20Sopenharmony_ci byte += (((in[((inbits - 1) - (msbit >> 3)) % inbits] << 8)| 1118c2ecf20Sopenharmony_ci (in[((inbits) - (msbit >> 3)) % inbits])) 1128c2ecf20Sopenharmony_ci >> ((msbit & 7) + 1)) & 0xff; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* do the addition */ 1158c2ecf20Sopenharmony_ci byte += out[i % outbits]; 1168c2ecf20Sopenharmony_ci out[i % outbits] = byte & 0xff; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* keep around the carry bit, if any */ 1198c2ecf20Sopenharmony_ci byte >>= 8; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* if there's a carry bit left over, add it back in */ 1248c2ecf20Sopenharmony_ci if (byte) { 1258c2ecf20Sopenharmony_ci for (i = outbits - 1; i >= 0; i--) { 1268c2ecf20Sopenharmony_ci /* do the addition */ 1278c2ecf20Sopenharmony_ci byte += out[i]; 1288c2ecf20Sopenharmony_ci out[i] = byte & 0xff; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* keep around the carry bit, if any */ 1318c2ecf20Sopenharmony_ci byte >>= 8; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/* 1378c2ecf20Sopenharmony_ci * This is the DK (derive_key) function as described in rfc3961, sec 5.1 1388c2ecf20Sopenharmony_ci * Taken from MIT Kerberos and modified. 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ciu32 krb5_derive_key(const struct gss_krb5_enctype *gk5e, 1428c2ecf20Sopenharmony_ci const struct xdr_netobj *inkey, 1438c2ecf20Sopenharmony_ci struct xdr_netobj *outkey, 1448c2ecf20Sopenharmony_ci const struct xdr_netobj *in_constant, 1458c2ecf20Sopenharmony_ci gfp_t gfp_mask) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci size_t blocksize, keybytes, keylength, n; 1488c2ecf20Sopenharmony_ci unsigned char *inblockdata, *outblockdata, *rawkey; 1498c2ecf20Sopenharmony_ci struct xdr_netobj inblock, outblock; 1508c2ecf20Sopenharmony_ci struct crypto_sync_skcipher *cipher; 1518c2ecf20Sopenharmony_ci u32 ret = EINVAL; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci blocksize = gk5e->blocksize; 1548c2ecf20Sopenharmony_ci keybytes = gk5e->keybytes; 1558c2ecf20Sopenharmony_ci keylength = gk5e->keylength; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if ((inkey->len != keylength) || (outkey->len != keylength)) 1588c2ecf20Sopenharmony_ci goto err_return; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci cipher = crypto_alloc_sync_skcipher(gk5e->encrypt_name, 0, 0); 1618c2ecf20Sopenharmony_ci if (IS_ERR(cipher)) 1628c2ecf20Sopenharmony_ci goto err_return; 1638c2ecf20Sopenharmony_ci if (crypto_sync_skcipher_setkey(cipher, inkey->data, inkey->len)) 1648c2ecf20Sopenharmony_ci goto err_return; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* allocate and set up buffers */ 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci ret = ENOMEM; 1698c2ecf20Sopenharmony_ci inblockdata = kmalloc(blocksize, gfp_mask); 1708c2ecf20Sopenharmony_ci if (inblockdata == NULL) 1718c2ecf20Sopenharmony_ci goto err_free_cipher; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci outblockdata = kmalloc(blocksize, gfp_mask); 1748c2ecf20Sopenharmony_ci if (outblockdata == NULL) 1758c2ecf20Sopenharmony_ci goto err_free_in; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci rawkey = kmalloc(keybytes, gfp_mask); 1788c2ecf20Sopenharmony_ci if (rawkey == NULL) 1798c2ecf20Sopenharmony_ci goto err_free_out; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci inblock.data = (char *) inblockdata; 1828c2ecf20Sopenharmony_ci inblock.len = blocksize; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci outblock.data = (char *) outblockdata; 1858c2ecf20Sopenharmony_ci outblock.len = blocksize; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci /* initialize the input block */ 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (in_constant->len == inblock.len) { 1908c2ecf20Sopenharmony_ci memcpy(inblock.data, in_constant->data, inblock.len); 1918c2ecf20Sopenharmony_ci } else { 1928c2ecf20Sopenharmony_ci krb5_nfold(in_constant->len * 8, in_constant->data, 1938c2ecf20Sopenharmony_ci inblock.len * 8, inblock.data); 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* loop encrypting the blocks until enough key bytes are generated */ 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci n = 0; 1998c2ecf20Sopenharmony_ci while (n < keybytes) { 2008c2ecf20Sopenharmony_ci (*(gk5e->encrypt))(cipher, NULL, inblock.data, 2018c2ecf20Sopenharmony_ci outblock.data, inblock.len); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if ((keybytes - n) <= outblock.len) { 2048c2ecf20Sopenharmony_ci memcpy(rawkey + n, outblock.data, (keybytes - n)); 2058c2ecf20Sopenharmony_ci break; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci memcpy(rawkey + n, outblock.data, outblock.len); 2098c2ecf20Sopenharmony_ci memcpy(inblock.data, outblock.data, outblock.len); 2108c2ecf20Sopenharmony_ci n += outblock.len; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* postprocess the key */ 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci inblock.data = (char *) rawkey; 2168c2ecf20Sopenharmony_ci inblock.len = keybytes; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci BUG_ON(gk5e->mk_key == NULL); 2198c2ecf20Sopenharmony_ci ret = (*(gk5e->mk_key))(gk5e, &inblock, outkey); 2208c2ecf20Sopenharmony_ci if (ret) { 2218c2ecf20Sopenharmony_ci dprintk("%s: got %d from mk_key function for '%s'\n", 2228c2ecf20Sopenharmony_ci __func__, ret, gk5e->encrypt_name); 2238c2ecf20Sopenharmony_ci goto err_free_raw; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* clean memory, free resources and exit */ 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci ret = 0; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cierr_free_raw: 2318c2ecf20Sopenharmony_ci kfree_sensitive(rawkey); 2328c2ecf20Sopenharmony_cierr_free_out: 2338c2ecf20Sopenharmony_ci kfree_sensitive(outblockdata); 2348c2ecf20Sopenharmony_cierr_free_in: 2358c2ecf20Sopenharmony_ci kfree_sensitive(inblockdata); 2368c2ecf20Sopenharmony_cierr_free_cipher: 2378c2ecf20Sopenharmony_ci crypto_free_sync_skcipher(cipher); 2388c2ecf20Sopenharmony_cierr_return: 2398c2ecf20Sopenharmony_ci return ret; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci#define smask(step) ((1<<step)-1) 2438c2ecf20Sopenharmony_ci#define pstep(x, step) (((x)&smask(step))^(((x)>>step)&smask(step))) 2448c2ecf20Sopenharmony_ci#define parity_char(x) pstep(pstep(pstep((x), 4), 2), 1) 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic void mit_des_fixup_key_parity(u8 key[8]) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci int i; 2498c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 2508c2ecf20Sopenharmony_ci key[i] &= 0xfe; 2518c2ecf20Sopenharmony_ci key[i] |= 1^parity_char(key[i]); 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci/* 2568c2ecf20Sopenharmony_ci * This is the des3 key derivation postprocess function 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_ciu32 gss_krb5_des3_make_key(const struct gss_krb5_enctype *gk5e, 2598c2ecf20Sopenharmony_ci struct xdr_netobj *randombits, 2608c2ecf20Sopenharmony_ci struct xdr_netobj *key) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci int i; 2638c2ecf20Sopenharmony_ci u32 ret = EINVAL; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (key->len != 24) { 2668c2ecf20Sopenharmony_ci dprintk("%s: key->len is %d\n", __func__, key->len); 2678c2ecf20Sopenharmony_ci goto err_out; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci if (randombits->len != 21) { 2708c2ecf20Sopenharmony_ci dprintk("%s: randombits->len is %d\n", 2718c2ecf20Sopenharmony_ci __func__, randombits->len); 2728c2ecf20Sopenharmony_ci goto err_out; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* take the seven bytes, move them around into the top 7 bits of the 2768c2ecf20Sopenharmony_ci 8 key bytes, then compute the parity bits. Do this three times. */ 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 2798c2ecf20Sopenharmony_ci memcpy(key->data + i*8, randombits->data + i*7, 7); 2808c2ecf20Sopenharmony_ci key->data[i*8+7] = (((key->data[i*8]&1)<<1) | 2818c2ecf20Sopenharmony_ci ((key->data[i*8+1]&1)<<2) | 2828c2ecf20Sopenharmony_ci ((key->data[i*8+2]&1)<<3) | 2838c2ecf20Sopenharmony_ci ((key->data[i*8+3]&1)<<4) | 2848c2ecf20Sopenharmony_ci ((key->data[i*8+4]&1)<<5) | 2858c2ecf20Sopenharmony_ci ((key->data[i*8+5]&1)<<6) | 2868c2ecf20Sopenharmony_ci ((key->data[i*8+6]&1)<<7)); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci mit_des_fixup_key_parity(key->data + i*8); 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci ret = 0; 2918c2ecf20Sopenharmony_cierr_out: 2928c2ecf20Sopenharmony_ci return ret; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/* 2968c2ecf20Sopenharmony_ci * This is the aes key derivation postprocess function 2978c2ecf20Sopenharmony_ci */ 2988c2ecf20Sopenharmony_ciu32 gss_krb5_aes_make_key(const struct gss_krb5_enctype *gk5e, 2998c2ecf20Sopenharmony_ci struct xdr_netobj *randombits, 3008c2ecf20Sopenharmony_ci struct xdr_netobj *key) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci u32 ret = EINVAL; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (key->len != 16 && key->len != 32) { 3058c2ecf20Sopenharmony_ci dprintk("%s: key->len is %d\n", __func__, key->len); 3068c2ecf20Sopenharmony_ci goto err_out; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci if (randombits->len != 16 && randombits->len != 32) { 3098c2ecf20Sopenharmony_ci dprintk("%s: randombits->len is %d\n", 3108c2ecf20Sopenharmony_ci __func__, randombits->len); 3118c2ecf20Sopenharmony_ci goto err_out; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci if (randombits->len != key->len) { 3148c2ecf20Sopenharmony_ci dprintk("%s: randombits->len is %d, key->len is %d\n", 3158c2ecf20Sopenharmony_ci __func__, randombits->len, key->len); 3168c2ecf20Sopenharmony_ci goto err_out; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci memcpy(key->data, randombits->data, key->len); 3198c2ecf20Sopenharmony_ci ret = 0; 3208c2ecf20Sopenharmony_cierr_out: 3218c2ecf20Sopenharmony_ci return ret; 3228c2ecf20Sopenharmony_ci} 323