diff options
author | Nathaniel McCallum <npmccallum@redhat.com> | 2015-06-14 21:03:00 -0400 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 2015-08-09 17:19:45 -0400 |
commit | 35f288092f0df7f4aca92e1f51db3611a3b32ada (patch) | |
tree | 17c5f06bbb608dbafeb43be14c5674603ccb6244 /src/lib | |
parent | bd6a449f6591f75d0db6dbf3fb702268b92d7eb8 (diff) | |
download | krb5-35f288092f0df7f4aca92e1f51db3611a3b32ada.zip krb5-35f288092f0df7f4aca92e1f51db3611a3b32ada.tar.gz krb5-35f288092f0df7f4aca92e1f51db3611a3b32ada.tar.bz2 |
Add krb5_c_prfplus() and krb5_c_derive_prfplus()
This commit permits the external use of the RFC 6113 PRF+ function.
It also adds a function to derive a key from an input key and string
using PRF+.
[ghudson@mit.edu: adjust style; avoid new C99isms; use string2data(),
empty_data(), and alloc_data() where appropriate; add some explanatory
comments; edit docstrings and commit message]
ticket: 8228 (new)
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/crypto/krb/cf2.c | 209 | ||||
-rw-r--r-- | src/lib/crypto/libk5crypto.exports | 2 | ||||
-rw-r--r-- | src/lib/krb5_32.def | 2 |
3 files changed, 123 insertions, 90 deletions
diff --git a/src/lib/crypto/krb/cf2.c b/src/lib/crypto/krb/cf2.c index 49584ef..2ee5aeb 100644 --- a/src/lib/crypto/krb/cf2.c +++ b/src/lib/crypto/krb/cf2.c @@ -1,8 +1,8 @@ /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* lib/crypto/krb/cf2.c */ /* - * Copyright (C) 2009 by the Massachusetts Institute of Technology. - * All rights reserved. + * Copyright (C) 2009, 2015 by the Massachusetts Institute of Technology. All + * rights reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. @@ -31,60 +31,94 @@ #include "crypto_int.h" -/* - * Call the PRF function multiple times with the pepper prefixed with - * a count byte to get enough bits of output. - */ -static krb5_error_code -prf_plus(krb5_context context, const krb5_keyblock *k, const char *pepper, - size_t keybytes, char **out) +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +krb5_error_code KRB5_CALLCONV +krb5_c_prfplus(krb5_context context, const krb5_keyblock *k, + const krb5_data *input, krb5_data *output) { - krb5_error_code retval = 0; - size_t prflen, iterations; - krb5_data out_data; - krb5_data in_data; - char *buffer = NULL; - struct k5buf prf_inbuf; - - k5_buf_init_dynamic(&prf_inbuf); - k5_buf_add_len(&prf_inbuf, "\001", 1); - k5_buf_add(&prf_inbuf, pepper); - retval = krb5_c_prf_length( context, k->enctype, &prflen); - if (retval) - goto cleanup; - iterations = keybytes / prflen; - if (keybytes % prflen != 0) - iterations++; - assert(iterations <= 254); - buffer = k5calloc(iterations, prflen, &retval); - if (retval) + krb5_error_code ret; + krb5_data prf_in = empty_data(), prf_out = empty_data(); + size_t prflen, nblocks, i; + + /* Calculate the number of PRF invocations we will need. */ + ret = krb5_c_prf_length(context, k->enctype, &prflen); + if (ret) + return ret; + nblocks = (output->length + prflen - 1)/ prflen; + if (nblocks > 255) + return E2BIG; + + /* Allocate PRF input and output buffers. */ + ret = alloc_data(&prf_in, input->length + 1); + if (ret) goto cleanup; - retval = k5_buf_status(&prf_inbuf); - if (retval) + ret = alloc_data(&prf_out, prflen); + if (ret) goto cleanup; - in_data.length = prf_inbuf.len; - in_data.data = prf_inbuf.data; - out_data.length = prflen; - out_data.data = buffer; - - while (iterations > 0) { - retval = krb5_c_prf(context, k, &in_data, &out_data); - if (retval) + + /* Concatenate PRF(k, 1||input) || PRF(k, 2||input) || ... to produce the + * desired number of bytes. */ + memcpy(&prf_in.data[1], input->data, input->length); + for (i = 0; i < nblocks; i++) { + prf_in.data[0] = i + 1; + ret = krb5_c_prf(context, k, &prf_in, &prf_out); + if (ret) goto cleanup; - out_data.data += prflen; - in_data.data[0]++; - iterations--; - } - *out = buffer; - buffer = NULL; + memcpy(&output->data[i * prflen], prf_out.data, + MIN(prflen, output->length - i * prflen)); + } cleanup: - free(buffer); - k5_buf_free(&prf_inbuf); - return retval; + zapfree(prf_out.data, prf_out.length); + zapfree(prf_in.data, prf_in.length); + return ret; } +krb5_error_code KRB5_CALLCONV +krb5_c_derive_prfplus(krb5_context context, const krb5_keyblock *k, + const krb5_data *input, krb5_enctype enctype, + krb5_keyblock **out) +{ + krb5_error_code ret; + const struct krb5_keytypes *ktp; + krb5_data rnd = empty_data(); + krb5_keyblock *kb = NULL; + + *out = NULL; + + ktp = find_enctype((enctype == ENCTYPE_NULL) ? k->enctype : enctype); + if (ktp == NULL) + return KRB5_BAD_ENCTYPE; + + /* Generate enough pseudo-random bytes for the random-to-key function. */ + ret = alloc_data(&rnd, ktp->enc->keybytes); + if (ret) + goto cleanup; + ret = krb5_c_prfplus(context, k, input, &rnd); + if (ret) + goto cleanup; + + /* Generate a key from the pseudo-random bytes. */ + ret = krb5int_c_init_keyblock(context, ktp->etype, ktp->enc->keylength, + &kb); + if (ret) + goto cleanup; + ret = (*ktp->rand2key)(&rnd, kb); + if (ret) + goto cleanup; + + *out = kb; + kb = NULL; + +cleanup: + zapfree(rnd.data, rnd.length); + krb5int_c_free_keyblock(context, kb); + return ret; +} krb5_error_code KRB5_CALLCONV krb5_c_fx_cf2_simple(krb5_context context, @@ -92,56 +126,51 @@ krb5_c_fx_cf2_simple(krb5_context context, const krb5_keyblock *k2, const char *pepper2, krb5_keyblock **out) { - const struct krb5_keytypes *out_enctype; - size_t keybytes, keylength, i; - char *prf1 = NULL, *prf2 = NULL; - krb5_data keydata; - krb5_enctype out_enctype_num; - krb5_error_code retval = 0; - krb5_keyblock *out_key = NULL; - - if (k1 == NULL || !krb5_c_valid_enctype(k1->enctype)) - return KRB5_BAD_ENCTYPE; - if (k2 == NULL || !krb5_c_valid_enctype(k2->enctype)) + krb5_error_code ret; + const struct krb5_keytypes *ktp = NULL; + const krb5_data pepper1_data = string2data((char *)pepper1); + const krb5_data pepper2_data = string2data((char *)pepper2); + krb5_data prf1 = empty_data(), prf2 = empty_data(); + unsigned int i; + krb5_keyblock *kb = NULL; + + *out = NULL; + + ktp = find_enctype(k1->enctype); + if (ktp == NULL) return KRB5_BAD_ENCTYPE; - out_enctype_num = k1->enctype; - assert(out != NULL); - out_enctype = find_enctype(out_enctype_num); - assert(out_enctype != NULL); - if (out_enctype->prf == NULL) { - if (context) { - k5_set_error(&(context->err), KRB5_CRYPTO_INTERNAL, - _("Enctype %d has no PRF"), out_enctype_num); - } - return KRB5_CRYPTO_INTERNAL; - } - keybytes = out_enctype->enc->keybytes; - keylength = out_enctype->enc->keylength; - retval = prf_plus(context, k1, pepper1, keybytes, &prf1); - if (retval) + /* Generate PRF+(k1, pepper1) and PRF+(k2, kepper2). */ + ret = alloc_data(&prf1, ktp->enc->keybytes); + if (ret) + goto cleanup; + ret = krb5_c_prfplus(context, k1, &pepper1_data, &prf1); + if (ret) goto cleanup; - retval = prf_plus(context, k2, pepper2, keybytes, &prf2); - if (retval) + ret = alloc_data(&prf2, ktp->enc->keybytes); + if (ret) goto cleanup; - for (i = 0; i < keybytes; i++) - prf1[i] ^= prf2[i]; - retval = krb5int_c_init_keyblock(context, out_enctype_num, keylength, - &out_key); - if (retval) + ret = krb5_c_prfplus(context, k2, &pepper2_data, &prf2); + if (ret) + goto cleanup; + + /* Compute the XOR of the two PRF+ values and generate a key. */ + for (i = 0; i < prf1.length; i++) + prf1.data[i] ^= prf2.data[i]; + ret = krb5int_c_init_keyblock(context, ktp->etype, ktp->enc->keylength, + &kb); + if (ret) goto cleanup; - keydata.data = prf1; - keydata.length = keybytes; - retval = (*out_enctype->rand2key)(&keydata, out_key); - if (retval) + ret = (*ktp->rand2key)(&prf1, kb); + if (ret) goto cleanup; - *out = out_key; - out_key = NULL; + *out = kb; + kb = NULL; cleanup: - krb5int_c_free_keyblock( context, out_key); - zapfree(prf1, keybytes); - zapfree(prf2, keybytes); - return retval; + zapfree(prf2.data, prf2.length); + zapfree(prf1.data, prf1.length); + krb5int_c_free_keyblock(context, kb); + return ret; } diff --git a/src/lib/crypto/libk5crypto.exports b/src/lib/crypto/libk5crypto.exports index 9342387..d0f0d29 100644 --- a/src/lib/crypto/libk5crypto.exports +++ b/src/lib/crypto/libk5crypto.exports @@ -102,3 +102,5 @@ k5_sha256_init k5_sha256_update krb5int_nfold k5_allow_weak_pbkdf2iter +krb5_c_prfplus +krb5_c_derive_prfplus diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def index 226155f..3734e9b 100644 --- a/src/lib/krb5_32.def +++ b/src/lib/krb5_32.def @@ -461,3 +461,5 @@ EXPORTS krb5_vprepend_error_message @428 krb5_wrap_error_message @429 krb5_vwrap_error_message @430 + krb5_c_prfplus @431 + krb5_c_derive_prfplus @432 |