crypto.c revision 55682
155682Smarkm/*
255682Smarkm * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska H�gskolan
355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden).
455682Smarkm * All rights reserved.
555682Smarkm *
655682Smarkm * Redistribution and use in source and binary forms, with or without
755682Smarkm * modification, are permitted provided that the following conditions
855682Smarkm * are met:
955682Smarkm *
1055682Smarkm * 1. Redistributions of source code must retain the above copyright
1155682Smarkm *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1455682Smarkm *    notice, this list of conditions and the following disclaimer in the
1555682Smarkm *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors
1855682Smarkm *    may be used to endorse or promote products derived from this software
1955682Smarkm *    without specific prior written permission.
2055682Smarkm *
2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2455682Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3155682Smarkm * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "krb5_locl.h"
3555682SmarkmRCSID("$Id: crypto.c,v 1.28 2000/01/06 20:21:13 assar Exp $");
3655682Smarkm
3755682Smarkm#undef CRYPTO_DEBUG
3855682Smarkm#ifdef CRYPTO_DEBUG
3955682Smarkmstatic void krb5_crypto_debug(krb5_context, int, size_t, krb5_keyblock*);
4055682Smarkm#endif
4155682Smarkm
4255682Smarkm
4355682Smarkmstruct key_data {
4455682Smarkm    krb5_keyblock *key;
4555682Smarkm    krb5_data *schedule;
4655682Smarkm};
4755682Smarkm
4855682Smarkmstruct key_usage {
4955682Smarkm    unsigned usage;
5055682Smarkm    struct key_data key;
5155682Smarkm};
5255682Smarkm
5355682Smarkmstruct krb5_crypto_data {
5455682Smarkm    struct encryption_type *et;
5555682Smarkm    struct key_data key;
5655682Smarkm    int num_key_usage;
5755682Smarkm    struct key_usage *key_usage;
5855682Smarkm};
5955682Smarkm
6055682Smarkm#define CRYPTO_ETYPE(C) ((C)->et->type)
6155682Smarkm
6255682Smarkm/* bits for `flags' below */
6355682Smarkm#define F_KEYED		 1	/* checksum is keyed */
6455682Smarkm#define F_CPROOF	 2	/* checksum is collision proof */
6555682Smarkm#define F_DERIVED	 4	/* uses derived keys */
6655682Smarkm#define F_VARIANT	 8	/* uses `variant' keys (6.4.3) */
6755682Smarkm#define F_PSEUDO	16	/* not a real protocol type */
6855682Smarkm
6955682Smarkmstruct salt_type {
7055682Smarkm    krb5_salttype type;
7155682Smarkm    const char *name;
7255682Smarkm    krb5_error_code (*string_to_key)(krb5_context, krb5_enctype, krb5_data,
7355682Smarkm				     krb5_salt, krb5_keyblock*);
7455682Smarkm};
7555682Smarkm
7655682Smarkmstruct key_type {
7755682Smarkm    krb5_keytype type; /* XXX */
7855682Smarkm    const char *name;
7955682Smarkm    size_t bits;
8055682Smarkm    size_t size;
8155682Smarkm    size_t schedule_size;
8255682Smarkm#if 0
8355682Smarkm    krb5_enctype best_etype;
8455682Smarkm#endif
8555682Smarkm    void (*random_key)(krb5_context, krb5_keyblock*);
8655682Smarkm    void (*schedule)(krb5_context, struct key_data *);
8755682Smarkm    struct salt_type *string_to_key;
8855682Smarkm};
8955682Smarkm
9055682Smarkmstruct checksum_type {
9155682Smarkm    krb5_cksumtype type;
9255682Smarkm    const char *name;
9355682Smarkm    size_t blocksize;
9455682Smarkm    size_t checksumsize;
9555682Smarkm    unsigned flags;
9655682Smarkm    void (*checksum)(krb5_context, struct key_data*, void*, size_t, Checksum*);
9755682Smarkm    krb5_error_code (*verify)(krb5_context, struct key_data*,
9855682Smarkm			      void*, size_t, Checksum*);
9955682Smarkm};
10055682Smarkm
10155682Smarkmstruct encryption_type {
10255682Smarkm    krb5_enctype type;
10355682Smarkm    const char *name;
10455682Smarkm    size_t blocksize;
10555682Smarkm    size_t confoundersize;
10655682Smarkm    struct key_type *keytype;
10755682Smarkm    struct checksum_type *cksumtype;
10855682Smarkm    struct checksum_type *keyed_checksum;
10955682Smarkm    unsigned flags;
11055682Smarkm    void (*encrypt)(struct key_data *, void *, size_t, int);
11155682Smarkm};
11255682Smarkm
11355682Smarkm#define ENCRYPTION_USAGE(U) (((U) << 8) | 0xAA)
11455682Smarkm#define INTEGRITY_USAGE(U) (((U) << 8) | 0x55)
11555682Smarkm#define CHECKSUM_USAGE(U) (((U) << 8) | 0x99)
11655682Smarkm
11755682Smarkmstatic struct checksum_type *_find_checksum(krb5_cksumtype type);
11855682Smarkmstatic struct encryption_type *_find_enctype(krb5_enctype type);
11955682Smarkmstatic struct key_type *_find_keytype(krb5_keytype type);
12055682Smarkmstatic krb5_error_code _get_derived_key(krb5_context, krb5_crypto,
12155682Smarkm					unsigned, struct key_data**);
12255682Smarkmstatic struct key_data *_new_derived_key(krb5_crypto crypto, unsigned usage);
12355682Smarkm
12455682Smarkm/************************************************************
12555682Smarkm *                                                          *
12655682Smarkm ************************************************************/
12755682Smarkm
12855682Smarkmstatic void
12955682SmarkmDES_random_key(krb5_context context,
13055682Smarkm	       krb5_keyblock *key)
13155682Smarkm{
13255682Smarkm    des_cblock *k = key->keyvalue.data;
13355682Smarkm    do {
13455682Smarkm	krb5_generate_random_block(k, sizeof(des_cblock));
13555682Smarkm	des_set_odd_parity(k);
13655682Smarkm    } while(des_is_weak_key(k));
13755682Smarkm}
13855682Smarkm
13955682Smarkmstatic void
14055682SmarkmDES_schedule(krb5_context context,
14155682Smarkm	     struct key_data *key)
14255682Smarkm{
14355682Smarkm    des_set_key(key->key->keyvalue.data, key->schedule->data);
14455682Smarkm}
14555682Smarkm
14655682Smarkmstatic krb5_error_code
14755682SmarkmDES_string_to_key(krb5_context context,
14855682Smarkm		  krb5_enctype enctype,
14955682Smarkm		  krb5_data password,
15055682Smarkm		  krb5_salt salt,
15155682Smarkm		  krb5_keyblock *key)
15255682Smarkm{
15355682Smarkm    char *s;
15455682Smarkm    size_t len;
15555682Smarkm    des_cblock tmp;
15655682Smarkm
15755682Smarkm    len = password.length + salt.saltvalue.length + 1;
15855682Smarkm    s = malloc(len);
15955682Smarkm    if(s == NULL)
16055682Smarkm	return ENOMEM;
16155682Smarkm    memcpy(s, password.data, password.length);
16255682Smarkm    memcpy(s + password.length, salt.saltvalue.data, salt.saltvalue.length);
16355682Smarkm    s[len - 1] = '\0';
16455682Smarkm    des_string_to_key(s, &tmp);
16555682Smarkm    key->keytype = enctype;
16655682Smarkm    krb5_data_copy(&key->keyvalue, tmp, sizeof(tmp));
16755682Smarkm    memset(&tmp, 0, sizeof(tmp));
16855682Smarkm    memset(s, 0, len);
16955682Smarkm    free(s);
17055682Smarkm    return 0;
17155682Smarkm}
17255682Smarkm
17355682Smarkm/* This defines the Andrew string_to_key function.  It accepts a password
17455682Smarkm * string as input and converts its via a one-way encryption algorithm to a DES
17555682Smarkm * encryption key.  It is compatible with the original Andrew authentication
17655682Smarkm * service password database.
17755682Smarkm */
17855682Smarkm
17955682Smarkm/*
18055682Smarkm * Short passwords, i.e 8 characters or less.
18155682Smarkm */
18255682Smarkmstatic void
18355682SmarkmDES_AFS3_CMU_string_to_key (krb5_data pw,
18455682Smarkm			    krb5_data cell,
18555682Smarkm			    des_cblock *key)
18655682Smarkm{
18755682Smarkm    char  password[8+1];	/* crypt is limited to 8 chars anyway */
18855682Smarkm    int   i;
18955682Smarkm
19055682Smarkm    for(i = 0; i < 8; i++) {
19155682Smarkm	char c = ((i < pw.length) ? ((char*)pw.data)[i] : 0) ^
19255682Smarkm		 ((i < cell.length) ? ((char*)cell.data)[i] : 0);
19355682Smarkm	password[i] = c ? c : 'X';
19455682Smarkm    }
19555682Smarkm    password[8] = '\0';
19655682Smarkm
19755682Smarkm    memcpy(key, crypt(password, "#~") + 2, sizeof(des_cblock));
19855682Smarkm
19955682Smarkm    /* parity is inserted into the LSB so left shift each byte up one
20055682Smarkm       bit. This allows ascii characters with a zero MSB to retain as
20155682Smarkm       much significance as possible. */
20255682Smarkm    for (i = 0; i < sizeof(des_cblock); i++)
20355682Smarkm	((unsigned char*)key)[i] <<= 1;
20455682Smarkm    des_set_odd_parity (key);
20555682Smarkm}
20655682Smarkm
20755682Smarkm/*
20855682Smarkm * Long passwords, i.e 9 characters or more.
20955682Smarkm */
21055682Smarkmstatic void
21155682SmarkmDES_AFS3_Transarc_string_to_key (krb5_data pw,
21255682Smarkm				 krb5_data cell,
21355682Smarkm				 des_cblock *key)
21455682Smarkm{
21555682Smarkm    des_key_schedule schedule;
21655682Smarkm    des_cblock temp_key;
21755682Smarkm    des_cblock ivec;
21855682Smarkm    char password[512];
21955682Smarkm    size_t passlen;
22055682Smarkm
22155682Smarkm    memcpy(password, pw.data, min(pw.length, sizeof(password)));
22255682Smarkm    if(pw.length < sizeof(password))
22355682Smarkm	memcpy(password + pw.length,
22455682Smarkm	       cell.data, min(cell.length,
22555682Smarkm			      sizeof(password) - pw.length));
22655682Smarkm    passlen = min(sizeof(password), pw.length + cell.length);
22755682Smarkm    memcpy(&ivec, "kerberos", 8);
22855682Smarkm    memcpy(&temp_key, "kerberos", 8);
22955682Smarkm    des_set_odd_parity (&temp_key);
23055682Smarkm    des_set_key (&temp_key, schedule);
23155682Smarkm    des_cbc_cksum ((des_cblock *)password, &ivec, passlen, schedule, &ivec);
23255682Smarkm
23355682Smarkm    memcpy(&temp_key, &ivec, 8);
23455682Smarkm    des_set_odd_parity (&temp_key);
23555682Smarkm    des_set_key (&temp_key, schedule);
23655682Smarkm    des_cbc_cksum ((des_cblock *)password, key, passlen, schedule, &ivec);
23755682Smarkm    memset(&schedule, 0, sizeof(schedule));
23855682Smarkm    memset(&temp_key, 0, sizeof(temp_key));
23955682Smarkm    memset(&ivec, 0, sizeof(ivec));
24055682Smarkm    memset(password, 0, sizeof(password));
24155682Smarkm
24255682Smarkm    des_set_odd_parity (key);
24355682Smarkm}
24455682Smarkm
24555682Smarkmstatic krb5_error_code
24655682SmarkmDES_AFS3_string_to_key(krb5_context context,
24755682Smarkm		       krb5_enctype enctype,
24855682Smarkm		       krb5_data password,
24955682Smarkm		       krb5_salt salt,
25055682Smarkm		       krb5_keyblock *key)
25155682Smarkm{
25255682Smarkm    des_cblock tmp;
25355682Smarkm    if(password.length > 8)
25455682Smarkm	DES_AFS3_Transarc_string_to_key(password, salt.saltvalue, &tmp);
25555682Smarkm    else
25655682Smarkm	DES_AFS3_CMU_string_to_key(password, salt.saltvalue, &tmp);
25755682Smarkm    key->keytype = enctype;
25855682Smarkm    krb5_data_copy(&key->keyvalue, tmp, sizeof(tmp));
25955682Smarkm    memset(&key, 0, sizeof(key));
26055682Smarkm    return 0;
26155682Smarkm}
26255682Smarkm
26355682Smarkmstatic void
26455682SmarkmDES3_random_key(krb5_context context,
26555682Smarkm		krb5_keyblock *key)
26655682Smarkm{
26755682Smarkm    des_cblock *k = key->keyvalue.data;
26855682Smarkm    do {
26955682Smarkm	krb5_generate_random_block(k, 3 * sizeof(des_cblock));
27055682Smarkm	des_set_odd_parity(&k[0]);
27155682Smarkm	des_set_odd_parity(&k[1]);
27255682Smarkm	des_set_odd_parity(&k[2]);
27355682Smarkm    } while(des_is_weak_key(&k[0]) ||
27455682Smarkm	    des_is_weak_key(&k[1]) ||
27555682Smarkm	    des_is_weak_key(&k[2]));
27655682Smarkm}
27755682Smarkm
27855682Smarkmstatic void
27955682SmarkmDES3_schedule(krb5_context context,
28055682Smarkm	      struct key_data *key)
28155682Smarkm{
28255682Smarkm    des_cblock *k = key->key->keyvalue.data;
28355682Smarkm    des_key_schedule *s = key->schedule->data;
28455682Smarkm    des_set_key(&k[0], s[0]);
28555682Smarkm    des_set_key(&k[1], s[1]);
28655682Smarkm    des_set_key(&k[2], s[2]);
28755682Smarkm}
28855682Smarkm
28955682Smarkm/*
29055682Smarkm * A = A xor B. A & B are 8 bytes.
29155682Smarkm */
29255682Smarkm
29355682Smarkmstatic void
29455682Smarkmxor (des_cblock *key, const unsigned char *b)
29555682Smarkm{
29655682Smarkm    unsigned char *a = (unsigned char*)key;
29755682Smarkm    a[0] ^= b[0];
29855682Smarkm    a[1] ^= b[1];
29955682Smarkm    a[2] ^= b[2];
30055682Smarkm    a[3] ^= b[3];
30155682Smarkm    a[4] ^= b[4];
30255682Smarkm    a[5] ^= b[5];
30355682Smarkm    a[6] ^= b[6];
30455682Smarkm    a[7] ^= b[7];
30555682Smarkm}
30655682Smarkm
30755682Smarkmstatic krb5_error_code
30855682SmarkmDES3_string_to_key(krb5_context context,
30955682Smarkm		   krb5_enctype enctype,
31055682Smarkm		   krb5_data password,
31155682Smarkm		   krb5_salt salt,
31255682Smarkm		   krb5_keyblock *key)
31355682Smarkm{
31455682Smarkm    char *str;
31555682Smarkm    size_t len;
31655682Smarkm    unsigned char tmp[24];
31755682Smarkm    des_cblock keys[3];
31855682Smarkm
31955682Smarkm    len = password.length + salt.saltvalue.length;
32055682Smarkm    str = malloc(len);
32155682Smarkm    if(len != 0 && str == NULL)
32255682Smarkm	return ENOMEM;
32355682Smarkm    memcpy(str, password.data, password.length);
32455682Smarkm    memcpy(str + password.length, salt.saltvalue.data, salt.saltvalue.length);
32555682Smarkm    {
32655682Smarkm	des_cblock ivec;
32755682Smarkm	des_key_schedule s[3];
32855682Smarkm	int i;
32955682Smarkm
33055682Smarkm	_krb5_n_fold(str, len, tmp, 24);
33155682Smarkm
33255682Smarkm	for(i = 0; i < 3; i++){
33355682Smarkm	    memcpy(keys + i, tmp + i * 8, sizeof(keys[i]));
33455682Smarkm	    des_set_odd_parity(keys + i);
33555682Smarkm	    if(des_is_weak_key(keys + i))
33655682Smarkm		xor(keys + i, (unsigned char*)"\0\0\0\0\0\0\0\xf0");
33755682Smarkm	    des_set_key(keys + i, s[i]);
33855682Smarkm	}
33955682Smarkm	memset(&ivec, 0, sizeof(ivec));
34055682Smarkm	des_ede3_cbc_encrypt((void*)tmp, (void*)tmp, sizeof(tmp),
34155682Smarkm			     s[0], s[1], s[2], &ivec, DES_ENCRYPT);
34255682Smarkm	memset(s, 0, sizeof(s));
34355682Smarkm	memset(&ivec, 0, sizeof(ivec));
34455682Smarkm	for(i = 0; i < 3; i++){
34555682Smarkm	    memcpy(keys + i, tmp + i * 8, sizeof(keys[i]));
34655682Smarkm	    des_set_odd_parity(keys + i);
34755682Smarkm	    if(des_is_weak_key(keys + i))
34855682Smarkm		xor(keys + i, (unsigned char*)"\0\0\0\0\0\0\0\xf0");
34955682Smarkm	}
35055682Smarkm	memset(tmp, 0, sizeof(tmp));
35155682Smarkm    }
35255682Smarkm    key->keytype = enctype;
35355682Smarkm    krb5_data_copy(&key->keyvalue, keys, sizeof(keys));
35455682Smarkm    memset(keys, 0, sizeof(keys));
35555682Smarkm    memset(str, 0, len);
35655682Smarkm    free(str);
35755682Smarkm    return 0;
35855682Smarkm}
35955682Smarkm
36055682Smarkmstatic krb5_error_code
36155682SmarkmDES3_string_to_key_derived(krb5_context context,
36255682Smarkm			   krb5_enctype enctype,
36355682Smarkm			   krb5_data password,
36455682Smarkm			   krb5_salt salt,
36555682Smarkm			   krb5_keyblock *key)
36655682Smarkm{
36755682Smarkm    krb5_error_code ret;
36855682Smarkm    size_t len = password.length + salt.saltvalue.length;
36955682Smarkm    char *s;
37055682Smarkm
37155682Smarkm    s = malloc(len);
37255682Smarkm    if(len != 0 && s == NULL)
37355682Smarkm	return ENOMEM;
37455682Smarkm    memcpy(s, password.data, password.length);
37555682Smarkm    memcpy(s + password.length, salt.saltvalue.data, salt.saltvalue.length);
37655682Smarkm    ret = krb5_string_to_key_derived(context,
37755682Smarkm				     s,
37855682Smarkm				     len,
37955682Smarkm				     enctype,
38055682Smarkm				     key);
38155682Smarkm    memset(s, 0, len);
38255682Smarkm    free(s);
38355682Smarkm    return ret;
38455682Smarkm}
38555682Smarkm
38655682Smarkm/*
38755682Smarkm * ARCFOUR
38855682Smarkm */
38955682Smarkm
39055682Smarkmstatic void
39155682SmarkmARCFOUR_random_key(krb5_context context, krb5_keyblock *key)
39255682Smarkm{
39355682Smarkm    krb5_generate_random_block (key->keyvalue.data,
39455682Smarkm				key->keyvalue.length);
39555682Smarkm}
39655682Smarkm
39755682Smarkmstatic void
39855682SmarkmARCFOUR_schedule(krb5_context context, struct key_data *kd)
39955682Smarkm{
40055682Smarkm    RC4_set_key (kd->schedule->data,
40155682Smarkm		 kd->key->keyvalue.length, kd->key->keyvalue.data);
40255682Smarkm}
40355682Smarkm
40455682Smarkmstatic krb5_error_code
40555682SmarkmARCFOUR_string_to_key(krb5_context context,
40655682Smarkm		  krb5_enctype enctype,
40755682Smarkm		  krb5_data password,
40855682Smarkm		  krb5_salt salt,
40955682Smarkm		  krb5_keyblock *key)
41055682Smarkm{
41155682Smarkm    char *s, *p;
41255682Smarkm    size_t len;
41355682Smarkm    int i;
41455682Smarkm    struct md4 m;
41555682Smarkm
41655682Smarkm    len = 2 * (password.length + salt.saltvalue.length);
41755682Smarkm    s = malloc (len);
41855682Smarkm    if (len != 0 && s == NULL)
41955682Smarkm	return ENOMEM;
42055682Smarkm    for (p = s, i = 0; i < password.length; ++i) {
42155682Smarkm	*p++ = ((char *)password.data)[i];
42255682Smarkm	*p++ = 0;
42355682Smarkm    }
42455682Smarkm    for (i = 0; i < salt.saltvalue.length; ++i) {
42555682Smarkm	*p++ = ((char *)salt.saltvalue.data)[i];
42655682Smarkm	*p++ = 0;
42755682Smarkm    }
42855682Smarkm    md4_init(&m);
42955682Smarkm    md4_update(&m, s, len);
43055682Smarkm    key->keytype = enctype;
43155682Smarkm    krb5_data_alloc (&key->keyvalue, 16);
43255682Smarkm    md4_finito(&m, key->keyvalue.data);
43355682Smarkm    memset (s, 0, len);
43455682Smarkm    free (s);
43555682Smarkm    return 0;
43655682Smarkm}
43755682Smarkm
43855682Smarkmextern struct salt_type des_salt[],
43955682Smarkm    des3_salt[], des3_salt_derived[], arcfour_salt[];
44055682Smarkm
44155682Smarkmstruct key_type keytype_null = {
44255682Smarkm    KEYTYPE_NULL,
44355682Smarkm    "null",
44455682Smarkm    0,
44555682Smarkm    0,
44655682Smarkm    0,
44755682Smarkm    NULL,
44855682Smarkm    NULL,
44955682Smarkm    NULL
45055682Smarkm};
45155682Smarkm
45255682Smarkmstruct key_type keytype_des = {
45355682Smarkm    KEYTYPE_DES,
45455682Smarkm    "des",
45555682Smarkm    56,
45655682Smarkm    sizeof(des_cblock),
45755682Smarkm    sizeof(des_key_schedule),
45855682Smarkm    DES_random_key,
45955682Smarkm    DES_schedule,
46055682Smarkm    des_salt
46155682Smarkm};
46255682Smarkm
46355682Smarkmstruct key_type keytype_des3 = {
46455682Smarkm    KEYTYPE_DES3,
46555682Smarkm    "des3",
46655682Smarkm    168,
46755682Smarkm    3 * sizeof(des_cblock),
46855682Smarkm    3 * sizeof(des_key_schedule),
46955682Smarkm    DES3_random_key,
47055682Smarkm    DES3_schedule,
47155682Smarkm    des3_salt
47255682Smarkm};
47355682Smarkm
47455682Smarkmstruct key_type keytype_des3_derived = {
47555682Smarkm    KEYTYPE_DES3,
47655682Smarkm    "des3",
47755682Smarkm    168,
47855682Smarkm    3 * sizeof(des_cblock),
47955682Smarkm    3 * sizeof(des_key_schedule),
48055682Smarkm    DES3_random_key,
48155682Smarkm    DES3_schedule,
48255682Smarkm    des3_salt_derived
48355682Smarkm};
48455682Smarkm
48555682Smarkmstruct key_type keytype_arcfour = {
48655682Smarkm    KEYTYPE_ARCFOUR,
48755682Smarkm    "arcfour",
48855682Smarkm    128,
48955682Smarkm    16,
49055682Smarkm    sizeof(RC4_KEY),
49155682Smarkm    ARCFOUR_random_key,
49255682Smarkm    ARCFOUR_schedule,
49355682Smarkm    arcfour_salt
49455682Smarkm};
49555682Smarkm
49655682Smarkmstruct key_type *keytypes[] = {
49755682Smarkm    &keytype_null,
49855682Smarkm    &keytype_des,
49955682Smarkm    &keytype_des3_derived,
50055682Smarkm    &keytype_des3,
50155682Smarkm    &keytype_arcfour
50255682Smarkm};
50355682Smarkm
50455682Smarkmstatic int num_keytypes = sizeof(keytypes) / sizeof(keytypes[0]);
50555682Smarkm
50655682Smarkmstatic struct key_type *
50755682Smarkm_find_keytype(krb5_keytype type)
50855682Smarkm{
50955682Smarkm    int i;
51055682Smarkm    for(i = 0; i < num_keytypes; i++)
51155682Smarkm	if(keytypes[i]->type == type)
51255682Smarkm	    return keytypes[i];
51355682Smarkm    return NULL;
51455682Smarkm}
51555682Smarkm
51655682Smarkm
51755682Smarkmstruct salt_type des_salt[] = {
51855682Smarkm    {
51955682Smarkm	KRB5_PW_SALT,
52055682Smarkm	"pw-salt",
52155682Smarkm	DES_string_to_key
52255682Smarkm    },
52355682Smarkm    {
52455682Smarkm	KRB5_AFS3_SALT,
52555682Smarkm	"afs3-salt",
52655682Smarkm	DES_AFS3_string_to_key
52755682Smarkm    },
52855682Smarkm    { 0 }
52955682Smarkm};
53055682Smarkm
53155682Smarkmstruct salt_type des3_salt[] = {
53255682Smarkm    {
53355682Smarkm	KRB5_PW_SALT,
53455682Smarkm	"pw-salt",
53555682Smarkm	DES3_string_to_key
53655682Smarkm    },
53755682Smarkm    { 0 }
53855682Smarkm};
53955682Smarkm
54055682Smarkmstruct salt_type des3_salt_derived[] = {
54155682Smarkm    {
54255682Smarkm	KRB5_PW_SALT,
54355682Smarkm	"pw-salt",
54455682Smarkm	DES3_string_to_key_derived
54555682Smarkm    },
54655682Smarkm    { 0 }
54755682Smarkm};
54855682Smarkm
54955682Smarkmstruct salt_type arcfour_salt[] = {
55055682Smarkm    {
55155682Smarkm	KRB5_PW_SALT,
55255682Smarkm	"pw-salt",
55355682Smarkm	ARCFOUR_string_to_key
55455682Smarkm    },
55555682Smarkm    { 0 }
55655682Smarkm};
55755682Smarkm
55855682Smarkmkrb5_error_code
55955682Smarkmkrb5_salttype_to_string (krb5_context context,
56055682Smarkm			 krb5_enctype etype,
56155682Smarkm			 krb5_salttype stype,
56255682Smarkm			 char **string)
56355682Smarkm{
56455682Smarkm    struct encryption_type *e;
56555682Smarkm    struct salt_type *st;
56655682Smarkm
56755682Smarkm    e = _find_enctype (etype);
56855682Smarkm    if (e == NULL)
56955682Smarkm	return KRB5_PROG_ETYPE_NOSUPP;
57055682Smarkm    for (st = e->keytype->string_to_key; st && st->type; st++) {
57155682Smarkm	if (st->type == stype) {
57255682Smarkm	    *string = strdup (st->name);
57355682Smarkm	    if (*string == NULL)
57455682Smarkm		return ENOMEM;
57555682Smarkm	    return 0;
57655682Smarkm	}
57755682Smarkm    }
57855682Smarkm    return HEIM_ERR_SALTTYPE_NOSUPP;
57955682Smarkm}
58055682Smarkm
58155682Smarkmkrb5_error_code
58255682Smarkmkrb5_string_to_salttype (krb5_context context,
58355682Smarkm			 krb5_enctype etype,
58455682Smarkm			 const char *string,
58555682Smarkm			 krb5_salttype *salttype)
58655682Smarkm{
58755682Smarkm    struct encryption_type *e;
58855682Smarkm    struct salt_type *st;
58955682Smarkm
59055682Smarkm    e = _find_enctype (etype);
59155682Smarkm    if (e == NULL)
59255682Smarkm	return KRB5_PROG_ETYPE_NOSUPP;
59355682Smarkm    for (st = e->keytype->string_to_key; st && st->type; st++) {
59455682Smarkm	if (strcasecmp (st->name, string) == 0) {
59555682Smarkm	    *salttype = st->type;
59655682Smarkm	    return 0;
59755682Smarkm	}
59855682Smarkm    }
59955682Smarkm    return HEIM_ERR_SALTTYPE_NOSUPP;
60055682Smarkm}
60155682Smarkm
60255682Smarkmkrb5_error_code
60355682Smarkmkrb5_get_pw_salt(krb5_context context,
60455682Smarkm		 krb5_const_principal principal,
60555682Smarkm		 krb5_salt *salt)
60655682Smarkm{
60755682Smarkm    size_t len;
60855682Smarkm    int i;
60955682Smarkm    krb5_error_code ret;
61055682Smarkm    char *p;
61155682Smarkm
61255682Smarkm    salt->salttype = KRB5_PW_SALT;
61355682Smarkm    len = strlen(principal->realm);
61455682Smarkm    for (i = 0; i < principal->name.name_string.len; ++i)
61555682Smarkm	len += strlen(principal->name.name_string.val[i]);
61655682Smarkm    ret = krb5_data_alloc (&salt->saltvalue, len);
61755682Smarkm    if (ret)
61855682Smarkm	return ret;
61955682Smarkm    p = salt->saltvalue.data;
62055682Smarkm    memcpy (p, principal->realm, strlen(principal->realm));
62155682Smarkm    p += strlen(principal->realm);
62255682Smarkm    for (i = 0; i < principal->name.name_string.len; ++i) {
62355682Smarkm	memcpy (p,
62455682Smarkm		principal->name.name_string.val[i],
62555682Smarkm		strlen(principal->name.name_string.val[i]));
62655682Smarkm	p += strlen(principal->name.name_string.val[i]);
62755682Smarkm    }
62855682Smarkm    return 0;
62955682Smarkm}
63055682Smarkm
63155682Smarkmkrb5_error_code
63255682Smarkmkrb5_free_salt(krb5_context context,
63355682Smarkm	       krb5_salt salt)
63455682Smarkm{
63555682Smarkm    krb5_data_free(&salt.saltvalue);
63655682Smarkm    return 0;
63755682Smarkm}
63855682Smarkm
63955682Smarkmkrb5_error_code
64055682Smarkmkrb5_string_to_key_data (krb5_context context,
64155682Smarkm			 krb5_enctype enctype,
64255682Smarkm			 krb5_data password,
64355682Smarkm			 krb5_principal principal,
64455682Smarkm			 krb5_keyblock *key)
64555682Smarkm{
64655682Smarkm    krb5_error_code ret;
64755682Smarkm    krb5_salt salt;
64855682Smarkm
64955682Smarkm    ret = krb5_get_pw_salt(context, principal, &salt);
65055682Smarkm    if(ret)
65155682Smarkm	return ret;
65255682Smarkm    ret = krb5_string_to_key_data_salt(context, enctype, password, salt, key);
65355682Smarkm    krb5_free_salt(context, salt);
65455682Smarkm    return ret;
65555682Smarkm}
65655682Smarkm
65755682Smarkmkrb5_error_code
65855682Smarkmkrb5_string_to_key (krb5_context context,
65955682Smarkm		    krb5_enctype enctype,
66055682Smarkm		    const char *password,
66155682Smarkm		    krb5_principal principal,
66255682Smarkm		    krb5_keyblock *key)
66355682Smarkm{
66455682Smarkm    krb5_data pw;
66555682Smarkm    pw.data = (void*)password;
66655682Smarkm    pw.length = strlen(password);
66755682Smarkm    return krb5_string_to_key_data(context, enctype, pw, principal, key);
66855682Smarkm}
66955682Smarkm
67055682Smarkmkrb5_error_code
67155682Smarkmkrb5_string_to_key_data_salt (krb5_context context,
67255682Smarkm			      krb5_enctype enctype,
67355682Smarkm			      krb5_data password,
67455682Smarkm			      krb5_salt salt,
67555682Smarkm			      krb5_keyblock *key)
67655682Smarkm{
67755682Smarkm    struct encryption_type *et =_find_enctype(enctype);
67855682Smarkm    struct salt_type *st;
67955682Smarkm    if(et == NULL)
68055682Smarkm	return KRB5_PROG_ETYPE_NOSUPP;
68155682Smarkm    for(st = et->keytype->string_to_key; st && st->type; st++)
68255682Smarkm	if(st->type == salt.salttype)
68355682Smarkm	    return (*st->string_to_key)(context, enctype, password, salt, key);
68455682Smarkm    return HEIM_ERR_SALTTYPE_NOSUPP;
68555682Smarkm}
68655682Smarkm
68755682Smarkmkrb5_error_code
68855682Smarkmkrb5_string_to_key_salt (krb5_context context,
68955682Smarkm			 krb5_enctype enctype,
69055682Smarkm			 const char *password,
69155682Smarkm			 krb5_salt salt,
69255682Smarkm			 krb5_keyblock *key)
69355682Smarkm{
69455682Smarkm    krb5_data pw;
69555682Smarkm    pw.data = (void*)password;
69655682Smarkm    pw.length = strlen(password);
69755682Smarkm    return krb5_string_to_key_data_salt(context, enctype, pw, salt, key);
69855682Smarkm}
69955682Smarkm
70055682Smarkmkrb5_error_code
70155682Smarkmkrb5_keytype_to_string(krb5_context context,
70255682Smarkm		       krb5_keytype keytype,
70355682Smarkm		       char **string)
70455682Smarkm{
70555682Smarkm    struct key_type *kt = _find_keytype(keytype);
70655682Smarkm    if(kt == NULL)
70755682Smarkm	return KRB5_PROG_KEYTYPE_NOSUPP;
70855682Smarkm    *string = strdup(kt->name);
70955682Smarkm    if(*string == NULL)
71055682Smarkm	return ENOMEM;
71155682Smarkm    return 0;
71255682Smarkm}
71355682Smarkm
71455682Smarkmkrb5_error_code
71555682Smarkmkrb5_string_to_keytype(krb5_context context,
71655682Smarkm		       const char *string,
71755682Smarkm		       krb5_keytype *keytype)
71855682Smarkm{
71955682Smarkm    int i;
72055682Smarkm    for(i = 0; i < num_keytypes; i++)
72155682Smarkm	if(strcasecmp(keytypes[i]->name, string) == 0){
72255682Smarkm	    *keytype = keytypes[i]->type;
72355682Smarkm	    return 0;
72455682Smarkm	}
72555682Smarkm    return KRB5_PROG_KEYTYPE_NOSUPP;
72655682Smarkm}
72755682Smarkm
72855682Smarkmkrb5_error_code
72955682Smarkmkrb5_generate_random_keyblock(krb5_context context,
73055682Smarkm			      krb5_enctype type,
73155682Smarkm			      krb5_keyblock *key)
73255682Smarkm{
73355682Smarkm    krb5_error_code ret;
73455682Smarkm    struct encryption_type *et = _find_enctype(type);
73555682Smarkm    if(et == NULL)
73655682Smarkm	return KRB5_PROG_ETYPE_NOSUPP;
73755682Smarkm    ret = krb5_data_alloc(&key->keyvalue, et->keytype->size);
73855682Smarkm    if(ret)
73955682Smarkm	return ret;
74055682Smarkm    key->keytype = type;
74155682Smarkm    if(et->keytype->random_key)
74255682Smarkm	(*et->keytype->random_key)(context, key);
74355682Smarkm    else
74455682Smarkm	krb5_generate_random_block(key->keyvalue.data,
74555682Smarkm				   key->keyvalue.length);
74655682Smarkm    return 0;
74755682Smarkm}
74855682Smarkm
74955682Smarkmstatic krb5_error_code
75055682Smarkm_key_schedule(krb5_context context,
75155682Smarkm	      struct key_data *key)
75255682Smarkm{
75355682Smarkm    krb5_error_code ret;
75455682Smarkm    struct encryption_type *et = _find_enctype(key->key->keytype);
75555682Smarkm    struct key_type *kt = et->keytype;
75655682Smarkm
75755682Smarkm    if(kt->schedule == NULL)
75855682Smarkm	return 0;
75955682Smarkm    ALLOC(key->schedule, 1);
76055682Smarkm    if(key->schedule == NULL)
76155682Smarkm	return ENOMEM;
76255682Smarkm    ret = krb5_data_alloc(key->schedule, kt->schedule_size);
76355682Smarkm    if(ret) {
76455682Smarkm	free(key->schedule);
76555682Smarkm	key->schedule = NULL;
76655682Smarkm	return ret;
76755682Smarkm    }
76855682Smarkm    (*kt->schedule)(context, key);
76955682Smarkm    return 0;
77055682Smarkm}
77155682Smarkm
77255682Smarkm/************************************************************
77355682Smarkm *                                                          *
77455682Smarkm ************************************************************/
77555682Smarkm
77655682Smarkmstatic void
77755682SmarkmNONE_checksum(krb5_context context,
77855682Smarkm	      struct key_data *key,
77955682Smarkm	      void *data,
78055682Smarkm	      size_t len,
78155682Smarkm	      Checksum *C)
78255682Smarkm{
78355682Smarkm}
78455682Smarkm
78555682Smarkmstatic void
78655682SmarkmCRC32_checksum(krb5_context context,
78755682Smarkm	       struct key_data *key,
78855682Smarkm	       void *data,
78955682Smarkm	       size_t len,
79055682Smarkm	       Checksum *C)
79155682Smarkm{
79255682Smarkm    u_int32_t crc;
79355682Smarkm    unsigned char *r = C->checksum.data;
79455682Smarkm    _krb5_crc_init_table ();
79555682Smarkm    crc = _krb5_crc_update (data, len, 0);
79655682Smarkm    r[0] = crc & 0xff;
79755682Smarkm    r[1] = (crc >> 8)  & 0xff;
79855682Smarkm    r[2] = (crc >> 16) & 0xff;
79955682Smarkm    r[3] = (crc >> 24) & 0xff;
80055682Smarkm}
80155682Smarkm
80255682Smarkmstatic void
80355682SmarkmRSA_MD4_checksum(krb5_context context,
80455682Smarkm		 struct key_data *key,
80555682Smarkm		 void *data,
80655682Smarkm		 size_t len,
80755682Smarkm		 Checksum *C)
80855682Smarkm{
80955682Smarkm    struct md4 m;
81055682Smarkm    md4_init(&m);
81155682Smarkm    md4_update(&m, data, len);
81255682Smarkm    md4_finito(&m, C->checksum.data);
81355682Smarkm}
81455682Smarkm
81555682Smarkmstatic void
81655682SmarkmRSA_MD4_DES_checksum(krb5_context context,
81755682Smarkm		     struct key_data *key,
81855682Smarkm		     void *data,
81955682Smarkm		     size_t len,
82055682Smarkm		     Checksum *cksum)
82155682Smarkm{
82255682Smarkm    struct md4 md4;
82355682Smarkm    des_cblock ivec;
82455682Smarkm    unsigned char *p = cksum->checksum.data;
82555682Smarkm
82655682Smarkm    krb5_generate_random_block(p, 8);
82755682Smarkm    md4_init(&md4);
82855682Smarkm    md4_update(&md4, p, 8);
82955682Smarkm    md4_update(&md4, data, len);
83055682Smarkm    md4_finito(&md4, p + 8);
83155682Smarkm    memset (&ivec, 0, sizeof(ivec));
83255682Smarkm    des_cbc_encrypt((des_cblock*)p,
83355682Smarkm		    (des_cblock*)p,
83455682Smarkm		    24,
83555682Smarkm		    key->schedule->data,
83655682Smarkm		    &ivec,
83755682Smarkm		    DES_ENCRYPT);
83855682Smarkm}
83955682Smarkm
84055682Smarkmstatic krb5_error_code
84155682SmarkmRSA_MD4_DES_verify(krb5_context context,
84255682Smarkm		   struct key_data *key,
84355682Smarkm		   void *data,
84455682Smarkm		   size_t len,
84555682Smarkm		   Checksum *C)
84655682Smarkm{
84755682Smarkm    struct md4 md4;
84855682Smarkm    unsigned char tmp[24];
84955682Smarkm    unsigned char res[16];
85055682Smarkm    des_cblock ivec;
85155682Smarkm    krb5_error_code ret = 0;
85255682Smarkm
85355682Smarkm    memset(&ivec, 0, sizeof(ivec));
85455682Smarkm    des_cbc_encrypt(C->checksum.data,
85555682Smarkm		    (void*)tmp,
85655682Smarkm		    C->checksum.length,
85755682Smarkm		    key->schedule->data,
85855682Smarkm		    &ivec,
85955682Smarkm		    DES_DECRYPT);
86055682Smarkm    md4_init(&md4);
86155682Smarkm    md4_update(&md4, tmp, 8); /* confounder */
86255682Smarkm    md4_update(&md4, data, len);
86355682Smarkm    md4_finito(&md4, res);
86455682Smarkm    if(memcmp(res, tmp + 8, sizeof(res)) != 0)
86555682Smarkm	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
86655682Smarkm    memset(tmp, 0, sizeof(tmp));
86755682Smarkm    memset(res, 0, sizeof(res));
86855682Smarkm    return ret;
86955682Smarkm}
87055682Smarkm
87155682Smarkmstatic void
87255682SmarkmRSA_MD5_checksum(krb5_context context,
87355682Smarkm		 struct key_data *key,
87455682Smarkm		 void *data,
87555682Smarkm		 size_t len,
87655682Smarkm		 Checksum *C)
87755682Smarkm{
87855682Smarkm    struct md5 m;
87955682Smarkm    md5_init(&m);
88055682Smarkm    md5_update(&m, data, len);
88155682Smarkm    md5_finito(&m, C->checksum.data);
88255682Smarkm}
88355682Smarkm
88455682Smarkmstatic void
88555682SmarkmRSA_MD5_DES_checksum(krb5_context context,
88655682Smarkm		     struct key_data *key,
88755682Smarkm		     void *data,
88855682Smarkm		     size_t len,
88955682Smarkm		     Checksum *C)
89055682Smarkm{
89155682Smarkm    struct md5 md5;
89255682Smarkm    des_cblock ivec;
89355682Smarkm    unsigned char *p = C->checksum.data;
89455682Smarkm
89555682Smarkm    krb5_generate_random_block(p, 8);
89655682Smarkm    md5_init(&md5);
89755682Smarkm    md5_update(&md5, p, 8);
89855682Smarkm    md5_update(&md5, data, len);
89955682Smarkm    md5_finito(&md5, p + 8);
90055682Smarkm    memset (&ivec, 0, sizeof(ivec));
90155682Smarkm    des_cbc_encrypt((des_cblock*)p,
90255682Smarkm		    (des_cblock*)p,
90355682Smarkm		    24,
90455682Smarkm		    key->schedule->data,
90555682Smarkm		    &ivec,
90655682Smarkm		    DES_ENCRYPT);
90755682Smarkm}
90855682Smarkm
90955682Smarkmstatic krb5_error_code
91055682SmarkmRSA_MD5_DES_verify(krb5_context context,
91155682Smarkm		   struct key_data *key,
91255682Smarkm		   void *data,
91355682Smarkm		   size_t len,
91455682Smarkm		   Checksum *C)
91555682Smarkm{
91655682Smarkm    struct md5 md5;
91755682Smarkm    unsigned char tmp[24];
91855682Smarkm    unsigned char res[16];
91955682Smarkm    des_cblock ivec;
92055682Smarkm    des_key_schedule *sched = key->schedule->data;
92155682Smarkm    krb5_error_code ret = 0;
92255682Smarkm
92355682Smarkm    memset(&ivec, 0, sizeof(ivec));
92455682Smarkm    des_cbc_encrypt(C->checksum.data,
92555682Smarkm		    (void*)tmp,
92655682Smarkm		    C->checksum.length,
92755682Smarkm		    sched[0],
92855682Smarkm		    &ivec,
92955682Smarkm		    DES_DECRYPT);
93055682Smarkm    md5_init(&md5);
93155682Smarkm    md5_update(&md5, tmp, 8); /* confounder */
93255682Smarkm    md5_update(&md5, data, len);
93355682Smarkm    md5_finito(&md5, res);
93455682Smarkm    if(memcmp(res, tmp + 8, sizeof(res)) != 0)
93555682Smarkm	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
93655682Smarkm    memset(tmp, 0, sizeof(tmp));
93755682Smarkm    memset(res, 0, sizeof(res));
93855682Smarkm    return ret;
93955682Smarkm}
94055682Smarkm
94155682Smarkmstatic void
94255682SmarkmRSA_MD5_DES3_checksum(krb5_context context,
94355682Smarkm		      struct key_data *key,
94455682Smarkm		      void *data,
94555682Smarkm		      size_t len,
94655682Smarkm		      Checksum *C)
94755682Smarkm{
94855682Smarkm    struct md5 md5;
94955682Smarkm    des_cblock ivec;
95055682Smarkm    unsigned char *p = C->checksum.data;
95155682Smarkm    des_key_schedule *sched = key->schedule->data;
95255682Smarkm
95355682Smarkm    krb5_generate_random_block(p, 8);
95455682Smarkm    md5_init(&md5);
95555682Smarkm    md5_update(&md5, p, 8);
95655682Smarkm    md5_update(&md5, data, len);
95755682Smarkm    md5_finito(&md5, p + 8);
95855682Smarkm    memset (&ivec, 0, sizeof(ivec));
95955682Smarkm    des_ede3_cbc_encrypt((des_cblock*)p,
96055682Smarkm			 (des_cblock*)p,
96155682Smarkm			 24,
96255682Smarkm			 sched[0], sched[1], sched[2],
96355682Smarkm			 &ivec,
96455682Smarkm			 DES_ENCRYPT);
96555682Smarkm}
96655682Smarkm
96755682Smarkmstatic krb5_error_code
96855682SmarkmRSA_MD5_DES3_verify(krb5_context context,
96955682Smarkm		    struct key_data *key,
97055682Smarkm		    void *data,
97155682Smarkm		    size_t len,
97255682Smarkm		    Checksum *C)
97355682Smarkm{
97455682Smarkm    struct md5 md5;
97555682Smarkm    unsigned char tmp[24];
97655682Smarkm    unsigned char res[16];
97755682Smarkm    des_cblock ivec;
97855682Smarkm    des_key_schedule *sched = key->schedule->data;
97955682Smarkm    krb5_error_code ret = 0;
98055682Smarkm
98155682Smarkm    memset(&ivec, 0, sizeof(ivec));
98255682Smarkm    des_ede3_cbc_encrypt(C->checksum.data,
98355682Smarkm			 (void*)tmp,
98455682Smarkm			 C->checksum.length,
98555682Smarkm			 sched[0], sched[1], sched[2],
98655682Smarkm			 &ivec,
98755682Smarkm			 DES_DECRYPT);
98855682Smarkm    md5_init(&md5);
98955682Smarkm    md5_update(&md5, tmp, 8); /* confounder */
99055682Smarkm    md5_update(&md5, data, len);
99155682Smarkm    md5_finito(&md5, res);
99255682Smarkm    if(memcmp(res, tmp + 8, sizeof(res)) != 0)
99355682Smarkm	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
99455682Smarkm    memset(tmp, 0, sizeof(tmp));
99555682Smarkm    memset(res, 0, sizeof(res));
99655682Smarkm    return ret;
99755682Smarkm}
99855682Smarkm
99955682Smarkmstatic void
100055682SmarkmSHA1_checksum(krb5_context context,
100155682Smarkm	      struct key_data *key,
100255682Smarkm	      void *data,
100355682Smarkm	      size_t len,
100455682Smarkm	      Checksum *C)
100555682Smarkm{
100655682Smarkm    struct sha m;
100755682Smarkm    sha_init(&m);
100855682Smarkm    sha_update(&m, data, len);
100955682Smarkm    sha_finito(&m, C->checksum.data);
101055682Smarkm}
101155682Smarkm
101255682Smarkm/* HMAC according to RFC2104 */
101355682Smarkmstatic void
101455682Smarkmhmac(krb5_context context,
101555682Smarkm     struct checksum_type *cm,
101655682Smarkm     void *data,
101755682Smarkm     size_t len,
101855682Smarkm     struct key_data *keyblock,
101955682Smarkm     Checksum *result)
102055682Smarkm{
102155682Smarkm    unsigned char *ipad, *opad;
102255682Smarkm    unsigned char *key;
102355682Smarkm    size_t key_len;
102455682Smarkm    int i;
102555682Smarkm
102655682Smarkm    if(keyblock->key->keyvalue.length > cm->blocksize){
102755682Smarkm	(*cm->checksum)(context,
102855682Smarkm			keyblock,
102955682Smarkm			keyblock->key->keyvalue.data,
103055682Smarkm			keyblock->key->keyvalue.length,
103155682Smarkm			result);
103255682Smarkm	key = result->checksum.data;
103355682Smarkm	key_len = result->checksum.length;
103455682Smarkm    } else {
103555682Smarkm	key = keyblock->key->keyvalue.data;
103655682Smarkm	key_len = keyblock->key->keyvalue.length;
103755682Smarkm    }
103855682Smarkm    ipad = malloc(cm->blocksize + len);
103955682Smarkm    opad = malloc(cm->blocksize + cm->checksumsize);
104055682Smarkm    memset(ipad, 0x36, cm->blocksize);
104155682Smarkm    memset(opad, 0x5c, cm->blocksize);
104255682Smarkm    for(i = 0; i < key_len; i++){
104355682Smarkm	ipad[i] ^= key[i];
104455682Smarkm	opad[i] ^= key[i];
104555682Smarkm    }
104655682Smarkm    memcpy(ipad + cm->blocksize, data, len);
104755682Smarkm    (*cm->checksum)(context, keyblock, ipad, cm->blocksize + len, result);
104855682Smarkm    memcpy(opad + cm->blocksize, result->checksum.data,
104955682Smarkm	   result->checksum.length);
105055682Smarkm    (*cm->checksum)(context, keyblock, opad,
105155682Smarkm		    cm->blocksize + cm->checksumsize, result);
105255682Smarkm    memset(ipad, 0, cm->blocksize + len);
105355682Smarkm    free(ipad);
105455682Smarkm    memset(opad, 0, cm->blocksize + cm->checksumsize);
105555682Smarkm    free(opad);
105655682Smarkm}
105755682Smarkm
105855682Smarkmstatic void
105955682SmarkmHMAC_SHA1_DES3_checksum(krb5_context context,
106055682Smarkm			struct key_data *key,
106155682Smarkm			void *data,
106255682Smarkm			size_t len,
106355682Smarkm			Checksum *result)
106455682Smarkm{
106555682Smarkm    struct checksum_type *c = _find_checksum(CKSUMTYPE_SHA1);
106655682Smarkm
106755682Smarkm    hmac(context, c, data, len, key, result);
106855682Smarkm}
106955682Smarkm
107055682Smarkmstruct checksum_type checksum_none = {
107155682Smarkm    CKSUMTYPE_NONE,
107255682Smarkm    "none",
107355682Smarkm    1,
107455682Smarkm    0,
107555682Smarkm    0,
107655682Smarkm    NONE_checksum,
107755682Smarkm    NULL
107855682Smarkm};
107955682Smarkmstruct checksum_type checksum_crc32 = {
108055682Smarkm    CKSUMTYPE_CRC32,
108155682Smarkm    "crc32",
108255682Smarkm    1,
108355682Smarkm    4,
108455682Smarkm    0,
108555682Smarkm    CRC32_checksum,
108655682Smarkm    NULL
108755682Smarkm};
108855682Smarkmstruct checksum_type checksum_rsa_md4 = {
108955682Smarkm    CKSUMTYPE_RSA_MD4,
109055682Smarkm    "rsa-md4",
109155682Smarkm    64,
109255682Smarkm    16,
109355682Smarkm    F_CPROOF,
109455682Smarkm    RSA_MD4_checksum,
109555682Smarkm    NULL
109655682Smarkm};
109755682Smarkmstruct checksum_type checksum_rsa_md4_des = {
109855682Smarkm    CKSUMTYPE_RSA_MD4_DES,
109955682Smarkm    "rsa-md4-des",
110055682Smarkm    64,
110155682Smarkm    24,
110255682Smarkm    F_KEYED | F_CPROOF | F_VARIANT,
110355682Smarkm    RSA_MD4_DES_checksum,
110455682Smarkm    RSA_MD4_DES_verify
110555682Smarkm};
110655682Smarkm#if 0
110755682Smarkmstruct checksum_type checksum_des_mac = {
110855682Smarkm    CKSUMTYPE_DES_MAC,
110955682Smarkm    "des-mac",
111055682Smarkm    0,
111155682Smarkm    0,
111255682Smarkm    0,
111355682Smarkm    DES_MAC_checksum,
111455682Smarkm};
111555682Smarkmstruct checksum_type checksum_des_mac_k = {
111655682Smarkm    CKSUMTYPE_DES_MAC_K,
111755682Smarkm    "des-mac-k",
111855682Smarkm    0,
111955682Smarkm    0,
112055682Smarkm    0,
112155682Smarkm    DES_MAC_K_checksum,
112255682Smarkm};
112355682Smarkmstruct checksum_type checksum_rsa_md4_des_k = {
112455682Smarkm    CKSUMTYPE_RSA_MD4_DES_K,
112555682Smarkm    "rsa-md4-des-k",
112655682Smarkm    0,
112755682Smarkm    0,
112855682Smarkm    0,
112955682Smarkm    RSA_MD4_DES_K_checksum,
113055682Smarkm    RSA_MD4_DES_K_verify,
113155682Smarkm};
113255682Smarkm#endif
113355682Smarkmstruct checksum_type checksum_rsa_md5 = {
113455682Smarkm    CKSUMTYPE_RSA_MD5,
113555682Smarkm    "rsa-md5",
113655682Smarkm    64,
113755682Smarkm    16,
113855682Smarkm    F_CPROOF,
113955682Smarkm    RSA_MD5_checksum,
114055682Smarkm    NULL
114155682Smarkm};
114255682Smarkmstruct checksum_type checksum_rsa_md5_des = {
114355682Smarkm    CKSUMTYPE_RSA_MD5_DES,
114455682Smarkm    "rsa-md5-des",
114555682Smarkm    64,
114655682Smarkm    24,
114755682Smarkm    F_KEYED | F_CPROOF | F_VARIANT,
114855682Smarkm    RSA_MD5_DES_checksum,
114955682Smarkm    RSA_MD5_DES_verify,
115055682Smarkm};
115155682Smarkmstruct checksum_type checksum_rsa_md5_des3 = {
115255682Smarkm    CKSUMTYPE_RSA_MD5_DES3,
115355682Smarkm    "rsa-md5-des3",
115455682Smarkm    64,
115555682Smarkm    24,
115655682Smarkm    F_KEYED | F_CPROOF | F_VARIANT,
115755682Smarkm    RSA_MD5_DES3_checksum,
115855682Smarkm    RSA_MD5_DES3_verify,
115955682Smarkm};
116055682Smarkmstruct checksum_type checksum_sha1 = {
116155682Smarkm    CKSUMTYPE_SHA1,
116255682Smarkm    "sha1",
116355682Smarkm    64,
116455682Smarkm    20,
116555682Smarkm    F_CPROOF,
116655682Smarkm    SHA1_checksum,
116755682Smarkm    NULL
116855682Smarkm};
116955682Smarkmstruct checksum_type checksum_hmac_sha1_des3 = {
117055682Smarkm    CKSUMTYPE_HMAC_SHA1_DES3,
117155682Smarkm    "hmac-sha1-des3",
117255682Smarkm    64,
117355682Smarkm    20,
117455682Smarkm    F_KEYED | F_CPROOF | F_DERIVED,
117555682Smarkm    HMAC_SHA1_DES3_checksum,
117655682Smarkm    NULL
117755682Smarkm};
117855682Smarkm
117955682Smarkmstruct checksum_type *checksum_types[] = {
118055682Smarkm    &checksum_none,
118155682Smarkm    &checksum_crc32,
118255682Smarkm    &checksum_rsa_md4,
118355682Smarkm    &checksum_rsa_md4_des,
118455682Smarkm#if 0
118555682Smarkm    &checksum_des_mac,
118655682Smarkm    &checksum_des_mac_k,
118755682Smarkm    &checksum_rsa_md4_des_k,
118855682Smarkm#endif
118955682Smarkm    &checksum_rsa_md5,
119055682Smarkm    &checksum_rsa_md5_des,
119155682Smarkm    &checksum_rsa_md5_des3,
119255682Smarkm    &checksum_sha1,
119355682Smarkm    &checksum_hmac_sha1_des3
119455682Smarkm};
119555682Smarkm
119655682Smarkmstatic int num_checksums = sizeof(checksum_types) / sizeof(checksum_types[0]);
119755682Smarkm
119855682Smarkmstatic struct checksum_type *
119955682Smarkm_find_checksum(krb5_cksumtype type)
120055682Smarkm{
120155682Smarkm    int i;
120255682Smarkm    for(i = 0; i < num_checksums; i++)
120355682Smarkm	if(checksum_types[i]->type == type)
120455682Smarkm	    return checksum_types[i];
120555682Smarkm    return NULL;
120655682Smarkm}
120755682Smarkm
120855682Smarkmstatic krb5_error_code
120955682Smarkmget_checksum_key(krb5_context context,
121055682Smarkm		 krb5_crypto crypto,
121155682Smarkm		 unsigned usage,  /* not krb5_key_usage */
121255682Smarkm		 struct checksum_type *ct,
121355682Smarkm		 struct key_data **key)
121455682Smarkm{
121555682Smarkm    krb5_error_code ret = 0;
121655682Smarkm
121755682Smarkm    if(ct->flags & F_DERIVED)
121855682Smarkm	ret = _get_derived_key(context, crypto, usage, key);
121955682Smarkm    else if(ct->flags & F_VARIANT) {
122055682Smarkm	int i;
122155682Smarkm
122255682Smarkm	*key = _new_derived_key(crypto, 0xff/* KRB5_KU_RFC1510_VARIANT */);
122355682Smarkm	if(*key == NULL)
122455682Smarkm	    return ENOMEM;
122555682Smarkm	ret = krb5_copy_keyblock(context, crypto->key.key, &(*key)->key);
122655682Smarkm	if(ret)
122755682Smarkm	    return ret;
122855682Smarkm	for(i = 0; i < (*key)->key->keyvalue.length; i++)
122955682Smarkm	    ((unsigned char*)(*key)->key->keyvalue.data)[i] ^= 0xF0;
123055682Smarkm    } else {
123155682Smarkm	*key = &crypto->key;
123255682Smarkm    }
123355682Smarkm    if(ret == 0)
123455682Smarkm	ret = _key_schedule(context, *key);
123555682Smarkm    return ret;
123655682Smarkm}
123755682Smarkm
123855682Smarkmstatic krb5_error_code
123955682Smarkmdo_checksum (krb5_context context,
124055682Smarkm	     struct checksum_type *ct,
124155682Smarkm	     krb5_crypto crypto,
124255682Smarkm	     unsigned usage,
124355682Smarkm	     void *data,
124455682Smarkm	     size_t len,
124555682Smarkm	     Checksum *result)
124655682Smarkm{
124755682Smarkm    krb5_error_code ret;
124855682Smarkm    struct key_data *dkey;
124955682Smarkm    int keyed_checksum;
125055682Smarkm
125155682Smarkm    keyed_checksum = (ct->flags & F_KEYED) != 0;
125255682Smarkm    if(keyed_checksum && crypto == NULL)
125355682Smarkm	return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
125455682Smarkm    if(keyed_checksum)
125555682Smarkm	ret = get_checksum_key(context, crypto, usage, ct, &dkey);
125655682Smarkm    else
125755682Smarkm	dkey = NULL;
125855682Smarkm    result->cksumtype = ct->type;
125955682Smarkm    krb5_data_alloc(&result->checksum, ct->checksumsize);
126055682Smarkm    (*ct->checksum)(context, dkey, data, len, result);
126155682Smarkm    return 0;
126255682Smarkm}
126355682Smarkm
126455682Smarkmstatic krb5_error_code
126555682Smarkmcreate_checksum(krb5_context context,
126655682Smarkm		krb5_crypto crypto,
126755682Smarkm		unsigned usage, /* not krb5_key_usage */
126855682Smarkm		krb5_cksumtype type, /* if crypto == NULL */
126955682Smarkm		void *data,
127055682Smarkm		size_t len,
127155682Smarkm		Checksum *result)
127255682Smarkm{
127355682Smarkm    struct checksum_type *ct;
127455682Smarkm
127555682Smarkm    if(crypto) {
127655682Smarkm	ct = crypto->et->keyed_checksum;
127755682Smarkm	if(ct == NULL)
127855682Smarkm	    ct = crypto->et->cksumtype;
127955682Smarkm    } else
128055682Smarkm	ct = _find_checksum(type);
128155682Smarkm    if(ct == NULL)
128255682Smarkm	return KRB5_PROG_SUMTYPE_NOSUPP;
128355682Smarkm    return do_checksum (context, ct, crypto, usage, data, len, result);
128455682Smarkm}
128555682Smarkm
128655682Smarkmkrb5_error_code
128755682Smarkmkrb5_create_checksum(krb5_context context,
128855682Smarkm		     krb5_crypto crypto,
128955682Smarkm		     unsigned usage_or_type,
129055682Smarkm		     void *data,
129155682Smarkm		     size_t len,
129255682Smarkm		     Checksum *result)
129355682Smarkm{
129455682Smarkm    return create_checksum(context, crypto,
129555682Smarkm			   CHECKSUM_USAGE(usage_or_type),
129655682Smarkm			   usage_or_type, data, len, result);
129755682Smarkm}
129855682Smarkm
129955682Smarkmstatic krb5_error_code
130055682Smarkmverify_checksum(krb5_context context,
130155682Smarkm		krb5_crypto crypto,
130255682Smarkm		unsigned usage, /* not krb5_key_usage */
130355682Smarkm		void *data,
130455682Smarkm		size_t len,
130555682Smarkm		Checksum *cksum)
130655682Smarkm{
130755682Smarkm    krb5_error_code ret;
130855682Smarkm    struct key_data *dkey;
130955682Smarkm    int keyed_checksum;
131055682Smarkm    Checksum c;
131155682Smarkm    struct checksum_type *ct;
131255682Smarkm
131355682Smarkm    ct = _find_checksum(cksum->cksumtype);
131455682Smarkm    if(ct == NULL)
131555682Smarkm	return KRB5_PROG_SUMTYPE_NOSUPP;
131655682Smarkm    if(ct->checksumsize != cksum->checksum.length)
131755682Smarkm	return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */
131855682Smarkm    keyed_checksum = (ct->flags & F_KEYED) != 0;
131955682Smarkm    if(keyed_checksum && crypto == NULL)
132055682Smarkm	return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */
132155682Smarkm    if(keyed_checksum)
132255682Smarkm	ret = get_checksum_key(context, crypto, usage, ct, &dkey);
132355682Smarkm    else
132455682Smarkm	dkey = NULL;
132555682Smarkm    if(ct->verify)
132655682Smarkm	return (*ct->verify)(context, dkey, data, len, cksum);
132755682Smarkm
132855682Smarkm    ret = krb5_data_alloc (&c.checksum, ct->checksumsize);
132955682Smarkm    if (ret)
133055682Smarkm	return ret;
133155682Smarkm
133255682Smarkm    (*ct->checksum)(context, dkey, data, len, &c);
133355682Smarkm
133455682Smarkm    if(c.checksum.length != cksum->checksum.length ||
133555682Smarkm       memcmp(c.checksum.data, cksum->checksum.data, c.checksum.length))
133655682Smarkm	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
133755682Smarkm    else
133855682Smarkm	ret = 0;
133955682Smarkm    krb5_data_free (&c.checksum);
134055682Smarkm    return ret;
134155682Smarkm}
134255682Smarkm
134355682Smarkmkrb5_error_code
134455682Smarkmkrb5_verify_checksum(krb5_context context,
134555682Smarkm		     krb5_crypto crypto,
134655682Smarkm		     krb5_key_usage usage,
134755682Smarkm		     void *data,
134855682Smarkm		     size_t len,
134955682Smarkm		     Checksum *cksum)
135055682Smarkm{
135155682Smarkm    return verify_checksum(context, crypto,
135255682Smarkm			   CHECKSUM_USAGE(usage), data, len, cksum);
135355682Smarkm}
135455682Smarkm
135555682Smarkmkrb5_error_code
135655682Smarkmkrb5_checksumsize(krb5_context context,
135755682Smarkm		  krb5_cksumtype type,
135855682Smarkm		  size_t *size)
135955682Smarkm{
136055682Smarkm    struct checksum_type *ct = _find_checksum(type);
136155682Smarkm    if(ct == NULL)
136255682Smarkm	return KRB5_PROG_SUMTYPE_NOSUPP;
136355682Smarkm    *size = ct->checksumsize;
136455682Smarkm    return 0;
136555682Smarkm}
136655682Smarkm
136755682Smarkmkrb5_boolean
136855682Smarkmkrb5_checksum_is_keyed(krb5_context context,
136955682Smarkm		       krb5_cksumtype type)
137055682Smarkm{
137155682Smarkm    struct checksum_type *ct = _find_checksum(type);
137255682Smarkm    if(ct == NULL)
137355682Smarkm	return KRB5_PROG_SUMTYPE_NOSUPP;
137455682Smarkm    return ct->flags & F_KEYED;
137555682Smarkm}
137655682Smarkm
137755682Smarkmkrb5_boolean
137855682Smarkmkrb5_checksum_is_collision_proof(krb5_context context,
137955682Smarkm				 krb5_cksumtype type)
138055682Smarkm{
138155682Smarkm    struct checksum_type *ct = _find_checksum(type);
138255682Smarkm    if(ct == NULL)
138355682Smarkm	return KRB5_PROG_SUMTYPE_NOSUPP;
138455682Smarkm    return ct->flags & F_CPROOF;
138555682Smarkm}
138655682Smarkm
138755682Smarkm/************************************************************
138855682Smarkm *                                                          *
138955682Smarkm ************************************************************/
139055682Smarkm
139155682Smarkmstatic void
139255682SmarkmNULL_encrypt(struct key_data *key,
139355682Smarkm	     void *data,
139455682Smarkm	     size_t len,
139555682Smarkm	     krb5_boolean encrypt)
139655682Smarkm{
139755682Smarkm}
139855682Smarkm
139955682Smarkmstatic void
140055682SmarkmDES_CBC_encrypt_null_ivec(struct key_data *key,
140155682Smarkm			  void *data,
140255682Smarkm			  size_t len,
140355682Smarkm			  krb5_boolean encrypt)
140455682Smarkm{
140555682Smarkm    des_cblock ivec;
140655682Smarkm    des_key_schedule *s = key->schedule->data;
140755682Smarkm    memset(&ivec, 0, sizeof(ivec));
140855682Smarkm    des_cbc_encrypt(data, data, len, *s, &ivec, encrypt);
140955682Smarkm}
141055682Smarkm
141155682Smarkmstatic void
141255682SmarkmDES_CBC_encrypt_key_ivec(struct key_data *key,
141355682Smarkm			 void *data,
141455682Smarkm			 size_t len,
141555682Smarkm			 krb5_boolean encrypt)
141655682Smarkm{
141755682Smarkm    des_cblock ivec;
141855682Smarkm    des_key_schedule *s = key->schedule->data;
141955682Smarkm    memcpy(&ivec, key->key->keyvalue.data, sizeof(ivec));
142055682Smarkm    des_cbc_encrypt(data, data, len, *s, &ivec, encrypt);
142155682Smarkm}
142255682Smarkm
142355682Smarkmstatic void
142455682SmarkmDES3_CBC_encrypt(struct key_data *key,
142555682Smarkm		 void *data,
142655682Smarkm		 size_t len,
142755682Smarkm		 krb5_boolean encrypt)
142855682Smarkm{
142955682Smarkm    des_cblock ivec;
143055682Smarkm    des_key_schedule *s = key->schedule->data;
143155682Smarkm    memset(&ivec, 0, sizeof(ivec));
143255682Smarkm    des_ede3_cbc_encrypt(data, data, len, s[0], s[1], s[2], &ivec, encrypt);
143355682Smarkm}
143455682Smarkm
143555682Smarkmstatic void
143655682SmarkmARCFOUR_encrypt(struct key_data *key,
143755682Smarkm		void *data,
143855682Smarkm		size_t len,
143955682Smarkm		krb5_boolean encrypt)
144055682Smarkm{
144155682Smarkm
144255682Smarkm}
144355682Smarkm
144455682Smarkm/*
144555682Smarkm * these should currently be in reverse preference order.
144655682Smarkm */
144755682Smarkm
144855682Smarkmstatic struct encryption_type etypes[] = {
144955682Smarkm    {
145055682Smarkm	ETYPE_NULL,
145155682Smarkm	"null",
145255682Smarkm	1,
145355682Smarkm	0,
145455682Smarkm	&keytype_null,
145555682Smarkm	&checksum_none,
145655682Smarkm	NULL,
145755682Smarkm	0,
145855682Smarkm	NULL_encrypt,
145955682Smarkm    },
146055682Smarkm    {
146155682Smarkm	ETYPE_DES_CBC_CRC,
146255682Smarkm	"des-cbc-crc",
146355682Smarkm	8,
146455682Smarkm	8,
146555682Smarkm	&keytype_des,
146655682Smarkm	&checksum_crc32,
146755682Smarkm	NULL,
146855682Smarkm	0,
146955682Smarkm	DES_CBC_encrypt_key_ivec,
147055682Smarkm    },
147155682Smarkm    {
147255682Smarkm	ETYPE_DES_CBC_MD4,
147355682Smarkm	"des-cbc-md4",
147455682Smarkm	8,
147555682Smarkm	8,
147655682Smarkm	&keytype_des,
147755682Smarkm	&checksum_rsa_md4,
147855682Smarkm	&checksum_rsa_md4_des,
147955682Smarkm	0,
148055682Smarkm	DES_CBC_encrypt_null_ivec,
148155682Smarkm    },
148255682Smarkm    {
148355682Smarkm	ETYPE_DES_CBC_MD5,
148455682Smarkm	"des-cbc-md5",
148555682Smarkm	8,
148655682Smarkm	8,
148755682Smarkm	&keytype_des,
148855682Smarkm	&checksum_rsa_md5,
148955682Smarkm	&checksum_rsa_md5_des,
149055682Smarkm	0,
149155682Smarkm	DES_CBC_encrypt_null_ivec,
149255682Smarkm    },
149355682Smarkm    {
149455682Smarkm	ETYPE_DES3_CBC_MD5,
149555682Smarkm	"des3-cbc-md5",
149655682Smarkm	8,
149755682Smarkm	8,
149855682Smarkm	&keytype_des3,
149955682Smarkm	&checksum_rsa_md5,
150055682Smarkm	&checksum_rsa_md5_des3,
150155682Smarkm	0,
150255682Smarkm 	DES3_CBC_encrypt,
150355682Smarkm    },
150455682Smarkm    {
150555682Smarkm	ETYPE_DES3_CBC_SHA1,
150655682Smarkm	"des3-cbc-sha1",
150755682Smarkm	8,
150855682Smarkm	8,
150955682Smarkm	&keytype_des3_derived,
151055682Smarkm	&checksum_sha1,
151155682Smarkm	&checksum_hmac_sha1_des3,
151255682Smarkm	F_DERIVED,
151355682Smarkm 	DES3_CBC_encrypt,
151455682Smarkm    },
151555682Smarkm    {
151655682Smarkm	ETYPE_OLD_DES3_CBC_SHA1,
151755682Smarkm	"old-des3-cbc-sha1",
151855682Smarkm	8,
151955682Smarkm	8,
152055682Smarkm	&keytype_des3,
152155682Smarkm	&checksum_sha1,
152255682Smarkm	&checksum_hmac_sha1_des3,
152355682Smarkm	0,
152455682Smarkm 	DES3_CBC_encrypt,
152555682Smarkm    },
152655682Smarkm    {
152755682Smarkm	ETYPE_DES_CBC_NONE,
152855682Smarkm	"des-cbc-none",
152955682Smarkm	8,
153055682Smarkm	0,
153155682Smarkm	&keytype_des,
153255682Smarkm	&checksum_none,
153355682Smarkm	NULL,
153455682Smarkm	F_PSEUDO,
153555682Smarkm	DES_CBC_encrypt_null_ivec,
153655682Smarkm    },
153755682Smarkm    {
153855682Smarkm	ETYPE_DES3_CBC_NONE,
153955682Smarkm	"des3-cbc-none",
154055682Smarkm	8,
154155682Smarkm	0,
154255682Smarkm	&keytype_des3_derived,
154355682Smarkm	&checksum_none,
154455682Smarkm	NULL,
154555682Smarkm	F_PSEUDO,
154655682Smarkm	DES_CBC_encrypt_null_ivec,
154755682Smarkm    },
154855682Smarkm};
154955682Smarkm
155055682Smarkmstatic unsigned num_etypes = sizeof(etypes) / sizeof(etypes[0]);
155155682Smarkm
155255682Smarkm
155355682Smarkmstatic struct encryption_type *
155455682Smarkm_find_enctype(krb5_enctype type)
155555682Smarkm{
155655682Smarkm    int i;
155755682Smarkm    for(i = 0; i < num_etypes; i++)
155855682Smarkm	if(etypes[i].type == type)
155955682Smarkm	    return &etypes[i];
156055682Smarkm    return NULL;
156155682Smarkm}
156255682Smarkm
156355682Smarkm
156455682Smarkmkrb5_error_code
156555682Smarkmkrb5_enctype_to_string(krb5_context context,
156655682Smarkm		       krb5_enctype etype,
156755682Smarkm		       char **string)
156855682Smarkm{
156955682Smarkm    struct encryption_type *e;
157055682Smarkm    e = _find_enctype(etype);
157155682Smarkm    if(e == NULL)
157255682Smarkm	return KRB5_PROG_ETYPE_NOSUPP;
157355682Smarkm    *string = strdup(e->name);
157455682Smarkm    if(*string == NULL)
157555682Smarkm	return ENOMEM;
157655682Smarkm    return 0;
157755682Smarkm}
157855682Smarkm
157955682Smarkmkrb5_error_code
158055682Smarkmkrb5_string_to_enctype(krb5_context context,
158155682Smarkm		       const char *string,
158255682Smarkm		       krb5_enctype *etype)
158355682Smarkm{
158455682Smarkm    int i;
158555682Smarkm    for(i = 0; i < num_etypes; i++)
158655682Smarkm	if(strcasecmp(etypes[i].name, string) == 0){
158755682Smarkm	    *etype = etypes[i].type;
158855682Smarkm	    return 0;
158955682Smarkm	}
159055682Smarkm    return KRB5_PROG_ETYPE_NOSUPP;
159155682Smarkm}
159255682Smarkm
159355682Smarkmkrb5_error_code
159455682Smarkmkrb5_enctype_to_keytype(krb5_context context,
159555682Smarkm			krb5_enctype etype,
159655682Smarkm			krb5_keytype *keytype)
159755682Smarkm{
159855682Smarkm    struct encryption_type *e = _find_enctype(etype);
159955682Smarkm    if(e == NULL)
160055682Smarkm	return KRB5_PROG_ETYPE_NOSUPP;
160155682Smarkm    *keytype = e->keytype->type; /* XXX */
160255682Smarkm    return 0;
160355682Smarkm}
160455682Smarkm
160555682Smarkm#if 0
160655682Smarkmkrb5_error_code
160755682Smarkmkrb5_keytype_to_enctype(krb5_context context,
160855682Smarkm			krb5_keytype keytype,
160955682Smarkm			krb5_enctype *etype)
161055682Smarkm{
161155682Smarkm    struct key_type *kt = _find_keytype(keytype);
161255682Smarkm    krb5_warnx(context, "krb5_keytype_to_enctype(%u)", keytype);
161355682Smarkm    if(kt == NULL)
161455682Smarkm	return KRB5_PROG_KEYTYPE_NOSUPP;
161555682Smarkm    *etype = kt->best_etype;
161655682Smarkm    return 0;
161755682Smarkm}
161855682Smarkm#endif
161955682Smarkm
162055682Smarkmkrb5_error_code
162155682Smarkmkrb5_keytype_to_enctypes (krb5_context context,
162255682Smarkm			  krb5_keytype keytype,
162355682Smarkm			  unsigned *len,
162455682Smarkm			  int **val)
162555682Smarkm{
162655682Smarkm    int i;
162755682Smarkm    unsigned n = 0;
162855682Smarkm    int *ret;
162955682Smarkm
163055682Smarkm    for (i = num_etypes - 1; i >= 0; --i) {
163155682Smarkm	if (etypes[i].keytype->type == keytype
163255682Smarkm	    && !(etypes[i].flags & F_PSEUDO))
163355682Smarkm	    ++n;
163455682Smarkm    }
163555682Smarkm    ret = malloc(n * sizeof(int));
163655682Smarkm    if (ret == NULL && n != 0)
163755682Smarkm	return ENOMEM;
163855682Smarkm    n = 0;
163955682Smarkm    for (i = num_etypes - 1; i >= 0; --i) {
164055682Smarkm	if (etypes[i].keytype->type == keytype
164155682Smarkm	    && !(etypes[i].flags & F_PSEUDO))
164255682Smarkm	    ret[n++] = etypes[i].type;
164355682Smarkm    }
164455682Smarkm    *len = n;
164555682Smarkm    *val = ret;
164655682Smarkm    return 0;
164755682Smarkm}
164855682Smarkm
164955682Smarkm/*
165055682Smarkm * First take the configured list of etypes for `keytype' if available,
165155682Smarkm * else, do `krb5_keytype_to_enctypes'.
165255682Smarkm */
165355682Smarkm
165455682Smarkmkrb5_error_code
165555682Smarkmkrb5_keytype_to_enctypes_default (krb5_context context,
165655682Smarkm				  krb5_keytype keytype,
165755682Smarkm				  unsigned *len,
165855682Smarkm				  int **val)
165955682Smarkm{
166055682Smarkm    int i, n;
166155682Smarkm    int *ret;
166255682Smarkm
166355682Smarkm    if (keytype != KEYTYPE_DES || context->etypes_des == NULL)
166455682Smarkm	return krb5_keytype_to_enctypes (context, keytype, len, val);
166555682Smarkm
166655682Smarkm    for (n = 0; context->etypes_des[n]; ++n)
166755682Smarkm	;
166855682Smarkm    ret = malloc (n * sizeof(*ret));
166955682Smarkm    if (ret == NULL && n != 0)
167055682Smarkm	return ENOMEM;
167155682Smarkm    for (i = 0; i < n; ++i)
167255682Smarkm	ret[i] = context->etypes_des[i];
167355682Smarkm    *len = n;
167455682Smarkm    *val = ret;
167555682Smarkm    return 0;
167655682Smarkm}
167755682Smarkm
167855682Smarkmkrb5_error_code
167955682Smarkmkrb5_enctype_valid(krb5_context context,
168055682Smarkm		 krb5_enctype etype)
168155682Smarkm{
168255682Smarkm    return _find_enctype(etype) != NULL;
168355682Smarkm}
168455682Smarkm
168555682Smarkm/* if two enctypes have compatible keys */
168655682Smarkmkrb5_boolean
168755682Smarkmkrb5_enctypes_compatible_keys(krb5_context context,
168855682Smarkm			      krb5_enctype etype1,
168955682Smarkm			      krb5_enctype etype2)
169055682Smarkm{
169155682Smarkm    struct encryption_type *e1 = _find_enctype(etype1);
169255682Smarkm    struct encryption_type *e2 = _find_enctype(etype2);
169355682Smarkm    return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype;
169455682Smarkm}
169555682Smarkm
169655682Smarkmstatic krb5_boolean
169755682Smarkmderived_crypto(krb5_context context,
169855682Smarkm	       krb5_crypto crypto)
169955682Smarkm{
170055682Smarkm    return (crypto->et->flags & F_DERIVED) != 0;
170155682Smarkm}
170255682Smarkm
170355682Smarkm
170455682Smarkm#define CHECKSUMSIZE(C) ((C)->checksumsize)
170555682Smarkm#define CHECKSUMTYPE(C) ((C)->type)
170655682Smarkm
170755682Smarkmstatic krb5_error_code
170855682Smarkmencrypt_internal_derived(krb5_context context,
170955682Smarkm			 krb5_crypto crypto,
171055682Smarkm			 unsigned usage,
171155682Smarkm			 void *data,
171255682Smarkm			 size_t len,
171355682Smarkm			 krb5_data *result)
171455682Smarkm{
171555682Smarkm    size_t sz, block_sz, checksum_sz;
171655682Smarkm    Checksum cksum;
171755682Smarkm    unsigned char *p, *q;
171855682Smarkm    krb5_error_code ret;
171955682Smarkm    struct key_data *dkey;
172055682Smarkm    struct encryption_type *et = crypto->et;
172155682Smarkm
172255682Smarkm    checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
172355682Smarkm
172455682Smarkm    sz = et->confoundersize + /* 4 - length */ len;
172555682Smarkm    block_sz = (sz + et->blocksize - 1) &~ (et->blocksize - 1); /* pad */
172655682Smarkm    p = calloc(1, block_sz + checksum_sz);
172755682Smarkm    if(p == NULL)
172855682Smarkm	return ENOMEM;
172955682Smarkm
173055682Smarkm    q = p;
173155682Smarkm    krb5_generate_random_block(q, et->confoundersize); /* XXX */
173255682Smarkm    q += et->confoundersize;
173355682Smarkm    memcpy(q, data, len);
173455682Smarkm
173555682Smarkm    ret = create_checksum(context,
173655682Smarkm			  crypto,
173755682Smarkm			  INTEGRITY_USAGE(usage),
173855682Smarkm			  0,
173955682Smarkm			  p,
174055682Smarkm			  block_sz,
174155682Smarkm			  &cksum);
174255682Smarkm    if(ret == 0 && cksum.checksum.length != checksum_sz)
174355682Smarkm	ret =  KRB5_CRYPTO_INTERNAL;
174455682Smarkm    if(ret) {
174555682Smarkm	memset(p, 0, block_sz + checksum_sz);
174655682Smarkm	free(p);
174755682Smarkm	return ret;
174855682Smarkm    }
174955682Smarkm    memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length);
175055682Smarkm    ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
175155682Smarkm    if(ret) {
175255682Smarkm	memset(p, 0, block_sz + checksum_sz);
175355682Smarkm	free(p);
175455682Smarkm	return ret;
175555682Smarkm    }
175655682Smarkm    ret = _key_schedule(context, dkey);
175755682Smarkm    if(ret) {
175855682Smarkm	memset(p, 0, block_sz);
175955682Smarkm	free(p);
176055682Smarkm	return ret;
176155682Smarkm    }
176255682Smarkm#ifdef CRYPTO_DEBUG
176355682Smarkm    krb5_crypto_debug(context, 1, block_sz, dkey->key);
176455682Smarkm#endif
176555682Smarkm    (*et->encrypt)(dkey, p, block_sz, 1);
176655682Smarkm    result->data = p;
176755682Smarkm    result->length = block_sz + checksum_sz;
176855682Smarkm    return 0;
176955682Smarkm}
177055682Smarkm
177155682Smarkmstatic krb5_error_code
177255682Smarkmencrypt_internal(krb5_context context,
177355682Smarkm		 krb5_crypto crypto,
177455682Smarkm		 void *data,
177555682Smarkm		 size_t len,
177655682Smarkm		 krb5_data *result)
177755682Smarkm{
177855682Smarkm    size_t sz, block_sz, checksum_sz;
177955682Smarkm    Checksum cksum;
178055682Smarkm    unsigned char *p, *q;
178155682Smarkm    krb5_error_code ret;
178255682Smarkm    struct encryption_type *et = crypto->et;
178355682Smarkm
178455682Smarkm    checksum_sz = CHECKSUMSIZE(et->cksumtype);
178555682Smarkm
178655682Smarkm    sz = et->confoundersize + checksum_sz + len;
178755682Smarkm    block_sz = (sz + et->blocksize - 1) &~ (et->blocksize - 1); /* pad */
178855682Smarkm    p = calloc(1, block_sz);
178955682Smarkm    if(p == NULL)
179055682Smarkm	return ENOMEM;
179155682Smarkm
179255682Smarkm    q = p;
179355682Smarkm    krb5_generate_random_block(q, et->confoundersize); /* XXX */
179455682Smarkm    q += et->confoundersize;
179555682Smarkm    memset(q, 0, checksum_sz);
179655682Smarkm    q += checksum_sz;
179755682Smarkm    memcpy(q, data, len);
179855682Smarkm
179955682Smarkm    ret = create_checksum(context,
180055682Smarkm			  NULL,
180155682Smarkm			  0,
180255682Smarkm			  CHECKSUMTYPE(et->cksumtype),
180355682Smarkm			  p,
180455682Smarkm			  block_sz,
180555682Smarkm			  &cksum);
180655682Smarkm    if(ret == 0 && cksum.checksum.length != checksum_sz) {
180755682Smarkm	free_Checksum (&cksum);
180855682Smarkm	ret = KRB5_CRYPTO_INTERNAL;
180955682Smarkm    }
181055682Smarkm    if(ret) {
181155682Smarkm	memset(p, 0, block_sz);
181255682Smarkm	free(p);
181355682Smarkm	free_Checksum(&cksum);
181455682Smarkm	return ret;
181555682Smarkm    }
181655682Smarkm    memcpy(p + et->confoundersize, cksum.checksum.data, cksum.checksum.length);
181755682Smarkm    free_Checksum(&cksum);
181855682Smarkm    ret = _key_schedule(context, &crypto->key);
181955682Smarkm    if(ret) {
182055682Smarkm	memset(p, 0, block_sz);
182155682Smarkm	free(p);
182255682Smarkm	return ret;
182355682Smarkm    }
182455682Smarkm#ifdef CRYPTO_DEBUG
182555682Smarkm    krb5_crypto_debug(context, 1, block_sz, crypto->key.key);
182655682Smarkm#endif
182755682Smarkm    (*et->encrypt)(&crypto->key, p, block_sz, 1);
182855682Smarkm    result->data = p;
182955682Smarkm    result->length = block_sz;
183055682Smarkm    return 0;
183155682Smarkm}
183255682Smarkm
183355682Smarkmstatic krb5_error_code
183455682Smarkmdecrypt_internal_derived(krb5_context context,
183555682Smarkm			 krb5_crypto crypto,
183655682Smarkm			 unsigned usage,
183755682Smarkm			 void *data,
183855682Smarkm			 size_t len,
183955682Smarkm			 krb5_data *result)
184055682Smarkm{
184155682Smarkm    size_t checksum_sz;
184255682Smarkm    Checksum cksum;
184355682Smarkm    unsigned char *p;
184455682Smarkm    krb5_error_code ret;
184555682Smarkm    struct key_data *dkey;
184655682Smarkm    struct encryption_type *et = crypto->et;
184755682Smarkm    unsigned long l;
184855682Smarkm
184955682Smarkm    p = malloc(len);
185055682Smarkm    if(len != 0 && p == NULL)
185155682Smarkm	return ENOMEM;
185255682Smarkm    memcpy(p, data, len);
185355682Smarkm
185455682Smarkm    checksum_sz = CHECKSUMSIZE(et->keyed_checksum);
185555682Smarkm    len -= checksum_sz;
185655682Smarkm
185755682Smarkm    ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey);
185855682Smarkm    if(ret) {
185955682Smarkm	free(p);
186055682Smarkm	return ret;
186155682Smarkm    }
186255682Smarkm    ret = _key_schedule(context, dkey);
186355682Smarkm    if(ret) {
186455682Smarkm	free(p);
186555682Smarkm	return ret;
186655682Smarkm    }
186755682Smarkm#ifdef CRYPTO_DEBUG
186855682Smarkm    krb5_crypto_debug(context, 0, len, dkey->key);
186955682Smarkm#endif
187055682Smarkm    (*et->encrypt)(dkey, p, len, 0);
187155682Smarkm
187255682Smarkm    cksum.checksum.data   = p + len;
187355682Smarkm    cksum.checksum.length = checksum_sz;
187455682Smarkm    cksum.cksumtype       = CHECKSUMTYPE(et->keyed_checksum);
187555682Smarkm
187655682Smarkm    ret = verify_checksum(context,
187755682Smarkm			  crypto,
187855682Smarkm			  INTEGRITY_USAGE(usage),
187955682Smarkm			  p,
188055682Smarkm			  len,
188155682Smarkm			  &cksum);
188255682Smarkm    if(ret) {
188355682Smarkm	free(p);
188455682Smarkm	return ret;
188555682Smarkm    }
188655682Smarkm    l = len - et->confoundersize;
188755682Smarkm    memmove(p, p + et->confoundersize, l);
188855682Smarkm    result->data = realloc(p, l);
188955682Smarkm    if(p == NULL) {
189055682Smarkm	free(p);
189155682Smarkm	return ENOMEM;
189255682Smarkm    }
189355682Smarkm    result->length = l;
189455682Smarkm    return 0;
189555682Smarkm}
189655682Smarkm
189755682Smarkmstatic krb5_error_code
189855682Smarkmdecrypt_internal(krb5_context context,
189955682Smarkm		 krb5_crypto crypto,
190055682Smarkm		 void *data,
190155682Smarkm		 size_t len,
190255682Smarkm		 krb5_data *result)
190355682Smarkm{
190455682Smarkm    krb5_error_code ret;
190555682Smarkm    unsigned char *p;
190655682Smarkm    Checksum cksum;
190755682Smarkm    size_t checksum_sz, l;
190855682Smarkm    struct encryption_type *et = crypto->et;
190955682Smarkm
191055682Smarkm    checksum_sz = CHECKSUMSIZE(et->cksumtype);
191155682Smarkm    p = malloc(len);
191255682Smarkm    if(len != 0 && p == NULL)
191355682Smarkm	return ENOMEM;
191455682Smarkm    memcpy(p, data, len);
191555682Smarkm
191655682Smarkm    ret = _key_schedule(context, &crypto->key);
191755682Smarkm    if(ret) {
191855682Smarkm	free(p);
191955682Smarkm	return ret;
192055682Smarkm    }
192155682Smarkm#ifdef CRYPTO_DEBUG
192255682Smarkm    krb5_crypto_debug(context, 0, len, crypto->key.key);
192355682Smarkm#endif
192455682Smarkm    (*et->encrypt)(&crypto->key, p, len, 0);
192555682Smarkm    ret = krb5_data_copy(&cksum.checksum, p + et->confoundersize, checksum_sz);
192655682Smarkm    if(ret) {
192755682Smarkm	free(p);
192855682Smarkm	return ret;
192955682Smarkm    }
193055682Smarkm    memset(p + et->confoundersize, 0, checksum_sz);
193155682Smarkm    cksum.cksumtype = CHECKSUMTYPE(et->cksumtype);
193255682Smarkm    ret = verify_checksum(context, NULL, 0, p, len, &cksum);
193355682Smarkm    free_Checksum(&cksum);
193455682Smarkm    if(ret) {
193555682Smarkm	free(p);
193655682Smarkm	return ret;
193755682Smarkm    }
193855682Smarkm    l = len - et->confoundersize - checksum_sz;
193955682Smarkm    memmove(p, p + et->confoundersize + checksum_sz, l);
194055682Smarkm    result->data = realloc(p, l);
194155682Smarkm    if(result->data == NULL) {
194255682Smarkm	free(p);
194355682Smarkm	return ENOMEM;
194455682Smarkm    }
194555682Smarkm    result->length = l;
194655682Smarkm    return 0;
194755682Smarkm}
194855682Smarkm
194955682Smarkmkrb5_error_code
195055682Smarkmkrb5_encrypt(krb5_context context,
195155682Smarkm	     krb5_crypto crypto,
195255682Smarkm	     unsigned usage,
195355682Smarkm	     void *data,
195455682Smarkm	     size_t len,
195555682Smarkm	     krb5_data *result)
195655682Smarkm{
195755682Smarkm    if(derived_crypto(context, crypto))
195855682Smarkm	return encrypt_internal_derived(context, crypto, usage,
195955682Smarkm					data, len, result);
196055682Smarkm    else
196155682Smarkm	return encrypt_internal(context, crypto, data, len, result);
196255682Smarkm}
196355682Smarkm
196455682Smarkmkrb5_error_code
196555682Smarkmkrb5_encrypt_EncryptedData(krb5_context context,
196655682Smarkm			   krb5_crypto crypto,
196755682Smarkm			   unsigned usage,
196855682Smarkm			   void *data,
196955682Smarkm			   size_t len,
197055682Smarkm			   int kvno,
197155682Smarkm			   EncryptedData *result)
197255682Smarkm{
197355682Smarkm    result->etype = CRYPTO_ETYPE(crypto);
197455682Smarkm    if(kvno){
197555682Smarkm	ALLOC(result->kvno, 1);
197655682Smarkm	*result->kvno = kvno;
197755682Smarkm    }else
197855682Smarkm	result->kvno = NULL;
197955682Smarkm    return krb5_encrypt(context, crypto, usage, data, len, &result->cipher);
198055682Smarkm}
198155682Smarkm
198255682Smarkmkrb5_error_code
198355682Smarkmkrb5_decrypt(krb5_context context,
198455682Smarkm	     krb5_crypto crypto,
198555682Smarkm	     unsigned usage,
198655682Smarkm	     void *data,
198755682Smarkm	     size_t len,
198855682Smarkm	     krb5_data *result)
198955682Smarkm{
199055682Smarkm    if(derived_crypto(context, crypto))
199155682Smarkm	return decrypt_internal_derived(context, crypto, usage,
199255682Smarkm					data, len, result);
199355682Smarkm    else
199455682Smarkm	return decrypt_internal(context, crypto, data, len, result);
199555682Smarkm}
199655682Smarkm
199755682Smarkmkrb5_error_code
199855682Smarkmkrb5_decrypt_EncryptedData(krb5_context context,
199955682Smarkm			   krb5_crypto crypto,
200055682Smarkm			   unsigned usage,
200155682Smarkm			   EncryptedData *e,
200255682Smarkm			   krb5_data *result)
200355682Smarkm{
200455682Smarkm    return krb5_decrypt(context, crypto, usage,
200555682Smarkm			e->cipher.data, e->cipher.length, result);
200655682Smarkm}
200755682Smarkm
200855682Smarkm/************************************************************
200955682Smarkm *                                                          *
201055682Smarkm ************************************************************/
201155682Smarkm
201255682Smarkmvoid
201355682Smarkmkrb5_generate_random_block(void *buf, size_t len)
201455682Smarkm{
201555682Smarkm    des_cblock key, out;
201655682Smarkm    static des_cblock counter;
201755682Smarkm    static des_key_schedule schedule;
201855682Smarkm    int i;
201955682Smarkm    static int initialized = 0;
202055682Smarkm
202155682Smarkm    if(!initialized) {
202255682Smarkm	des_new_random_key(&key);
202355682Smarkm	des_set_key(&key, schedule);
202455682Smarkm	memset(&key, 0, sizeof(key));
202555682Smarkm	des_new_random_key(&counter);
202655682Smarkm    }
202755682Smarkm    while(len > 0) {
202855682Smarkm	des_ecb_encrypt(&counter, &out, schedule, DES_ENCRYPT);
202955682Smarkm	for(i = 7; i >=0; i--)
203055682Smarkm	    if(counter[i]++)
203155682Smarkm		break;
203255682Smarkm	memcpy(buf, out, min(len, sizeof(out)));
203355682Smarkm	len -= min(len, sizeof(out));
203455682Smarkm	buf = (char*)buf + sizeof(out);
203555682Smarkm    }
203655682Smarkm}
203755682Smarkm
203855682Smarkmstatic void
203955682SmarkmDES3_postproc(krb5_context context,
204055682Smarkm	      unsigned char *k, size_t len, struct key_data *key)
204155682Smarkm{
204255682Smarkm    unsigned char x[24];
204355682Smarkm    int i, j;
204455682Smarkm
204555682Smarkm    memset(x, 0, sizeof(x));
204655682Smarkm    for (i = 0; i < 3; ++i) {
204755682Smarkm	unsigned char foo;
204855682Smarkm
204955682Smarkm	for (j = 0; j < 7; ++j) {
205055682Smarkm	    unsigned char b = k[7 * i + j];
205155682Smarkm
205255682Smarkm	    x[8 * i + j] = b;
205355682Smarkm	}
205455682Smarkm	foo = 0;
205555682Smarkm	for (j = 6; j >= 0; --j) {
205655682Smarkm	    foo |= k[7 * i + j] & 1;
205755682Smarkm	    foo <<= 1;
205855682Smarkm	}
205955682Smarkm	x[8 * i + 7] = foo;
206055682Smarkm    }
206155682Smarkm    k = key->key->keyvalue.data;
206255682Smarkm    memcpy(k, x, 24);
206355682Smarkm    memset(x, 0, sizeof(x));
206455682Smarkm    if (key->schedule) {
206555682Smarkm	krb5_free_data(context, key->schedule);
206655682Smarkm	key->schedule = NULL;
206755682Smarkm    }
206855682Smarkm    des_set_odd_parity((des_cblock*)k);
206955682Smarkm    des_set_odd_parity((des_cblock*)(k + 8));
207055682Smarkm    des_set_odd_parity((des_cblock*)(k + 16));
207155682Smarkm}
207255682Smarkm
207355682Smarkmstatic krb5_error_code
207455682Smarkmderive_key(krb5_context context,
207555682Smarkm	   struct encryption_type *et,
207655682Smarkm	   struct key_data *key,
207755682Smarkm	   void *constant,
207855682Smarkm	   size_t len)
207955682Smarkm{
208055682Smarkm    unsigned char *k;
208155682Smarkm    unsigned int nblocks = 0, i;
208255682Smarkm    krb5_error_code ret = 0;
208355682Smarkm
208455682Smarkm    struct key_type *kt = et->keytype;
208555682Smarkm    ret = _key_schedule(context, key);
208655682Smarkm    if(ret)
208755682Smarkm	return ret;
208855682Smarkm    if(et->blocksize * 8 < kt->bits ||
208955682Smarkm       len != et->blocksize) {
209055682Smarkm	nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8);
209155682Smarkm	k = malloc(nblocks * et->blocksize);
209255682Smarkm	if(k == NULL)
209355682Smarkm	    return ENOMEM;
209455682Smarkm	_krb5_n_fold(constant, len, k, et->blocksize);
209555682Smarkm	for(i = 0; i < nblocks; i++) {
209655682Smarkm	    if(i > 0)
209755682Smarkm		memcpy(k + i * et->blocksize,
209855682Smarkm		       k + (i - 1) * et->blocksize,
209955682Smarkm		       et->blocksize);
210055682Smarkm	    (*et->encrypt)(key, k + i * et->blocksize, et->blocksize, 1);
210155682Smarkm	}
210255682Smarkm    } else {
210355682Smarkm	void *c = malloc(len);
210455682Smarkm	size_t res_len = (kt->bits + 7) / 8;
210555682Smarkm
210655682Smarkm	if(len != 0 && c == NULL)
210755682Smarkm	    return ENOMEM;
210855682Smarkm	memcpy(c, constant, len);
210955682Smarkm	(*et->encrypt)(key, c, len, 1);
211055682Smarkm	k = malloc(res_len);
211155682Smarkm	if(res_len != 0 && k == NULL)
211255682Smarkm	    return ENOMEM;
211355682Smarkm	_krb5_n_fold(c, len, k, res_len);
211455682Smarkm	free(c);
211555682Smarkm    }
211655682Smarkm
211755682Smarkm    /* XXX keytype dependent post-processing */
211855682Smarkm    switch(kt->type) {
211955682Smarkm    case KEYTYPE_DES3:
212055682Smarkm	DES3_postproc(context, k, nblocks * et->blocksize, key);
212155682Smarkm	break;
212255682Smarkm    default:
212355682Smarkm	krb5_warnx(context, "derive_key() called with unknown keytype (%u)",
212455682Smarkm		   kt->type);
212555682Smarkm	ret = KRB5_CRYPTO_INTERNAL;
212655682Smarkm	break;
212755682Smarkm    }
212855682Smarkm    memset(k, 0, nblocks * et->blocksize);
212955682Smarkm    free(k);
213055682Smarkm    return ret;
213155682Smarkm}
213255682Smarkm
213355682Smarkmstatic struct key_data *
213455682Smarkm_new_derived_key(krb5_crypto crypto, unsigned usage)
213555682Smarkm{
213655682Smarkm    struct key_usage *d = crypto->key_usage;
213755682Smarkm    d = realloc(d, (crypto->num_key_usage + 1) * sizeof(*d));
213855682Smarkm    if(d == NULL)
213955682Smarkm	return NULL;
214055682Smarkm    crypto->key_usage = d;
214155682Smarkm    d += crypto->num_key_usage++;
214255682Smarkm    memset(d, 0, sizeof(*d));
214355682Smarkm    d->usage = usage;
214455682Smarkm    return &d->key;
214555682Smarkm}
214655682Smarkm
214755682Smarkmstatic krb5_error_code
214855682Smarkm_get_derived_key(krb5_context context,
214955682Smarkm		 krb5_crypto crypto,
215055682Smarkm		 unsigned usage,
215155682Smarkm		 struct key_data **key)
215255682Smarkm{
215355682Smarkm    int i;
215455682Smarkm    struct key_data *d;
215555682Smarkm    unsigned char constant[5];
215655682Smarkm
215755682Smarkm    for(i = 0; i < crypto->num_key_usage; i++)
215855682Smarkm	if(crypto->key_usage[i].usage == usage) {
215955682Smarkm	    *key = &crypto->key_usage[i].key;
216055682Smarkm	    return 0;
216155682Smarkm	}
216255682Smarkm    d = _new_derived_key(crypto, usage);
216355682Smarkm    if(d == NULL)
216455682Smarkm	return ENOMEM;
216555682Smarkm    krb5_copy_keyblock(context, crypto->key.key, &d->key);
216655682Smarkm    _krb5_put_int(constant, usage, 5);
216755682Smarkm    derive_key(context, crypto->et, d, constant, sizeof(constant));
216855682Smarkm    *key = d;
216955682Smarkm    return 0;
217055682Smarkm}
217155682Smarkm
217255682Smarkm
217355682Smarkmkrb5_error_code
217455682Smarkmkrb5_crypto_init(krb5_context context,
217555682Smarkm		 krb5_keyblock *key,
217655682Smarkm		 krb5_enctype etype,
217755682Smarkm		 krb5_crypto *crypto)
217855682Smarkm{
217955682Smarkm    krb5_error_code ret;
218055682Smarkm    ALLOC(*crypto, 1);
218155682Smarkm    if(*crypto == NULL)
218255682Smarkm	return ENOMEM;
218355682Smarkm    if(etype == ETYPE_NULL)
218455682Smarkm	etype = key->keytype;
218555682Smarkm    (*crypto)->et = _find_enctype(etype);
218655682Smarkm    if((*crypto)->et == NULL) {
218755682Smarkm	free(*crypto);
218855682Smarkm	return KRB5_PROG_ETYPE_NOSUPP;
218955682Smarkm    }
219055682Smarkm    ret = krb5_copy_keyblock(context, key, &(*crypto)->key.key);
219155682Smarkm    if(ret) {
219255682Smarkm	free(*crypto);
219355682Smarkm	return ret;
219455682Smarkm    }
219555682Smarkm    (*crypto)->key.schedule = NULL;
219655682Smarkm    (*crypto)->num_key_usage = 0;
219755682Smarkm    (*crypto)->key_usage = NULL;
219855682Smarkm    return 0;
219955682Smarkm}
220055682Smarkm
220155682Smarkmstatic void
220255682Smarkmfree_key_data(krb5_context context, struct key_data *key)
220355682Smarkm{
220455682Smarkm    krb5_free_keyblock(context, key->key);
220555682Smarkm    if(key->schedule) {
220655682Smarkm	memset(key->schedule->data, 0, key->schedule->length);
220755682Smarkm	krb5_free_data(context, key->schedule);
220855682Smarkm    }
220955682Smarkm}
221055682Smarkm
221155682Smarkmstatic void
221255682Smarkmfree_key_usage(krb5_context context, struct key_usage *ku)
221355682Smarkm{
221455682Smarkm    free_key_data(context, &ku->key);
221555682Smarkm}
221655682Smarkm
221755682Smarkmkrb5_error_code
221855682Smarkmkrb5_crypto_destroy(krb5_context context,
221955682Smarkm		    krb5_crypto crypto)
222055682Smarkm{
222155682Smarkm    int i;
222255682Smarkm
222355682Smarkm    for(i = 0; i < crypto->num_key_usage; i++)
222455682Smarkm	free_key_usage(context, &crypto->key_usage[i]);
222555682Smarkm    free(crypto->key_usage);
222655682Smarkm    free_key_data(context, &crypto->key);
222755682Smarkm    free (crypto);
222855682Smarkm    return 0;
222955682Smarkm}
223055682Smarkm
223155682Smarkmkrb5_error_code
223255682Smarkmkrb5_string_to_key_derived(krb5_context context,
223355682Smarkm			   const void *str,
223455682Smarkm			   size_t len,
223555682Smarkm			   krb5_enctype etype,
223655682Smarkm			   krb5_keyblock *key)
223755682Smarkm{
223855682Smarkm    struct encryption_type *et = _find_enctype(etype);
223955682Smarkm    krb5_error_code ret;
224055682Smarkm    struct key_data kd;
224155682Smarkm    u_char *tmp;
224255682Smarkm
224355682Smarkm    if(et == NULL)
224455682Smarkm	return KRB5_PROG_ETYPE_NOSUPP;
224555682Smarkm    ALLOC(kd.key, 1);
224655682Smarkm    kd.key->keytype = etype;
224755682Smarkm    tmp = malloc (et->keytype->bits / 8);
224855682Smarkm    _krb5_n_fold(str, len, tmp, et->keytype->bits / 8);
224955682Smarkm    krb5_data_alloc(&kd.key->keyvalue, et->keytype->size);
225055682Smarkm    kd.schedule = NULL;
225155682Smarkm    DES3_postproc (context, tmp, et->keytype->bits / 8, &kd); /* XXX */
225255682Smarkm    ret = derive_key(context,
225355682Smarkm		     et,
225455682Smarkm		     &kd,
225555682Smarkm		     "kerberos", /* XXX well known constant */
225655682Smarkm		     strlen("kerberos"));
225755682Smarkm    ret = krb5_copy_keyblock_contents(context, kd.key, key);
225855682Smarkm    free_key_data(context, &kd);
225955682Smarkm    return ret;
226055682Smarkm}
226155682Smarkm
226255682Smarkm/*
226355682Smarkm * Return the size of an encrypted packet of length `data_len'
226455682Smarkm */
226555682Smarkm
226655682Smarkmsize_t
226755682Smarkmkrb5_get_wrapped_length (krb5_context context,
226855682Smarkm			 krb5_crypto  crypto,
226955682Smarkm			 size_t       data_len)
227055682Smarkm{
227155682Smarkm    struct encryption_type *et = crypto->et;
227255682Smarkm    size_t blocksize = et->blocksize;
227355682Smarkm    size_t res;
227455682Smarkm
227555682Smarkm    res = (data_len + blocksize - 1) / blocksize * blocksize;
227655682Smarkm    res = res + et->confoundersize + et->cksumtype->checksumsize;
227755682Smarkm    return res;
227855682Smarkm}
227955682Smarkm
228055682Smarkm#ifdef CRYPTO_DEBUG
228155682Smarkm
228255682Smarkmstatic krb5_error_code
228355682Smarkmkrb5_get_keyid(krb5_context context,
228455682Smarkm	       krb5_keyblock *key,
228555682Smarkm	       u_int32_t *keyid)
228655682Smarkm{
228755682Smarkm    struct md5 md5;
228855682Smarkm    unsigned char tmp[16];
228955682Smarkm    md5_init(&md5);
229055682Smarkm    md5_update(&md5, key->keyvalue.data, key->keyvalue.length);
229155682Smarkm    md5_finito(&md5, tmp);
229255682Smarkm    *keyid = (tmp[12] << 24) | (tmp[13] << 16) | (tmp[14] << 8) | tmp[15];
229355682Smarkm    return 0;
229455682Smarkm}
229555682Smarkm
229655682Smarkmstatic void
229755682Smarkmkrb5_crypto_debug(krb5_context context,
229855682Smarkm		  int encrypt,
229955682Smarkm		  size_t len,
230055682Smarkm		  krb5_keyblock *key)
230155682Smarkm{
230255682Smarkm    u_int32_t keyid;
230355682Smarkm    char *kt;
230455682Smarkm    krb5_get_keyid(context, key, &keyid);
230555682Smarkm    krb5_enctype_to_string(context, key->keytype, &kt);
230655682Smarkm    krb5_warnx(context, "%s %lu bytes with key-id %#x (%s)",
230755682Smarkm	       encrypt ? "encrypting" : "decrypting",
230855682Smarkm	       (unsigned long)len,
230955682Smarkm	       keyid,
231055682Smarkm	       kt);
231155682Smarkm    free(kt);
231255682Smarkm}
231355682Smarkm
231455682Smarkm#endif /* CRYPTO_DEBUG */
2315