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