/src/boringssl/crypto/fipsmodule/hkdf/hkdf.c.inc
Line | Count | Source (jump to first uncovered line) |
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 | 73 | size_t salt_len, const uint8_t *info, size_t info_len) { |
29 | | // https://tools.ietf.org/html/rfc5869#section-2 |
30 | 73 | uint8_t prk[EVP_MAX_MD_SIZE]; |
31 | 73 | size_t prk_len; |
32 | | |
33 | 73 | if (!HKDF_extract(prk, &prk_len, digest, secret, secret_len, salt, |
34 | 73 | salt_len) || |
35 | 73 | !HKDF_expand(out_key, out_len, digest, prk, prk_len, info, info_len)) { |
36 | 14 | return 0; |
37 | 14 | } |
38 | | |
39 | 59 | return 1; |
40 | 73 | } |
41 | | |
42 | | int HKDF_extract(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 | 73 | 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 | 73 | unsigned len; |
50 | 73 | if (HMAC(digest, salt, salt_len, secret, secret_len, out_key, &len) == NULL) { |
51 | 0 | OPENSSL_PUT_ERROR(HKDF, ERR_R_HMAC_LIB); |
52 | 0 | return 0; |
53 | 0 | } |
54 | 73 | *out_len = len; |
55 | 73 | assert(*out_len == EVP_MD_size(digest)); |
56 | 73 | return 1; |
57 | 73 | } |
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 | 73 | size_t info_len) { |
62 | | // https://tools.ietf.org/html/rfc5869#section-2.3 |
63 | 73 | const size_t digest_len = EVP_MD_size(digest); |
64 | 73 | uint8_t previous[EVP_MAX_MD_SIZE]; |
65 | 73 | size_t n, done = 0; |
66 | 73 | unsigned i; |
67 | 73 | int ret = 0; |
68 | 73 | HMAC_CTX hmac; |
69 | | |
70 | | // Expand key material to desired length. |
71 | 73 | n = (out_len + digest_len - 1) / digest_len; |
72 | 73 | if (out_len + digest_len < out_len || n > 255) { |
73 | 14 | OPENSSL_PUT_ERROR(HKDF, HKDF_R_OUTPUT_TOO_LARGE); |
74 | 14 | return 0; |
75 | 14 | } |
76 | | |
77 | 59 | HMAC_CTX_init(&hmac); |
78 | 59 | if (!HMAC_Init_ex(&hmac, prk, prk_len, digest, NULL)) { |
79 | 0 | goto out; |
80 | 0 | } |
81 | | |
82 | 5.58k | for (i = 0; i < n; i++) { |
83 | 5.52k | uint8_t ctr = i + 1; |
84 | 5.52k | size_t todo; |
85 | | |
86 | 5.52k | if (i != 0 && (!HMAC_Init_ex(&hmac, NULL, 0, NULL, NULL) || |
87 | 5.46k | !HMAC_Update(&hmac, previous, digest_len))) { |
88 | 0 | goto out; |
89 | 0 | } |
90 | 5.52k | if (!HMAC_Update(&hmac, info, info_len) || |
91 | 5.52k | !HMAC_Update(&hmac, &ctr, 1) || |
92 | 5.52k | !HMAC_Final(&hmac, previous, NULL)) { |
93 | 0 | goto out; |
94 | 0 | } |
95 | | |
96 | 5.52k | todo = digest_len; |
97 | 5.52k | if (todo > out_len - done) { |
98 | 55 | todo = out_len - done; |
99 | 55 | } |
100 | 5.52k | OPENSSL_memcpy(out_key + done, previous, todo); |
101 | 5.52k | done += todo; |
102 | 5.52k | } |
103 | | |
104 | 59 | ret = 1; |
105 | | |
106 | 59 | out: |
107 | 59 | HMAC_CTX_cleanup(&hmac); |
108 | 59 | if (ret != 1) { |
109 | 0 | OPENSSL_PUT_ERROR(HKDF, ERR_R_HMAC_LIB); |
110 | 0 | } |
111 | 59 | return ret; |
112 | 59 | } |