1 /* $NetBSD: rxkad_kdf.c,v 1.2 2017/01/28 21:31:49 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1995-2003 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Portions Copyright (c) 2013-2014 Carnegie Mellon University 9 * All rights reserved. 10 * 11 * Portions Copyright (c) 2013 by the Massachusetts Institute of Technology 12 * All rights reserved. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 25 * 3. Neither the name of the Institute nor the names of its contributors 26 * may be used to endorse or promote products derived from this software 27 * without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 */ 41 42 #include "kafs_locl.h" 43 44 static int rxkad_derive_des_key(const void *, size_t, char[8]); 45 static int compress_parity_bits(void *, size_t *); 46 47 /** 48 * Use NIST SP800-108 with HMAC(MD5) in counter mode as the PRF to derive a 49 * des key from another type of key. 50 * 51 * L is 64, as we take 64 random bits and turn them into a 56-bit des key. 52 * The output of hmac_md5 is 128 bits; we take the first 64 only, so n 53 * properly should be 1. However, we apply a slight variation due to the 54 * possibility of producing a weak des key. If the output key is weak, do NOT 55 * simply correct it, instead, the counter is advanced and the next output 56 * used. As such, we code so as to have n be the full 255 permitted by our 57 * encoding of the counter i in an 8-bit field. L itself is encoded as a 58 * 32-bit field, big-endian. We use the constant string "rxkad" as a label 59 * for this key derivation, the standard NUL byte separator, and omit a 60 * key-derivation context. The input key is unique to the krb5 service ticket, 61 * which is unlikely to be used in an other location. If it is used in such 62 * a fashion, both locations will derive the same des key from the PRF, but 63 * this is no different from if a krb5 des key had been used in the same way, 64 * as traditional krb5 rxkad uses the ticket session key directly as the token 65 * key. 66 * 67 * @param[in] in pointer to input key data 68 * @param[in] insize length of input key data 69 * @param[out] out 8-byte buffer to hold the derived key 70 * 71 * @return Returns 0 to indicate success, or an error code. 72 * 73 * @retval KRB5DES_WEAK_KEY Successive derivation attempts with all 74 * 255 possible counter values each produced weak DES keys. This input 75 * cannot be used to produce a usable key. 76 */ 77 static int 78 rxkad_derive_des_key(const void *in, size_t insize, char out[8]) 79 { 80 unsigned char i; 81 static unsigned char label[] = "rxkad"; 82 /* bits of output, as 32 bit word, MSB first */ 83 static unsigned char Lbuf[4] = { 0, 0, 0, 64 }; 84 /* only needs to be 16 for md5, but lets be sure it fits */ 85 unsigned char tmp[64]; 86 unsigned int mdsize; 87 DES_cblock ktmp; 88 HMAC_CTX mctx; 89 90 /* stop when 8 bit counter wraps to 0 */ 91 for (i = 1; i; i++) { 92 HMAC_CTX_init(&mctx); 93 HMAC_Init_ex(&mctx, in, insize, EVP_md5(), NULL); 94 HMAC_Update(&mctx, &i, 1); 95 HMAC_Update(&mctx, label, sizeof(label)); /* includes label and separator */ 96 HMAC_Update(&mctx, Lbuf, 4); 97 mdsize = sizeof(tmp); 98 HMAC_Final(&mctx, tmp, &mdsize); 99 memcpy(ktmp, tmp, 8); 100 DES_set_odd_parity(&ktmp); 101 if (!DES_is_weak_key(&ktmp)) { 102 memcpy(out, ktmp, 8); 103 return 0; 104 } 105 } 106 return KRB5DES_WEAK_KEY; 107 } 108 109 /** 110 * This is the inverse of the random-to-key for 3des specified in 111 * rfc3961, converting blocks of 8 bytes to blocks of 7 bytes by distributing 112 * the bits of each 8th byte as the lsb of the previous 7 bytes. 113 * 114 * @param[in,out] buffer Buffer containing the key to be converted 115 * @param[in,out] bufsiz Points to the size of the key data. On 116 * return, this is updated to reflect the size of the compressed data. 117 * 118 * @return Returns 0 to indicate success, or an error code. 119 * 120 * @retval KRB5_BAD_KEYSIZE The key size was not a multiple of 8 bytes. 121 */ 122 static int 123 compress_parity_bits(void *buffer, size_t *bufsiz) 124 { 125 unsigned char *cb, tmp; 126 int i, j, nk; 127 128 if (*bufsiz % 8 != 0) 129 return KRB5_BAD_KEYSIZE; 130 cb = (unsigned char *)buffer; 131 nk = *bufsiz / 8; 132 for (i = 0; i < nk; i++) { 133 tmp = cb[8 * i + 7] >> 1; 134 for (j = 0; j < 7; j++) { 135 cb[8 * i + j] &= 0xfe; 136 cb[8 * i + j] |= tmp & 0x1; 137 tmp >>= 1; 138 } 139 } 140 for (i = 1; i < nk; i++) 141 memmove(cb + 7 * i, cb + 8 * i, 7); 142 *bufsiz = 7 * nk; 143 return 0; 144 } 145 146 /** 147 * Derive a DES key for use with rxkad and fcrypt from a given Kerberos 148 * key of (almost) any type. This function encodes enctype-specific 149 * knowledge about how to derive a DES key from a given key type. 150 * If given a des key, use it directly; otherwise, perform any parity 151 * fixup that may be needed and pass through to the hmad-md5 bits. 152 * 153 * @param[in] enctype Kerberos enctype of the input key 154 * @param[in] keydata Input key data 155 * @param[in] keylen Size of input key data 156 * @param[out] output 8-byte buffer to hold the derived key 157 * 158 * @return Returns 0 to indicate success, or an error code. 159 * 160 * @retval KRB5_PROG_ETYPE_NOSUPP The enctype is one for which rxkad-kdf 161 * is not supported. This includes several reserved enctypes, enctype 162 * values used in PKINIT to stand for CMS algorithm identifiers, and all 163 * private-use (negative) enctypes. 164 * 165 * @retval KRB5_BAD_KEYSIZE The key size was not a multiple of 8 bytes 166 * (for 3DES key types), exactly 8 bytes (for DES key types), or at least 167 * 8 bytes (for other key types). 168 * 169 * @retval KRB5DES_WEAK_KEY Successive derivation attempts with all 170 * 255 possible counter values each produced weak DES keys. This input 171 * cannot be used to produce a usable key. 172 */ 173 int 174 _kafs_derive_des_key(krb5_enctype enctype, void *keydata, size_t keylen, 175 char output[8]) 176 { 177 int ret = 0; 178 179 switch ((int)enctype) { 180 case ETYPE_DES_CBC_CRC: 181 case ETYPE_DES_CBC_MD4: 182 case ETYPE_DES_CBC_MD5: 183 if (keylen != 8) 184 return KRB5_BAD_KEYSIZE; 185 186 /* Extract session key */ 187 memcpy(output, keydata, 8); 188 break; 189 case ETYPE_NULL: 190 case 4: 191 case 6: 192 case 8: 193 case 9: 194 case 10: 195 case 11: 196 case 12: 197 case 13: 198 case 14: 199 case 15: 200 return KRB5_PROG_ETYPE_NOSUPP; 201 /*In order to become a "Cryptographic Key" as specified in 202 * SP800-108, it must be indistinguishable from a random bitstring. */ 203 case ETYPE_DES3_CBC_MD5: 204 case ETYPE_OLD_DES3_CBC_SHA1: 205 case ETYPE_DES3_CBC_SHA1: 206 ret = compress_parity_bits(keydata, &keylen); 207 if (ret) 208 return ret; 209 /* FALLTHROUGH */ 210 default: 211 if (enctype < 0) 212 return KRB5_PROG_ETYPE_NOSUPP; 213 if (keylen < 7) 214 return KRB5_BAD_KEYSIZE; 215 ret = rxkad_derive_des_key(keydata, keylen, output); 216 } 217 return ret; 218 } 219