/src/mbedtls/library/hkdf.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * HKDF implementation -- RFC 5869 |
3 | | * |
4 | | * Copyright The Mbed TLS Contributors |
5 | | * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later |
6 | | */ |
7 | | #include "common.h" |
8 | | |
9 | | #if defined(MBEDTLS_HKDF_C) |
10 | | |
11 | | #include <string.h> |
12 | | #include "mbedtls/hkdf.h" |
13 | | #include "mbedtls/platform_util.h" |
14 | | #include "mbedtls/error.h" |
15 | | |
16 | | int mbedtls_hkdf(const mbedtls_md_info_t *md, const unsigned char *salt, |
17 | | size_t salt_len, const unsigned char *ikm, size_t ikm_len, |
18 | | const unsigned char *info, size_t info_len, |
19 | | unsigned char *okm, size_t okm_len) |
20 | 201 | { |
21 | 201 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
22 | 201 | unsigned char prk[MBEDTLS_MD_MAX_SIZE]; |
23 | | |
24 | 201 | ret = mbedtls_hkdf_extract(md, salt, salt_len, ikm, ikm_len, prk); |
25 | | |
26 | 201 | if (ret == 0) { |
27 | 201 | ret = mbedtls_hkdf_expand(md, prk, mbedtls_md_get_size(md), |
28 | 201 | info, info_len, okm, okm_len); |
29 | 201 | } |
30 | | |
31 | 201 | mbedtls_platform_zeroize(prk, sizeof(prk)); |
32 | | |
33 | 201 | return ret; |
34 | 201 | } |
35 | | |
36 | | int mbedtls_hkdf_extract(const mbedtls_md_info_t *md, |
37 | | const unsigned char *salt, size_t salt_len, |
38 | | const unsigned char *ikm, size_t ikm_len, |
39 | | unsigned char *prk) |
40 | 201 | { |
41 | 201 | unsigned char null_salt[MBEDTLS_MD_MAX_SIZE] = { '\0' }; |
42 | | |
43 | 201 | if (salt == NULL) { |
44 | 0 | size_t hash_len; |
45 | |
|
46 | 0 | if (salt_len != 0) { |
47 | 0 | return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA; |
48 | 0 | } |
49 | | |
50 | 0 | hash_len = mbedtls_md_get_size(md); |
51 | |
|
52 | 0 | if (hash_len == 0) { |
53 | 0 | return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA; |
54 | 0 | } |
55 | | |
56 | 0 | salt = null_salt; |
57 | 0 | salt_len = hash_len; |
58 | 0 | } |
59 | | |
60 | 201 | return mbedtls_md_hmac(md, salt, salt_len, ikm, ikm_len, prk); |
61 | 201 | } |
62 | | |
63 | | int mbedtls_hkdf_expand(const mbedtls_md_info_t *md, const unsigned char *prk, |
64 | | size_t prk_len, const unsigned char *info, |
65 | | size_t info_len, unsigned char *okm, size_t okm_len) |
66 | 201 | { |
67 | 201 | size_t hash_len; |
68 | 201 | size_t where = 0; |
69 | 201 | size_t n; |
70 | 201 | size_t t_len = 0; |
71 | 201 | size_t i; |
72 | 201 | int ret = 0; |
73 | 201 | mbedtls_md_context_t ctx; |
74 | 201 | unsigned char t[MBEDTLS_MD_MAX_SIZE]; |
75 | | |
76 | 201 | if (okm == NULL) { |
77 | 3 | return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA; |
78 | 3 | } |
79 | | |
80 | 198 | hash_len = mbedtls_md_get_size(md); |
81 | | |
82 | 198 | if (prk_len < hash_len || hash_len == 0) { |
83 | 0 | return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA; |
84 | 0 | } |
85 | | |
86 | 198 | if (info == NULL) { |
87 | 0 | info = (const unsigned char *) ""; |
88 | 0 | info_len = 0; |
89 | 0 | } |
90 | | |
91 | 198 | n = okm_len / hash_len; |
92 | | |
93 | 198 | if (okm_len % hash_len != 0) { |
94 | 188 | n++; |
95 | 188 | } |
96 | | |
97 | | /* |
98 | | * Per RFC 5869 Section 2.3, okm_len must not exceed |
99 | | * 255 times the hash length |
100 | | */ |
101 | 198 | if (n > 255) { |
102 | 0 | return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA; |
103 | 0 | } |
104 | | |
105 | 198 | mbedtls_md_init(&ctx); |
106 | | |
107 | 198 | if ((ret = mbedtls_md_setup(&ctx, md, 1)) != 0) { |
108 | 0 | goto exit; |
109 | 0 | } |
110 | | |
111 | 198 | memset(t, 0, hash_len); |
112 | | |
113 | | /* |
114 | | * Compute T = T(1) | T(2) | T(3) | ... | T(N) |
115 | | * Where T(N) is defined in RFC 5869 Section 2.3 |
116 | | */ |
117 | 23.2k | for (i = 1; i <= n; i++) { |
118 | 23.0k | size_t num_to_copy; |
119 | 23.0k | unsigned char c = i & 0xff; |
120 | | |
121 | 23.0k | ret = mbedtls_md_hmac_starts(&ctx, prk, prk_len); |
122 | 23.0k | if (ret != 0) { |
123 | 0 | goto exit; |
124 | 0 | } |
125 | | |
126 | 23.0k | ret = mbedtls_md_hmac_update(&ctx, t, t_len); |
127 | 23.0k | if (ret != 0) { |
128 | 0 | goto exit; |
129 | 0 | } |
130 | | |
131 | 23.0k | ret = mbedtls_md_hmac_update(&ctx, info, info_len); |
132 | 23.0k | if (ret != 0) { |
133 | 0 | goto exit; |
134 | 0 | } |
135 | | |
136 | | /* The constant concatenated to the end of each T(n) is a single octet. |
137 | | * */ |
138 | 23.0k | ret = mbedtls_md_hmac_update(&ctx, &c, 1); |
139 | 23.0k | if (ret != 0) { |
140 | 0 | goto exit; |
141 | 0 | } |
142 | | |
143 | 23.0k | ret = mbedtls_md_hmac_finish(&ctx, t); |
144 | 23.0k | if (ret != 0) { |
145 | 0 | goto exit; |
146 | 0 | } |
147 | | |
148 | 23.0k | num_to_copy = i != n ? hash_len : okm_len - where; |
149 | 23.0k | memcpy(okm + where, t, num_to_copy); |
150 | 23.0k | where += hash_len; |
151 | 23.0k | t_len = hash_len; |
152 | 23.0k | } |
153 | | |
154 | 198 | exit: |
155 | 198 | mbedtls_md_free(&ctx); |
156 | 198 | mbedtls_platform_zeroize(t, sizeof(t)); |
157 | | |
158 | 198 | return ret; |
159 | 198 | } |
160 | | |
161 | | #endif /* MBEDTLS_HKDF_C */ |