1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 #pragma ident "%Z%%M% %I% %E% SMI" 6 7 /* 8 * Copyright (c) 2000 by Computer Science Laboratory, 9 * Rensselaer Polytechnic Institute 10 * #include STD_DISCLAIMER 11 */ 12 13 #include <k5-int.h> 14 #include <arcfour.h> 15 16 /* from a random bitstrem, construct a key */ 17 static krb5_error_code 18 k5_arcfour_make_key(krb5_context, const krb5_data *, krb5_keyblock *); 19 20 #ifndef _KERNEL 21 static krb5_error_code 22 setup_arcfour_crypto(CK_SESSION_HANDLE session, 23 const krb5_keyblock *key, 24 KRB5_MECH_TO_PKCS *algos, 25 CK_OBJECT_HANDLE *hKey) 26 { 27 krb5_error_code ret = 0; 28 CK_RV rv; 29 CK_OBJECT_CLASS class = CKO_SECRET_KEY; 30 CK_KEY_TYPE keyType = CKK_RC4; 31 CK_BBOOL true = TRUE, false = FALSE; 32 CK_ATTRIBUTE template[5]; 33 34 if ((rv = get_algo(key->enctype, algos)) != CKR_OK) { 35 KRB5_LOG0(KRB5_ERR, "failure to get algo id in function " 36 "k5_arcfour_decrypt."); 37 return (PKCS_ERR); 38 } 39 40 template[0].type = CKA_CLASS; 41 template[0].pValue = &class; 42 template[0].ulValueLen = sizeof (class); 43 template[1].type = CKA_KEY_TYPE; 44 template[1].pValue = &keyType; 45 template[1].ulValueLen = sizeof (keyType); 46 template[2].type = CKA_TOKEN; 47 template[2].pValue = &false; 48 template[2].ulValueLen = sizeof (false); 49 template[3].type = CKA_ENCRYPT; 50 template[3].pValue = &true; 51 template[3].ulValueLen = sizeof (true); 52 template[4].type = CKA_VALUE; 53 template[4].pValue = key->contents; 54 template[4].ulValueLen = key->length; 55 56 /* Create an object handle for the key */ 57 if ((rv = C_CreateObject(session, template, 58 sizeof(template)/sizeof(CK_ATTRIBUTE), 59 hKey)) != CKR_OK) { 60 KRB5_LOG(KRB5_ERR, "C_CreateObject failed in " 61 "k5_arcfour_decrypt: rv = 0x%x.", rv); 62 ret = PKCS_ERR; 63 } 64 65 return (ret); 66 } 67 #endif /* !_KERNEL */ 68 69 70 /* The workhorse of the arcfour system, this impliments the cipher */ 71 /* ARGSUSED */ 72 static krb5_error_code 73 k5_arcfour_decrypt(krb5_context context, 74 const krb5_keyblock *key, const krb5_data *state, 75 const krb5_data *input, krb5_data *output) 76 { 77 krb5_error_code ret = 0; 78 79 #ifndef _KERNEL 80 CK_RV rv; 81 KRB5_MECH_TO_PKCS algos; 82 CK_OBJECT_HANDLE *kptr = NULL, hKey = CK_INVALID_HANDLE; 83 CK_MECHANISM mechanism; 84 CK_SESSION_HANDLE session = 0; 85 CK_ULONG outlen; 86 int need_init = 0; 87 #endif 88 89 KRB5_LOG0(KRB5_INFO, "k5_arcfour_decrypt start"); 90 if (key->length != 16) 91 return(KRB5_BAD_KEYSIZE); 92 if (input->length != output->length) 93 return(KRB5_BAD_MSIZE); 94 95 #ifndef _KERNEL 96 /* 97 * If RC4 is being used to encrypt a stream of data blocks, 98 * the keys for encrypt and decrypt must be kept separate 99 * so that their associated state data doesn't get mixed up 100 * between operations. The r-cmds (rlogin, rsh, rcp) use 101 * the "init_state" function (see bottom of this module) 102 * to set up and prepare for stream encryption. 103 * 104 * Normally, the RC4 key is used as a single operation 105 * (i.e. call C_Encrypt) instead of a constantly updating 106 * stream cipher (C_EncryptUpdate). In those cases, we just 107 * use a short-term key object defined locally. We don't 108 * have to save state between operations. 109 * 110 * This logic here is to make sure that the keys are tracked 111 * correctly depending on how they are used and that the RC4 112 * context record is properly initialized. 113 */ 114 if (!context->arcfour_ctx.initialized) { 115 session = krb_ctx_hSession(context); 116 /* Just use a local, 1-time only key object */ 117 kptr = (CK_OBJECT_HANDLE *)&hKey; 118 need_init = 1; 119 } else { 120 session = context->arcfour_ctx.dSession; 121 /* If the dKey handle was not defined, we need to initialize one */ 122 if (context->arcfour_ctx.dKey == CK_INVALID_HANDLE) { 123 need_init = 1; 124 /* Use the long-term key object in the RC4 context area */ 125 kptr = &context->arcfour_ctx.dKey; 126 } 127 } 128 129 if (need_init) { 130 ret = setup_arcfour_crypto(session, key, &algos, kptr); 131 if (ret) 132 goto cleanup; 133 134 mechanism.mechanism = algos.enc_algo; 135 mechanism.pParameter = NULL; 136 mechanism.ulParameterLen = 0; 137 138 rv = C_DecryptInit(session, &mechanism, *kptr); 139 140 if (rv != CKR_OK) { 141 KRB5_LOG(KRB5_ERR, "C_DecryptInit failed in " 142 "k5_arcfour_decrypt: rv = 0x%x", rv); 143 ret = PKCS_ERR; 144 goto cleanup; 145 } 146 } 147 148 outlen = (CK_ULONG)output->length; 149 if (context->arcfour_ctx.initialized) 150 rv = C_DecryptUpdate(session, 151 (CK_BYTE_PTR)input->data, 152 (CK_ULONG)input->length, 153 (CK_BYTE_PTR)output->data, 154 (CK_ULONG_PTR)&outlen); 155 else { 156 rv = C_Decrypt(session, 157 (CK_BYTE_PTR)input->data, 158 (CK_ULONG)input->length, 159 (CK_BYTE_PTR)output->data, 160 (CK_ULONG_PTR)&outlen); 161 } 162 output->length = (uint32_t)outlen; 163 164 if (rv != CKR_OK) { 165 KRB5_LOG(KRB5_ERR, 166 "C_DecryptUpdate failed in k5_arcfour_decrypt: " 167 "rv = 0x%x", rv); 168 ret = PKCS_ERR; 169 } 170 cleanup: 171 if (ret) 172 bzero(output->data, input->length); 173 174 /* If we used a 1-time only key object, destroy it now */ 175 if (hKey != CK_INVALID_HANDLE) 176 (void)C_DestroyObject(session, hKey); 177 178 #else /* !_KERNEL */ 179 KRB5_LOG(KRB5_INFO, "key->kef_mt = %ld", (ulong_t) key->kef_mt); 180 ret = k5_ef_crypto((const char *)input->data, (char *)output->data, 181 input->length, (krb5_keyblock *)key, NULL, 0); 182 #endif /* !_KERNEL */ 183 184 KRB5_LOG0(KRB5_INFO, "k5_arcfour_docrypt end"); 185 return (ret); 186 } 187 188 /* ARGSUSED */ 189 static krb5_error_code 190 k5_arcfour_encrypt(krb5_context context, 191 const krb5_keyblock *key, const krb5_data *state, 192 const krb5_data *input, krb5_data *output) 193 { 194 krb5_error_code ret = 0; 195 196 #ifndef _KERNEL 197 CK_RV rv; 198 KRB5_MECH_TO_PKCS algos; 199 CK_MECHANISM mechanism; 200 CK_OBJECT_HANDLE *kptr = NULL, hKey = CK_INVALID_HANDLE; 201 CK_SESSION_HANDLE session; 202 int need_init = 0; 203 CK_ULONG outlen; 204 #endif 205 206 KRB5_LOG0(KRB5_INFO, "k5_arcfour_encrypt start"); 207 if (key->length != 16) 208 return(KRB5_BAD_KEYSIZE); 209 if (input->length != output->length) 210 return(KRB5_BAD_MSIZE); 211 212 #ifndef _KERNEL 213 214 /* 215 * See the comments in the k5_arcfour_decrypt routine (above) 216 * for an explanation of why the key handles are initialized 217 * and used as they are here. 218 */ 219 if (!context->arcfour_ctx.initialized) { 220 session = krb_ctx_hSession(context); 221 kptr = (CK_OBJECT_HANDLE *)&hKey; 222 need_init = 1; 223 } else { 224 session = context->arcfour_ctx.eSession; 225 if (context->arcfour_ctx.eKey == 0) { 226 kptr = &context->arcfour_ctx.eKey; 227 need_init = 1; 228 } 229 } 230 231 if (need_init) { 232 ret = setup_arcfour_crypto(session, key, &algos, kptr); 233 if (ret) 234 goto cleanup; 235 236 mechanism.mechanism = algos.enc_algo; 237 mechanism.pParameter = NULL; 238 mechanism.ulParameterLen = 0; 239 240 rv = C_EncryptInit(session, &mechanism, *kptr); 241 242 if (rv != CKR_OK) { 243 KRB5_LOG(KRB5_ERR, "C_EncryptInit failed in " 244 "k5_arcfour_encrypt: rv = 0x%x", rv); 245 ret = PKCS_ERR; 246 goto cleanup; 247 } 248 } 249 250 /* 251 * If we've initialize the stream for use with r-commands, 252 * use the open-ended session handle and call. 253 */ 254 outlen = (CK_ULONG)output->length; 255 if (context->arcfour_ctx.initialized) 256 rv = C_EncryptUpdate(session, 257 (CK_BYTE_PTR)input->data, 258 (CK_ULONG)input->length, 259 (CK_BYTE_PTR)output->data, 260 (CK_ULONG_PTR)&outlen); 261 else { 262 rv = C_Encrypt(session, 263 (CK_BYTE_PTR)input->data, 264 (CK_ULONG)input->length, 265 (CK_BYTE_PTR)output->data, 266 (CK_ULONG_PTR)&outlen); 267 } 268 output->length = (uint32_t)outlen; 269 270 if (rv != CKR_OK) { 271 KRB5_LOG(KRB5_ERR, 272 "C_EncryptUpdate failed in k5_arcfour_encrypt: " 273 "rv = 0x%x", rv); 274 ret = PKCS_ERR; 275 } 276 cleanup: 277 final_cleanup: 278 if (ret) 279 bzero(output->data, input->length); 280 281 if (hKey != CK_INVALID_HANDLE) 282 (void)C_DestroyObject(session, hKey); 283 284 #else /* !_KERNEL */ 285 KRB5_LOG1(KRB5_INFO, "key->kef_mt = %ld key->key_tmpl = %ld", 286 (ulong_t) key->kef_mt, (ulong_t) key->key_tmpl); 287 ret = k5_ef_crypto((const char *)input->data, (char *)output->data, 288 input->length, (krb5_keyblock *)key, NULL, 1); 289 #endif /* !_KERNEL */ 290 291 KRB5_LOG0(KRB5_INFO, "k5_arcfour_docrypt end"); 292 return (ret); 293 } 294 295 /* ARGSUSED */ 296 static krb5_error_code 297 k5_arcfour_make_key(krb5_context context, 298 const krb5_data *randombits, krb5_keyblock *key) 299 { 300 krb5_error_code ret = 0; 301 KRB5_LOG0(KRB5_INFO, "k5_arcfour_make_key() start\n"); 302 303 if (key->length != 16) 304 return(KRB5_BAD_KEYSIZE); 305 if (randombits->length != 16) 306 return(KRB5_CRYPTO_INTERNAL); 307 308 key->magic = KV5M_KEYBLOCK; 309 key->length = 16; 310 key->dk_list = NULL; 311 #ifdef _KERNEL 312 key->kef_key.ck_data = NULL; 313 key->key_tmpl = NULL; 314 ret = init_key_kef(context->kef_cipher_mt, key); 315 #else 316 key->hKey = CK_INVALID_HANDLE; 317 ret = init_key_uef(krb_ctx_hSession(context), key); 318 #endif /* _KERNEL */ 319 320 bcopy(randombits->data, key->contents, randombits->length); 321 322 KRB5_LOG0(KRB5_INFO, "k5_arcfour_make_key() end\n"); 323 return (ret); 324 } 325 326 /*ARGSUSED*/ 327 static krb5_error_code 328 k5_arcfour_init_state (krb5_context context, 329 const krb5_keyblock *key, 330 krb5_keyusage keyusage, krb5_data *new_state) 331 { 332 krb5_error_code retval = 0; 333 #ifndef _KERNEL 334 if (!context->arcfour_ctx.initialized) { 335 retval = krb5_open_pkcs11_session(&context->arcfour_ctx.eSession); 336 if (retval) 337 return (retval); 338 retval = krb5_open_pkcs11_session(&context->arcfour_ctx.dSession); 339 if (retval) 340 return (retval); 341 context->arcfour_ctx.initialized = 1; 342 context->arcfour_ctx.eKey = CK_INVALID_HANDLE; 343 context->arcfour_ctx.dKey = CK_INVALID_HANDLE; 344 } 345 #endif 346 return (retval); 347 } 348 349 /* Since the arcfour cipher is identical going forwards and backwards, 350 we just call "docrypt" directly 351 */ 352 const struct krb5_enc_provider krb5int_enc_arcfour = { 353 1, 354 16, 16, 355 k5_arcfour_encrypt, 356 k5_arcfour_decrypt, 357 k5_arcfour_make_key, 358 k5_arcfour_init_state, 359 krb5int_default_free_state 360 }; 361