1*afab4e30Schristos /* $NetBSD: sp800-108-kdf.c,v 1.4 2023/06/19 21:41:44 christos Exp $ */
2b9d004c6Schristos
3b9d004c6Schristos /*
4b9d004c6Schristos * Copyright (c) 2015, Secure Endpoints Inc.
5b9d004c6Schristos * All rights reserved.
6b9d004c6Schristos *
7b9d004c6Schristos * Redistribution and use in source and binary forms, with or without
8b9d004c6Schristos * modification, are permitted provided that the following conditions
9b9d004c6Schristos * are met:
10b9d004c6Schristos *
11b9d004c6Schristos * - Redistributions of source code must retain the above copyright
12b9d004c6Schristos * notice, this list of conditions and the following disclaimer.
13b9d004c6Schristos *
14b9d004c6Schristos * - Redistributions in binary form must reproduce the above copyright
15b9d004c6Schristos * notice, this list of conditions and the following disclaimer in
16b9d004c6Schristos * the documentation and/or other materials provided with the
17b9d004c6Schristos * distribution.
18b9d004c6Schristos *
19b9d004c6Schristos * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20b9d004c6Schristos * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21b9d004c6Schristos * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22b9d004c6Schristos * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23b9d004c6Schristos * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24b9d004c6Schristos * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25b9d004c6Schristos * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26b9d004c6Schristos * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27b9d004c6Schristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28b9d004c6Schristos * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29b9d004c6Schristos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30b9d004c6Schristos * OF THE POSSIBILITY OF SUCH DAMAGE.
31b9d004c6Schristos *
32b9d004c6Schristos */
33b9d004c6Schristos
34b9d004c6Schristos #include "krb5_locl.h"
35b9d004c6Schristos
36b9d004c6Schristos /*
37b9d004c6Schristos * SP800-108 KDF
38b9d004c6Schristos */
39b9d004c6Schristos
40b9d004c6Schristos /**
41b9d004c6Schristos * As described in SP800-108 5.1 (for HMAC)
42b9d004c6Schristos *
43b9d004c6Schristos * @param context Kerberos 5 context
44b9d004c6Schristos * @param kdf_K1 Base key material.
45b9d004c6Schristos * @param kdf_label A string that identifies the purpose for the derived key.
46b9d004c6Schristos * @param kdf_context A binary string containing parties, nonce, etc.
47b9d004c6Schristos * @param md Message digest function to use for PRF.
48b9d004c6Schristos * @param kdf_K0 Derived key data.
49b9d004c6Schristos *
50b9d004c6Schristos * @return Return an error code for an failure or 0 on success.
51b9d004c6Schristos * @ingroup krb5_crypto
52b9d004c6Schristos */
53b9d004c6Schristos krb5_error_code
_krb5_SP800_108_HMAC_KDF(krb5_context context,const krb5_data * kdf_K1,const krb5_data * kdf_label,const krb5_data * kdf_context,const EVP_MD * md,krb5_data * kdf_K0)54b9d004c6Schristos _krb5_SP800_108_HMAC_KDF(krb5_context context,
55b9d004c6Schristos const krb5_data *kdf_K1,
56b9d004c6Schristos const krb5_data *kdf_label,
57b9d004c6Schristos const krb5_data *kdf_context,
58b9d004c6Schristos const EVP_MD *md,
59b9d004c6Schristos krb5_data *kdf_K0)
60b9d004c6Schristos {
616680b65dSchristos HMAC_CTX *c;
62b9d004c6Schristos unsigned char *p = kdf_K0->data;
63b9d004c6Schristos size_t i, n, left = kdf_K0->length;
64b9d004c6Schristos unsigned char hmac[EVP_MAX_MD_SIZE];
65b9d004c6Schristos unsigned int h = EVP_MD_size(md);
66b9d004c6Schristos const size_t L = kdf_K0->length;
67b9d004c6Schristos
68b9d004c6Schristos heim_assert(md != NULL, "SP800-108 KDF internal error");
69b9d004c6Schristos
706680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
716680b65dSchristos HMAC_CTX cs;
726680b65dSchristos c = &cs;
736680b65dSchristos HMAC_CTX_init(c);
746680b65dSchristos #else
756680b65dSchristos c = HMAC_CTX_new();
766680b65dSchristos #endif
77b9d004c6Schristos
78b9d004c6Schristos n = L / h;
79b9d004c6Schristos
80b9d004c6Schristos for (i = 0; i <= n; i++) {
81b9d004c6Schristos unsigned char tmp[4];
82b9d004c6Schristos size_t len;
83b9d004c6Schristos
846680b65dSchristos HMAC_Init_ex(c, kdf_K1->data, kdf_K1->length, md, NULL);
85b9d004c6Schristos
86b9d004c6Schristos _krb5_put_int(tmp, i + 1, 4);
876680b65dSchristos HMAC_Update(c, tmp, 4);
886680b65dSchristos HMAC_Update(c, kdf_label->data, kdf_label->length);
896680b65dSchristos HMAC_Update(c, (unsigned char *)"", 1);
90b9d004c6Schristos if (kdf_context)
916680b65dSchristos HMAC_Update(c, kdf_context->data, kdf_context->length);
92b9d004c6Schristos _krb5_put_int(tmp, L * 8, 4);
936680b65dSchristos HMAC_Update(c, tmp, 4);
94b9d004c6Schristos
956680b65dSchristos HMAC_Final(c, hmac, &h);
96b9d004c6Schristos len = h > left ? left : h;
97b9d004c6Schristos memcpy(p, hmac, len);
98b9d004c6Schristos p += len;
99b9d004c6Schristos left -= len;
100b9d004c6Schristos }
101b9d004c6Schristos
1026680b65dSchristos #if OPENSSL_VERSION_NUMBER < 0x10100000UL
1036680b65dSchristos HMAC_CTX_cleanup(c);
1046680b65dSchristos #else
1056680b65dSchristos HMAC_CTX_free(c);
1066680b65dSchristos #endif
107b9d004c6Schristos
108b9d004c6Schristos return 0;
109b9d004c6Schristos }
110