Makefile: Add security compiling option (RELRO, SC, and FORTIFY)
[platform/upstream/cryptsetup.git] / lib / luks2 / luks2_digest_pbkdf2.c
1 /*
2  * LUKS - Linux Unified Key Setup v2, PBKDF2 digest handler (LUKS1 compatible)
3  *
4  * Copyright (C) 2015-2023 Red Hat, Inc. All rights reserved.
5  * Copyright (C) 2015-2023 Milan Broz
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "luks2_internal.h"
23
24 #define LUKS_DIGESTSIZE 20 // since SHA1
25 #define LUKS_SALTSIZE 32
26 #define LUKS_MKD_ITERATIONS_MS 125
27
28 static int PBKDF2_digest_verify(struct crypt_device *cd,
29         int digest,
30         const char *volume_key,
31         size_t volume_key_len)
32 {
33         char checkHashBuf[64];
34         json_object *jobj_digest, *jobj1;
35         const char *hashSpec;
36         char *mkDigest = NULL, *mkDigestSalt = NULL;
37         unsigned int mkDigestIterations;
38         size_t len;
39         int r = -EINVAL;
40
41         /* This can be done only for internally linked digests */
42         jobj_digest = LUKS2_get_digest_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), digest);
43         if (!jobj_digest)
44                 return -EINVAL;
45
46         if (!json_object_object_get_ex(jobj_digest, "hash", &jobj1))
47                 return -EINVAL;
48         hashSpec = json_object_get_string(jobj1);
49
50         if (!json_object_object_get_ex(jobj_digest, "iterations", &jobj1))
51                 return -EINVAL;
52         mkDigestIterations = json_object_get_int64(jobj1);
53
54         if (!json_object_object_get_ex(jobj_digest, "salt", &jobj1))
55                 return -EINVAL;
56         r = crypt_base64_decode(&mkDigestSalt, &len, json_object_get_string(jobj1),
57                                 json_object_get_string_len(jobj1));
58         if (r < 0)
59                 goto out;
60         if (len != LUKS_SALTSIZE)
61                 goto out;
62
63         if (!json_object_object_get_ex(jobj_digest, "digest", &jobj1))
64                 goto out;
65         r = crypt_base64_decode(&mkDigest, &len, json_object_get_string(jobj1),
66                                 json_object_get_string_len(jobj1));
67         if (r < 0)
68                 goto out;
69         if (len < LUKS_DIGESTSIZE ||
70             len > sizeof(checkHashBuf) ||
71             (len != LUKS_DIGESTSIZE && len != (size_t)crypt_hash_size(hashSpec)))
72                 goto out;
73
74         r = -EPERM;
75         if (crypt_pbkdf(CRYPT_KDF_PBKDF2, hashSpec, volume_key, volume_key_len,
76                         mkDigestSalt, LUKS_SALTSIZE,
77                         checkHashBuf, len,
78                         mkDigestIterations, 0, 0) < 0) {
79                 r = -EINVAL;
80         } else {
81                 if (crypt_backend_memeq(checkHashBuf, mkDigest, len) == 0)
82                         r = 0;
83         }
84 out:
85         free(mkDigest);
86         free(mkDigestSalt);
87         return r;
88 }
89
90 static int PBKDF2_digest_store(struct crypt_device *cd,
91         int digest,
92         const char *volume_key,
93         size_t volume_key_len)
94 {
95         json_object *jobj_digest, *jobj_digests;
96         char salt[LUKS_SALTSIZE], digest_raw[128];
97         int hmac_size, r;
98         char *base64_str;
99         struct luks2_hdr *hdr;
100         struct crypt_pbkdf_limits pbkdf_limits;
101         const struct crypt_pbkdf_type *pbkdf_cd;
102         struct crypt_pbkdf_type pbkdf = {
103                 .type = CRYPT_KDF_PBKDF2,
104                 .time_ms = LUKS_MKD_ITERATIONS_MS,
105         };
106
107         /* Inherit hash from PBKDF setting */
108         pbkdf_cd = crypt_get_pbkdf_type(cd);
109         if (pbkdf_cd)
110                 pbkdf.hash = pbkdf_cd->hash;
111         if (!pbkdf.hash)
112                 pbkdf.hash = DEFAULT_LUKS1_HASH;
113
114         log_dbg(cd, "Setting PBKDF2 type key digest %d.", digest);
115
116         r = crypt_random_get(cd, salt, LUKS_SALTSIZE, CRYPT_RND_SALT);
117         if (r < 0)
118                 return r;
119
120         r = crypt_pbkdf_get_limits(CRYPT_KDF_PBKDF2, &pbkdf_limits);
121         if (r < 0)
122                 return r;
123
124         if (crypt_get_pbkdf(cd)->flags & CRYPT_PBKDF_NO_BENCHMARK)
125                 pbkdf.iterations = pbkdf_limits.min_iterations;
126         else {
127                 r = crypt_benchmark_pbkdf_internal(cd, &pbkdf, volume_key_len);
128                 if (r < 0)
129                         return r;
130         }
131
132         hmac_size = crypt_hmac_size(pbkdf.hash);
133         if (hmac_size < 0 || hmac_size > (int)sizeof(digest_raw))
134                 return -EINVAL;
135
136         r = crypt_pbkdf(CRYPT_KDF_PBKDF2, pbkdf.hash, volume_key, volume_key_len,
137                         salt, LUKS_SALTSIZE, digest_raw, hmac_size,
138                         pbkdf.iterations, 0, 0);
139         if (r < 0)
140                 return r;
141
142         jobj_digest = LUKS2_get_digest_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), digest);
143         jobj_digests = NULL;
144         if (!jobj_digest) {
145                 hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
146                 jobj_digest = json_object_new_object();
147                 json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
148         }
149
150         json_object_object_add(jobj_digest, "type", json_object_new_string("pbkdf2"));
151         json_object_object_add(jobj_digest, "keyslots", json_object_new_array());
152         json_object_object_add(jobj_digest, "segments", json_object_new_array());
153         json_object_object_add(jobj_digest, "hash", json_object_new_string(pbkdf.hash));
154         json_object_object_add(jobj_digest, "iterations", json_object_new_int(pbkdf.iterations));
155
156         r = crypt_base64_encode(&base64_str, NULL, salt, LUKS_SALTSIZE);
157         if (r < 0) {
158                 json_object_put(jobj_digest);
159                 return r;
160         }
161         json_object_object_add(jobj_digest, "salt", json_object_new_string(base64_str));
162         free(base64_str);
163
164         r = crypt_base64_encode(&base64_str, NULL, digest_raw, hmac_size);
165         if (r < 0) {
166                 json_object_put(jobj_digest);
167                 return r;
168         }
169         json_object_object_add(jobj_digest, "digest", json_object_new_string(base64_str));
170         free(base64_str);
171
172         if (jobj_digests)
173                 json_object_object_add_by_uint(jobj_digests, digest, jobj_digest);
174
175         JSON_DBG(cd, jobj_digest, "Digest JSON:");
176         return 0;
177 }
178
179 static int PBKDF2_digest_dump(struct crypt_device *cd, int digest)
180 {
181         json_object *jobj_digest, *jobj1;
182
183         /* This can be done only for internally linked digests */
184         jobj_digest = LUKS2_get_digest_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), digest);
185         if (!jobj_digest)
186                 return -EINVAL;
187
188         json_object_object_get_ex(jobj_digest, "hash", &jobj1);
189         log_std(cd, "\tHash:       %s\n", json_object_get_string(jobj1));
190
191         json_object_object_get_ex(jobj_digest, "iterations", &jobj1);
192         log_std(cd, "\tIterations: %" PRIu64 "\n", json_object_get_int64(jobj1));
193
194         json_object_object_get_ex(jobj_digest, "salt", &jobj1);
195         log_std(cd, "\tSalt:       ");
196         hexprint_base64(cd, jobj1, " ", "            ");
197
198         json_object_object_get_ex(jobj_digest, "digest", &jobj1);
199         log_std(cd, "\tDigest:     ");
200         hexprint_base64(cd, jobj1, " ", "            ");
201
202         return 0;
203 }
204
205 const digest_handler PBKDF2_digest = {
206         .name   = "pbkdf2",
207         .verify = PBKDF2_digest_verify,
208         .store  = PBKDF2_digest_store,
209         .dump   = PBKDF2_digest_dump,
210 };