1 /* $NetBSD: crypto-arcfour.c,v 1.4 2019/12/15 22:50:50 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 42 static 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 60 krb5_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 108 struct _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 124 static krb5_error_code 125 ARCFOUR_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 EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 1); 188 EVP_Cipher(ctx, cdata + 16, cdata + 16, len - 16); 189 #if OPENSSL_VERSION_NUMBER < 0x10100000UL 190 EVP_CIPHER_CTX_cleanup(ctx); 191 #else 192 EVP_CIPHER_CTX_free(ctx); 193 #endif 194 195 memset_s(k1_c_data, sizeof(k1_c_data), 0, sizeof(k1_c_data)); 196 memset_s(k2_c_data, sizeof(k2_c_data), 0, sizeof(k2_c_data)); 197 memset_s(k3_c_data, sizeof(k3_c_data), 0, sizeof(k3_c_data)); 198 return 0; 199 } 200 201 static krb5_error_code 202 ARCFOUR_subdecrypt(krb5_context context, 203 struct _krb5_key_data *key, 204 void *data, 205 size_t len, 206 unsigned usage, 207 void *ivec) 208 { 209 EVP_CIPHER_CTX *ctx; 210 struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5); 211 Checksum k1_c, k2_c, k3_c, cksum; 212 struct _krb5_key_data ke; 213 krb5_keyblock kb; 214 unsigned char t[4]; 215 unsigned char *cdata = data; 216 unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16]; 217 unsigned char cksum_data[16]; 218 krb5_error_code ret; 219 220 t[0] = (usage >> 0) & 0xFF; 221 t[1] = (usage >> 8) & 0xFF; 222 t[2] = (usage >> 16) & 0xFF; 223 t[3] = (usage >> 24) & 0xFF; 224 225 k1_c.checksum.length = sizeof(k1_c_data); 226 k1_c.checksum.data = k1_c_data; 227 228 ret = _krb5_internal_hmac(context, c, t, sizeof(t), 0, key, &k1_c); 229 if (ret) 230 krb5_abortx(context, "hmac failed"); 231 232 memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data)); 233 234 k2_c.checksum.length = sizeof(k2_c_data); 235 k2_c.checksum.data = k2_c_data; 236 237 ke.key = &kb; 238 kb.keyvalue = k1_c.checksum; 239 240 k3_c.checksum.length = sizeof(k3_c_data); 241 k3_c.checksum.data = k3_c_data; 242 243 ret = _krb5_internal_hmac(context, c, cdata, 16, 0, &ke, &k3_c); 244 if (ret) 245 krb5_abortx(context, "hmac failed"); 246 247 #if OPENSSL_VERSION_NUMBER < 0x10100000UL 248 EVP_CIPHER_CTX ctxst; 249 ctx = &ctxst; 250 EVP_CIPHER_CTX_init(ctx); 251 #else 252 ctx = EVP_CIPHER_CTX_new(); 253 #endif 254 EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 0); 255 EVP_Cipher(ctx, cdata + 16, cdata + 16, len - 16); 256 #if OPENSSL_VERSION_NUMBER < 0x10100000UL 257 EVP_CIPHER_CTX_cleanup(ctx); 258 #else 259 EVP_CIPHER_CTX_free(ctx); 260 #endif 261 262 ke.key = &kb; 263 kb.keyvalue = k2_c.checksum; 264 265 cksum.checksum.length = 16; 266 cksum.checksum.data = cksum_data; 267 268 ret = _krb5_internal_hmac(context, c, cdata + 16, len - 16, 0, &ke, &cksum); 269 if (ret) 270 krb5_abortx(context, "hmac failed"); 271 272 memset_s(k1_c_data, sizeof(k1_c_data), 0, sizeof(k1_c_data)); 273 memset_s(k2_c_data, sizeof(k2_c_data), 0, sizeof(k2_c_data)); 274 memset_s(k3_c_data, sizeof(k3_c_data), 0, sizeof(k3_c_data)); 275 276 if (ct_memcmp (cksum.checksum.data, data, 16) != 0) { 277 krb5_clear_error_message (context); 278 return KRB5KRB_AP_ERR_BAD_INTEGRITY; 279 } else { 280 return 0; 281 } 282 } 283 284 /* 285 * convert the usage numbers used in 286 * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in 287 * draft-brezak-win2k-krb-rc4-hmac-04.txt 288 */ 289 290 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 291 _krb5_usage2arcfour(krb5_context context, unsigned *usage) 292 { 293 switch (*usage) { 294 case KRB5_KU_AS_REP_ENC_PART : /* 3 */ 295 *usage = 8; 296 return 0; 297 case KRB5_KU_USAGE_SEAL : /* 22 */ 298 *usage = 13; 299 return 0; 300 case KRB5_KU_USAGE_SIGN : /* 23 */ 301 *usage = 15; 302 return 0; 303 case KRB5_KU_USAGE_SEQ: /* 24 */ 304 *usage = 0; 305 return 0; 306 default : 307 return 0; 308 } 309 } 310 311 static krb5_error_code 312 ARCFOUR_encrypt(krb5_context context, 313 struct _krb5_key_data *key, 314 void *data, 315 size_t len, 316 krb5_boolean encryptp, 317 int usage, 318 void *ivec) 319 { 320 krb5_error_code ret; 321 unsigned keyusage = usage; 322 323 if((ret = _krb5_usage2arcfour (context, &keyusage)) != 0) 324 return ret; 325 326 if (encryptp) 327 return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec); 328 else 329 return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec); 330 } 331 332 static krb5_error_code 333 ARCFOUR_prf(krb5_context context, 334 krb5_crypto crypto, 335 const krb5_data *in, 336 krb5_data *out) 337 { 338 struct _krb5_checksum_type *c = _krb5_find_checksum(CKSUMTYPE_SHA1); 339 krb5_error_code ret; 340 Checksum res; 341 342 ret = krb5_data_alloc(out, c->checksumsize); 343 if (ret) 344 return ret; 345 346 res.checksum.data = out->data; 347 res.checksum.length = out->length; 348 349 ret = _krb5_internal_hmac(context, c, in->data, in->length, 0, &crypto->key, &res); 350 if (ret) 351 krb5_data_free(out); 352 return 0; 353 } 354 355 356 struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5 = { 357 ETYPE_ARCFOUR_HMAC_MD5, 358 "arcfour-hmac-md5", 359 "rc4-hmac", 360 1, 361 1, 362 8, 363 &keytype_arcfour, 364 &_krb5_checksum_hmac_md5, 365 &_krb5_checksum_hmac_md5, 366 F_SPECIAL | F_WEAK, 367 ARCFOUR_encrypt, 368 0, 369 ARCFOUR_prf 370 }; 371