1 /* 2 * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 /* 35 * ARCFOUR 36 */ 37 38 #include "krb5_locl.h" 39 40 static struct _krb5_key_type keytype_arcfour = { 41 ENCTYPE_ARCFOUR_HMAC_MD5, 42 "arcfour", 43 128, 44 16, 45 sizeof(struct _krb5_evp_schedule), 46 NULL, 47 _krb5_evp_schedule, 48 _krb5_arcfour_salt, 49 NULL, 50 _krb5_evp_cleanup, 51 EVP_rc4 52 }; 53 54 /* 55 * checksum according to section 5. of draft-brezak-win2k-krb-rc4-hmac-03.txt 56 */ 57 58 krb5_error_code 59 _krb5_HMAC_MD5_checksum(krb5_context context, 60 struct _krb5_key_data *key, 61 const void *data, 62 size_t len, 63 unsigned usage, 64 Checksum *result) 65 { 66 EVP_MD_CTX *m; 67 struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5); 68 const char signature[] = "signaturekey"; 69 Checksum ksign_c; 70 struct _krb5_key_data ksign; 71 krb5_keyblock kb; 72 unsigned char t[4]; 73 unsigned char tmp[16]; 74 unsigned char ksign_c_data[16]; 75 krb5_error_code ret; 76 77 m = EVP_MD_CTX_create(); 78 if (m == NULL) { 79 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 80 return ENOMEM; 81 } 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(NULL, 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(NULL, 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(NULL, c, data, 16, 0, &ke, &k3_c); 176 if (ret) 177 krb5_abortx(context, "hmac failed"); 178 179 ctx = EVP_CIPHER_CTX_new(); 180 if (ctx == NULL) 181 krb5_abortx(context, "malloc failed"); 182 183 EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 1); 184 EVP_Cipher(ctx, cdata + 16, cdata + 16, len - 16); 185 EVP_CIPHER_CTX_free(ctx); 186 187 memset (k1_c_data, 0, sizeof(k1_c_data)); 188 memset (k2_c_data, 0, sizeof(k2_c_data)); 189 memset (k3_c_data, 0, sizeof(k3_c_data)); 190 return 0; 191 } 192 193 static krb5_error_code 194 ARCFOUR_subdecrypt(krb5_context context, 195 struct _krb5_key_data *key, 196 void *data, 197 size_t len, 198 unsigned usage, 199 void *ivec) 200 { 201 EVP_CIPHER_CTX *ctx; 202 struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5); 203 Checksum k1_c, k2_c, k3_c, cksum; 204 struct _krb5_key_data ke; 205 krb5_keyblock kb; 206 unsigned char t[4]; 207 unsigned char *cdata = data; 208 unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16]; 209 unsigned char cksum_data[16]; 210 krb5_error_code ret; 211 212 t[0] = (usage >> 0) & 0xFF; 213 t[1] = (usage >> 8) & 0xFF; 214 t[2] = (usage >> 16) & 0xFF; 215 t[3] = (usage >> 24) & 0xFF; 216 217 k1_c.checksum.length = sizeof(k1_c_data); 218 k1_c.checksum.data = k1_c_data; 219 220 ret = _krb5_internal_hmac(NULL, c, t, sizeof(t), 0, key, &k1_c); 221 if (ret) 222 krb5_abortx(context, "hmac failed"); 223 224 memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data)); 225 226 k2_c.checksum.length = sizeof(k2_c_data); 227 k2_c.checksum.data = k2_c_data; 228 229 ke.key = &kb; 230 kb.keyvalue = k1_c.checksum; 231 232 k3_c.checksum.length = sizeof(k3_c_data); 233 k3_c.checksum.data = k3_c_data; 234 235 ret = _krb5_internal_hmac(NULL, c, cdata, 16, 0, &ke, &k3_c); 236 if (ret) 237 krb5_abortx(context, "hmac failed"); 238 239 ctx = EVP_CIPHER_CTX_new(); 240 if (ctx == NULL) 241 krb5_abortx(context, "malloc failed"); 242 EVP_CipherInit_ex(ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 0); 243 EVP_Cipher(ctx, cdata + 16, cdata + 16, len - 16); 244 EVP_CIPHER_CTX_free(ctx); 245 246 ke.key = &kb; 247 kb.keyvalue = k2_c.checksum; 248 249 cksum.checksum.length = 16; 250 cksum.checksum.data = cksum_data; 251 252 ret = _krb5_internal_hmac(NULL, c, cdata + 16, len - 16, 0, &ke, &cksum); 253 if (ret) 254 krb5_abortx(context, "hmac failed"); 255 256 memset (k1_c_data, 0, sizeof(k1_c_data)); 257 memset (k2_c_data, 0, sizeof(k2_c_data)); 258 memset (k3_c_data, 0, sizeof(k3_c_data)); 259 260 if (ct_memcmp (cksum.checksum.data, data, 16) != 0) { 261 krb5_clear_error_message (context); 262 return KRB5KRB_AP_ERR_BAD_INTEGRITY; 263 } else { 264 return 0; 265 } 266 } 267 268 /* 269 * convert the usage numbers used in 270 * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in 271 * draft-brezak-win2k-krb-rc4-hmac-04.txt 272 */ 273 274 krb5_error_code 275 _krb5_usage2arcfour(krb5_context context, unsigned *usage) 276 { 277 switch (*usage) { 278 case KRB5_KU_AS_REP_ENC_PART : /* 3 */ 279 *usage = 8; 280 return 0; 281 case KRB5_KU_USAGE_SEAL : /* 22 */ 282 *usage = 13; 283 return 0; 284 case KRB5_KU_USAGE_SIGN : /* 23 */ 285 *usage = 15; 286 return 0; 287 case KRB5_KU_USAGE_SEQ: /* 24 */ 288 *usage = 0; 289 return 0; 290 default : 291 return 0; 292 } 293 } 294 295 static krb5_error_code 296 ARCFOUR_encrypt(krb5_context context, 297 struct _krb5_key_data *key, 298 void *data, 299 size_t len, 300 krb5_boolean encryptp, 301 int usage, 302 void *ivec) 303 { 304 krb5_error_code ret; 305 unsigned keyusage = usage; 306 307 if((ret = _krb5_usage2arcfour (context, &keyusage)) != 0) 308 return ret; 309 310 if (encryptp) 311 return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec); 312 else 313 return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec); 314 } 315 316 struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5 = { 317 ETYPE_ARCFOUR_HMAC_MD5, 318 "arcfour-hmac-md5", 319 1, 320 1, 321 8, 322 &keytype_arcfour, 323 &_krb5_checksum_hmac_md5, 324 &_krb5_checksum_hmac_md5, 325 F_SPECIAL, 326 ARCFOUR_encrypt, 327 0, 328 NULL 329 }; 330