Exemplo n.º 1
0
/*ARGSUSED*/
krb5_error_code KRB5_CALLCONV
krb5_c_decrypt(krb5_context context, const krb5_keyblock *key,
	    krb5_keyusage usage, const krb5_data *ivec,
	    const krb5_enc_data *input, krb5_data *output)
{
    int i;
    krb5_error_code ret = 0;

    for (i=0; i<krb5_enctypes_length; i++) {
	if (krb5_enctypes_list[i].etype == key->enctype)
	    break;
    }

    if (i == krb5_enctypes_length)
	return(KRB5_BAD_ENCTYPE);

    if ((input->enctype != ENCTYPE_UNKNOWN) &&
	(krb5_enctypes_list[i].etype != input->enctype))
	return(KRB5_BAD_ENCTYPE);

#ifdef _KERNEL
    context->kef_cipher_mt = krb5_enctypes_list[i].kef_cipher_mt;
    context->kef_hash_mt = krb5_enctypes_list[i].kef_hash_mt;
    if (key->kef_key.ck_data == NULL)
      ret = init_key_kef(context->kef_cipher_mt, (krb5_keyblock *)key);
    if (ret)
	    return(ret);

#else
    if ((ret = init_key_uef(krb_ctx_hSession(context), (krb5_keyblock *)key)))
	return (ret);

#endif /* _KERNEL */

    return((*(krb5_enctypes_list[i].decrypt))
	   (context, krb5_enctypes_list[i].enc, krb5_enctypes_list[i].hash,
	    key, usage, ivec, &input->ciphertext, output));
}
Exemplo n.º 2
0
krb5_error_code
gss_krb5int_make_seal_token_v3 (krb5_context context,
				krb5_gss_ctx_id_rec *ctx,
				const gss_buffer_desc * message,
				gss_buffer_t token,
				int conf_req_flag, int toktype)
{
    size_t bufsize = 16;
    unsigned char *outbuf = 0;
    krb5_error_code err;
    int key_usage;
    unsigned char acceptor_flag;
    const gss_buffer_desc *message2 = message;
#ifdef CFX_EXERCISE
    size_t rrc;
#endif
    size_t ec;
    unsigned short tok_id;
    krb5_checksum sum;
    krb5_keyblock *key;

    ASSERT(toktype != KG_TOK_SEAL_MSG || ctx->enc != 0);
    ASSERT(ctx->big_endian == 0);

    acceptor_flag = ctx->initiate ? 0 : FLAG_SENDER_IS_ACCEPTOR;
    key_usage = (toktype == KG_TOK_WRAP_MSG
		 ? (ctx->initiate
		    ? KG_USAGE_INITIATOR_SEAL
		    : KG_USAGE_ACCEPTOR_SEAL)
		 : (ctx->initiate
		    ? KG_USAGE_INITIATOR_SIGN
		    : KG_USAGE_ACCEPTOR_SIGN));
    if (ctx->have_acceptor_subkey) {
	key = ctx->acceptor_subkey;
    } else {
	key = ctx->enc;
    }

#ifdef _KERNEL
    context->kef_cipher_mt = get_cipher_mech_type(context, key);
    context->kef_hash_mt = get_hash_mech_type(context, key);

    if ((err = init_key_kef(context->kef_cipher_mt, key))) {
	return (GSS_S_FAILURE);
    }

#endif /* _KERNEL */

#ifdef CFX_EXERCISE
    {
	static int initialized = 0;
	if (!initialized) {
	    srand(time(0));
	    initialized = 1;
	}
    }
#endif

    if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
	krb5_data plain;
	krb5_enc_data cipher;
	size_t ec_max;
	size_t tlen;

	/* 300: Adds some slop.  */
	if (SIZE_MAX - 300 < message->length)
	    return ENOMEM;
	ec_max = SIZE_MAX - message->length - 300;
	if (ec_max > 0xffff)
	    ec_max = 0xffff;
	/*
	 * EC should really be a multiple (1) of the number of octets that
	 * the cryptosystem would pad by if we didn't have the filler.
	 *
	 * For AES-CTS this will always be 0 and we expect no further
	 * enctypes, so there should be no issue here.
	 */
	ec = 0;
	plain.length = message->length + 16 + ec;
	plain.data = MALLOC(plain.length);
	if (plain.data == NULL)
	    return ENOMEM;

	/* Get size of ciphertext.  */
	if ((err = krb5_c_encrypt_length(context,
		ctx->enc->enctype, plain.length, &tlen))) {
	    FREE(plain.data, plain.length);
	    return (err);
        }
	
	bufsize = 16 + tlen;
	/* Allocate space for header plus encrypted data.  */
	outbuf = MALLOC(bufsize);
	if (outbuf == NULL) {
	    FREE(plain.data, plain.length);
	    return ENOMEM;
	}

	/* TOK_ID */
	store_16_be(0x0504, outbuf);
	/* flags */
	outbuf[2] = (acceptor_flag
		     | (conf_req_flag ? FLAG_WRAP_CONFIDENTIAL : 0)
		     | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
	/* filler */
	outbuf[3] = 0xff;
	/* EC */
	store_16_be(ec, outbuf+4);
	/* RRC */
	store_16_be(0, outbuf+6);
	store_64_be(ctx->seq_send, outbuf+8);

	(void) memcpy(plain.data, message->value, message->length);
	(void) memset(plain.data + message->length, 'x', ec);
	(void) memcpy(plain.data + message->length + ec, outbuf, 16);

	/* Should really use scatter/gather crypto interfaces */
	cipher.ciphertext.data = (char *)outbuf + 16;
	cipher.ciphertext.length = bufsize - 16;
	cipher.enctype = key->enctype;
	err = krb5_c_encrypt(context, key, key_usage, 0, &plain, &cipher);
	(void) bzero(plain.data, plain.length);
	FREE(plain.data, plain.length);
	plain.data = 0;
	if (err)
	    goto error;

	/* Now that we know we're returning a valid token....  */
	ctx->seq_send++;

#ifdef CFX_EXERCISE
	rrc = rand() & 0xffff;
	if (rotate_left(outbuf+16, bufsize-16,
			(bufsize-16) - (rrc % (bufsize - 16))))
	    store_16_be(rrc, outbuf+6);
	/* If the rotate fails, don't worry about it.  */
#endif
    } else if (toktype == KG_TOK_WRAP_MSG && !conf_req_flag) {
	krb5_data plain;

	/* Here, message is the application-supplied data; message2 is
	   what goes into the output token.  They may be the same, or
	   message2 may be empty (for MIC).  */

	tok_id = 0x0504;

    wrap_with_checksum:
	plain.length = message->length + 16;
	plain.data = MALLOC(message->length + 16);
	if (plain.data == NULL)
	    return ENOMEM;

	if (ctx->cksum_size > 0xffff) {
	    FREE(plain.data, plain.length);
	    return EINVAL;
	}

	bufsize = 16 + message2->length + ctx->cksum_size;
	outbuf = MALLOC(bufsize);
	if (outbuf == NULL) {
	    FREE(plain.data, plain.length);
	    plain.data = 0;
	    err = ENOMEM;
	    goto error;
	}

	/* TOK_ID */
	store_16_be(tok_id, outbuf);
	/* flags */
	outbuf[2] = (acceptor_flag
		     | (ctx->have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0));
	/* filler */
	outbuf[3] = 0xff;
	if (toktype == KG_TOK_WRAP_MSG) {
	    /* Use 0 for checksum calculation, substitute
	       checksum length later.  */
	    /* EC */
	    store_16_be(0, outbuf+4);
	    /* RRC */
	    store_16_be(0, outbuf+6);
	} else {
	    /* MIC and DEL store 0xFF in EC and RRC.  */
	    store_16_be(0xffff, outbuf+4);
	    store_16_be(0xffff, outbuf+6);
	}
	store_64_be(ctx->seq_send, outbuf+8);

	(void) memcpy(plain.data, message->value, message->length);
	(void) memcpy(plain.data + message->length, outbuf, 16);

	/* Fill in the output token -- data contents, if any, and
	   space for the checksum.  */
	if (message2->length)
	    (void) memcpy(outbuf + 16, message2->value, message2->length);

	sum.contents = outbuf + 16 + message2->length;
	sum.length = ctx->cksum_size;

	err = krb5_c_make_checksum(context, ctx->cksumtype, key,
				   key_usage, &plain, &sum);
	bzero(plain.data, plain.length);
	FREE(plain.data, plain.length);
	plain.data = 0;
	if (err) {
	    bzero(outbuf,bufsize);
	    err = KRB5KRB_AP_ERR_BAD_INTEGRITY;
	    goto error;
	}
	if (sum.length != ctx->cksum_size) {
	    err = KRB5KRB_AP_ERR_BAD_INTEGRITY;
	    goto error;
	}
	(void) memcpy(outbuf + 16 + message2->length, sum.contents,
	    ctx->cksum_size);
	krb5_free_checksum_contents(context, &sum);
	sum.contents = 0;
	/* Now that we know we're actually generating the token...  */
	ctx->seq_send++;

	if (toktype == KG_TOK_WRAP_MSG) {
#ifdef CFX_EXERCISE
	    rrc = rand() & 0xffff;
	    /* If the rotate fails, don't worry about it.  */
	    if (rotate_left(outbuf+16, bufsize-16,
			    (bufsize-16) - (rrc % (bufsize - 16))))
		store_16_be(rrc, outbuf+6);
#endif
	    /* Fix up EC field.  */
	    store_16_be(ctx->cksum_size, outbuf+4);
	} else {
	    store_16_be(0xffff, outbuf+6);
	}
    } else if (toktype == KG_TOK_MIC_MSG) {
	tok_id = 0x0404;
	message2 = &empty_message;
	goto wrap_with_checksum;
    } else if (toktype == KG_TOK_DEL_CTX) {
	/*
	 * Solaris Kerberos:
	 * No token should be generated for context deletion. Just
	 * return.
	 */
	return 0;
    } else {
	err = KRB5KRB_AP_ERR_BAD_INTEGRITY;
	goto error;
    }

    token->value = outbuf;
    token->length = bufsize;
    return 0;

error:
    FREE(outbuf, bufsize);
    token->value = NULL;
    token->length = 0;
    return err;
}
Exemplo n.º 3
0
OM_uint32
gss_krb5int_unseal_token_v3(krb5_context *contextptr,
			    OM_uint32 *minor_status,
			    krb5_gss_ctx_id_rec *ctx,
			    unsigned char *ptr, int bodysize,
			    gss_buffer_t message_buffer,
			    int *conf_state, int *qop_state, int toktype)
{
    krb5_context context = *contextptr;
    krb5_data plain;
    gssint_uint64 seqnum;
    size_t ec, rrc;
    int key_usage;
    unsigned char acceptor_flag;
    krb5_checksum sum;
    krb5_error_code err;
    krb5_boolean valid;
    krb5_keyblock *key;

    ASSERT(toktype != KG_TOK_SEAL_MSG || ctx->enc != 0);
    ASSERT(ctx->big_endian == 0);
    ASSERT(ctx->proto == 1);

    if (qop_state)
	*qop_state = GSS_C_QOP_DEFAULT;

    acceptor_flag = ctx->initiate ? FLAG_SENDER_IS_ACCEPTOR : 0;
    key_usage = (toktype == KG_TOK_WRAP_MSG
		 ? (!ctx->initiate
		    ? KG_USAGE_INITIATOR_SEAL
		    : KG_USAGE_ACCEPTOR_SEAL)
		 : (!ctx->initiate
		    ? KG_USAGE_INITIATOR_SIGN
		    : KG_USAGE_ACCEPTOR_SIGN));

    /* Oops.  I wrote this code assuming ptr would be at the start of
       the token header.  */
    ptr -= 2;
    bodysize += 2;

    if (bodysize < 16) {
    defective:
	*minor_status = 0;
	return GSS_S_DEFECTIVE_TOKEN;
    }
    if ((ptr[2] & FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) {
	*minor_status = (OM_uint32)G_BAD_DIRECTION;
	return GSS_S_BAD_SIG;
    }

    /* Two things to note here.

       First, we can't really enforce the use of the acceptor's subkey,
       if we're the acceptor; the initiator may have sent messages
       before getting the subkey.  We could probably enforce it if
       we're the initiator.

       Second, if someone tweaks the code to not set the flag telling
       the krb5 library to generate a new subkey in the AP-REP
       message, the MIT library may include a subkey anyways --
       namely, a copy of the AP-REQ subkey, if it was provided.  So
       the initiator may think we wanted a subkey, and set the flag,
       even though we weren't trying to set the subkey.  The "other"
       key, the one not asserted by the acceptor, will have the same
       value in that case, though, so we can just ignore the flag.  */
    if (ctx->have_acceptor_subkey && (ptr[2] & FLAG_ACCEPTOR_SUBKEY)) {
	key = ctx->acceptor_subkey;
    } else {
	key = ctx->enc;
    }

#ifdef _KERNEL
    context->kef_cipher_mt = get_cipher_mech_type(context, key);
    context->kef_hash_mt = get_hash_mech_type(context, key);

    if ((err = init_key_kef(context->kef_cipher_mt, key))) {
	return (GSS_S_FAILURE);
    }
#endif /* _KERNEL */

    if (toktype == KG_TOK_WRAP_MSG) {
	if (load_16_be(ptr) != 0x0504)
	    goto defective;
	if (ptr[3] != 0xff)
	    goto defective;
	ec = load_16_be(ptr+4);
	rrc = load_16_be(ptr+6);
	seqnum = load_64_be(ptr+8);
	if (!rotate_left(ptr+16, bodysize-16, rrc)) {
	no_mem:
	    *minor_status = ENOMEM;
	    return GSS_S_FAILURE;
	}
	if (ptr[2] & FLAG_WRAP_CONFIDENTIAL) {
	    /* confidentiality */
	    krb5_enc_data cipher;
	    unsigned char *althdr;
            size_t plainlen;

	    if (conf_state)
		*conf_state = 1;
	    /* Do we have no decrypt_size function?

	       For all current cryptosystems, the ciphertext size will
	       be larger than the plaintext size.  */
	    cipher.enctype = key->enctype;
	    cipher.ciphertext.length = bodysize - 16;
	    cipher.ciphertext.data = (char *)ptr + 16;
	    plain.length = plainlen = bodysize - 16;
	    plain.data = MALLOC(plain.length);
	    if (plain.data == NULL)
		goto no_mem;
	    err = krb5_c_decrypt(context, key, key_usage, 0,
				 &cipher, &plain);
	    if (err) {
		goto error;
	    }
	    /* Don't use bodysize here!  Use the fact that
	       plain.length has been adjusted to the
	       correct length.  */
	    althdr = (uchar_t *)plain.data + plain.length - 16;
	    if (load_16_be(althdr) != 0x0504
		|| althdr[2] != ptr[2]
		|| althdr[3] != ptr[3]
		|| memcmp(althdr+8, ptr+8, 8)) {
		FREE(plain.data, plainlen);
		goto defective;
	    }
	    message_buffer->length = plain.length - ec - 16;
	    message_buffer->value = MALLOC(message_buffer->length);
	    if (message_buffer->value == NULL) {
		FREE(plain.data, plainlen);
		goto no_mem;
	    }
	    (void) memcpy(message_buffer->value, plain.data,
			message_buffer->length);
	    FREE(plain.data, plainlen);
	} else {
	    /* no confidentiality */
	    if (conf_state)
		*conf_state = 0;
	    if (ec + 16 < ec)
		/* overflow check */
		goto defective;
	    if (ec + 16 > bodysize)
		goto defective;
	    /* We have: header | msg | cksum.
	       We need cksum(msg | header).
	       Rotate the first two.  */
	    store_16_be(0, ptr+4);
	    store_16_be(0, ptr+6);
	    plain.length = bodysize-ec;
	    plain.data = (char *)ptr;
	    if (!rotate_left(ptr, bodysize-ec, 16))
		goto no_mem;
	    sum.length = ec;
	    if (sum.length != ctx->cksum_size) {
		*minor_status = 0;
		return GSS_S_BAD_SIG;
	    }
	    sum.contents = ptr+bodysize-ec;
	    sum.checksum_type = ctx->cksumtype;
	    err = krb5_c_verify_checksum(context, key, key_usage,
					 &plain, &sum, &valid);
	    if (err) {
		*minor_status = err;
		return GSS_S_BAD_SIG;
	    }
	    if (!valid) {
		*minor_status = 0;
		return GSS_S_BAD_SIG;
	    }
	    message_buffer->length = plain.length - 16;
	    message_buffer->value = MALLOC(message_buffer->length);
	    if (message_buffer->value == NULL)
		goto no_mem;
	    (void) memcpy(message_buffer->value,
		plain.data, message_buffer->length);

		/*
		 * Solaris Kerberos: Restore the original token.
		 * This allows the token to be detected as a duplicate if it
		 * is passed in to gss_unwrap() again.
		 */
		if (!rotate_left(ptr, bodysize-ec, bodysize - ec - 16))
			goto no_mem;
		store_16_be(ec, ptr+4);
		store_16_be(rrc, ptr+6);
	}
	err = g_order_check(&ctx->seqstate, seqnum);
	*minor_status = 0;
	return err;
    } else if (toktype == KG_TOK_MIC_MSG) {
	/* wrap token, no confidentiality */
	if (load_16_be(ptr) != 0x0404)
	    goto defective;
    verify_mic_1:
	if (ptr[3] != 0xff)
	    goto defective;
	if (load_32_be(ptr+4) != (ulong_t)0xffffffffU)
	    goto defective;
	seqnum = load_64_be(ptr+8);
	plain.length = message_buffer->length + 16;
	plain.data = MALLOC(plain.length);
	if (plain.data == NULL)
	    goto no_mem;
	if (message_buffer->length)
	    (void) memcpy(plain.data,
		message_buffer->value, message_buffer->length);
	(void) memcpy(plain.data + message_buffer->length, ptr, 16);
	sum.length = bodysize - 16;
	sum.contents = ptr + 16;
	sum.checksum_type = ctx->cksumtype;
	err = krb5_c_verify_checksum(context, key, key_usage,
				     &plain, &sum, &valid);
	if (err) {
	error:
	    FREE(plain.data, plain.length);
	    *minor_status = err;
	    save_error_info(*minor_status, context);
	    return GSS_S_BAD_SIG; /* XXX */
	}
	FREE(plain.data, plain.length);
	if (!valid) {
	    *minor_status = 0;
	    return GSS_S_BAD_SIG;
	}
	err = g_order_check(&ctx->seqstate, seqnum);
	*minor_status = 0;
	return err;
    } else if (toktype == KG_TOK_DEL_CTX) {
	if (load_16_be(ptr) != 0x0405)
	    goto defective;
	message_buffer = (gss_buffer_t)&empty_message;
	goto verify_mic_1;
    } else {
	goto defective;
    }
}
krb5_error_code KRB5_CALLCONV
krb5_c_make_checksum(krb5_context context, krb5_cksumtype cksumtype,
		     const krb5_keyblock *key, krb5_keyusage usage,
		     const krb5_data *input, krb5_checksum *cksum)
{
    int i, e1, e2;
    krb5_data data;
    krb5_error_code ret = 0;
    size_t cksumlen;

    KRB5_LOG0(KRB5_INFO, "krb5_c_make_checksum() start.");

    for (i=0; i<krb5_cksumtypes_length; i++) {
	if (krb5_cksumtypes_list[i].ctype == cksumtype)
	    break;
    }

    if (i == krb5_cksumtypes_length)
	return(KRB5_BAD_ENCTYPE);

    if (krb5_cksumtypes_list[i].keyhash)
	cksumlen = krb5_cksumtypes_list[i].keyhash->hashsize;
    else
	cksumlen = krb5_cksumtypes_list[i].hash->hashsize;

#ifdef _KERNEL
    context->kef_cksum_mt = krb5_cksumtypes_list[i].kef_cksum_mt;
#endif
    cksum->length = cksumlen;

    if ((cksum->contents = (krb5_octet *) MALLOC(cksum->length)) == NULL)
	return(ENOMEM);

    data.length = cksum->length;
    data.data = (char *) cksum->contents;

    if (krb5_cksumtypes_list[i].keyhash) {
	/* check if key is compatible */

	if (krb5_cksumtypes_list[i].keyed_etype) {
	    for (e1=0; e1<krb5_enctypes_length; e1++) 
		if (krb5_enctypes_list[e1].etype ==
		    krb5_cksumtypes_list[i].keyed_etype)
		    break;

	    for (e2=0; e2<krb5_enctypes_length; e2++) 
		if (krb5_enctypes_list[e2].etype == key->enctype)
		    break;

	    if ((e1 == krb5_enctypes_length) ||
		(e2 == krb5_enctypes_length) ||
		(krb5_enctypes_list[e1].enc != krb5_enctypes_list[e2].enc)) {
		ret = KRB5_BAD_ENCTYPE;
		goto cleanup;
	    }
	}
#ifdef _KERNEL
	context->kef_cipher_mt = krb5_enctypes_list[e1].kef_cipher_mt;
	context->kef_hash_mt = krb5_enctypes_list[e1].kef_hash_mt;
	if (key->kef_key.ck_data == NULL) {
		if ((ret = init_key_kef(context->kef_cipher_mt,
				(krb5_keyblock *)key)))
			goto cleanup;
	}
#else
	if ((ret = init_key_uef(krb_ctx_hSession(context), (krb5_keyblock *)key)))
		return (ret);
#endif /* _KERNEL */

	ret = (*(krb5_cksumtypes_list[i].keyhash->hash))(context, key,
						usage, 0, input, &data);
    } else if (krb5_cksumtypes_list[i].flags & KRB5_CKSUMFLAG_DERIVE) {
#ifdef _KERNEL
    	context->kef_cipher_mt = get_cipher_mech_type(context,
					(krb5_keyblock *)key);
    	context->kef_hash_mt = get_hash_mech_type(context,
					(krb5_keyblock *)key);
	/*
	 * If the hash_mt is invalid, try using the cksum_mt
	 * because "hash" and "checksum" are overloaded terms
	 * in some places.
	 */ 
	if (context->kef_hash_mt == CRYPTO_MECH_INVALID)
		context->kef_hash_mt = context->kef_cksum_mt;
#else
	ret = init_key_uef(krb_ctx_hSession(context), (krb5_keyblock *)key);
	if (ret)
		return (ret);
#endif /* _KERNEL */
	ret = krb5_dk_make_checksum(context,
				krb5_cksumtypes_list[i].hash,
				key, usage, input, &data);
    } else {
	    /*
	     * No key is used, hash and cksum are synonymous
	     * in this case
	     */
#ifdef _KERNEL
	    context->kef_hash_mt = context->kef_cksum_mt;
#endif /* _KERNEL */
	    ret = (*(krb5_cksumtypes_list[i].hash->hash))(context, 1,
							input, &data);
    }

    if (!ret) {
	cksum->magic = KV5M_CHECKSUM;
	cksum->checksum_type = cksumtype;
	if (krb5_cksumtypes_list[i].trunc_size) {
	    krb5_octet *trunc;
            size_t old_len = cksum->length;

            /*
             * Solaris Kerberos:
             * The Kernel does not like 'realloc' (which is what
             * MIT code does here), so we do our own "realloc".
             */
            cksum->length = krb5_cksumtypes_list[i].trunc_size;
            trunc = (krb5_octet *) MALLOC(cksum->length);
            if (trunc) {
                (void) memcpy(trunc, cksum->contents, cksum->length);
                FREE(cksum->contents, old_len);
                cksum->contents = trunc;
            } else {
                ret = ENOMEM;
            }
        }
    }

cleanup:
    if (ret) {
	(void) memset(cksum->contents, 0, cksum->length);
	FREE(cksum->contents, cksum->length);
	cksum->length = 0;
	cksum->contents = NULL;
    }

    KRB5_LOG(KRB5_INFO, "krb5_c_make_checksum() end ret = %d\n", ret);
    return(ret);
}
Exemplo n.º 5
0
/*ARGSUSED*/
static krb5_error_code
k5_md5des_hash(krb5_context context,
	krb5_const krb5_keyblock *key,
	krb5_keyusage usage,
	krb5_const krb5_data *ivec,
	krb5_const krb5_data *input, krb5_data *output)
{
    krb5_error_code ret = 0;
    krb5_data data;
    unsigned char conf[CONFLENGTH];
    unsigned char xorkey[MIT_DES_KEYSIZE];
    int i;
    krb5_data *hash_input;
    char *outptr;
    krb5_keyblock newkey;

    if (key->length != MIT_DES_KEYSIZE)
	return(KRB5_BAD_KEYSIZE);
    if (ivec)
	return(KRB5_CRYPTO_INTERNAL);
    if (output->length != (CONFLENGTH + MD5_CKSUM_LENGTH))
	return(KRB5_CRYPTO_INTERNAL);

    /* create the confounder */
    data.length = CONFLENGTH;
    data.data = (char *) conf;
    if ((ret = krb5_c_random_make_octets(context, &data)))
	return(ret);
    
    /* hash the confounder, then the input data */
    hash_input = (krb5_data *)MALLOC(sizeof(krb5_data) * 2);
    if (hash_input == NULL)
	return(KRB5_RC_MALLOC);

    hash_input[0].data = (char *)conf;
    hash_input[0].length = CONFLENGTH;
    hash_input[1].data = input->data;
    hash_input[1].length = input->length;

    /* Save the pointer to the beginning of the output buffer */
    outptr = (char *)output->data;

    /*
     * Move the output ptr ahead so we can write the hash
     * digest directly into the buffer.
     */
    output->data = output->data + CONFLENGTH;

    /* Use generic hash function that calls to kEF */
    if (k5_ef_hash(context, 2, hash_input, output)) {
	FREE(hash_input, sizeof(krb5_data) * 2);
	return(KRB5_KEF_ERROR);
    }

    /* restore the original ptr to the output data */
    output->data = outptr;

    /*
     * Put the confounder in the beginning of the buffer to be
     * encrypted.
     */
    bcopy(conf, output->data, CONFLENGTH); 

    bcopy(key->contents, xorkey, sizeof(xorkey));
    for (i=0; i<sizeof(xorkey); i++)
	xorkey[i] ^= 0xf0;

    /*
     * Solaris Kerberos:
     * Encryption Framework checks for parity and weak keys.
     */
    bzero(&newkey, sizeof(krb5_keyblock));
    newkey.enctype = key->enctype;
    newkey.contents = xorkey;
    newkey.length = sizeof(xorkey);
    newkey.dk_list = NULL;
    newkey.kef_key.ck_data = NULL;
    ret = init_key_kef(context->kef_cipher_mt, &newkey);
    if (ret) {
	FREE(hash_input, sizeof(krb5_data) * 2);
	return (ret);
    }

    /* encrypt it, in place.  this has a return value, but it's
       always zero.  */
    ret = mit_des_cbc_encrypt(context, (krb5_pointer) output->data,
	(krb5_pointer) output->data, output->length,
	&newkey, (unsigned char*) mit_des_zeroblock, 1);

    FREE(hash_input, sizeof(krb5_data) * 2);
    (void)crypto_destroy_ctx_template(newkey.key_tmpl);
    return(ret);
}
Exemplo n.º 6
0
/*ARGSUSED*/
static krb5_error_code
k5_md5des_verify(krb5_context context,
	krb5_const krb5_keyblock *key,
	krb5_keyusage usage,
	krb5_const krb5_data *ivec,
	krb5_const krb5_data *input,
	krb5_const krb5_data *hash,
	krb5_boolean *valid)
{
    krb5_error_code ret = 0;
    unsigned char plaintext[CONFLENGTH + MD5_CKSUM_LENGTH];
    unsigned char xorkey[8];
    int i;
    int compathash = 0;
    krb5_octet outtmp[MD5_CKSUM_LENGTH];
    size_t hisize;
    krb5_data *hash_input;
    krb5_data hash_output;
    krb5_keyblock newkey;

    if (key->length != MIT_DES_KEYSIZE)
	return(KRB5_BAD_KEYSIZE);
    if (ivec)
	return(KRB5_CRYPTO_INTERNAL);
    if (hash->length != (CONFLENGTH + MD5_CKSUM_LENGTH)) {
#ifdef KRB5_MD5DES_BETA5_COMPAT
	if (hash->length != MD5_CKSUM_LENGTH)
	    return(KRB5_CRYPTO_INTERNAL);
	else
	    compathash = 1;
#else
	return(KRB5_CRYPTO_INTERNAL);
#endif
    }

    /* create and schedule the encryption key */
    (void) bcopy(key->contents, xorkey, sizeof(xorkey));
    if (!compathash) {
	for (i=0; i<sizeof(xorkey); i++)
	    xorkey[i] ^= 0xf0;
    }
    
    /*
     * Solaris Kerberos:
     * Encryption Framework checks for parity and weak keys
     */
    bzero(&newkey, sizeof(krb5_keyblock));
    newkey.enctype = key->enctype;
    newkey.contents = xorkey;
    newkey.length = sizeof(xorkey);
    newkey.dk_list = NULL;
    newkey.kef_key.ck_data = NULL;
    ret = init_key_kef(context->kef_cipher_mt, &newkey);

    /* decrypt it.  this has a return value, but it's always zero.  */
    if (!compathash) {
	ret = mit_des_cbc_encrypt(context, (krb5_pointer) hash->data,
			    (krb5_pointer) plaintext, hash->length,
			    &newkey, (unsigned char*) mit_des_zeroblock, 0);
    } else {
	ret = mit_des_cbc_encrypt(context, (krb5_pointer) hash->data,
			    (krb5_pointer) plaintext, hash->length,
			    &newkey, xorkey, 0);
    }
    if (ret) goto cleanup;

    /* hash the confounder, then the input data */
    i = 1;
    if (!compathash)
	i++;

    hisize = sizeof(krb5_data) * i;
    hash_input = (krb5_data *)MALLOC(hisize);
    if (hash_input == NULL)
	return(KRB5_RC_MALLOC);

    i=0;
    if (!compathash) {
    	hash_input[i].data = (char *)plaintext;
    	hash_input[i].length = CONFLENGTH;
	i++;
    }
    hash_input[i].data = input->data;
    hash_input[i].length = input->length;

    hash_output.data = (char *)outtmp;
    hash_output.length = sizeof(outtmp);

    if (k5_ef_hash(context, 1, hash_input, &hash_output)) {
	ret = KRB5_KEF_ERROR;
	goto cleanup;
    }

    /* compare the decrypted hash to the computed one */
    if (!compathash) {
	*valid = !bcmp((const void *)(plaintext+CONFLENGTH),
		(void *)outtmp, MD5_CKSUM_LENGTH);
    } else {
	*valid = !bcmp((const void *)plaintext,
		(void *)outtmp, MD5_CKSUM_LENGTH);
    }
    bzero((void *)plaintext, sizeof(plaintext));

cleanup:
    if (hash_input != NULL && hisize > 0)
	    FREE(hash_input, hisize);
    (void)crypto_destroy_ctx_template(newkey.key_tmpl);

    return(ret);
}