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