/src/libressl/crypto/hkdf/hkdf.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* $OpenBSD: hkdf.c,v 1.7 2021/12/12 21:30:14 tb Exp $ */ |
2 | | /* Copyright (c) 2014, Google Inc. |
3 | | * |
4 | | * Permission to use, copy, modify, and/or distribute this software for any |
5 | | * purpose with or without fee is hereby granted, provided that the above |
6 | | * copyright notice and this permission notice appear in all copies. |
7 | | * |
8 | | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
11 | | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
13 | | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
14 | | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | | */ |
16 | | |
17 | | #include <openssl/hkdf.h> |
18 | | |
19 | | #include <string.h> |
20 | | |
21 | | #include <openssl/err.h> |
22 | | #include <openssl/hmac.h> |
23 | | |
24 | | #include "evp_locl.h" |
25 | | #include "hmac_local.h" |
26 | | |
27 | | /* https://tools.ietf.org/html/rfc5869#section-2 */ |
28 | | int |
29 | | HKDF(uint8_t *out_key, size_t out_len, const EVP_MD *digest, |
30 | | const uint8_t *secret, size_t secret_len, const uint8_t *salt, |
31 | | size_t salt_len, const uint8_t *info, size_t info_len) |
32 | 0 | { |
33 | 0 | uint8_t prk[EVP_MAX_MD_SIZE]; |
34 | 0 | size_t prk_len; |
35 | |
|
36 | 0 | if (!HKDF_extract(prk, &prk_len, digest, secret, secret_len, salt, |
37 | 0 | salt_len)) |
38 | 0 | return 0; |
39 | 0 | if (!HKDF_expand(out_key, out_len, digest, prk, prk_len, info, |
40 | 0 | info_len)) |
41 | 0 | return 0; |
42 | | |
43 | 0 | return 1; |
44 | 0 | } |
45 | | |
46 | | /* https://tools.ietf.org/html/rfc5869#section-2.2 */ |
47 | | int |
48 | | HKDF_extract(uint8_t *out_key, size_t *out_len, |
49 | | const EVP_MD *digest, const uint8_t *secret, size_t secret_len, |
50 | | const uint8_t *salt, size_t salt_len) |
51 | 0 | { |
52 | 0 | unsigned int len; |
53 | | |
54 | | /* |
55 | | * If salt is not given, HashLength zeros are used. However, HMAC does |
56 | | * that internally already so we can ignore it. |
57 | | */ |
58 | 0 | if (HMAC(digest, salt, salt_len, secret, secret_len, out_key, &len) == |
59 | 0 | NULL) { |
60 | 0 | CRYPTOerror(ERR_R_CRYPTO_LIB); |
61 | 0 | return 0; |
62 | 0 | } |
63 | 0 | *out_len = len; |
64 | 0 | return 1; |
65 | 0 | } |
66 | | |
67 | | /* https://tools.ietf.org/html/rfc5869#section-2.3 */ |
68 | | int |
69 | | HKDF_expand(uint8_t *out_key, size_t out_len, |
70 | | const EVP_MD *digest, const uint8_t *prk, size_t prk_len, |
71 | | const uint8_t *info, size_t info_len) |
72 | 0 | { |
73 | 0 | const size_t digest_len = EVP_MD_size(digest); |
74 | 0 | uint8_t previous[EVP_MAX_MD_SIZE]; |
75 | 0 | size_t n, done = 0; |
76 | 0 | unsigned int i; |
77 | 0 | int ret = 0; |
78 | 0 | HMAC_CTX hmac; |
79 | | |
80 | | /* Expand key material to desired length. */ |
81 | 0 | n = (out_len + digest_len - 1) / digest_len; |
82 | 0 | if (out_len + digest_len < out_len || n > 255) { |
83 | 0 | CRYPTOerror(EVP_R_TOO_LARGE); |
84 | 0 | return 0; |
85 | 0 | } |
86 | | |
87 | 0 | HMAC_CTX_init(&hmac); |
88 | 0 | if (!HMAC_Init_ex(&hmac, prk, prk_len, digest, NULL)) |
89 | 0 | goto out; |
90 | | |
91 | 0 | for (i = 0; i < n; i++) { |
92 | 0 | uint8_t ctr = i + 1; |
93 | 0 | size_t todo; |
94 | |
|
95 | 0 | if (i != 0 && (!HMAC_Init_ex(&hmac, NULL, 0, NULL, NULL) || |
96 | 0 | !HMAC_Update(&hmac, previous, digest_len))) |
97 | 0 | goto out; |
98 | | |
99 | 0 | if (!HMAC_Update(&hmac, info, info_len) || |
100 | 0 | !HMAC_Update(&hmac, &ctr, 1) || |
101 | 0 | !HMAC_Final(&hmac, previous, NULL)) |
102 | 0 | goto out; |
103 | | |
104 | 0 | todo = digest_len; |
105 | 0 | if (done + todo > out_len) |
106 | 0 | todo = out_len - done; |
107 | |
|
108 | 0 | memcpy(out_key + done, previous, todo); |
109 | 0 | done += todo; |
110 | 0 | } |
111 | | |
112 | 0 | ret = 1; |
113 | |
|
114 | 0 | out: |
115 | 0 | HMAC_CTX_cleanup(&hmac); |
116 | 0 | explicit_bzero(previous, sizeof(previous)); |
117 | 0 | if (ret != 1) |
118 | 0 | CRYPTOerror(ERR_R_CRYPTO_LIB); |
119 | 0 | return ret; |
120 | 0 | } |