xref: /optee_os/lib/libmbedtls/mbedtls/library/hkdf.c (revision b0563631928755fe864b97785160fb3088e9efdc)
13d3b0591SJens Wiklander /*
23d3b0591SJens Wiklander  *  HKDF implementation -- RFC 5869
33d3b0591SJens Wiklander  *
47901324dSJerome Forissier  *  Copyright The Mbed TLS Contributors
5*b0563631STom Van Eyck  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
63d3b0591SJens Wiklander  */
77901324dSJerome Forissier #include "common.h"
83d3b0591SJens Wiklander 
93d3b0591SJens Wiklander #if defined(MBEDTLS_HKDF_C)
103d3b0591SJens Wiklander 
113d3b0591SJens Wiklander #include <string.h>
123d3b0591SJens Wiklander #include "mbedtls/hkdf.h"
133d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
1411fa71b9SJerome Forissier #include "mbedtls/error.h"
153d3b0591SJens Wiklander 
mbedtls_hkdf(const mbedtls_md_info_t * md,const unsigned char * salt,size_t salt_len,const unsigned char * ikm,size_t ikm_len,const unsigned char * info,size_t info_len,unsigned char * okm,size_t okm_len)163d3b0591SJens Wiklander int mbedtls_hkdf(const mbedtls_md_info_t *md, const unsigned char *salt,
173d3b0591SJens Wiklander                  size_t salt_len, const unsigned char *ikm, size_t ikm_len,
183d3b0591SJens Wiklander                  const unsigned char *info, size_t info_len,
193d3b0591SJens Wiklander                  unsigned char *okm, size_t okm_len)
203d3b0591SJens Wiklander {
2111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
223d3b0591SJens Wiklander     unsigned char prk[MBEDTLS_MD_MAX_SIZE];
233d3b0591SJens Wiklander 
243d3b0591SJens Wiklander     ret = mbedtls_hkdf_extract(md, salt, salt_len, ikm, ikm_len, prk);
253d3b0591SJens Wiklander 
2632b31808SJens Wiklander     if (ret == 0) {
273d3b0591SJens Wiklander         ret = mbedtls_hkdf_expand(md, prk, mbedtls_md_get_size(md),
283d3b0591SJens Wiklander                                   info, info_len, okm, okm_len);
293d3b0591SJens Wiklander     }
303d3b0591SJens Wiklander 
313d3b0591SJens Wiklander     mbedtls_platform_zeroize(prk, sizeof(prk));
323d3b0591SJens Wiklander 
3332b31808SJens Wiklander     return ret;
343d3b0591SJens Wiklander }
353d3b0591SJens Wiklander 
mbedtls_hkdf_extract(const mbedtls_md_info_t * md,const unsigned char * salt,size_t salt_len,const unsigned char * ikm,size_t ikm_len,unsigned char * prk)363d3b0591SJens Wiklander int mbedtls_hkdf_extract(const mbedtls_md_info_t *md,
373d3b0591SJens Wiklander                          const unsigned char *salt, size_t salt_len,
383d3b0591SJens Wiklander                          const unsigned char *ikm, size_t ikm_len,
393d3b0591SJens Wiklander                          unsigned char *prk)
403d3b0591SJens Wiklander {
413d3b0591SJens Wiklander     unsigned char null_salt[MBEDTLS_MD_MAX_SIZE] = { '\0' };
423d3b0591SJens Wiklander 
4332b31808SJens Wiklander     if (salt == NULL) {
443d3b0591SJens Wiklander         size_t hash_len;
453d3b0591SJens Wiklander 
4632b31808SJens Wiklander         if (salt_len != 0) {
473d3b0591SJens Wiklander             return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
483d3b0591SJens Wiklander         }
493d3b0591SJens Wiklander 
503d3b0591SJens Wiklander         hash_len = mbedtls_md_get_size(md);
513d3b0591SJens Wiklander 
5232b31808SJens Wiklander         if (hash_len == 0) {
533d3b0591SJens Wiklander             return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
543d3b0591SJens Wiklander         }
553d3b0591SJens Wiklander 
563d3b0591SJens Wiklander         salt = null_salt;
573d3b0591SJens Wiklander         salt_len = hash_len;
583d3b0591SJens Wiklander     }
593d3b0591SJens Wiklander 
6032b31808SJens Wiklander     return mbedtls_md_hmac(md, salt, salt_len, ikm, ikm_len, prk);
613d3b0591SJens Wiklander }
623d3b0591SJens Wiklander 
mbedtls_hkdf_expand(const mbedtls_md_info_t * md,const unsigned char * prk,size_t prk_len,const unsigned char * info,size_t info_len,unsigned char * okm,size_t okm_len)633d3b0591SJens Wiklander int mbedtls_hkdf_expand(const mbedtls_md_info_t *md, const unsigned char *prk,
643d3b0591SJens Wiklander                         size_t prk_len, const unsigned char *info,
653d3b0591SJens Wiklander                         size_t info_len, unsigned char *okm, size_t okm_len)
663d3b0591SJens Wiklander {
673d3b0591SJens Wiklander     size_t hash_len;
683d3b0591SJens Wiklander     size_t where = 0;
693d3b0591SJens Wiklander     size_t n;
703d3b0591SJens Wiklander     size_t t_len = 0;
713d3b0591SJens Wiklander     size_t i;
723d3b0591SJens Wiklander     int ret = 0;
733d3b0591SJens Wiklander     mbedtls_md_context_t ctx;
743d3b0591SJens Wiklander     unsigned char t[MBEDTLS_MD_MAX_SIZE];
753d3b0591SJens Wiklander 
7632b31808SJens Wiklander     if (okm == NULL) {
7732b31808SJens Wiklander         return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
783d3b0591SJens Wiklander     }
793d3b0591SJens Wiklander 
803d3b0591SJens Wiklander     hash_len = mbedtls_md_get_size(md);
813d3b0591SJens Wiklander 
8232b31808SJens Wiklander     if (prk_len < hash_len || hash_len == 0) {
8332b31808SJens Wiklander         return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
843d3b0591SJens Wiklander     }
853d3b0591SJens Wiklander 
8632b31808SJens Wiklander     if (info == NULL) {
873d3b0591SJens Wiklander         info = (const unsigned char *) "";
883d3b0591SJens Wiklander         info_len = 0;
893d3b0591SJens Wiklander     }
903d3b0591SJens Wiklander 
913d3b0591SJens Wiklander     n = okm_len / hash_len;
923d3b0591SJens Wiklander 
9332b31808SJens Wiklander     if (okm_len % hash_len != 0) {
943d3b0591SJens Wiklander         n++;
953d3b0591SJens Wiklander     }
963d3b0591SJens Wiklander 
973d3b0591SJens Wiklander     /*
983d3b0591SJens Wiklander      * Per RFC 5869 Section 2.3, okm_len must not exceed
993d3b0591SJens Wiklander      * 255 times the hash length
1003d3b0591SJens Wiklander      */
10132b31808SJens Wiklander     if (n > 255) {
10232b31808SJens Wiklander         return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
1033d3b0591SJens Wiklander     }
1043d3b0591SJens Wiklander 
1053d3b0591SJens Wiklander     mbedtls_md_init(&ctx);
1063d3b0591SJens Wiklander 
10732b31808SJens Wiklander     if ((ret = mbedtls_md_setup(&ctx, md, 1)) != 0) {
1083d3b0591SJens Wiklander         goto exit;
1093d3b0591SJens Wiklander     }
1103d3b0591SJens Wiklander 
11111fa71b9SJerome Forissier     memset(t, 0, hash_len);
11211fa71b9SJerome Forissier 
1133d3b0591SJens Wiklander     /*
1143d3b0591SJens Wiklander      * Compute T = T(1) | T(2) | T(3) | ... | T(N)
1153d3b0591SJens Wiklander      * Where T(N) is defined in RFC 5869 Section 2.3
1163d3b0591SJens Wiklander      */
11732b31808SJens Wiklander     for (i = 1; i <= n; i++) {
1183d3b0591SJens Wiklander         size_t num_to_copy;
1193d3b0591SJens Wiklander         unsigned char c = i & 0xff;
1203d3b0591SJens Wiklander 
1213d3b0591SJens Wiklander         ret = mbedtls_md_hmac_starts(&ctx, prk, prk_len);
12232b31808SJens Wiklander         if (ret != 0) {
1233d3b0591SJens Wiklander             goto exit;
1243d3b0591SJens Wiklander         }
1253d3b0591SJens Wiklander 
1263d3b0591SJens Wiklander         ret = mbedtls_md_hmac_update(&ctx, t, t_len);
12732b31808SJens Wiklander         if (ret != 0) {
1283d3b0591SJens Wiklander             goto exit;
1293d3b0591SJens Wiklander         }
1303d3b0591SJens Wiklander 
1313d3b0591SJens Wiklander         ret = mbedtls_md_hmac_update(&ctx, info, info_len);
13232b31808SJens Wiklander         if (ret != 0) {
1333d3b0591SJens Wiklander             goto exit;
1343d3b0591SJens Wiklander         }
1353d3b0591SJens Wiklander 
1363d3b0591SJens Wiklander         /* The constant concatenated to the end of each T(n) is a single octet.
1373d3b0591SJens Wiklander          * */
1383d3b0591SJens Wiklander         ret = mbedtls_md_hmac_update(&ctx, &c, 1);
13932b31808SJens Wiklander         if (ret != 0) {
1403d3b0591SJens Wiklander             goto exit;
1413d3b0591SJens Wiklander         }
1423d3b0591SJens Wiklander 
1433d3b0591SJens Wiklander         ret = mbedtls_md_hmac_finish(&ctx, t);
14432b31808SJens Wiklander         if (ret != 0) {
1453d3b0591SJens Wiklander             goto exit;
1463d3b0591SJens Wiklander         }
1473d3b0591SJens Wiklander 
1483d3b0591SJens Wiklander         num_to_copy = i != n ? hash_len : okm_len - where;
1493d3b0591SJens Wiklander         memcpy(okm + where, t, num_to_copy);
1503d3b0591SJens Wiklander         where += hash_len;
1513d3b0591SJens Wiklander         t_len = hash_len;
1523d3b0591SJens Wiklander     }
1533d3b0591SJens Wiklander 
1543d3b0591SJens Wiklander exit:
1553d3b0591SJens Wiklander     mbedtls_md_free(&ctx);
1563d3b0591SJens Wiklander     mbedtls_platform_zeroize(t, sizeof(t));
1573d3b0591SJens Wiklander 
15832b31808SJens Wiklander     return ret;
1593d3b0591SJens Wiklander }
1603d3b0591SJens Wiklander 
1613d3b0591SJens Wiklander #endif /* MBEDTLS_HKDF_C */
162