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