xref: /optee_os/lib/libmbedtls/mbedtls/library/hkdf.c (revision 32b3180828fa15a49ccc86ecb4be9d274c140c89)
13d3b0591SJens Wiklander /*
23d3b0591SJens Wiklander  *  HKDF implementation -- RFC 5869
33d3b0591SJens Wiklander  *
47901324dSJerome Forissier  *  Copyright The Mbed TLS Contributors
53d3b0591SJens Wiklander  *  SPDX-License-Identifier: Apache-2.0
63d3b0591SJens Wiklander  *
73d3b0591SJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
83d3b0591SJens Wiklander  *  not use this file except in compliance with the License.
93d3b0591SJens Wiklander  *  You may obtain a copy of the License at
103d3b0591SJens Wiklander  *
113d3b0591SJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
123d3b0591SJens Wiklander  *
133d3b0591SJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
143d3b0591SJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
153d3b0591SJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
163d3b0591SJens Wiklander  *  See the License for the specific language governing permissions and
173d3b0591SJens Wiklander  *  limitations under the License.
183d3b0591SJens Wiklander  */
197901324dSJerome Forissier #include "common.h"
203d3b0591SJens Wiklander 
213d3b0591SJens Wiklander #if defined(MBEDTLS_HKDF_C)
223d3b0591SJens Wiklander 
233d3b0591SJens Wiklander #include <string.h>
243d3b0591SJens Wiklander #include "mbedtls/hkdf.h"
253d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
2611fa71b9SJerome Forissier #include "mbedtls/error.h"
273d3b0591SJens Wiklander 
283d3b0591SJens Wiklander int mbedtls_hkdf(const mbedtls_md_info_t *md, const unsigned char *salt,
293d3b0591SJens Wiklander                  size_t salt_len, const unsigned char *ikm, size_t ikm_len,
303d3b0591SJens Wiklander                  const unsigned char *info, size_t info_len,
313d3b0591SJens Wiklander                  unsigned char *okm, size_t okm_len)
323d3b0591SJens Wiklander {
3311fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
343d3b0591SJens Wiklander     unsigned char prk[MBEDTLS_MD_MAX_SIZE];
353d3b0591SJens Wiklander 
363d3b0591SJens Wiklander     ret = mbedtls_hkdf_extract(md, salt, salt_len, ikm, ikm_len, prk);
373d3b0591SJens Wiklander 
38*32b31808SJens Wiklander     if (ret == 0) {
393d3b0591SJens Wiklander         ret = mbedtls_hkdf_expand(md, prk, mbedtls_md_get_size(md),
403d3b0591SJens Wiklander                                   info, info_len, okm, okm_len);
413d3b0591SJens Wiklander     }
423d3b0591SJens Wiklander 
433d3b0591SJens Wiklander     mbedtls_platform_zeroize(prk, sizeof(prk));
443d3b0591SJens Wiklander 
45*32b31808SJens Wiklander     return ret;
463d3b0591SJens Wiklander }
473d3b0591SJens Wiklander 
483d3b0591SJens Wiklander int mbedtls_hkdf_extract(const mbedtls_md_info_t *md,
493d3b0591SJens Wiklander                          const unsigned char *salt, size_t salt_len,
503d3b0591SJens Wiklander                          const unsigned char *ikm, size_t ikm_len,
513d3b0591SJens Wiklander                          unsigned char *prk)
523d3b0591SJens Wiklander {
533d3b0591SJens Wiklander     unsigned char null_salt[MBEDTLS_MD_MAX_SIZE] = { '\0' };
543d3b0591SJens Wiklander 
55*32b31808SJens Wiklander     if (salt == NULL) {
563d3b0591SJens Wiklander         size_t hash_len;
573d3b0591SJens Wiklander 
58*32b31808SJens Wiklander         if (salt_len != 0) {
593d3b0591SJens Wiklander             return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
603d3b0591SJens Wiklander         }
613d3b0591SJens Wiklander 
623d3b0591SJens Wiklander         hash_len = mbedtls_md_get_size(md);
633d3b0591SJens Wiklander 
64*32b31808SJens Wiklander         if (hash_len == 0) {
653d3b0591SJens Wiklander             return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
663d3b0591SJens Wiklander         }
673d3b0591SJens Wiklander 
683d3b0591SJens Wiklander         salt = null_salt;
693d3b0591SJens Wiklander         salt_len = hash_len;
703d3b0591SJens Wiklander     }
713d3b0591SJens Wiklander 
72*32b31808SJens Wiklander     return mbedtls_md_hmac(md, salt, salt_len, ikm, ikm_len, prk);
733d3b0591SJens Wiklander }
743d3b0591SJens Wiklander 
753d3b0591SJens Wiklander int mbedtls_hkdf_expand(const mbedtls_md_info_t *md, const unsigned char *prk,
763d3b0591SJens Wiklander                         size_t prk_len, const unsigned char *info,
773d3b0591SJens Wiklander                         size_t info_len, unsigned char *okm, size_t okm_len)
783d3b0591SJens Wiklander {
793d3b0591SJens Wiklander     size_t hash_len;
803d3b0591SJens Wiklander     size_t where = 0;
813d3b0591SJens Wiklander     size_t n;
823d3b0591SJens Wiklander     size_t t_len = 0;
833d3b0591SJens Wiklander     size_t i;
843d3b0591SJens Wiklander     int ret = 0;
853d3b0591SJens Wiklander     mbedtls_md_context_t ctx;
863d3b0591SJens Wiklander     unsigned char t[MBEDTLS_MD_MAX_SIZE];
873d3b0591SJens Wiklander 
88*32b31808SJens Wiklander     if (okm == NULL) {
89*32b31808SJens Wiklander         return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
903d3b0591SJens Wiklander     }
913d3b0591SJens Wiklander 
923d3b0591SJens Wiklander     hash_len = mbedtls_md_get_size(md);
933d3b0591SJens Wiklander 
94*32b31808SJens Wiklander     if (prk_len < hash_len || hash_len == 0) {
95*32b31808SJens Wiklander         return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
963d3b0591SJens Wiklander     }
973d3b0591SJens Wiklander 
98*32b31808SJens Wiklander     if (info == NULL) {
993d3b0591SJens Wiklander         info = (const unsigned char *) "";
1003d3b0591SJens Wiklander         info_len = 0;
1013d3b0591SJens Wiklander     }
1023d3b0591SJens Wiklander 
1033d3b0591SJens Wiklander     n = okm_len / hash_len;
1043d3b0591SJens Wiklander 
105*32b31808SJens Wiklander     if (okm_len % hash_len != 0) {
1063d3b0591SJens Wiklander         n++;
1073d3b0591SJens Wiklander     }
1083d3b0591SJens Wiklander 
1093d3b0591SJens Wiklander     /*
1103d3b0591SJens Wiklander      * Per RFC 5869 Section 2.3, okm_len must not exceed
1113d3b0591SJens Wiklander      * 255 times the hash length
1123d3b0591SJens Wiklander      */
113*32b31808SJens Wiklander     if (n > 255) {
114*32b31808SJens Wiklander         return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
1153d3b0591SJens Wiklander     }
1163d3b0591SJens Wiklander 
1173d3b0591SJens Wiklander     mbedtls_md_init(&ctx);
1183d3b0591SJens Wiklander 
119*32b31808SJens Wiklander     if ((ret = mbedtls_md_setup(&ctx, md, 1)) != 0) {
1203d3b0591SJens Wiklander         goto exit;
1213d3b0591SJens Wiklander     }
1223d3b0591SJens Wiklander 
12311fa71b9SJerome Forissier     memset(t, 0, hash_len);
12411fa71b9SJerome Forissier 
1253d3b0591SJens Wiklander     /*
1263d3b0591SJens Wiklander      * Compute T = T(1) | T(2) | T(3) | ... | T(N)
1273d3b0591SJens Wiklander      * Where T(N) is defined in RFC 5869 Section 2.3
1283d3b0591SJens Wiklander      */
129*32b31808SJens Wiklander     for (i = 1; i <= n; i++) {
1303d3b0591SJens Wiklander         size_t num_to_copy;
1313d3b0591SJens Wiklander         unsigned char c = i & 0xff;
1323d3b0591SJens Wiklander 
1333d3b0591SJens Wiklander         ret = mbedtls_md_hmac_starts(&ctx, prk, prk_len);
134*32b31808SJens Wiklander         if (ret != 0) {
1353d3b0591SJens Wiklander             goto exit;
1363d3b0591SJens Wiklander         }
1373d3b0591SJens Wiklander 
1383d3b0591SJens Wiklander         ret = mbedtls_md_hmac_update(&ctx, t, t_len);
139*32b31808SJens Wiklander         if (ret != 0) {
1403d3b0591SJens Wiklander             goto exit;
1413d3b0591SJens Wiklander         }
1423d3b0591SJens Wiklander 
1433d3b0591SJens Wiklander         ret = mbedtls_md_hmac_update(&ctx, info, info_len);
144*32b31808SJens Wiklander         if (ret != 0) {
1453d3b0591SJens Wiklander             goto exit;
1463d3b0591SJens Wiklander         }
1473d3b0591SJens Wiklander 
1483d3b0591SJens Wiklander         /* The constant concatenated to the end of each T(n) is a single octet.
1493d3b0591SJens Wiklander          * */
1503d3b0591SJens Wiklander         ret = mbedtls_md_hmac_update(&ctx, &c, 1);
151*32b31808SJens Wiklander         if (ret != 0) {
1523d3b0591SJens Wiklander             goto exit;
1533d3b0591SJens Wiklander         }
1543d3b0591SJens Wiklander 
1553d3b0591SJens Wiklander         ret = mbedtls_md_hmac_finish(&ctx, t);
156*32b31808SJens Wiklander         if (ret != 0) {
1573d3b0591SJens Wiklander             goto exit;
1583d3b0591SJens Wiklander         }
1593d3b0591SJens Wiklander 
1603d3b0591SJens Wiklander         num_to_copy = i != n ? hash_len : okm_len - where;
1613d3b0591SJens Wiklander         memcpy(okm + where, t, num_to_copy);
1623d3b0591SJens Wiklander         where += hash_len;
1633d3b0591SJens Wiklander         t_len = hash_len;
1643d3b0591SJens Wiklander     }
1653d3b0591SJens Wiklander 
1663d3b0591SJens Wiklander exit:
1673d3b0591SJens Wiklander     mbedtls_md_free(&ctx);
1683d3b0591SJens Wiklander     mbedtls_platform_zeroize(t, sizeof(t));
1693d3b0591SJens Wiklander 
170*32b31808SJens Wiklander     return ret;
1713d3b0591SJens Wiklander }
1723d3b0591SJens Wiklander 
1733d3b0591SJens Wiklander #endif /* MBEDTLS_HKDF_C */
174