1/* $NetBSD: crypto-arcfour.c,v 1.6 2023/06/19 21:41:44 christos Exp $ */ 2 3/* 4 * Copyright (c) 1997 - 2008 Kungliga Tekniska H��gskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36/* 37 * ARCFOUR 38 */ 39 40#include "krb5_locl.h" 41 42static struct _krb5_key_type keytype_arcfour = { 43 KRB5_ENCTYPE_ARCFOUR_HMAC_MD5, 44 "arcfour", 45 128, 46 16, 47 sizeof(struct _krb5_evp_schedule), 48 NULL, 49 _krb5_evp_schedule, 50 _krb5_arcfour_salt, 51 NULL, 52 _krb5_evp_cleanup, 53 EVP_rc4 54}; 55 56/* 57 * checksum according to section 5. of draft-brezak-win2k-krb-rc4-hmac-03.txt 58 */ 59 60krb5_error_code 61_krb5_HMAC_MD5_checksum(krb5_context context, 62 struct _krb5_key_data *key, 63 const void *data, 64 size_t len, 65 unsigned usage, 66 Checksum *result) 67{ 68 EVP_MD_CTX *m; 69 struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5); 70 const char signature[] = "signaturekey"; 71 Checksum ksign_c; 72 struct _krb5_key_data ksign; 73 krb5_keyblock kb; 74 unsigned char t[4]; 75 unsigned char tmp[16]; 76 unsigned char ksign_c_data[16]; 77 krb5_error_code ret; 78 79 m = EVP_MD_CTX_create(); 80 if (m == NULL) 81 return krb5_enomem(context); 82 ksign_c.checksum.length = sizeof(ksign_c_data); 83 ksign_c.checksum.data = ksign_c_data; 84 ret = _krb5_internal_hmac(context, c, signature, sizeof(signature), 85 0, key, &ksign_c); 86 if (ret) { 87 EVP_MD_CTX_destroy(m); 88 return ret; 89 } 90 ksign.key = &kb; 91 kb.keyvalue = ksign_c.checksum; 92 EVP_DigestInit_ex(m, EVP_md5(), NULL); 93 t[0] = (usage >> 0) & 0xFF; 94 t[1] = (usage >> 8) & 0xFF; 95 t[2] = (usage >> 16) & 0xFF; 96 t[3] = (usage >> 24) & 0xFF; 97 EVP_DigestUpdate(m, t, 4); 98 EVP_DigestUpdate(m, data, len); 99 EVP_DigestFinal_ex (m, tmp, NULL); 100 EVP_MD_CTX_destroy(m); 101 102 ret = _krb5_internal_hmac(context, c, tmp, sizeof(tmp), 0, &ksign, result); 103 if (ret) 104 return ret; 105 return 0; 106} 107 108struct _krb5_checksum_type _krb5_checksum_hmac_md5 = { 109 CKSUMTYPE_HMAC_MD5, 110 "hmac-md5", 111 64, 112 16, 113 F_KEYED | F_CPROOF, 114 _krb5_HMAC_MD5_checksum, 115 NULL 116}; 117 118/* 119 * section 6 of draft-brezak-win2k-krb-rc4-hmac-03 120 * 121 * warning: not for small children 122 */ 123 124static krb5_error_code 125ARCFOUR_subencrypt(krb5_context context, 126 struct _krb5_key_data *key, 127 void *data, 128 size_t len, 129 unsigned usage, 130 void *ivec) 131{ 132 EVP_CIPHER_CTX *ctx; 133 struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5); 134 Checksum k1_c, k2_c, k3_c, cksum; 135 struct _krb5_key_data ke; 136 krb5_keyblock kb; 137 unsigned char t[4]; 138 unsigned char *cdata = data; 139 unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16]; 140 krb5_error_code ret; 141 142 t[0] = (usage >> 0) & 0xFF; 143 t[1] = (usage >> 8) & 0xFF; 144 t[2] = (usage >> 16) & 0xFF; 145 t[3] = (usage >> 24) & 0xFF; 146 147 k1_c.checksum.length = sizeof(k1_c_data); 148 k1_c.checksum.data = k1_c_data; 149 150 ret = _krb5_internal_hmac(context, c, t, sizeof(t), 0, key, &k1_c); 151 if (ret) 152 krb5_abortx(context, "hmac failed"); 153 154 memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data)); 155 156 k2_c.checksum.length = sizeof(k2_c_data); 157 k2_c.checksum.data = k2_c_data; 158 159 ke.key = &kb; 160 kb.keyvalue = k2_c.checksum; 161 162 cksum.checksum.length = 16; 163 cksum.checksum.data = data; 164 165 ret = _krb5_internal_hmac(context, c, cdata + 16, len - 16, 0, &ke, &cksum); 166 if (ret) 167 krb5_abortx(context, "hmac failed"); 168 169 ke.key = &kb; 170 kb.keyvalue = k1_c.checksum; 171 172 k3_c.checksum.length = sizeof(k3_c_data); 173 k3_c.checksum.data = k3_c_data; 174 175 ret = _krb5_internal_hmac(context, c, data, 16, 0, &ke, &k3_c); 176 if (ret) 177 krb5_abortx(context, "hmac failed"); 178 179#if OPENSSL_VERSION_NUMBER < 0x10100000UL 180 EVP_CIPHER_CTX ctxst; 181 ctx = &ctxst; 182 EVP_CIPHER_CTX_init(ctx); 183#else 184 ctx = EVP_CIPHER_CTX_new(); 185#endif 186 187 if (!EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 1)) 188 krb5_abortx(context, "rc4 cipher not supported"); 189 EVP_Cipher(ctx, cdata + 16, cdata + 16, len - 16); 190#if OPENSSL_VERSION_NUMBER < 0x10100000UL 191 EVP_CIPHER_CTX_cleanup(ctx); 192#else 193 EVP_CIPHER_CTX_free(ctx); 194#endif 195 196 memset_s(k1_c_data, sizeof(k1_c_data), 0, sizeof(k1_c_data)); 197 memset_s(k2_c_data, sizeof(k2_c_data), 0, sizeof(k2_c_data)); 198 memset_s(k3_c_data, sizeof(k3_c_data), 0, sizeof(k3_c_data)); 199 return 0; 200} 201 202static krb5_error_code 203ARCFOUR_subdecrypt(krb5_context context, 204 struct _krb5_key_data *key, 205 void *data, 206 size_t len, 207 unsigned usage, 208 void *ivec) 209{ 210 EVP_CIPHER_CTX *ctx; 211 struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5); 212 Checksum k1_c, k2_c, k3_c, cksum; 213 struct _krb5_key_data ke; 214 krb5_keyblock kb; 215 unsigned char t[4]; 216 unsigned char *cdata = data; 217 unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16]; 218 unsigned char cksum_data[16]; 219 krb5_error_code ret; 220 221 t[0] = (usage >> 0) & 0xFF; 222 t[1] = (usage >> 8) & 0xFF; 223 t[2] = (usage >> 16) & 0xFF; 224 t[3] = (usage >> 24) & 0xFF; 225 226 k1_c.checksum.length = sizeof(k1_c_data); 227 k1_c.checksum.data = k1_c_data; 228 229 ret = _krb5_internal_hmac(context, c, t, sizeof(t), 0, key, &k1_c); 230 if (ret) 231 krb5_abortx(context, "hmac failed"); 232 233 memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data)); 234 235 k2_c.checksum.length = sizeof(k2_c_data); 236 k2_c.checksum.data = k2_c_data; 237 238 ke.key = &kb; 239 kb.keyvalue = k1_c.checksum; 240 241 k3_c.checksum.length = sizeof(k3_c_data); 242 k3_c.checksum.data = k3_c_data; 243 244 ret = _krb5_internal_hmac(context, c, cdata, 16, 0, &ke, &k3_c); 245 if (ret) 246 krb5_abortx(context, "hmac failed"); 247 248#if OPENSSL_VERSION_NUMBER < 0x10100000UL 249 EVP_CIPHER_CTX ctxst; 250 ctx = &ctxst; 251 EVP_CIPHER_CTX_init(ctx); 252#else 253 ctx = EVP_CIPHER_CTX_new(); 254#endif 255 if (!EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 0)) 256 krb5_abortx(context, "rc4 cipher not supported"); 257 EVP_Cipher(ctx, cdata + 16, cdata + 16, len - 16); 258#if OPENSSL_VERSION_NUMBER < 0x10100000UL 259 EVP_CIPHER_CTX_cleanup(ctx); 260#else 261 EVP_CIPHER_CTX_free(ctx); 262#endif 263 264 ke.key = &kb; 265 kb.keyvalue = k2_c.checksum; 266 267 cksum.checksum.length = 16; 268 cksum.checksum.data = cksum_data; 269 270 ret = _krb5_internal_hmac(context, c, cdata + 16, len - 16, 0, &ke, &cksum); 271 if (ret) 272 krb5_abortx(context, "hmac failed"); 273 274 memset_s(k1_c_data, sizeof(k1_c_data), 0, sizeof(k1_c_data)); 275 memset_s(k2_c_data, sizeof(k2_c_data), 0, sizeof(k2_c_data)); 276 memset_s(k3_c_data, sizeof(k3_c_data), 0, sizeof(k3_c_data)); 277 278 if (ct_memcmp (cksum.checksum.data, data, 16) != 0) { 279 krb5_clear_error_message (context); 280 return KRB5KRB_AP_ERR_BAD_INTEGRITY; 281 } else { 282 return 0; 283 } 284} 285 286/* 287 * convert the usage numbers used in 288 * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in 289 * draft-brezak-win2k-krb-rc4-hmac-04.txt 290 */ 291 292KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 293_krb5_usage2arcfour(krb5_context context, unsigned *usage) 294{ 295 switch (*usage) { 296 case KRB5_KU_AS_REP_ENC_PART : /* 3 */ 297 *usage = 8; 298 return 0; 299 case KRB5_KU_USAGE_SEAL : /* 22 */ 300 *usage = 13; 301 return 0; 302 case KRB5_KU_USAGE_SIGN : /* 23 */ 303 *usage = 15; 304 return 0; 305 case KRB5_KU_USAGE_SEQ: /* 24 */ 306 *usage = 0; 307 return 0; 308 default : 309 return 0; 310 } 311} 312 313static krb5_error_code 314ARCFOUR_encrypt(krb5_context context, 315 struct _krb5_key_data *key, 316 void *data, 317 size_t len, 318 krb5_boolean encryptp, 319 int usage, 320 void *ivec) 321{ 322 krb5_error_code ret; 323 unsigned keyusage = usage; 324 325 if((ret = _krb5_usage2arcfour (context, &keyusage)) != 0) 326 return ret; 327 328 if (encryptp) 329 return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec); 330 else 331 return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec); 332} 333 334static krb5_error_code 335ARCFOUR_prf(krb5_context context, 336 krb5_crypto crypto, 337 const krb5_data *in, 338 krb5_data *out) 339{ 340 struct _krb5_checksum_type *c = _krb5_find_checksum(CKSUMTYPE_SHA1); 341 krb5_error_code ret; 342 Checksum res; 343 344 ret = krb5_data_alloc(out, c->checksumsize); 345 if (ret) 346 return ret; 347 348 res.checksum.data = out->data; 349 res.checksum.length = out->length; 350 351 ret = _krb5_internal_hmac(context, c, in->data, in->length, 0, &crypto->key, &res); 352 if (ret) 353 krb5_data_free(out); 354 return 0; 355} 356 357 358struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5 = { 359 ETYPE_ARCFOUR_HMAC_MD5, 360 "arcfour-hmac-md5", 361 "rc4-hmac", 362 1, 363 1, 364 8, 365 &keytype_arcfour, 366 &_krb5_checksum_hmac_md5, 367 &_krb5_checksum_hmac_md5, 368 F_SPECIAL | F_WEAK, 369 ARCFOUR_encrypt, 370 0, 371 ARCFOUR_prf 372}; 373