]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/encrypt.c
libfrog: move path.h to libfrog/
[thirdparty/xfsprogs-dev.git] / io / encrypt.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2016 Google, Inc. All Rights Reserved.
4 * Author: Eric Biggers <ebiggers@google.com>
5 */
6
7 #include "platform_defs.h"
8 #include "command.h"
9 #include "init.h"
10 #include "libfrog/paths.h"
11 #include "io.h"
12
13 #ifndef ARRAY_SIZE
14 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
15 #endif
16
17 /*
18 * We may have to declare the fscrypt ioctls ourselves because someone may be
19 * compiling xfsprogs with old kernel headers. And since some old versions of
20 * <linux/fs.h> declared the policy struct and ioctl numbers but not the flags
21 * and modes, our declarations must be split into two conditional blocks.
22 */
23
24 /* Policy struct and ioctl numbers */
25 #ifndef FS_IOC_SET_ENCRYPTION_POLICY
26 #define FS_KEY_DESCRIPTOR_SIZE 8
27
28 struct fscrypt_policy {
29 __u8 version;
30 __u8 contents_encryption_mode;
31 __u8 filenames_encryption_mode;
32 __u8 flags;
33 __u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
34 } __attribute__((packed));
35
36 #define FS_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct fscrypt_policy)
37 #define FS_IOC_GET_ENCRYPTION_PWSALT _IOW('f', 20, __u8[16])
38 #define FS_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct fscrypt_policy)
39 #endif /* FS_IOC_SET_ENCRYPTION_POLICY */
40
41 /* Policy flags and encryption modes */
42 #ifndef FS_ENCRYPTION_MODE_AES_256_XTS
43 #define FS_POLICY_FLAGS_PAD_4 0x00
44 #define FS_POLICY_FLAGS_PAD_8 0x01
45 #define FS_POLICY_FLAGS_PAD_16 0x02
46 #define FS_POLICY_FLAGS_PAD_32 0x03
47 #define FS_POLICY_FLAGS_PAD_MASK 0x03
48 #define FS_POLICY_FLAGS_VALID 0x03
49
50 #define FS_ENCRYPTION_MODE_INVALID 0
51 #define FS_ENCRYPTION_MODE_AES_256_XTS 1
52 #define FS_ENCRYPTION_MODE_AES_256_GCM 2
53 #define FS_ENCRYPTION_MODE_AES_256_CBC 3
54 #define FS_ENCRYPTION_MODE_AES_256_CTS 4
55 #endif /* FS_ENCRYPTION_MODE_AES_256_XTS */
56
57 static cmdinfo_t get_encpolicy_cmd;
58 static cmdinfo_t set_encpolicy_cmd;
59
60 static void
61 set_encpolicy_help(void)
62 {
63 printf(_(
64 "\n"
65 " assign an encryption policy to the currently open file\n"
66 "\n"
67 " Examples:\n"
68 " 'set_encpolicy' - assign policy with default key [0000000000000000]\n"
69 " 'set_encpolicy 0000111122223333' - assign policy with specified key\n"
70 "\n"
71 " -c MODE -- contents encryption mode\n"
72 " -n MODE -- filenames encryption mode\n"
73 " -f FLAGS -- policy flags\n"
74 " -v VERSION -- version of policy structure\n"
75 "\n"
76 " MODE can be numeric or one of the following predefined values:\n"
77 " AES-256-XTS, AES-256-CTS, AES-256-GCM, AES-256-CBC\n"
78 " FLAGS and VERSION must be numeric.\n"
79 "\n"
80 " Note that it's only possible to set an encryption policy on an empty\n"
81 " directory. It's then inherited by new files and subdirectories.\n"
82 "\n"));
83 }
84
85 static const struct {
86 __u8 mode;
87 const char *name;
88 } available_modes[] = {
89 {FS_ENCRYPTION_MODE_AES_256_XTS, "AES-256-XTS"},
90 {FS_ENCRYPTION_MODE_AES_256_CTS, "AES-256-CTS"},
91 {FS_ENCRYPTION_MODE_AES_256_GCM, "AES-256-GCM"},
92 {FS_ENCRYPTION_MODE_AES_256_CBC, "AES-256-CBC"},
93 };
94
95 static bool
96 parse_byte_value(const char *arg, __u8 *value_ret)
97 {
98 long value;
99 char *tmp;
100
101 value = strtol(arg, &tmp, 0);
102 if (value < 0 || value > 255 || tmp == arg || *tmp != '\0')
103 return false;
104 *value_ret = value;
105 return true;
106 }
107
108 static bool
109 parse_mode(const char *arg, __u8 *mode_ret)
110 {
111 int i;
112
113 for (i = 0; i < ARRAY_SIZE(available_modes); i++) {
114 if (strcmp(arg, available_modes[i].name) == 0) {
115 *mode_ret = available_modes[i].mode;
116 return true;
117 }
118 }
119
120 return parse_byte_value(arg, mode_ret);
121 }
122
123 static const char *
124 mode2str(__u8 mode)
125 {
126 static char buf[32];
127 int i;
128
129 for (i = 0; i < ARRAY_SIZE(available_modes); i++)
130 if (mode == available_modes[i].mode)
131 return available_modes[i].name;
132
133 sprintf(buf, "0x%02x", mode);
134 return buf;
135 }
136
137 static const char *
138 keydesc2str(__u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE])
139 {
140 static char buf[2 * FS_KEY_DESCRIPTOR_SIZE + 1];
141 int i;
142
143 for (i = 0; i < FS_KEY_DESCRIPTOR_SIZE; i++)
144 sprintf(&buf[2 * i], "%02x", master_key_descriptor[i]);
145
146 return buf;
147 }
148
149 static int
150 get_encpolicy_f(int argc, char **argv)
151 {
152 struct fscrypt_policy policy;
153
154 if (ioctl(file->fd, FS_IOC_GET_ENCRYPTION_POLICY, &policy) < 0) {
155 fprintf(stderr, "%s: failed to get encryption policy: %s\n",
156 file->name, strerror(errno));
157 exitcode = 1;
158 return 0;
159 }
160
161 printf("Encryption policy for %s:\n", file->name);
162 printf("\tPolicy version: %u\n", policy.version);
163 printf("\tMaster key descriptor: %s\n",
164 keydesc2str(policy.master_key_descriptor));
165 printf("\tContents encryption mode: %u (%s)\n",
166 policy.contents_encryption_mode,
167 mode2str(policy.contents_encryption_mode));
168 printf("\tFilenames encryption mode: %u (%s)\n",
169 policy.filenames_encryption_mode,
170 mode2str(policy.filenames_encryption_mode));
171 printf("\tFlags: 0x%02x\n", policy.flags);
172 return 0;
173 }
174
175 static int
176 set_encpolicy_f(int argc, char **argv)
177 {
178 int c;
179 struct fscrypt_policy policy;
180
181 /* Initialize the policy structure with default values */
182 memset(&policy, 0, sizeof(policy));
183 policy.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
184 policy.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
185 policy.flags = FS_POLICY_FLAGS_PAD_16;
186
187 /* Parse options */
188 while ((c = getopt(argc, argv, "c:n:f:v:")) != EOF) {
189 switch (c) {
190 case 'c':
191 if (!parse_mode(optarg,
192 &policy.contents_encryption_mode)) {
193 fprintf(stderr, "invalid contents encryption "
194 "mode: %s\n", optarg);
195 return 0;
196 }
197 break;
198 case 'n':
199 if (!parse_mode(optarg,
200 &policy.filenames_encryption_mode)) {
201 fprintf(stderr, "invalid filenames encryption "
202 "mode: %s\n", optarg);
203 return 0;
204 }
205 break;
206 case 'f':
207 if (!parse_byte_value(optarg, &policy.flags)) {
208 fprintf(stderr, "invalid flags: %s\n", optarg);
209 return 0;
210 }
211 break;
212 case 'v':
213 if (!parse_byte_value(optarg, &policy.version)) {
214 fprintf(stderr, "invalid policy version: %s\n",
215 optarg);
216 return 0;
217 }
218 break;
219 default:
220 return command_usage(&set_encpolicy_cmd);
221 }
222 }
223 argc -= optind;
224 argv += optind;
225
226 if (argc > 1)
227 return command_usage(&set_encpolicy_cmd);
228
229 /* Parse key descriptor if specified */
230 if (argc > 0) {
231 const char *keydesc = argv[0];
232 char *tmp;
233 unsigned long long x;
234 int i;
235
236 if (strlen(keydesc) != FS_KEY_DESCRIPTOR_SIZE * 2) {
237 fprintf(stderr, "invalid key descriptor: %s\n",
238 keydesc);
239 return 0;
240 }
241
242 x = strtoull(keydesc, &tmp, 16);
243 if (tmp == keydesc || *tmp != '\0') {
244 fprintf(stderr, "invalid key descriptor: %s\n",
245 keydesc);
246 return 0;
247 }
248
249 for (i = 0; i < FS_KEY_DESCRIPTOR_SIZE; i++) {
250 policy.master_key_descriptor[i] = x >> 56;
251 x <<= 8;
252 }
253 }
254
255 /* Set the encryption policy */
256 if (ioctl(file->fd, FS_IOC_SET_ENCRYPTION_POLICY, &policy) < 0) {
257 fprintf(stderr, "%s: failed to set encryption policy: %s\n",
258 file->name, strerror(errno));
259 exitcode = 1;
260 return 0;
261 }
262
263 return 0;
264 }
265
266 void
267 encrypt_init(void)
268 {
269 get_encpolicy_cmd.name = "get_encpolicy";
270 get_encpolicy_cmd.cfunc = get_encpolicy_f;
271 get_encpolicy_cmd.argmin = 0;
272 get_encpolicy_cmd.argmax = 0;
273 get_encpolicy_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
274 get_encpolicy_cmd.oneline =
275 _("display the encryption policy of the current file");
276
277 set_encpolicy_cmd.name = "set_encpolicy";
278 set_encpolicy_cmd.cfunc = set_encpolicy_f;
279 set_encpolicy_cmd.args =
280 _("[-c mode] [-n mode] [-f flags] [-v version] [keydesc]");
281 set_encpolicy_cmd.argmin = 0;
282 set_encpolicy_cmd.argmax = -1;
283 set_encpolicy_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
284 set_encpolicy_cmd.oneline =
285 _("assign an encryption policy to the current file");
286 set_encpolicy_cmd.help = set_encpolicy_help;
287
288 add_command(&get_encpolicy_cmd);
289 add_command(&set_encpolicy_cmd);
290 }