Merge lp:~wlxing/ecryptfs/lp342398 into lp:ecryptfs

Proposed by Jason Xing
Status: Needs review
Proposed branch: lp:~wlxing/ecryptfs/lp342398
Merge into: lp:ecryptfs
Diff against target: 449 lines (+354/-1)
4 files modified
debian/changelog (+2/-0)
src/include/ecryptfs.h (+20/-0)
src/libecryptfs/ecryptfs-stat.c (+322/-1)
src/utils/ecryptfs-stat.c (+10/-0)
To merge this branch: bzr merge lp:~wlxing/ecryptfs/lp342398
Reviewer Review Type Date Requested Status
Colin Ian King Pending
Tyler Hicks Pending
Review via email: mp+325438@code.launchpad.net

Description of the change

Add ecryptfs-stat support for encrypted filenames (LP: #342398). The main process has three parts: decoding filename, parsing filename and printing information.
Test output samples:
Case 1):
[...]
Filename encryption enabled
FNEK sig is [8f9887d2339cafb0]
Filename encrytion cipher is [aes]
Case 2):
[...]
Filename encryption disabled
Case 3):
[...]
Filename encryption enabled
ecryptfs_parse_tag_70_packet: max_packet_size is [42]; real packet size is [35]
ecryptfs_parse_filename: Could not parse tag 70 packet from filename

To post a comment you must log in.

Unmerged revisions

895. By Jason Xing

src/utils/ecryptfs-stat.c, src/libecryptfs/ecryptfs-stat.c, src/include/ecryptfs.h: Add ecryptfs-stat support for encrypted filenames (LP: #342398)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2017-06-08 23:29:22 +0000
3+++ debian/changelog 2017-06-10 01:37:57 +0000
4@@ -36,6 +36,8 @@
5 users that even though the mount was successful, their data may not be
6 decrypted when a mount passphrase was used for recovery
7 (LP: #1694272, LP: #1439825)
8+ * src/utils/ecryptfs-stat.c, src/libecryptfs/ecryptfs-stat.c, src/include/ecryptfs.h:
9+ Add ecryptfs-stat support for encrypted filenames. (LP: #342398)
10
11 [ Jelle van der Waa ]
12 * src/key_mod/ecryptfs_key_mod_openssl.c,
13
14=== modified file 'src/include/ecryptfs.h'
15--- src/include/ecryptfs.h 2015-02-14 22:11:29 +0000
16+++ src/include/ecryptfs.h 2017-06-10 01:37:57 +0000
17@@ -94,6 +94,7 @@
18 #define MAGIC_ECRYPTFS_MARKER 0x3c81b7f5
19 #define MAGIC_ECRYPTFS_MARKER_SIZE_BYTES 8 /* 4*2 */
20 #endif
21+#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32
22 #define MAX_NAME_SIZE 128
23 #define MAX_KEY_MOD_VALUE_SIZE 4096
24 #define ECRYPTFS_TAG_1_PACKET_TYPE 0x01
25@@ -103,6 +104,7 @@
26 #define ECRYPTFS_TAG_65_PACKET_TYPE 0x41
27 #define ECRYPTFS_TAG_66_PACKET_TYPE 0x42
28 #define ECRYPTFS_TAG_67_PACKET_TYPE 0x43
29+#define ECRYPTFS_TAG_70_PACKET_TYPE 0x46
30 #define ECRYPTFS_MSG_HELO 100
31 #define ECRYPTFS_MSG_QUIT 101
32 #define ECRYPTFS_MSG_REQUEST 102
33@@ -143,6 +145,21 @@
34 #define ECRYPTFS_ECHO_ON 1
35 #define ECRYPTFS_ECHO_OFF 0
36
37+#define ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX "ECRYPTFS_FNEK_ENCRYPTED."
38+#define ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE 24
39+#define ECRYPTFS_MIN_PKT_LEN_SIZE 1
40+#define ECRYPTFS_TAG_70_MIN_METADATA_SIZE (1 + ECRYPTFS_MIN_PKT_LEN_SIZE \
41+ + ECRYPTFS_SIG_SIZE + 1 + 1)
42+
43+#define RFC2440_CIPHER_DES3_EDE 0x02
44+#define RFC2440_CIPHER_CAST_5 0x03
45+#define RFC2440_CIPHER_BLOWFISH 0x04
46+#define RFC2440_CIPHER_AES_128 0x07
47+#define RFC2440_CIPHER_AES_192 0x08
48+#define RFC2440_CIPHER_AES_256 0x09
49+#define RFC2440_CIPHER_TWOFISH 0x0a
50+#define RFC2440_CIPHER_CAST_6 0x0b
51+
52 #define ECRYPTFS_AES_BLOCK_SIZE 16
53 #define ECRYPTFS_AES_KEY_BYTES 16
54
55@@ -437,6 +454,7 @@
56 #define ECRYPTFS_METADATA_IN_XATTR 0x00000100
57 #define ECRYPTFS_VIEW_AS_ENCRYPTED 0x00000200
58 #define ECRYPTFS_KEY_SET 0x00000400
59+#define ECRYPTFS_ENCRYPT_FILENAMES 0x00000800
60 uint32_t flags;
61 unsigned int file_version;
62 uint64_t file_size;
63@@ -580,4 +598,6 @@
64 char *ecryptfs_fetch_private_mnt(char *pw_dir);
65 int ecryptfs_private_is_mounted(char *dev, char *mnt, char *sig, int mounting);
66
67+int ecryptfs_parse_filename(const char *path, size_t path_len);
68+
69 #endif
70
71=== modified file 'src/libecryptfs/ecryptfs-stat.c'
72--- src/libecryptfs/ecryptfs-stat.c 2013-10-27 22:21:20 +0000
73+++ src/libecryptfs/ecryptfs-stat.c 2017-06-10 01:37:57 +0000
74@@ -65,7 +65,8 @@
75 static struct ecryptfs_flag_map_elem ecryptfs_flag_map[] = {
76 {0x00000001, ECRYPTFS_ENABLE_HMAC},
77 {0x00000002, ECRYPTFS_ENCRYPTED},
78- {0x00000004, ECRYPTFS_METADATA_IN_XATTR}
79+ {0x00000004, ECRYPTFS_METADATA_IN_XATTR},
80+ {0x00000008, ECRYPTFS_ENCRYPT_FILENAMES}
81 };
82
83 /**
84@@ -186,3 +187,323 @@
85 out:
86 return rc;
87 }
88+
89+/* We could either offset on every reverse map or just pad some 0x00's
90+ * at the front here */
91+static const unsigned char filename_rev_map[256] = {
92+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 7 */
93+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 15 */
94+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 23 */
95+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 31 */
96+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 39 */
97+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, /* 47 */
98+ 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, /* 55 */
99+ 0x0A, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 63 */
100+ 0x00, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, /* 71 */
101+ 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, /* 79 */
102+ 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, /* 87 */
103+ 0x23, 0x24, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, /* 95 */
104+ 0x00, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, /* 103 */
105+ 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, /* 111 */
106+ 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, /* 119 */
107+ 0x3D, 0x3E, 0x3F /* 123 - 255 initialized to 0x00 */
108+};
109+
110+static size_t ecryptfs_max_decoded_size(size_t encoded_size)
111+{
112+ /* Not exact; conservatively long. Every block of 4
113+ * encoded characters decodes into a block of 3
114+ * decoded characters. This segment of code provides
115+ * the caller with the maximum amount of allocated
116+ * space that @dst will need to point to in a
117+ * subsequent call. */
118+ return ((encoded_size + 1) * 3) / 4;
119+}
120+
121+/**
122+ * ecryptfs_decode_from_filename
123+ * @dst: If NULL, this function only sets @dst_size and returns. If
124+ * non-NULL, this function decodes the encoded octets in @src
125+ * into the memory that @dst points to.
126+ * @dst_size: Set to the size of the decoded string.
127+ * @src: The encoded set of octets to decode.
128+ * @src_size: The size of the encoded set of octets to decode.
129+ */
130+static void
131+ecryptfs_decode_from_filename(unsigned char *dst, size_t *dst_size,
132+ const unsigned char *src, size_t src_size)
133+{
134+ unsigned char current_bit_offset = 0;
135+ size_t src_byte_offset = 0;
136+ size_t dst_byte_offset = 0;
137+
138+ if (dst == NULL) {
139+ (*dst_size) = ecryptfs_max_decoded_size(src_size);
140+ goto out;
141+ }
142+ while (src_byte_offset < src_size) {
143+ unsigned char src_byte =
144+ filename_rev_map[(int)src[src_byte_offset]];
145+
146+ switch (current_bit_offset) {
147+ case 0:
148+ dst[dst_byte_offset] = (src_byte << 2);
149+ current_bit_offset = 6;
150+ break;
151+ case 6:
152+ dst[dst_byte_offset++] |= (src_byte >> 4);
153+ dst[dst_byte_offset] = ((src_byte & 0xF)
154+ << 4);
155+ current_bit_offset = 4;
156+ break;
157+ case 4:
158+ dst[dst_byte_offset++] |= (src_byte >> 2);
159+ dst[dst_byte_offset] = (src_byte << 6);
160+ current_bit_offset = 2;
161+ break;
162+ case 2:
163+ dst[dst_byte_offset++] |= (src_byte);
164+ dst[dst_byte_offset] = 0;
165+ current_bit_offset = 0;
166+ break;
167+ }
168+ src_byte_offset++;
169+ }
170+ (*dst_size) = dst_byte_offset;
171+out:
172+ return;
173+}
174+
175+static int ecryptfs_decode_filename(const char *name, size_t name_size,
176+ char **decoded_name, size_t *decoded_name_size)
177+{
178+ int rc = 0;
179+
180+ if ((name_size > ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE)
181+ && (strncmp(name, ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX,
182+ ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE) == 0)) {
183+ name += ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE;
184+ name_size -= ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE;
185+ ecryptfs_decode_from_filename(NULL, decoded_name_size,
186+ name, name_size);
187+ (*decoded_name) = (char *)malloc(*decoded_name_size);
188+ if (!(*decoded_name)) {
189+ printf("%s: Out of memory whilst attempting "
190+ "to malloc [%zd] bytes\n", __func__,
191+ *decoded_name_size);
192+ rc = -ENOMEM;
193+ goto out;
194+ }
195+ ecryptfs_decode_from_filename(*decoded_name, decoded_name_size,
196+ name, name_size);
197+ } else {
198+ rc = -EINVAL;
199+ }
200+out:
201+ return rc;
202+}
203+
204+struct ecryptfs_parse_tag_70_packet_stack {
205+ unsigned char cipher_code;
206+ size_t max_packet_size;
207+ size_t packet_size_len;
208+ size_t parsed_tag_70_packet_size;
209+ size_t block_aligned_filename_size;
210+ char fnek_sig_hex[ECRYPTFS_SIG_SIZE_HEX + 1];
211+ char cipher_string[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
212+};
213+
214+struct ecryptfs_cipher_code_str_map_elem {
215+ char cipher_str[16];
216+ unsigned char cipher_code;
217+};
218+
219+/* For now eCryptfs doesn't support public-key type for
220+ * filename encrytion/decrption*/
221+static struct ecryptfs_cipher_code_str_map_elem
222+ecryptfs_cipher_code_str_map[] = {
223+ {"aes",RFC2440_CIPHER_AES_128 },
224+ {"blowfish", RFC2440_CIPHER_BLOWFISH},
225+ {"des3_ede", RFC2440_CIPHER_DES3_EDE},
226+ {"cast5", RFC2440_CIPHER_CAST_5},
227+ {"twofish", RFC2440_CIPHER_TWOFISH},
228+ {"cast6", RFC2440_CIPHER_CAST_6},
229+ {"aes", RFC2440_CIPHER_AES_192},
230+ {"aes", RFC2440_CIPHER_AES_256}
231+};
232+
233+/**
234+ * ecryptfs_cipher_code_to_string
235+ * @str: Destination to write out the cipher name
236+ * @cipher_code: The code to convert to cipher name string
237+ *
238+ * Returns zero on success
239+ */
240+static int ecryptfs_cipher_code_to_string(char *str, unsigned char cipher_code)
241+{
242+ int rc = 0;
243+ int i;
244+
245+ str[0] = '\0';
246+ for (i = 0; i < (sizeof(ecryptfs_cipher_code_str_map) / sizeof(ecryptfs_cipher_code_str_map[0])); i++)
247+ if (cipher_code == ecryptfs_cipher_code_str_map[i].cipher_code)
248+ strcpy(str, ecryptfs_cipher_code_str_map[i].cipher_str);
249+ if (str[0] == '\0') {
250+ printf("Cipher code not recognized: [%d]\n", cipher_code);
251+ rc = -EINVAL;
252+ }
253+ return rc;
254+}
255+
256+/**
257+ * ecryptfs_to_hex
258+ * @dst: Buffer to take hex character representation of contents of
259+ * src; must be at least of size (src_size * 2)
260+ * @src: Buffer to be converted to a hex string respresentation
261+ * @src_size: number of bytes to convert
262+ */
263+static void ecryptfs_to_hex(char *dst, char *src, size_t src_size)
264+{
265+ int x;
266+
267+ for (x = 0; x < src_size; x++)
268+ sprintf(&dst[x * 2], "%.2x", (unsigned char)src[x]);
269+}
270+
271+/**
272+ * parse_tag_70_packet - Parse and process FNEK-encrypted passphrase packet
273+ * Tag 70 packet format:
274+ * Octet 0: Tag 70 identifier
275+ * Octets 1-N1: Tag 70 packet size (includes cipher identifier
276+ * and block-aligned encrypted filename size)
277+ * Octets N1-N2: FNEK sig (ECRYPTFS_SIG_SIZE)
278+ * Octet N2-N3: Cipher identifier (1 octet)
279+ * Octets N3-N4: Block-aligned encrypted filename
280+ *
281+ * @s: Parse tag 70 packet into this structure and print its members one by
282+ * one later
283+ * @packet_size: This function sets this to the the number of octets
284+ * in the packet parsed
285+ * @data: The memory location containing the start of the tag 70
286+ * packet
287+ * @max_packet_size: The maximum legal size of the packet to be parsed
288+ * from @data
289+ *
290+ * Returns zero on success; non-zero otherwise
291+ */
292+static int ecryptfs_parse_tag_70_packet(struct ecryptfs_parse_tag_70_packet_stack **s, size_t *packet_size,
293+ char *data, size_t max_packet_size)
294+{
295+ int rc = 0;
296+
297+ (*packet_size) = 0;
298+ *s = (struct ecryptfs_parse_tag_70_packet_stack *)malloc(sizeof(**s));
299+ if (!(*s)) {
300+ printf("%s: Out of memory whilst trying to malloc "
301+ "[%zd] bytes of memory\n", __func__, sizeof(**s));
302+ rc = -ENOMEM;
303+ goto out;
304+ }
305+ if (max_packet_size < ECRYPTFS_TAG_70_MIN_METADATA_SIZE) {
306+ printf("%s: max_packet_size is [%zd]; it must be "
307+ "at least [%d]\n", __func__, max_packet_size,
308+ ECRYPTFS_TAG_70_MIN_METADATA_SIZE);
309+ rc = -EINVAL;
310+ goto out;
311+ }
312+ /* Tag 70 identifier */
313+ if (data[(*packet_size)++] != ECRYPTFS_TAG_70_PACKET_TYPE) {
314+ printf("%s: Invalid packet tag [0x%.2x]; must be "
315+ "tag [0x%.2x]\n", __func__,
316+ data[((*packet_size) - 1)], ECRYPTFS_TAG_70_PACKET_TYPE);
317+ rc = -EINVAL;
318+ goto out;
319+ }
320+ /* Tag 70 packet size */
321+ rc = ecryptfs_parse_packet_length(&data[(*packet_size)],
322+ &(*s)->parsed_tag_70_packet_size,
323+ &(*s)->packet_size_len);
324+ if (rc) {
325+ printf("%s: Error parsing packet length; "
326+ "rc = [%d]\n", __func__, rc);
327+ goto out;
328+ }
329+ (*s)->block_aligned_filename_size = ((*s)->parsed_tag_70_packet_size
330+ - ECRYPTFS_SIG_SIZE - 1);
331+ if ((1 + (*s)->packet_size_len + (*s)->parsed_tag_70_packet_size)
332+ > max_packet_size) {
333+ printf("%s: max_packet_size is [%zd]; real packet "
334+ "size is [%zd]\n", __func__, max_packet_size,
335+ (1 + (*s)->packet_size_len + 1
336+ + (*s)->block_aligned_filename_size));
337+ rc = -EINVAL;
338+ goto out;
339+ }
340+ (*packet_size) += (*s)->packet_size_len;
341+ /* FNEK sig */
342+ ecryptfs_to_hex((*s)->fnek_sig_hex, &data[(*packet_size)],
343+ ECRYPTFS_SIG_SIZE);
344+ (*s)->fnek_sig_hex[ECRYPTFS_SIG_SIZE_HEX] = '\0';
345+ (*packet_size) += ECRYPTFS_SIG_SIZE;
346+ /* Cipher identifier */
347+ (*s)->cipher_code = data[(*packet_size)++];
348+ rc = ecryptfs_cipher_code_to_string((*s)->cipher_string, (*s)->cipher_code);
349+ if (rc) {
350+ printf("%s: Cipher code [%d] is invalid\n",
351+ __func__, (*s)->cipher_code);
352+ goto out;
353+ }
354+out:
355+ return rc;
356+}
357+
358+static void ecryptfs_print_stack(struct ecryptfs_parse_tag_70_packet_stack *s)
359+{
360+ printf("FNEK sig is [%s]\n", s->fnek_sig_hex);
361+ printf("Filename encrytion cipher is [%s]\n", s->cipher_string);
362+ return;
363+}
364+
365+/*
366+ * find filename portion of a path (/foo/bar -> baz)
367+ */
368+static char *ecryptfs_get_filename(const char *s, int len)
369+{
370+ const char *e = s + len;
371+
372+ while (e != s && *(e-1) != '/')
373+ e--;
374+ return (char *)e;
375+}
376+
377+int ecryptfs_parse_filename(const char *path, size_t path_len)
378+{
379+ const char *name;
380+ char *decoded_name = NULL;
381+ struct ecryptfs_parse_tag_70_packet_stack *s = NULL;
382+ size_t name_size, decoded_name_size, packet_size;
383+ int rc = 0;
384+
385+ name = ecryptfs_get_filename(path, path_len);
386+ name_size = strlen(name);
387+ rc = ecryptfs_decode_filename(name, name_size,
388+ &decoded_name, &decoded_name_size);
389+ if (rc) {
390+ printf("%s: Could not decode filename\n", __func__);
391+ goto out;
392+ }
393+ rc = ecryptfs_parse_tag_70_packet(&s,
394+ &packet_size,
395+ decoded_name,
396+ decoded_name_size);
397+ if (rc) {
398+ goto out;
399+ }
400+ ecryptfs_print_stack(s);
401+out:
402+ if (s)
403+ free(s);
404+ if (decoded_name)
405+ free(decoded_name);
406+ return rc;
407+}
408
409=== modified file 'src/utils/ecryptfs-stat.c'
410--- src/utils/ecryptfs-stat.c 2009-02-03 08:50:36 +0000
411+++ src/utils/ecryptfs-stat.c 2017-06-10 01:37:57 +0000
412@@ -3,6 +3,7 @@
413 */
414
415 #include <stdio.h>
416+#include <string.h>
417 #include <fcntl.h>
418 #include <unistd.h>
419 #include <errno.h>
420@@ -19,6 +20,7 @@
421 int main(int argc, const char *argv[])
422 {
423 const char *filename;
424+ size_t filename_size;
425 int fd = -1;
426 ssize_t quant_read;
427 struct ecryptfs_crypt_stat_user crypt_stat;
428@@ -30,6 +32,7 @@
429 goto out;
430 }
431 filename = argv[1];
432+ filename_size = strlen(filename);
433 fd = open(filename, O_RDONLY);
434 if (fd == -1) {
435 printf("Error opening file [%s] for RD_ONLY access; errno msg "
436@@ -68,6 +71,13 @@
437 printf("HMAC enabled\n");
438 else
439 printf("HMAC disabled\n");
440+ if (crypt_stat.flags & ECRYPTFS_ENCRYPT_FILENAMES) {
441+ printf("Filename encryption enabled\n");
442+ rc = ecryptfs_parse_filename(filename, filename_size);
443+ }
444+ else
445+ printf("Filename encryption disabled\n");
446+
447 out:
448 if (fd != -1)
449 close(fd);

Subscribers

People subscribed via source and target branches