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 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(NULL, 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(NULL, 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(NULL, 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_error_code 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 struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5 = { 313 ETYPE_ARCFOUR_HMAC_MD5, 314 "arcfour-hmac-md5", 315 1, 316 1, 317 8, 318 &keytype_arcfour, 319 &_krb5_checksum_hmac_md5, 320 &_krb5_checksum_hmac_md5, 321 F_SPECIAL, 322 ARCFOUR_encrypt, 323 0, 324 NULL 325 }; 326