From: Greg Hudson Date: Sun, 18 Oct 2009 18:28:26 +0000 (+0000) Subject: Implement derived key caching. For now, omit the "nocache" flag, because it X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6f4d8ca885a78f1a43b83b2e4201358f62faa2ae;p=thirdparty%2Fkrb5.git Implement derived key caching. For now, omit the "nocache" flag, because it would add code bulk without necessarily saving much work. git-svn-id: svn://anonsvn.mit.edu/krb5/branches/enc-perf@22919 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/include/k5-int.h b/src/include/k5-int.h index 34ce10d921..95398c0a34 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -635,10 +635,17 @@ krb5int_locate_server (krb5_context, const krb5_data *realm, struct addrlist *, enum locate_service_type svc, int sockettype, int family); +struct derived_key { + krb5_data constant; + krb5_key dkey; + struct derived_key *next; +}; + /* Internal structure of an opaque key identifier */ struct krb5_key_st { krb5_keyblock keyblock; int refcount; + struct derived_key *derived; }; /* new encryption provider api */ diff --git a/src/lib/crypto/krb/dk/derive.c b/src/lib/crypto/krb/dk/derive.c index ce55663107..c2638e804e 100644 --- a/src/lib/crypto/krb/dk/derive.c +++ b/src/lib/crypto/krb/dk/derive.c @@ -27,6 +27,63 @@ #include "k5-int.h" #include "dk.h" +static krb5_key +find_cached_dkey(struct derived_key *list, const krb5_data *constant) +{ + for (; list; list = list->next) { + if (data_eq(list->constant, *constant)) { + krb5_k_reference_key(NULL, list->dkey); + return list->dkey; + } + } + return NULL; +} + +static krb5_error_code +add_cached_dkey(krb5_key key, const krb5_data *constant, + const krb5_keyblock *dkeyblock, krb5_key *cached_dkey) +{ + krb5_key dkey; + krb5_error_code ret; + struct derived_key *dkent = NULL; + char *data = NULL; + + /* Allocate fields for the new entry. */ + dkent = malloc(sizeof(*dkent)); + if (dkent == NULL) + goto cleanup; + data = malloc(constant->length); + if (data == NULL) + goto cleanup; + ret = krb5_k_create_key(NULL, dkeyblock, &dkey); + if (ret != 0) + goto cleanup; + + /* Add the new entry to the list. */ + memcpy(data, constant->data, constant->length); + dkent->dkey = dkey; + dkent->constant.data = data; + dkent->constant.length = constant->length; + dkent->next = key->derived; + key->derived = dkent; + + /* Return a "copy" of the cached key. */ + krb5_k_reference_key(NULL, dkey); + *cached_dkey = dkey; + return 0; + +cleanup: + free(dkent); + free(data); + return ENOMEM; +} + +/* + * Compute a derived key into the keyblock outkey. This variation on + * krb5_derive_key does not cache the result, as it is only used + * directly in situations which are not expected to be repeated with + * the same inkey and constant. + */ krb5_error_code krb5_derive_keyblock(const struct krb5_enc_provider *enc, krb5_key inkey, krb5_keyblock *outkey, @@ -111,21 +168,32 @@ krb5_derive_key(const struct krb5_enc_provider *enc, { krb5_keyblock keyblock; krb5_error_code ret; + krb5_key dkey; *outkey = NULL; - /* Set up a temporary keyblock. */ + /* Check for a cached result. */ + dkey = find_cached_dkey(inkey->derived, in_constant); + if (dkey != NULL) { + *outkey = dkey; + return 0; + } + + /* Derive into a temporary keyblock. */ keyblock.length = enc->keylength; keyblock.contents = malloc(keyblock.length); if (keyblock.contents == NULL) return ENOMEM; - ret = krb5_derive_keyblock(enc, inkey, &keyblock, in_constant); if (ret) goto cleanup; - /* Convert the keyblock to a key. */ - ret = krb5_k_create_key(NULL, &keyblock, outkey); + /* Cache the derived key. */ + ret = add_cached_dkey(inkey, in_constant, &keyblock, &dkey); + if (ret != 0) + goto cleanup; + + *outkey = dkey; cleanup: zapfree(keyblock.contents, keyblock.length); diff --git a/src/lib/crypto/krb/key.c b/src/lib/crypto/krb/key.c index 1fb9bcc837..4ea72b478f 100644 --- a/src/lib/crypto/krb/key.c +++ b/src/lib/crypto/krb/key.c @@ -50,6 +50,7 @@ krb5_k_create_key(krb5_context context, const krb5_keyblock *key_data, goto cleanup; key->refcount = 1; + key->derived = NULL; *out = key; return 0; @@ -68,8 +69,17 @@ krb5_k_reference_key(krb5_context context, krb5_key key) void KRB5_CALLCONV krb5_k_free_key(krb5_context context, krb5_key key) { + struct derived_key *dk; + if (key == NULL || --key->refcount > 0) return; + + /* Free the derived key cache. */ + while ((dk = key->derived) != NULL) { + key->derived = dk->next; + krb5_k_free_key(context, dk->dkey); + free(dk); + } krb5int_c_free_keyblock_contents(context, &key->keyblock); }