1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3 * SPDX-License-Identifier: MIT
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #include "internal_crypt_lib.h"
25
26 // RFC 5869 has some very non-intuitive points, reading it is advised
lkca_hkdf_expand_only(struct crypto_shash * alg,const uint8_t * prk,size_t prk_size,const uint8_t * info,size_t info_size,uint8_t * out,size_t out_size)27 static bool lkca_hkdf_expand_only(struct crypto_shash *alg,
28 const uint8_t *prk, size_t prk_size,
29 const uint8_t *info, size_t info_size,
30 uint8_t *out, size_t out_size)
31 {
32 #ifndef USE_LKCA
33 return false;
34 #else
35 int ret;
36 int i;
37 uint8_t ctr = 1;
38 uint8_t tmp[HASH_MAX_DIGESTSIZE];
39 SHASH_DESC_ON_STACK(desc, alg);
40 desc->tfm = alg;
41
42 ret = crypto_shash_setkey(desc->tfm, prk, prk_size);
43 if (ret != 0) {
44 pr_info("key size mismatch %ld\n", prk_size);
45 return false;
46 }
47
48 for (i = 0, ctr = 1; i < out_size; i += prk_size, ctr++) {
49 ret = crypto_shash_init(desc);
50 if (ret) {
51 return false;
52 }
53
54 if (i != 0) {
55 ret = crypto_shash_update(desc, out + i - prk_size, prk_size);
56 if (ret) {
57 return false;
58 }
59 }
60
61 if (info_size > 0) {
62 ret = crypto_shash_update(desc, info, info_size);
63 if (ret) {
64 return false;
65 }
66 }
67
68 ret = crypto_shash_update(desc, &ctr, 1);
69 if (ret)
70 return false;
71
72 if ((out_size - i) < prk_size) {
73 ret = crypto_shash_final(desc, tmp);
74 if (ret) {
75 return false;
76 }
77 memcpy(out + i, tmp, out_size - i);
78 memzero_explicit(tmp, sizeof(tmp));
79 } else {
80 ret = crypto_shash_final(desc, out + i);
81 if (ret) {
82 return false;
83 }
84 }
85 }
86
87 return true;
88 #endif
89 }
90
lkca_hkdf_extract_and_expand(const char * alg_name,const uint8_t * key,size_t key_size,const uint8_t * salt,size_t salt_size,const uint8_t * info,size_t info_size,uint8_t * out,size_t out_size)91 bool lkca_hkdf_extract_and_expand(const char *alg_name,
92 const uint8_t *key, size_t key_size,
93 const uint8_t *salt, size_t salt_size,
94 const uint8_t *info, size_t info_size,
95 uint8_t *out, size_t out_size)
96 {
97 #ifndef USE_LKCA
98 return false;
99 #else
100 int ret = 0;
101 struct crypto_shash *alg;
102 uint8_t prk[HASH_MAX_DIGESTSIZE];
103
104 if (key == NULL || salt == NULL || info == NULL || out == NULL ||
105 key_size > sizeof(prk) || salt_size > INT_MAX || info_size > INT_MAX ||
106 out_size > (sizeof(prk) * 255)) {
107 return false;
108 }
109
110 alg = crypto_alloc_shash(alg_name, 0, 0);
111 if (IS_ERR(alg)) {
112 return false;
113 }
114
115 ret = crypto_shash_setkey(alg, salt, salt_size);
116 if (ret != 0) {
117 goto out;
118 }
119 ret = crypto_shash_tfm_digest(alg, key, key_size, prk);
120 if (ret != 0) {
121 goto out;
122 }
123
124 ret = !lkca_hkdf_expand_only(alg, prk, crypto_shash_digestsize(alg), info, info_size, out, out_size);
125
126 out:
127 crypto_free_shash(alg);
128 return ret == 0;
129 #endif
130 }
131
lkca_hkdf_expand(const char * alg_name,const uint8_t * prk,size_t prk_size,const uint8_t * info,size_t info_size,uint8_t * out,size_t out_size)132 bool lkca_hkdf_expand(const char *alg_name,
133 const uint8_t *prk, size_t prk_size,
134 const uint8_t *info, size_t info_size,
135 uint8_t *out, size_t out_size)
136 {
137 #ifndef USE_LKCA
138 return false;
139 #else
140 bool ret = false;
141 struct crypto_shash *alg;
142
143 if (prk == NULL || info == NULL || out == NULL || prk_size > (512 / 8) ||
144 info_size > INT_MAX || (out_size > (prk_size * 255))) {
145 return false;
146 }
147
148 alg = crypto_alloc_shash(alg_name, 0, 0);
149 if (IS_ERR(alg)) {
150 return false;
151 }
152
153 ret = lkca_hkdf_expand_only(alg, prk, prk_size, info, info_size, out, out_size);
154
155 crypto_free_shash(alg);
156 return ret;
157 #endif
158 }
159