/src/boringssl/crypto/fipsmodule/hkdf/hkdf.cc.inc
Line | Count | Source |
1 | | // Copyright 2014 The BoringSSL Authors |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
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 | | using namespace bssl; |
27 | | |
28 | | int HKDF(uint8_t *out_key, size_t out_len, const EVP_MD *digest, |
29 | | const uint8_t *secret, size_t secret_len, const uint8_t *salt, |
30 | 0 | size_t salt_len, const uint8_t *info, size_t info_len) { |
31 | | // https://tools.ietf.org/html/rfc5869#section-2 |
32 | 0 | uint8_t prk[EVP_MAX_MD_SIZE]; |
33 | 0 | size_t prk_len; |
34 | |
|
35 | 0 | if (!HKDF_extract(prk, &prk_len, digest, secret, secret_len, salt, |
36 | 0 | salt_len) || |
37 | 0 | !HKDF_expand(out_key, out_len, digest, prk, prk_len, info, info_len)) { |
38 | 0 | return 0; |
39 | 0 | } |
40 | | |
41 | 0 | return 1; |
42 | 0 | } |
43 | | |
44 | | int HKDF_extract(uint8_t *out_key, size_t *out_len, const EVP_MD *digest, |
45 | | const uint8_t *secret, size_t secret_len, const uint8_t *salt, |
46 | 18.4k | size_t salt_len) { |
47 | | // https://tools.ietf.org/html/rfc5869#section-2.2 |
48 | | |
49 | | // If salt is not given, HashLength zeros are used. However, HMAC does that |
50 | | // internally already so we can ignore it. |
51 | 18.4k | unsigned len; |
52 | 18.4k | if (HMAC(digest, salt, salt_len, secret, secret_len, out_key, &len) == |
53 | 18.4k | nullptr) { |
54 | 0 | OPENSSL_PUT_ERROR(HKDF, ERR_R_HMAC_LIB); |
55 | 0 | return 0; |
56 | 0 | } |
57 | 18.4k | *out_len = len; |
58 | 18.4k | assert(*out_len == EVP_MD_size(digest)); |
59 | 18.4k | return 1; |
60 | 18.4k | } |
61 | | |
62 | | int HKDF_expand(uint8_t *out_key, size_t out_len, const EVP_MD *digest, |
63 | | const uint8_t *prk, size_t prk_len, const uint8_t *info, |
64 | 249k | size_t info_len) { |
65 | | // https://tools.ietf.org/html/rfc5869#section-2.3 |
66 | 249k | const size_t digest_len = EVP_MD_size(digest); |
67 | 249k | uint8_t previous[EVP_MAX_MD_SIZE]; |
68 | 249k | size_t n, done = 0; |
69 | 249k | unsigned i; |
70 | 249k | int ret = 0; |
71 | 249k | HMAC_CTX hmac; |
72 | | |
73 | | // Expand key material to desired length. |
74 | 249k | n = (out_len + digest_len - 1) / digest_len; |
75 | 249k | if (out_len + digest_len < out_len || n > 255) { |
76 | 0 | OPENSSL_PUT_ERROR(HKDF, HKDF_R_OUTPUT_TOO_LARGE); |
77 | 0 | return 0; |
78 | 0 | } |
79 | | |
80 | 249k | HMAC_CTX_init(&hmac); |
81 | 249k | if (!HMAC_Init_ex(&hmac, prk, prk_len, digest, nullptr)) { |
82 | 0 | goto out; |
83 | 0 | } |
84 | | |
85 | 454k | for (i = 0; i < n; i++) { |
86 | 205k | uint8_t ctr = i + 1; |
87 | 205k | size_t todo; |
88 | | |
89 | 205k | if (i != 0 && (!HMAC_Init_ex(&hmac, nullptr, 0, nullptr, nullptr) || |
90 | 4 | !HMAC_Update(&hmac, previous, digest_len))) { |
91 | 0 | goto out; |
92 | 0 | } |
93 | 205k | if (!HMAC_Update(&hmac, info, info_len) || !HMAC_Update(&hmac, &ctr, 1) || |
94 | 205k | !HMAC_Final(&hmac, previous, nullptr)) { |
95 | 0 | goto out; |
96 | 0 | } |
97 | | |
98 | 205k | todo = digest_len; |
99 | 205k | if (todo > out_len - done) { |
100 | 94.2k | todo = out_len - done; |
101 | 94.2k | } |
102 | 205k | OPENSSL_memcpy(out_key + done, previous, todo); |
103 | 205k | done += todo; |
104 | 205k | } |
105 | | |
106 | 249k | ret = 1; |
107 | | |
108 | 249k | out: |
109 | 249k | HMAC_CTX_cleanup(&hmac); |
110 | 249k | if (ret != 1) { |
111 | 0 | OPENSSL_PUT_ERROR(HKDF, ERR_R_HMAC_LIB); |
112 | 0 | } |
113 | 249k | return ret; |
114 | 249k | } |