327 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			327 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
 | 
						|
 * (Royal Institute of Technology, Stockholm, Sweden).
 | 
						|
 * All rights reserved.
 | 
						|
 *
 | 
						|
 * Redistribution and use in source and binary forms, with or without
 | 
						|
 * modification, are permitted provided that the following conditions
 | 
						|
 * are met:
 | 
						|
 *
 | 
						|
 * 1. Redistributions of source code must retain the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer.
 | 
						|
 *
 | 
						|
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer in the
 | 
						|
 *    documentation and/or other materials provided with the distribution.
 | 
						|
 *
 | 
						|
 * 3. Neither the name of the Institute nor the names of its contributors
 | 
						|
 *    may be used to endorse or promote products derived from this software
 | 
						|
 *    without specific prior written permission.
 | 
						|
 *
 | 
						|
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 | 
						|
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
						|
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
						|
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 | 
						|
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
						|
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
						|
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
						|
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
						|
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
						|
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
						|
 * SUCH DAMAGE.
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * ARCFOUR
 | 
						|
 */
 | 
						|
 | 
						|
#include "krb5_locl.h"
 | 
						|
 | 
						|
static struct _krb5_key_type keytype_arcfour = {
 | 
						|
    KRB5_ENCTYPE_ARCFOUR_HMAC_MD5,
 | 
						|
    "arcfour",
 | 
						|
    128,
 | 
						|
    16,
 | 
						|
    sizeof(struct _krb5_evp_schedule),
 | 
						|
    NULL,
 | 
						|
    _krb5_evp_schedule,
 | 
						|
    _krb5_arcfour_salt,
 | 
						|
    NULL,
 | 
						|
    _krb5_evp_cleanup,
 | 
						|
    EVP_rc4
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
 * checksum according to section 5. of draft-brezak-win2k-krb-rc4-hmac-03.txt
 | 
						|
 */
 | 
						|
 | 
						|
krb5_error_code
 | 
						|
_krb5_HMAC_MD5_checksum(krb5_context context,
 | 
						|
			struct _krb5_key_data *key,
 | 
						|
			const void *data,
 | 
						|
			size_t len,
 | 
						|
			unsigned usage,
 | 
						|
			Checksum *result)
 | 
						|
{
 | 
						|
    EVP_MD_CTX *m;
 | 
						|
    struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
 | 
						|
    const char signature[] = "signaturekey";
 | 
						|
    Checksum ksign_c;
 | 
						|
    struct _krb5_key_data ksign;
 | 
						|
    krb5_keyblock kb;
 | 
						|
    unsigned char t[4];
 | 
						|
    unsigned char tmp[16];
 | 
						|
    unsigned char ksign_c_data[16];
 | 
						|
    krb5_error_code ret;
 | 
						|
 | 
						|
    m = EVP_MD_CTX_create();
 | 
						|
    if (m == NULL) {
 | 
						|
	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
 | 
						|
	return ENOMEM;
 | 
						|
    }
 | 
						|
    ksign_c.checksum.length = sizeof(ksign_c_data);
 | 
						|
    ksign_c.checksum.data   = ksign_c_data;
 | 
						|
    ret = _krb5_internal_hmac(context, c, signature, sizeof(signature),
 | 
						|
			      0, key, &ksign_c);
 | 
						|
    if (ret) {
 | 
						|
	EVP_MD_CTX_destroy(m);
 | 
						|
	return ret;
 | 
						|
    }
 | 
						|
    ksign.key = &kb;
 | 
						|
    kb.keyvalue = ksign_c.checksum;
 | 
						|
    EVP_DigestInit_ex(m, EVP_md5(), NULL);
 | 
						|
    t[0] = (usage >>  0) & 0xFF;
 | 
						|
    t[1] = (usage >>  8) & 0xFF;
 | 
						|
    t[2] = (usage >> 16) & 0xFF;
 | 
						|
    t[3] = (usage >> 24) & 0xFF;
 | 
						|
    EVP_DigestUpdate(m, t, 4);
 | 
						|
    EVP_DigestUpdate(m, data, len);
 | 
						|
    EVP_DigestFinal_ex (m, tmp, NULL);
 | 
						|
    EVP_MD_CTX_destroy(m);
 | 
						|
 | 
						|
    ret = _krb5_internal_hmac(context, c, tmp, sizeof(tmp), 0, &ksign, result);
 | 
						|
    if (ret)
 | 
						|
	return ret;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
struct _krb5_checksum_type _krb5_checksum_hmac_md5 = {
 | 
						|
    CKSUMTYPE_HMAC_MD5,
 | 
						|
    "hmac-md5",
 | 
						|
    64,
 | 
						|
    16,
 | 
						|
    F_KEYED | F_CPROOF,
 | 
						|
    _krb5_HMAC_MD5_checksum,
 | 
						|
    NULL
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
 * section 6 of draft-brezak-win2k-krb-rc4-hmac-03
 | 
						|
 *
 | 
						|
 * warning: not for small children
 | 
						|
 */
 | 
						|
 | 
						|
static krb5_error_code
 | 
						|
ARCFOUR_subencrypt(krb5_context context,
 | 
						|
		   struct _krb5_key_data *key,
 | 
						|
		   void *data,
 | 
						|
		   size_t len,
 | 
						|
		   unsigned usage,
 | 
						|
		   void *ivec)
 | 
						|
{
 | 
						|
    EVP_CIPHER_CTX ctx;
 | 
						|
    struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
 | 
						|
    Checksum k1_c, k2_c, k3_c, cksum;
 | 
						|
    struct _krb5_key_data ke;
 | 
						|
    krb5_keyblock kb;
 | 
						|
    unsigned char t[4];
 | 
						|
    unsigned char *cdata = data;
 | 
						|
    unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
 | 
						|
    krb5_error_code ret;
 | 
						|
 | 
						|
    t[0] = (usage >>  0) & 0xFF;
 | 
						|
    t[1] = (usage >>  8) & 0xFF;
 | 
						|
    t[2] = (usage >> 16) & 0xFF;
 | 
						|
    t[3] = (usage >> 24) & 0xFF;
 | 
						|
 | 
						|
    k1_c.checksum.length = sizeof(k1_c_data);
 | 
						|
    k1_c.checksum.data   = k1_c_data;
 | 
						|
 | 
						|
    ret = _krb5_internal_hmac(context, c, t, sizeof(t), 0, key, &k1_c);
 | 
						|
    if (ret)
 | 
						|
	krb5_abortx(context, "hmac failed");
 | 
						|
 | 
						|
    memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
 | 
						|
 | 
						|
    k2_c.checksum.length = sizeof(k2_c_data);
 | 
						|
    k2_c.checksum.data   = k2_c_data;
 | 
						|
 | 
						|
    ke.key = &kb;
 | 
						|
    kb.keyvalue = k2_c.checksum;
 | 
						|
 | 
						|
    cksum.checksum.length = 16;
 | 
						|
    cksum.checksum.data   = data;
 | 
						|
 | 
						|
    ret = _krb5_internal_hmac(context, c, cdata + 16, len - 16, 0, &ke, &cksum);
 | 
						|
    if (ret)
 | 
						|
	krb5_abortx(context, "hmac failed");
 | 
						|
 | 
						|
    ke.key = &kb;
 | 
						|
    kb.keyvalue = k1_c.checksum;
 | 
						|
 | 
						|
    k3_c.checksum.length = sizeof(k3_c_data);
 | 
						|
    k3_c.checksum.data   = k3_c_data;
 | 
						|
 | 
						|
    ret = _krb5_internal_hmac(context, c, data, 16, 0, &ke, &k3_c);
 | 
						|
    if (ret)
 | 
						|
	krb5_abortx(context, "hmac failed");
 | 
						|
 | 
						|
    EVP_CIPHER_CTX_init(&ctx);
 | 
						|
 | 
						|
    EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 1);
 | 
						|
    EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16);
 | 
						|
    EVP_CIPHER_CTX_cleanup(&ctx);
 | 
						|
 | 
						|
    memset (k1_c_data, 0, sizeof(k1_c_data));
 | 
						|
    memset (k2_c_data, 0, sizeof(k2_c_data));
 | 
						|
    memset (k3_c_data, 0, sizeof(k3_c_data));
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
static krb5_error_code
 | 
						|
ARCFOUR_subdecrypt(krb5_context context,
 | 
						|
		   struct _krb5_key_data *key,
 | 
						|
		   void *data,
 | 
						|
		   size_t len,
 | 
						|
		   unsigned usage,
 | 
						|
		   void *ivec)
 | 
						|
{
 | 
						|
    EVP_CIPHER_CTX ctx;
 | 
						|
    struct _krb5_checksum_type *c = _krb5_find_checksum (CKSUMTYPE_RSA_MD5);
 | 
						|
    Checksum k1_c, k2_c, k3_c, cksum;
 | 
						|
    struct _krb5_key_data ke;
 | 
						|
    krb5_keyblock kb;
 | 
						|
    unsigned char t[4];
 | 
						|
    unsigned char *cdata = data;
 | 
						|
    unsigned char k1_c_data[16], k2_c_data[16], k3_c_data[16];
 | 
						|
    unsigned char cksum_data[16];
 | 
						|
    krb5_error_code ret;
 | 
						|
 | 
						|
    t[0] = (usage >>  0) & 0xFF;
 | 
						|
    t[1] = (usage >>  8) & 0xFF;
 | 
						|
    t[2] = (usage >> 16) & 0xFF;
 | 
						|
    t[3] = (usage >> 24) & 0xFF;
 | 
						|
 | 
						|
    k1_c.checksum.length = sizeof(k1_c_data);
 | 
						|
    k1_c.checksum.data   = k1_c_data;
 | 
						|
 | 
						|
    ret = _krb5_internal_hmac(context, c, t, sizeof(t), 0, key, &k1_c);
 | 
						|
    if (ret)
 | 
						|
	krb5_abortx(context, "hmac failed");
 | 
						|
 | 
						|
    memcpy (k2_c_data, k1_c_data, sizeof(k1_c_data));
 | 
						|
 | 
						|
    k2_c.checksum.length = sizeof(k2_c_data);
 | 
						|
    k2_c.checksum.data   = k2_c_data;
 | 
						|
 | 
						|
    ke.key = &kb;
 | 
						|
    kb.keyvalue = k1_c.checksum;
 | 
						|
 | 
						|
    k3_c.checksum.length = sizeof(k3_c_data);
 | 
						|
    k3_c.checksum.data   = k3_c_data;
 | 
						|
 | 
						|
    ret = _krb5_internal_hmac(context, c, cdata, 16, 0, &ke, &k3_c);
 | 
						|
    if (ret)
 | 
						|
	krb5_abortx(context, "hmac failed");
 | 
						|
 | 
						|
    EVP_CIPHER_CTX_init(&ctx);
 | 
						|
    EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, k3_c.checksum.data, NULL, 0);
 | 
						|
    EVP_Cipher(&ctx, cdata + 16, cdata + 16, len - 16);
 | 
						|
    EVP_CIPHER_CTX_cleanup(&ctx);
 | 
						|
 | 
						|
    ke.key = &kb;
 | 
						|
    kb.keyvalue = k2_c.checksum;
 | 
						|
 | 
						|
    cksum.checksum.length = 16;
 | 
						|
    cksum.checksum.data   = cksum_data;
 | 
						|
 | 
						|
    ret = _krb5_internal_hmac(context, c, cdata + 16, len - 16, 0, &ke, &cksum);
 | 
						|
    if (ret)
 | 
						|
	krb5_abortx(context, "hmac failed");
 | 
						|
 | 
						|
    memset (k1_c_data, 0, sizeof(k1_c_data));
 | 
						|
    memset (k2_c_data, 0, sizeof(k2_c_data));
 | 
						|
    memset (k3_c_data, 0, sizeof(k3_c_data));
 | 
						|
 | 
						|
    if (ct_memcmp (cksum.checksum.data, data, 16) != 0) {
 | 
						|
	krb5_clear_error_message (context);
 | 
						|
	return KRB5KRB_AP_ERR_BAD_INTEGRITY;
 | 
						|
    } else {
 | 
						|
	return 0;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * convert the usage numbers used in
 | 
						|
 * draft-ietf-cat-kerb-key-derivation-00.txt to the ones in
 | 
						|
 * draft-brezak-win2k-krb-rc4-hmac-04.txt
 | 
						|
 */
 | 
						|
 | 
						|
krb5_error_code
 | 
						|
_krb5_usage2arcfour(krb5_context context, unsigned *usage)
 | 
						|
{
 | 
						|
    switch (*usage) {
 | 
						|
    case KRB5_KU_AS_REP_ENC_PART : /* 3 */
 | 
						|
	*usage = 8;
 | 
						|
	return 0;
 | 
						|
    case KRB5_KU_USAGE_SEAL :  /* 22 */
 | 
						|
	*usage = 13;
 | 
						|
	return 0;
 | 
						|
    case KRB5_KU_USAGE_SIGN : /* 23 */
 | 
						|
        *usage = 15;
 | 
						|
        return 0;
 | 
						|
    case KRB5_KU_USAGE_SEQ: /* 24 */
 | 
						|
	*usage = 0;
 | 
						|
	return 0;
 | 
						|
    default :
 | 
						|
	return 0;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static krb5_error_code
 | 
						|
ARCFOUR_encrypt(krb5_context context,
 | 
						|
		struct _krb5_key_data *key,
 | 
						|
		void *data,
 | 
						|
		size_t len,
 | 
						|
		krb5_boolean encryptp,
 | 
						|
		int usage,
 | 
						|
		void *ivec)
 | 
						|
{
 | 
						|
    krb5_error_code ret;
 | 
						|
    unsigned keyusage = usage;
 | 
						|
 | 
						|
    if((ret = _krb5_usage2arcfour (context, &keyusage)) != 0)
 | 
						|
	return ret;
 | 
						|
 | 
						|
    if (encryptp)
 | 
						|
	return ARCFOUR_subencrypt (context, key, data, len, keyusage, ivec);
 | 
						|
    else
 | 
						|
	return ARCFOUR_subdecrypt (context, key, data, len, keyusage, ivec);
 | 
						|
}
 | 
						|
 | 
						|
struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5 = {
 | 
						|
    ETYPE_ARCFOUR_HMAC_MD5,
 | 
						|
    "arcfour-hmac-md5",
 | 
						|
    "rc4-hmac",
 | 
						|
    1,
 | 
						|
    1,
 | 
						|
    8,
 | 
						|
    &keytype_arcfour,
 | 
						|
    &_krb5_checksum_hmac_md5,
 | 
						|
    &_krb5_checksum_hmac_md5,
 | 
						|
    F_SPECIAL,
 | 
						|
    ARCFOUR_encrypt,
 | 
						|
    0,
 | 
						|
    NULL
 | 
						|
};
 |