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