1/* $NetBSD: rxkad_kdf.c,v 1.4 2023/06/19 21:41:44 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#define HC_DEPRECATED_CRYPTO 43#include "kafs_locl.h" 44 45static int rxkad_derive_des_key(const void *, size_t, char[8]); 46static int compress_parity_bits(void *, size_t *); 47 48/** 49 * Use NIST SP800-108 with HMAC(MD5) in counter mode as the PRF to derive a 50 * des key from another type of key. 51 * 52 * L is 64, as we take 64 random bits and turn them into a 56-bit des key. 53 * The output of hmac_md5 is 128 bits; we take the first 64 only, so n 54 * properly should be 1. However, we apply a slight variation due to the 55 * possibility of producing a weak des key. If the output key is weak, do NOT 56 * simply correct it, instead, the counter is advanced and the next output 57 * used. As such, we code so as to have n be the full 255 permitted by our 58 * encoding of the counter i in an 8-bit field. L itself is encoded as a 59 * 32-bit field, big-endian. We use the constant string "rxkad" as a label 60 * for this key derivation, the standard NUL byte separator, and omit a 61 * key-derivation context. The input key is unique to the krb5 service ticket, 62 * which is unlikely to be used in an other location. If it is used in such 63 * a fashion, both locations will derive the same des key from the PRF, but 64 * this is no different from if a krb5 des key had been used in the same way, 65 * as traditional krb5 rxkad uses the ticket session key directly as the token 66 * key. 67 * 68 * @param[in] in pointer to input key data 69 * @param[in] insize length of input key data 70 * @param[out] out 8-byte buffer to hold the derived key 71 * 72 * @return Returns 0 to indicate success, or an error code. 73 * 74 * @retval KRB5DES_WEAK_KEY Successive derivation attempts with all 75 * 255 possible counter values each produced weak DES keys. This input 76 * cannot be used to produce a usable key. 77 */ 78static int 79rxkad_derive_des_key(const void *in, size_t insize, char out[8]) 80{ 81 unsigned char i; 82 static unsigned char label[] = "rxkad"; 83 /* bits of output, as 32 bit word, MSB first */ 84 static unsigned char Lbuf[4] = { 0, 0, 0, 64 }; 85 /* only needs to be 16 for md5, but lets be sure it fits */ 86 unsigned char tmp[64]; 87 unsigned int mdsize; 88 DES_cblock ktmp; 89 HMAC_CTX *mctx; 90 91 /* stop when 8 bit counter wraps to 0 */ 92 for (i = 1; i; i++) { 93#if OPENSSL_VERSION_NUMBER < 0x10100000UL 94 HMAC_CTX mctxs; 95 mctx = &mctxs; 96 HMAC_CTX_init(mctx); 97#else 98 mctx = HMAC_CTX_new(); 99#endif 100 HMAC_Init_ex(mctx, in, insize, EVP_md5(), NULL); 101 HMAC_Update(mctx, &i, 1); 102 HMAC_Update(mctx, label, sizeof(label)); /* includes label and separator */ 103 HMAC_Update(mctx, Lbuf, 4); 104 mdsize = sizeof(tmp); 105 HMAC_Final(mctx, tmp, &mdsize); 106 memcpy(ktmp, tmp, 8); 107#if OPENSSL_VERSION_NUMBER < 0x10100000UL 108 HMAC_CTX_cleanup(mctx); 109#else 110 HMAC_CTX_free(mctx); 111#endif 112 DES_set_odd_parity(&ktmp); 113 if (!DES_is_weak_key(&ktmp)) { 114 memcpy(out, ktmp, 8); 115 return 0; 116 } 117 } 118 return KRB5DES_WEAK_KEY; 119} 120 121/** 122 * This is the inverse of the random-to-key for 3des specified in 123 * rfc3961, converting blocks of 8 bytes to blocks of 7 bytes by distributing 124 * the bits of each 8th byte as the lsb of the previous 7 bytes. 125 * 126 * @param[in,out] buffer Buffer containing the key to be converted 127 * @param[in,out] bufsiz Points to the size of the key data. On 128 * return, this is updated to reflect the size of the compressed data. 129 * 130 * @return Returns 0 to indicate success, or an error code. 131 * 132 * @retval KRB5_BAD_KEYSIZE The key size was not a multiple of 8 bytes. 133 */ 134static int 135compress_parity_bits(void *buffer, size_t *bufsiz) 136{ 137 unsigned char *cb, tmp; 138 int i, j, nk; 139 140 if (*bufsiz % 8 != 0) 141 return KRB5_BAD_KEYSIZE; 142 cb = (unsigned char *)buffer; 143 nk = *bufsiz / 8; 144 for (i = 0; i < nk; i++) { 145 tmp = cb[8 * i + 7] >> 1; 146 for (j = 0; j < 7; j++) { 147 cb[8 * i + j] &= 0xfe; 148 cb[8 * i + j] |= tmp & 0x1; 149 tmp >>= 1; 150 } 151 } 152 for (i = 1; i < nk; i++) 153 memmove(cb + 7 * i, cb + 8 * i, 7); 154 *bufsiz = 7 * nk; 155 return 0; 156} 157 158/** 159 * Derive a DES key for use with rxkad and fcrypt from a given Kerberos 160 * key of (almost) any type. This function encodes enctype-specific 161 * knowledge about how to derive a DES key from a given key type. 162 * If given a des key, use it directly; otherwise, perform any parity 163 * fixup that may be needed and pass through to the hmad-md5 bits. 164 * 165 * @param[in] enctype Kerberos enctype of the input key 166 * @param[in] keydata Input key data 167 * @param[in] keylen Size of input key data 168 * @param[out] output 8-byte buffer to hold the derived key 169 * 170 * @return Returns 0 to indicate success, or an error code. 171 * 172 * @retval KRB5_PROG_ETYPE_NOSUPP The enctype is one for which rxkad-kdf 173 * is not supported. This includes several reserved enctypes, enctype 174 * values used in PKINIT to stand for CMS algorithm identifiers, and all 175 * private-use (negative) enctypes. 176 * 177 * @retval KRB5_BAD_KEYSIZE The key size was not a multiple of 8 bytes 178 * (for 3DES key types), exactly 8 bytes (for DES key types), or at least 179 * 8 bytes (for other key types). 180 * 181 * @retval KRB5DES_WEAK_KEY Successive derivation attempts with all 182 * 255 possible counter values each produced weak DES keys. This input 183 * cannot be used to produce a usable key. 184 */ 185int 186_kafs_derive_des_key(krb5_enctype enctype, void *keydata, size_t keylen, 187 char output[8]) 188{ 189 int ret = 0; 190 191 switch ((int)enctype) { 192 case ETYPE_DES_CBC_CRC: 193 case ETYPE_DES_CBC_MD4: 194 case ETYPE_DES_CBC_MD5: 195 if (keylen != 8) 196 return KRB5_BAD_KEYSIZE; 197 198 /* Extract session key */ 199 memcpy(output, keydata, 8); 200 break; 201 case ETYPE_NULL: 202 case 4: 203 case 6: 204 case 8: 205 case 9: 206 case 10: 207 case 11: 208 case 12: 209 case 13: 210 case 14: 211 case 15: 212 return KRB5_PROG_ETYPE_NOSUPP; 213 /*In order to become a "Cryptographic Key" as specified in 214 * SP800-108, it must be indistinguishable from a random bitstring. */ 215 case ETYPE_DES3_CBC_MD5: 216 case ETYPE_OLD_DES3_CBC_SHA1: 217 case ETYPE_DES3_CBC_SHA1: 218 ret = compress_parity_bits(keydata, &keylen); 219 if (ret) 220 return ret; 221 /* FALLTHROUGH */ 222 default: 223 if (enctype < 0) 224 return KRB5_PROG_ETYPE_NOSUPP; 225 if (keylen < 7) 226 return KRB5_BAD_KEYSIZE; 227 ret = rxkad_derive_des_key(keydata, keylen, output); 228 } 229 return ret; 230} 231