1 /* 2 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 10 ARCFOUR cipher (based on a cipher posted on the Usenet in Spring-95). 11 This cipher is widely believed and has been tested to be equivalent 12 with the RC4 cipher from RSA Data Security, Inc. (RC4 is a trademark 13 of RSA Data Security) 14 15 */ 16 #include <k5-int.h> 17 #include <arcfour.h> 18 19 /* salt string used for exportable ARCFOUR */ 20 static const char *l40 = "fortybits"; 21 22 void 23 krb5_arcfour_encrypt_length(enc, hash, inputlen, length) 24 const struct krb5_enc_provider *enc; 25 const struct krb5_hash_provider *hash; 26 size_t inputlen; 27 size_t *length; 28 { 29 size_t blocksize, hashsize; 30 31 (*(enc->block_size))(&blocksize); 32 (*(hash->hash_size))(&hashsize); 33 34 /* checksum + (confounder + inputlen, in even blocksize) */ 35 *length = hashsize + krb5_roundup(8 + inputlen, blocksize); 36 } 37 38 krb5_keyusage 39 krb5int_arcfour_translate_usage(krb5_keyusage usage) 40 { 41 switch (usage) { 42 case 1: /* AS-REQ PA-ENC-TIMESTAMP padata timestamp, */ 43 return 1; 44 case 2: /* ticket from kdc */ 45 return 2; 46 case 3: /* as-rep encrypted part */ 47 return 8; 48 case 4: /* tgs-req authz data */ 49 return 4; 50 case 5: /* tgs-req authz data in subkey */ 51 return 5; 52 case 6: /* tgs-req authenticator cksum */ 53 return 6; 54 case 7: /* tgs-req authenticator */ 55 return 7; 56 case 8: 57 return 8; 58 case 9: /* tgs-rep encrypted with subkey */ 59 return 8; 60 case 10: /* ap-rep authentication cksum */ 61 return 10; /* xxx Microsoft never uses this*/ 62 case 11: /* app-req authenticator */ 63 return 11; 64 case 12: /* app-rep encrypted part */ 65 return 12; 66 case 23: /* sign wrap token*/ 67 return 13; 68 default: 69 return usage; 70 } 71 } 72 73 krb5_error_code 74 krb5_arcfour_encrypt(context, enc, hash, key, usage, ivec, input, output) 75 krb5_context context; 76 const struct krb5_enc_provider *enc; 77 const struct krb5_hash_provider *hash; 78 const krb5_keyblock *key; 79 krb5_keyusage usage; 80 const krb5_data *ivec; 81 const krb5_data *input; 82 krb5_data *output; 83 { 84 krb5_keyblock k1, k2, k3; 85 krb5_keyblock *kptr; 86 krb5_data d1, d2, d3, salt, plaintext, checksum, ciphertext, confounder; 87 krb5_keyusage ms_usage; 88 size_t keylength, keybytes, blocksize, hashsize; 89 krb5_error_code ret = 0; 90 91 (*(enc->block_size))(&blocksize); 92 (*(enc->keysize))(&keybytes, &keylength); 93 (*(hash->hash_size))(&hashsize); 94 95 bzero(&d2, sizeof(krb5_data)); 96 bzero(&k2, sizeof(krb5_keyblock)); 97 /* 98 * d1 is the contents buffer for key k1. 99 * k1 = HMAC(input_key, salt) 100 */ 101 d1.length=keybytes; 102 d1.data=MALLOC(d1.length); 103 if (d1.data == NULL) 104 return (ENOMEM); 105 bcopy(key, &k1, sizeof (krb5_keyblock)); 106 k1.length=d1.length; 107 k1.contents= (void *) d1.data; 108 109 /* 110 * d2 is the contents of key 'k2', which is used to generate the 111 * checksum field. 'd2' == 'd1' when not using the exportable 112 * enctype. This is only needed when using the exportable 113 * enctype. 114 */ 115 if (key->enctype==ENCTYPE_ARCFOUR_HMAC_EXP) { 116 d2.length=keybytes; 117 d2.data=MALLOC(d2.length); 118 if (d2.data == NULL) { 119 FREE(d1.data, d1.length); 120 return (ENOMEM); 121 } 122 bcopy(key, &k2, sizeof (krb5_keyblock)); 123 k2.length=d2.length; 124 k2.contents=(void *) d2.data; 125 } 126 127 /* 128 * d3 will hold the contents of the final key used for the 129 * encryption step. 'k3' is the key structure that has 'd3' 130 * as its 'contents' field. 131 * k3 = HMAC(k1, checksum) 132 */ 133 d3.length=keybytes; 134 d3.data=MALLOC(d3.length); 135 if (d3.data == NULL) { 136 FREE(d1.data, d1.length); 137 if (d2.data) 138 FREE(d2.data, d2.length); 139 return (ENOMEM); 140 } 141 bcopy(key, &k3, sizeof (krb5_keyblock)); 142 k3.length=d3.length; 143 k3.contents= (void *) d3.data; 144 145 salt.length=14; 146 salt.data=MALLOC(salt.length); 147 148 if (salt.data == NULL) { 149 FREE(d1.data, d1.length); 150 if (d2.data) 151 FREE(d2.data, d2.length); 152 FREE(d3.data, d3.length); 153 return (ENOMEM); 154 } 155 156 /* is "input" already blocksize aligned? if it is, then we need this 157 step, otherwise we do not */ 158 plaintext.length=krb5_roundup(input->length+CONFOUNDERLENGTH,blocksize); 159 plaintext.data=MALLOC(plaintext.length); 160 161 if (plaintext.data == NULL) { 162 FREE(d1.data, d1.length); 163 if (d2.data) 164 FREE(d2.data, d2.length); 165 FREE(d3.data, d3.length); 166 FREE(salt.data, salt.length); 167 return(ENOMEM); 168 } 169 bzero(plaintext.data, plaintext.length); 170 171 /* setup convienient pointers into the allocated data */ 172 checksum.length=hashsize; 173 checksum.data=output->data; 174 175 ciphertext.length=krb5_roundup(input->length+CONFOUNDERLENGTH,blocksize); 176 ciphertext.data=output->data+hashsize; 177 178 confounder.length=CONFOUNDERLENGTH; 179 confounder.data=plaintext.data; 180 181 output->length = plaintext.length+hashsize; 182 183 /* begin the encryption, computer K1 */ 184 ms_usage=krb5int_arcfour_translate_usage(usage); 185 if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) { 186 (void) strncpy(salt.data, l40, salt.length); 187 salt.data[10]=ms_usage & 0xff; 188 salt.data[11]=(ms_usage >> 8) & 0xff; 189 salt.data[12]=(ms_usage >> 16) & 0xff; 190 salt.data[13]=(ms_usage >> 24) & 0xff; 191 } else { 192 salt.length=4; 193 salt.data[0]=ms_usage & 0xff; 194 salt.data[1]=(ms_usage >> 8) & 0xff; 195 salt.data[2]=(ms_usage >> 16) & 0xff; 196 salt.data[3]=(ms_usage >> 24) & 0xff; 197 } 198 199 #ifdef _KERNEL 200 ret = krb5_hmac(context, key, &salt, &d1); 201 #else 202 ret = krb5_hmac(context, hash, key, 1, &salt, &d1); 203 #endif /* _KERNEL */ 204 if (ret != 0) 205 goto cleanup; 206 207 if (key->enctype==ENCTYPE_ARCFOUR_HMAC_EXP) { 208 bcopy(k1.contents, k2.contents, k2.length); 209 (void) memset(k1.contents+7, 0xab, 9); 210 kptr = &k2; 211 } else { 212 kptr = &k1; 213 } 214 215 /* create a confounder block */ 216 ret=krb5_c_random_make_octets(context, &confounder); 217 bcopy(input->data, plaintext.data+confounder.length, input->length); 218 if (ret) 219 goto cleanup; 220 221 /* 222 * Compute the HMAC checksum field. 223 * checksum = HMAC(k1/k2, plaintext); 224 * k2 used when key->enctype==ENCTYPE_ARCFOUR_HMAC_EXP 225 */ 226 #ifdef _KERNEL 227 ret = krb5_hmac(context, kptr, &plaintext, &checksum); 228 #else 229 ret = krb5_hmac(context, hash, kptr, 1, &plaintext, &checksum); 230 #endif /* _KERNEL */ 231 if (ret) 232 goto cleanup; 233 234 /* 235 * The final encryption key is the HMAC of the checksum 236 * using k1 237 * 238 * k3 = HMAC(k1, checksum); 239 * == or (in other terms) == 240 * k3 = HMAC((HMAC(input_key,salt), HMAC(k1, plaintext)); 241 */ 242 #ifdef _KERNEL 243 ret = krb5_hmac(context, &k1, &checksum, &d3); 244 #else 245 ret = krb5_hmac(context, hash, &k1, 1, &checksum, &d3); 246 #endif /* _KERNEL */ 247 if (ret) 248 goto cleanup; 249 250 ret = (*(enc->encrypt))(context, &k3, ivec, &plaintext, &ciphertext); 251 252 cleanup: 253 bzero(d1.data, d1.length); 254 if (d2.data) { 255 bzero(d2.data, d2.length); 256 FREE(d2.data, d2.length); 257 } 258 bzero(d3.data, d3.length); 259 bzero(salt.data, salt.length); 260 bzero(plaintext.data, plaintext.length); 261 262 FREE(d1.data, d1.length); 263 FREE(d3.data, d3.length); 264 FREE(salt.data, salt.length); 265 FREE(plaintext.data, plaintext.length); 266 return (ret); 267 } 268 269 /* This is the arcfour-hmac decryption routine */ 270 krb5_error_code 271 krb5_arcfour_decrypt(context, enc, hash, key, usage, ivec, input, output) 272 krb5_context context; 273 const struct krb5_enc_provider *enc; 274 const struct krb5_hash_provider *hash; 275 const krb5_keyblock *key; 276 krb5_keyusage usage; 277 const krb5_data *ivec; 278 const krb5_data *input; 279 krb5_data *output; 280 { 281 krb5_keyblock k1,k2,k3, *kptr; 282 krb5_data d1,d2,d3,salt,ciphertext,plaintext,checksum; 283 krb5_keyusage ms_usage; 284 size_t keybytes, keylength, hashsize, blocksize; 285 krb5_error_code ret; 286 287 (*(enc->block_size))(&blocksize); 288 (*(enc->keysize))(&keybytes, &keylength); 289 (*(hash->hash_size))(&hashsize); 290 291 bzero(&d2, sizeof(krb5_data)); 292 bzero(&k2, sizeof(krb5_keyblock)); 293 /* 294 * d1 is the contents buffer for key k1. 295 * k1 = HMAC(input_key, salt) 296 */ 297 d1.length=keybytes; 298 d1.data=MALLOC(d1.length); 299 if (d1.data == NULL) 300 return (ENOMEM); 301 (void) bcopy(key, &k1, sizeof (krb5_keyblock)); 302 k1.length=d1.length; 303 k1.contents= (void *) d1.data; 304 305 /* 306 * d2 is the contents of key 'k2', which is used to generate the 307 * checksum field. 'd2' == 'd1' when not using the exportable 308 * enctype. This is only needed when using the exportable 309 * enctype. 310 */ 311 if (key->enctype==ENCTYPE_ARCFOUR_HMAC_EXP) { 312 d2.length=keybytes; 313 d2.data=MALLOC(d2.length); 314 if (d2.data == NULL) { 315 FREE(d1.data, d1.length); 316 return (ENOMEM); 317 } 318 (void) bcopy(key, &k2, sizeof(krb5_keyblock)); 319 k2.length=d2.length; 320 k2.contents= (void *) d2.data; 321 } 322 323 /* 324 * d3 will hold the contents of the final key used for the 325 * encryption step. 'k3' is the key structure that has 'd3' 326 * as its 'contents' field. 327 * k3 = HMAC(k1, checksum) 328 */ 329 d3.length=keybytes; 330 d3.data=MALLOC(d3.length); 331 if (d3.data == NULL) { 332 FREE(d1.data, d1.length); 333 if (d2.data) 334 FREE(d2.data, d2.length); 335 return (ENOMEM); 336 } 337 bcopy(key, &k3, sizeof(krb5_keyblock)); 338 k3.length=d3.length; 339 k3.contents= (void *) d3.data; 340 341 salt.length=14; 342 salt.data=MALLOC(salt.length); 343 if(salt.data==NULL) { 344 FREE(d1.data, d1.length); 345 if (d2.data) 346 FREE(d2.data, d2.length); 347 FREE(d3.data, d3.length); 348 return (ENOMEM); 349 } 350 351 ciphertext.length=input->length-hashsize; 352 ciphertext.data=input->data+hashsize; 353 354 plaintext.length=ciphertext.length; 355 plaintext.data=MALLOC(plaintext.length); 356 if (plaintext.data == NULL) { 357 FREE(d1.data, d1.length); 358 if (d2.data) 359 FREE(d2.data, d2.length); 360 FREE(d3.data, d3.length); 361 FREE(salt.data, salt.length); 362 return (ENOMEM); 363 } 364 365 checksum.length=hashsize; 366 checksum.data=input->data; 367 368 /* compute the salt */ 369 ms_usage=krb5int_arcfour_translate_usage(usage); 370 if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) { 371 (void) strncpy(salt.data, l40, salt.length); 372 salt.data[10]=ms_usage & 0xff; 373 salt.data[11]=(ms_usage>>8) & 0xff; 374 salt.data[12]=(ms_usage>>16) & 0xff; 375 salt.data[13]=(ms_usage>>24) & 0xff; 376 } else { 377 salt.length=4; 378 salt.data[0]=ms_usage & 0xff; 379 salt.data[1]=(ms_usage>>8) & 0xff; 380 salt.data[2]=(ms_usage>>16) & 0xff; 381 salt.data[3]=(ms_usage>>24) & 0xff; 382 } 383 384 #ifdef _KERNEL 385 ret=krb5_hmac(context, key, &salt, &d1); 386 #else 387 ret=krb5_hmac(context, hash, key, 1, &salt, &d1); 388 #endif /* _KERNEL */ 389 if (ret) 390 goto cleanup; 391 392 if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) { 393 bcopy(k1.contents, k2.contents, d1.length); 394 (void) memset(k1.contents+7, 0xab, 9); 395 kptr = &k2; 396 } else { 397 kptr = &k1; 398 } 399 400 #ifdef _KERNEL 401 ret = krb5_hmac(context, &k1, &checksum, &d3); 402 #else 403 ret = krb5_hmac(context, hash, &k1, 1, &checksum, &d3); 404 #endif /* _KERNEL */ 405 406 if (ret) 407 goto cleanup; 408 409 ret=(*(enc->decrypt))(context, &k3, ivec, &ciphertext, &plaintext); 410 if (ret) 411 goto cleanup; 412 413 #ifdef _KERNEL 414 ret = krb5_hmac(context, kptr, &plaintext, &d1); 415 #else 416 ret = krb5_hmac(context, hash, kptr, 1, &plaintext, &d1); 417 #endif /* _KERNEL */ 418 419 if (ret) 420 goto cleanup; 421 422 if (bcmp(checksum.data, d1.data, hashsize) != 0) { 423 ret=KRB5KRB_AP_ERR_BAD_INTEGRITY; 424 goto cleanup; 425 } 426 427 bcopy(plaintext.data+CONFOUNDERLENGTH, output->data, 428 (plaintext.length-CONFOUNDERLENGTH)); 429 output->length=plaintext.length-CONFOUNDERLENGTH; 430 431 cleanup: 432 bzero(d1.data, d1.length); 433 if (d2.data) { 434 bzero(d2.data, d2.length); 435 FREE(d2.data, d2.length); 436 } 437 bzero(d3.data, d2.length); 438 bzero(salt.data, salt.length); 439 bzero(plaintext.data, plaintext.length); 440 441 FREE(d1.data, d1.length); 442 FREE(d3.data, d3.length); 443 FREE(salt.data, salt.length); 444 FREE(plaintext.data, plaintext.length); 445 446 return (ret); 447 } 448 449