📄 crypto.c
字号:
/* * Copyright (c) 1997 - 2005 Kungliga Tekniska H鰃skolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include "krb5_locl.h"RCSID("$Id: crypto.c 22200 2007-12-07 13:48:01Z lha $");#undef CRYPTO_DEBUG#ifdef CRYPTO_DEBUGstatic void krb5_crypto_debug(krb5_context, int, size_t, krb5_keyblock*);#endifstruct key_data { krb5_keyblock *key; krb5_data *schedule;};struct key_usage { unsigned usage; struct key_data key;};struct krb5_crypto_data { struct encryption_type *et; struct key_data key; int num_key_usage; struct key_usage *key_usage;};#define CRYPTO_ETYPE(C) ((C)->et->type)/* bits for `flags' below */#define F_KEYED 1 /* checksum is keyed */#define F_CPROOF 2 /* checksum is collision proof */#define F_DERIVED 4 /* uses derived keys */#define F_VARIANT 8 /* uses `variant' keys (6.4.3) */#define F_PSEUDO 16 /* not a real protocol type */#define F_SPECIAL 32 /* backwards */#define F_DISABLED 64 /* enctype/checksum disabled */struct salt_type { krb5_salttype type; const char *name; krb5_error_code (*string_to_key)(krb5_context, krb5_enctype, krb5_data, krb5_salt, krb5_data, krb5_keyblock*);};struct key_type { krb5_keytype type; /* XXX */ const char *name; size_t bits; size_t size; size_t schedule_size;#if 0 krb5_enctype best_etype;#endif void (*random_key)(krb5_context, krb5_keyblock*); void (*schedule)(krb5_context, struct key_data *); struct salt_type *string_to_key; void (*random_to_key)(krb5_context, krb5_keyblock*, const void*, size_t);};struct checksum_type { krb5_cksumtype type; const char *name; size_t blocksize; size_t checksumsize; unsigned flags; void (*checksum)(krb5_context context, struct key_data *key, const void *buf, size_t len, unsigned usage, Checksum *csum); krb5_error_code (*verify)(krb5_context context, struct key_data *key, const void *buf, size_t len, unsigned usage, Checksum *csum);};struct encryption_type { krb5_enctype type; const char *name; heim_oid *oid; size_t blocksize; size_t padsize; size_t confoundersize; struct key_type *keytype; struct checksum_type *checksum; struct checksum_type *keyed_checksum; unsigned flags; krb5_error_code (*encrypt)(krb5_context context, struct key_data *key, void *data, size_t len, krb5_boolean encryptp, int usage, void *ivec); size_t prf_length; krb5_error_code (*prf)(krb5_context, krb5_crypto, const krb5_data *, krb5_data *);};#define ENCRYPTION_USAGE(U) (((U) << 8) | 0xAA)#define INTEGRITY_USAGE(U) (((U) << 8) | 0x55)#define CHECKSUM_USAGE(U) (((U) << 8) | 0x99)static struct checksum_type *_find_checksum(krb5_cksumtype type);static struct encryption_type *_find_enctype(krb5_enctype type);static struct key_type *_find_keytype(krb5_keytype type);static krb5_error_code _get_derived_key(krb5_context, krb5_crypto, unsigned, struct key_data**);static struct key_data *_new_derived_key(krb5_crypto crypto, unsigned usage);static krb5_error_code derive_key(krb5_context context, struct encryption_type *et, struct key_data *key, const void *constant, size_t len);static krb5_error_code hmac(krb5_context context, struct checksum_type *cm, const void *data, size_t len, unsigned usage, struct key_data *keyblock, Checksum *result);static void free_key_data(krb5_context context, struct key_data *key);static krb5_error_code usage2arcfour (krb5_context, unsigned *);static void xor (DES_cblock *, const unsigned char *);/************************************************************ * * ************************************************************/static HEIMDAL_MUTEX crypto_mutex = HEIMDAL_MUTEX_INITIALIZER;static voidkrb5_DES_random_key(krb5_context context, krb5_keyblock *key){ DES_cblock *k = key->keyvalue.data; do { krb5_generate_random_block(k, sizeof(DES_cblock)); DES_set_odd_parity(k); } while(DES_is_weak_key(k));}static voidkrb5_DES_schedule(krb5_context context, struct key_data *key){ DES_set_key(key->key->keyvalue.data, key->schedule->data);}#ifdef ENABLE_AFS_STRING_TO_KEY/* This defines the Andrew string_to_key function. It accepts a password * string as input and converts it via a one-way encryption algorithm to a DES * encryption key. It is compatible with the original Andrew authentication * service password database. *//* * Short passwords, i.e 8 characters or less. */static voidkrb5_DES_AFS3_CMU_string_to_key (krb5_data pw, krb5_data cell, DES_cblock *key){ char password[8+1]; /* crypt is limited to 8 chars anyway */ int i; for(i = 0; i < 8; i++) { char c = ((i < pw.length) ? ((char*)pw.data)[i] : 0) ^ ((i < cell.length) ? tolower(((unsigned char*)cell.data)[i]) : 0); password[i] = c ? c : 'X'; } password[8] = '\0'; memcpy(key, crypt(password, "p1") + 2, sizeof(DES_cblock)); /* parity is inserted into the LSB so left shift each byte up one bit. This allows ascii characters with a zero MSB to retain as much significance as possible. */ for (i = 0; i < sizeof(DES_cblock); i++) ((unsigned char*)key)[i] <<= 1; DES_set_odd_parity (key);}/* * Long passwords, i.e 9 characters or more. */static voidkrb5_DES_AFS3_Transarc_string_to_key (krb5_data pw, krb5_data cell, DES_cblock *key){ DES_key_schedule schedule; DES_cblock temp_key; DES_cblock ivec; char password[512]; size_t passlen; memcpy(password, pw.data, min(pw.length, sizeof(password))); if(pw.length < sizeof(password)) { int len = min(cell.length, sizeof(password) - pw.length); int i; memcpy(password + pw.length, cell.data, len); for (i = pw.length; i < pw.length + len; ++i) password[i] = tolower((unsigned char)password[i]); } passlen = min(sizeof(password), pw.length + cell.length); memcpy(&ivec, "kerberos", 8); memcpy(&temp_key, "kerberos", 8); DES_set_odd_parity (&temp_key); DES_set_key (&temp_key, &schedule); DES_cbc_cksum ((void*)password, &ivec, passlen, &schedule, &ivec); memcpy(&temp_key, &ivec, 8); DES_set_odd_parity (&temp_key); DES_set_key (&temp_key, &schedule); DES_cbc_cksum ((void*)password, key, passlen, &schedule, &ivec); memset(&schedule, 0, sizeof(schedule)); memset(&temp_key, 0, sizeof(temp_key)); memset(&ivec, 0, sizeof(ivec)); memset(password, 0, sizeof(password)); DES_set_odd_parity (key);}static krb5_error_codeDES_AFS3_string_to_key(krb5_context context, krb5_enctype enctype, krb5_data password, krb5_salt salt, krb5_data opaque, krb5_keyblock *key){ DES_cblock tmp; if(password.length > 8) krb5_DES_AFS3_Transarc_string_to_key(password, salt.saltvalue, &tmp); else krb5_DES_AFS3_CMU_string_to_key(password, salt.saltvalue, &tmp); key->keytype = enctype; krb5_data_copy(&key->keyvalue, tmp, sizeof(tmp)); memset(&key, 0, sizeof(key)); return 0;}#endif /* ENABLE_AFS_STRING_TO_KEY */static voidDES_string_to_key_int(unsigned char *data, size_t length, DES_cblock *key){ DES_key_schedule schedule; int i; int reverse = 0; unsigned char *p; unsigned char swap[] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf }; memset(key, 0, 8); p = (unsigned char*)key; for (i = 0; i < length; i++) { unsigned char tmp = data[i]; if (!reverse) *p++ ^= (tmp << 1); else *--p ^= (swap[tmp & 0xf] << 4) | swap[(tmp & 0xf0) >> 4]; if((i % 8) == 7) reverse = !reverse; } DES_set_odd_parity(key); if(DES_is_weak_key(key)) (*key)[7] ^= 0xF0; DES_set_key(key, &schedule); DES_cbc_cksum((void*)data, key, length, &schedule, key); memset(&schedule, 0, sizeof(schedule)); DES_set_odd_parity(key); if(DES_is_weak_key(key)) (*key)[7] ^= 0xF0;}static krb5_error_codekrb5_DES_string_to_key(krb5_context context, krb5_enctype enctype, krb5_data password, krb5_salt salt, krb5_data opaque, krb5_keyblock *key){ unsigned char *s; size_t len; DES_cblock tmp;#ifdef ENABLE_AFS_STRING_TO_KEY if (opaque.length == 1) { unsigned long v; _krb5_get_int(opaque.data, &v, 1); if (v == 1) return DES_AFS3_string_to_key(context, enctype, password, salt, opaque, key); }#endif len = password.length + salt.saltvalue.length; s = malloc(len); if(len > 0 && s == NULL) { krb5_set_error_string(context, "malloc: out of memory"); return ENOMEM; } memcpy(s, password.data, password.length); memcpy(s + password.length, salt.saltvalue.data, salt.saltvalue.length); DES_string_to_key_int(s, len, &tmp); key->keytype = enctype; krb5_data_copy(&key->keyvalue, tmp, sizeof(tmp)); memset(&tmp, 0, sizeof(tmp)); memset(s, 0, len); free(s); return 0;}static voidkrb5_DES_random_to_key(krb5_context context, krb5_keyblock *key, const void *data, size_t size){ DES_cblock *k = key->keyvalue.data; memcpy(k, data, key->keyvalue.length); DES_set_odd_parity(k); if(DES_is_weak_key(k)) xor(k, (const unsigned char*)"\0\0\0\0\0\0\0\xf0");}/* * */static voidDES3_random_key(krb5_context context, krb5_keyblock *key){ DES_cblock *k = key->keyvalue.data; do { krb5_generate_random_block(k, 3 * sizeof(DES_cblock)); DES_set_odd_parity(&k[0]); DES_set_odd_parity(&k[1]); DES_set_odd_parity(&k[2]); } while(DES_is_weak_key(&k[0]) || DES_is_weak_key(&k[1]) || DES_is_weak_key(&k[2]));}static voidDES3_schedule(krb5_context context, struct key_data *key){ DES_cblock *k = key->key->keyvalue.data; DES_key_schedule *s = key->schedule->data; DES_set_key(&k[0], &s[0]); DES_set_key(&k[1], &s[1]); DES_set_key(&k[2], &s[2]);}/* * A = A xor B. A & B are 8 bytes. */static voidxor (DES_cblock *key, const unsigned char *b){ unsigned char *a = (unsigned char*)key; a[0] ^= b[0]; a[1] ^= b[1]; a[2] ^= b[2]; a[3] ^= b[3]; a[4] ^= b[4]; a[5] ^= b[5]; a[6] ^= b[6]; a[7] ^= b[7];}static krb5_error_codeDES3_string_to_key(krb5_context context, krb5_enctype enctype, krb5_data password, krb5_salt salt, krb5_data opaque, krb5_keyblock *key){ char *str; size_t len; unsigned char tmp[24]; DES_cblock keys[3]; krb5_error_code ret; len = password.length + salt.saltvalue.length; str = malloc(len); if(len != 0 && str == NULL) { krb5_set_error_string(context, "malloc: out of memory"); return ENOMEM; } memcpy(str, password.data, password.length); memcpy(str + password.length, salt.saltvalue.data, salt.saltvalue.length); { DES_cblock ivec; DES_key_schedule s[3]; int i; ret = _krb5_n_fold(str, len, tmp, 24); if (ret) { memset(str, 0, len); free(str); krb5_set_error_string(context, "out of memory"); return ret; } for(i = 0; i < 3; i++){ memcpy(keys + i, tmp + i * 8, sizeof(keys[i])); DES_set_odd_parity(keys + i); if(DES_is_weak_key(keys + i)) xor(keys + i, (const unsigned char*)"\0\0\0\0\0\0\0\xf0"); DES_set_key(keys + i, &s[i]); } memset(&ivec, 0, sizeof(ivec)); DES_ede3_cbc_encrypt(tmp, tmp, sizeof(tmp), &s[0], &s[1], &s[2], &ivec, DES_ENCRYPT); memset(s, 0, sizeof(s)); memset(&ivec, 0, sizeof(ivec)); for(i = 0; i < 3; i++){ memcpy(keys + i, tmp + i * 8, sizeof(keys[i])); DES_set_odd_parity(keys + i); if(DES_is_weak_key(keys + i)) xor(keys + i, (const unsigned char*)"\0\0\0\0\0\0\0\xf0"); } memset(tmp, 0, sizeof(tmp)); } key->keytype = enctype; krb5_data_copy(&key->keyvalue, keys, sizeof(keys)); memset(keys, 0, sizeof(keys)); memset(str, 0, len); free(str); return 0;}static krb5_error_codeDES3_string_to_key_derived(krb5_context context, krb5_enctype enctype, krb5_data password, krb5_salt salt, krb5_data opaque, krb5_keyblock *key){ krb5_error_code ret; size_t len = password.length + salt.saltvalue.length; char *s; s = malloc(len); if(len != 0 && s == NULL) { krb5_set_error_string(context, "malloc: out of memory"); return ENOMEM; } memcpy(s, password.data, password.length); memcpy(s + password.length, salt.saltvalue.data, salt.saltvalue.length); ret = krb5_string_to_key_derived(context, s, len, enctype, key); memset(s, 0, len); free(s); return ret;}static voidDES3_random_to_key(krb5_context context, krb5_keyblock *key, const void *data, size_t size){ unsigned char *x = key->keyvalue.data; const u_char *q = data; DES_cblock *k; int i, j; memset(x, 0, sizeof(x)); for (i = 0; i < 3; ++i) { unsigned char foo; for (j = 0; j < 7; ++j) { unsigned char b = q[7 * i + j]; x[8 * i + j] = b; } foo = 0; for (j = 6; j >= 0; --j) { foo |= q[7 * i + j] & 1; foo <<= 1; } x[8 * i + 7] = foo; } k = key->keyvalue.data; for (i = 0; i < 3; i++) { DES_set_odd_parity(&k[i]); if(DES_is_weak_key(&k[i])) xor(&k[i], (const unsigned char*)"\0\0\0\0\0\0\0\xf0"); } }/* * ARCFOUR */static voidARCFOUR_schedule(krb5_context context, struct key_data *kd){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -