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