1
2 /* Dump the binary encrypted format of a keyring
3
4 Build like this:
5
6 $ gcc -o dump-keyring0-format $(pkg-config --cflags --libs glib-2.0) \
7 -lgcrypt dump-keyring0-format.c
8
9 Copyright (C) 2003 Red Hat, Inc
10 Copyright (C) 2007, 2009 Stefan Walter
11 Copyright (C) 2013 Red Hat, Inc
12
13 Gnome keyring is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 Gnome keyring is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26
27 Author: Alexander Larsson <alexl@redhat.com>
28 Author: Stef Walter <stef@memberwebs.com>
29 */
30
31 #include <glib.h>
32
33 #include <gcrypt.h>
34
35 #include <sys/types.h>
36 #include <sys/stat.h>
37
38 #include <ctype.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <unistd.h>
45
46 enum {
47 LOCK_ON_IDLE_FLAG = 1 << 0,
48 LOCK_AFTER_FLAG = 1 << 1
49 };
50
51 enum {
52 ACCESS_READ = 1 << 0,
53 ACCESS_WRITE = 1 << 1,
54 ACCESS_REMOVE = 1 << 2
55 };
56
57 #define KEYRING_FILE_HEADER "GnomeKeyring\n\r\0\n"
58 #define KEYRING_FILE_HEADER_LEN 16
59
60 typedef gpointer (* BufferAllocator) (gpointer, gsize);
61
62 #define DEFAULT_ALLOCATOR ((BufferAllocator)realloc)
63
64 typedef struct _Buffer {
65 unsigned char *buf;
66 gsize len;
67 gsize allocated_len;
68 int failures;
69 BufferAllocator allocator;
70 } Buffer;
71
72 #define BUFFER_EMPTY { NULL, 0, 0, 0, NULL }
73
74 static gint
buffer_init_full(Buffer * buffer,gsize reserve,BufferAllocator allocator)75 buffer_init_full (Buffer *buffer,
76 gsize reserve,
77 BufferAllocator allocator)
78 {
79 memset (buffer, 0, sizeof (*buffer));
80
81 if (!allocator)
82 allocator = DEFAULT_ALLOCATOR;
83 if (reserve == 0)
84 reserve = 64;
85
86 buffer->buf = (allocator) (NULL, reserve);
87 if (!buffer->buf) {
88 buffer->failures++;
89 return 0;
90 }
91
92 buffer->len = 0;
93 buffer->allocated_len = reserve;
94 buffer->failures = 0;
95 buffer->allocator = allocator;
96
97 return 1;
98 }
99
100 static gint
buffer_init(Buffer * buffer,gsize reserve)101 buffer_init (Buffer *buffer,
102 gsize reserve)
103 {
104 return buffer_init_full (buffer, reserve, NULL);
105 }
106
107
108 static void
buffer_init_static(Buffer * buffer,const guchar * buf,gsize len)109 buffer_init_static (Buffer* buffer,
110 const guchar *buf,
111 gsize len)
112 {
113 memset (buffer, 0, sizeof (*buffer));
114
115 buffer->buf = (unsigned char*)buf;
116 buffer->len = len;
117 buffer->allocated_len = len;
118 buffer->failures = 0;
119
120 /* A null allocator, and the buffer can't change in size */
121 buffer->allocator = NULL;
122 }
123
124 static void
buffer_uninit(Buffer * buffer)125 buffer_uninit (Buffer *buffer)
126 {
127 if (!buffer)
128 return;
129
130 /*
131 * Free the memory block using allocator. If no allocator,
132 * then this memory is ownerd elsewhere and not to be freed.
133 */
134 if (buffer->buf && buffer->allocator)
135 (buffer->allocator) (buffer->buf, 0);
136
137 memset (buffer, 0, sizeof (*buffer));
138 }
139
140 static guint32
buffer_decode_uint32(guchar * ptr)141 buffer_decode_uint32 (guchar* ptr)
142 {
143 guint32 val = ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
144 return val;
145 }
146
147 static int
buffer_get_uint32(Buffer * buffer,gsize offset,gsize * next_offset,guint32 * val)148 buffer_get_uint32 (Buffer *buffer,
149 gsize offset,
150 gsize *next_offset,
151 guint32 *val)
152 {
153 unsigned char *ptr;
154 if (buffer->len < 4 || offset > buffer->len - 4) {
155 buffer->failures++;
156 return 0;
157 }
158 ptr = (unsigned char*)buffer->buf + offset;
159 if (val != NULL)
160 *val = buffer_decode_uint32 (ptr);
161 if (next_offset != NULL)
162 *next_offset = offset + 4;
163 return 1;
164 }
165
166 static gboolean
buffer_get_bytes(Buffer * buffer,gsize offset,gsize * next_offset,guchar * out,gsize n_bytes)167 buffer_get_bytes (Buffer *buffer,
168 gsize offset,
169 gsize *next_offset,
170 guchar *out,
171 gsize n_bytes)
172 {
173 if (buffer->len < n_bytes || offset > buffer->len - n_bytes)
174 return FALSE;
175 memcpy (out, buffer->buf + offset, n_bytes);
176 *next_offset = offset + n_bytes;
177 return TRUE;
178 }
179
180 static gboolean
buffer_get_time(Buffer * buffer,gsize offset,gsize * next_offset,time_t * time)181 buffer_get_time (Buffer *buffer,
182 gsize offset,
183 gsize *next_offset,
184 time_t *time)
185 {
186 guint32 a, b;
187 guint64 val;
188
189 if (!buffer_get_uint32 (buffer, offset, &offset, &a) ||
190 !buffer_get_uint32 (buffer, offset, &offset, &b))
191 return FALSE;
192
193 val = ((guint64)a) << 32 | b;
194 *next_offset = offset;
195 *time = (time_t) val;
196 return TRUE;
197 }
198
199 static int
buffer_get_string(Buffer * buffer,gsize offset,gsize * next_offset,gchar ** str_ret,BufferAllocator allocator)200 buffer_get_string (Buffer *buffer,
201 gsize offset,
202 gsize *next_offset,
203 gchar **str_ret,
204 BufferAllocator allocator)
205 {
206 guint32 len;
207
208 if (!allocator)
209 allocator = buffer->allocator;
210 if (!allocator)
211 allocator = DEFAULT_ALLOCATOR;
212
213 if (!buffer_get_uint32 (buffer, offset, &offset, &len)) {
214 return 0;
215 }
216 if (len == 0xffffffff) {
217 *next_offset = offset;
218 *str_ret = NULL;
219 return 1;
220 } else if (len >= 0x7fffffff) {
221 return 0;
222 }
223
224 if (buffer->len < len ||
225 offset > buffer->len - len) {
226 return 0;
227 }
228
229 /* Make sure no null characters in string */
230 if (memchr (buffer->buf + offset, 0, len) != NULL)
231 return 0;
232
233 /* The passed allocator may be for non-pageable memory */
234 *str_ret = (allocator) (NULL, len + 1);
235 if (!*str_ret)
236 return 0;
237 memcpy (*str_ret, buffer->buf + offset, len);
238
239 /* Always zero terminate */
240 (*str_ret)[len] = 0;
241 *next_offset = offset + len;
242
243 return 1;
244 }
245
246 static gboolean
buffer_get_utf8_string(Buffer * buffer,gsize offset,gsize * next_offset,char ** str_ret)247 buffer_get_utf8_string (Buffer *buffer,
248 gsize offset,
249 gsize *next_offset,
250 char **str_ret)
251 {
252 gsize len;
253 char *str;
254
255 if (!buffer_get_string (buffer, offset, &offset, &str,
256 (BufferAllocator)g_realloc))
257 return FALSE;
258 len = str ? strlen (str) : 0;
259
260 if (str != NULL) {
261 if (!g_utf8_validate (str, len, NULL)) {
262 g_free (str);
263 return FALSE;
264 }
265 }
266
267 if (next_offset != NULL) {
268 *next_offset = offset;
269 }
270 if (str_ret != NULL) {
271 *str_ret = str;
272 } else {
273 g_free (str);
274 }
275 return TRUE;
276 }
277
278 static gint
buffer_get_byte_array(Buffer * buffer,gsize offset,gsize * next_offset,const guchar ** val,gsize * vlen)279 buffer_get_byte_array (Buffer *buffer,
280 gsize offset,
281 gsize *next_offset,
282 const guchar **val,
283 gsize *vlen)
284 {
285 guint32 len;
286 if (!buffer_get_uint32 (buffer, offset, &offset, &len))
287 return 0;
288 if (len == 0xffffffff) {
289 if (next_offset)
290 *next_offset = offset;
291 if (val)
292 *val = NULL;
293 if (vlen)
294 *vlen = 0;
295 return 1;
296 } else if (len >= 0x7fffffff) {
297 buffer->failures++;
298 return 0;
299 }
300
301 if (buffer->len < len || offset > buffer->len - len) {
302 buffer->failures++;
303 return 0;
304 }
305
306 if (val)
307 *val = buffer->buf + offset;
308 if (vlen)
309 *vlen = len;
310 if (next_offset)
311 *next_offset = offset + len;
312
313 return 1;
314 }
315
316
317 static gboolean
read_attributes(Buffer * buffer,gsize offset,gsize * next_offset,const gchar * identifier,GKeyFile * file)318 read_attributes (Buffer *buffer,
319 gsize offset,
320 gsize *next_offset,
321 const gchar *identifier,
322 GKeyFile *file)
323 {
324 guint32 list_size;
325 gchar *group = NULL;
326 gboolean res = FALSE;
327 char *name;
328 guint32 type;
329 char *str;
330 guint32 val;
331 int i;
332
333 if (!buffer_get_uint32 (buffer, offset, &offset, &list_size)) {
334 g_message ("couldn't read number of attributes");
335 goto bail;
336 }
337
338 for (i = 0; i < list_size; i++) {
339 g_free (group);
340 group = g_strdup_printf ("%s:attribute%d", identifier, i);
341
342 if (!buffer_get_utf8_string (buffer, offset, &offset, &name)) {
343 g_message ("couldn't read attribute name");
344 goto bail;
345 }
346 if (file)
347 g_key_file_set_string (file, group, "name", name);
348 g_free (name);
349
350 if (!buffer_get_uint32 (buffer, offset, &offset, &type)) {
351 g_message ("couldn't read attribute type");
352 goto bail;
353 }
354 if (file)
355 g_key_file_set_integer (file, group, "type", type);
356
357 switch (type) {
358 case 0: /* A string */
359 if (!buffer_get_utf8_string (buffer, offset, &offset, &str)) {
360 g_message ("couldn't read string attribute value");
361 goto bail;
362 }
363 if (file)
364 g_key_file_set_string (file, group, "value", str);
365 g_free (str);
366 break;
367
368 case 1: /* A uint32 */
369 if (!buffer_get_uint32 (buffer, offset, &offset, &val)) {
370 g_message ("couldn't read number attribute value");
371 goto bail;
372 }
373 if (file)
374 g_key_file_set_int64 (file, group, "value", val);
375 break;
376 default:
377 g_message ("invalid attribute type: %d", type);
378 goto bail;
379 }
380 }
381
382 *next_offset = offset;
383 res = TRUE;
384
385 bail:
386 return res;
387 }
388
389 static gboolean
symkey_generate_simple(int cipher_algo,int hash_algo,const gchar * password,gssize n_password,const guchar * salt,gsize n_salt,int iterations,guchar ** key,guchar ** iv)390 symkey_generate_simple (int cipher_algo,
391 int hash_algo,
392 const gchar *password,
393 gssize n_password,
394 const guchar *salt,
395 gsize n_salt,
396 int iterations,
397 guchar **key,
398 guchar **iv)
399 {
400 gcry_md_hd_t mdh;
401 gcry_error_t gcry;
402 guchar *digest;
403 guchar *digested;
404 guint n_digest;
405 gint pass, i;
406 gint needed_iv, needed_key;
407 guchar *at_iv, *at_key;
408
409 g_assert (cipher_algo);
410 g_assert (hash_algo);
411
412 g_return_val_if_fail (iterations >= 1, FALSE);
413
414 if (!password)
415 n_password = 0;
416 if (n_password == -1)
417 n_password = strlen (password);
418
419 /*
420 * If cipher algo needs more bytes than hash algo has available
421 * then the entire hashing process is done again (with the previous
422 * hash bytes as extra input), and so on until satisfied.
423 */
424
425 needed_key = gcry_cipher_get_algo_keylen (cipher_algo);
426 needed_iv = gcry_cipher_get_algo_blklen (cipher_algo);
427
428 gcry = gcry_md_open (&mdh, hash_algo, 0);
429 if (gcry) {
430 g_warning ("couldn't create '%s' hash context: %s",
431 gcry_md_algo_name (hash_algo), gcry_strerror (gcry));
432 return FALSE;
433 }
434
435 n_digest = gcry_md_get_algo_dlen (hash_algo);
436 g_return_val_if_fail (n_digest > 0, FALSE);
437
438 digest = g_malloc (n_digest);
439 g_return_val_if_fail (digest, FALSE);
440 if (key) {
441 *key = g_malloc (needed_key);
442 g_return_val_if_fail (*key, FALSE);
443 }
444 if (iv)
445 *iv = g_new0 (guchar, needed_iv);
446
447 at_key = key ? *key : NULL;
448 at_iv = iv ? *iv : NULL;
449
450 for (pass = 0; TRUE; ++pass) {
451 gcry_md_reset (mdh);
452
453 /* Hash in the previous buffer on later passes */
454 if (pass > 0)
455 gcry_md_write (mdh, digest, n_digest);
456
457 if (password)
458 gcry_md_write (mdh, password, n_password);
459 if (salt && n_salt)
460 gcry_md_write (mdh, salt, n_salt);
461 gcry_md_final (mdh);
462 digested = gcry_md_read (mdh, 0);
463 g_return_val_if_fail (digested, FALSE);
464 memcpy (digest, digested, n_digest);
465
466 for (i = 1; i < iterations; ++i) {
467 gcry_md_reset (mdh);
468 gcry_md_write (mdh, digest, n_digest);
469 gcry_md_final (mdh);
470 digested = gcry_md_read (mdh, 0);
471 g_return_val_if_fail (digested, FALSE);
472 memcpy (digest, digested, n_digest);
473 }
474
475 /* Copy as much as possible into the destinations */
476 i = 0;
477 while (needed_key && i < n_digest) {
478 if (at_key)
479 *(at_key++) = digest[i];
480 needed_key--;
481 i++;
482 }
483 while (needed_iv && i < n_digest) {
484 if (at_iv)
485 *(at_iv++) = digest[i];
486 needed_iv--;
487 i++;
488 }
489
490 if (needed_key == 0 && needed_iv == 0)
491 break;
492 }
493
494 g_free (digest);
495 gcry_md_close (mdh);
496
497 return TRUE;
498 }
499
500 static gboolean
decrypt_buffer(Buffer * buffer,const gchar * password,guchar salt[8],int iterations)501 decrypt_buffer (Buffer *buffer,
502 const gchar *password,
503 guchar salt[8],
504 int iterations)
505 {
506 gcry_cipher_hd_t cih;
507 gcry_error_t gerr;
508 guchar *key, *iv;
509 gsize n_password = 0;
510 gsize pos;
511
512 g_assert (buffer->len % 16 == 0);
513 g_assert (16 == gcry_cipher_get_algo_blklen (GCRY_CIPHER_AES128));
514 g_assert (16 == gcry_cipher_get_algo_keylen (GCRY_CIPHER_AES128));
515
516 /* No password is set, try an null password */
517 if (password == NULL)
518 n_password = 0;
519 else
520 n_password = strlen (password);
521
522 if (!symkey_generate_simple (GCRY_CIPHER_AES128, GCRY_MD_SHA256,
523 password, n_password, salt, 8, iterations, &key, &iv))
524 return FALSE;
525
526 gerr = gcry_cipher_open (&cih, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, 0);
527 if (gerr) {
528 g_warning ("couldn't create aes cipher context: %s",
529 gcry_strerror (gerr));
530 g_free (key);
531 g_free (iv);
532 return FALSE;
533 }
534
535 /* 16 = 128 bits */
536 gerr = gcry_cipher_setkey (cih, key, 16);
537 g_return_val_if_fail (!gerr, FALSE);
538 g_free (key);
539
540 /* 16 = 128 bits */
541 gerr = gcry_cipher_setiv (cih, iv, 16);
542 g_return_val_if_fail (!gerr, FALSE);
543 g_free (iv);
544
545 for (pos = 0; pos < buffer->len; pos += 16) {
546 /* In place encryption */
547 gerr = gcry_cipher_decrypt (cih, buffer->buf + pos, 16, NULL, 0);
548 g_return_val_if_fail (!gerr, FALSE);
549 }
550
551 gcry_cipher_close (cih);
552
553 return TRUE;
554 }
555
556 static gboolean
verify_decrypted_buffer(Buffer * buffer)557 verify_decrypted_buffer (Buffer *buffer)
558 {
559 guchar digest[16];
560
561 /* In case the world changes on us... */
562 g_return_val_if_fail (gcry_md_get_algo_dlen (GCRY_MD_MD5) == sizeof (digest), 0);
563
564 gcry_md_hash_buffer (GCRY_MD_MD5, (void*)digest,
565 (guchar*)buffer->buf + 16, buffer->len - 16);
566
567 return memcmp (buffer->buf, digest, 16) == 0;
568 }
569
570 static gboolean
read_acl(Buffer * buffer,gsize offset,gsize * offset_out,const gchar * identifier,GKeyFile * file)571 read_acl (Buffer *buffer,
572 gsize offset,
573 gsize *offset_out,
574 const gchar *identifier,
575 GKeyFile *file)
576 {
577 gboolean res = FALSE;
578 gchar *group = NULL;
579 guint32 num_acs;
580 guint32 x, y;
581 int i;
582 char *name, *path, *reserved;
583
584 if (!buffer_get_uint32 (buffer, offset, &offset, &num_acs)) {
585 g_message ("couldn't read number of acls");
586 return FALSE;
587 }
588
589 for (i = 0; i < num_acs; i++) {
590 g_free (group);
591 group = g_strdup_printf ("%s:acl%d", identifier, i);
592
593 if (!buffer_get_uint32 (buffer, offset, &offset, &x)) {
594 g_message ("couldn't read acl types allowed");
595 goto bail;
596 }
597 g_key_file_set_boolean (file, group, "read-access", x & ACCESS_READ);
598 g_key_file_set_boolean (file, group, "write-access", x & ACCESS_WRITE);
599 g_key_file_set_boolean (file, group, "remove-access", x & ACCESS_REMOVE);
600
601 if (!buffer_get_utf8_string (buffer, offset, &offset, &name)) {
602 g_message ("couldn't read acl application name");
603 goto bail;
604 }
605 g_key_file_set_string (file, group, "display-name", name);
606 g_free (name);
607
608 if (!buffer_get_utf8_string (buffer, offset, &offset, &path)) {
609 g_message ("couldn't read acl application path");
610 goto bail;
611 }
612 g_key_file_set_string (file, group, "path", path);
613 g_free (path);
614
615 reserved = NULL;
616 if (!buffer_get_utf8_string (buffer, offset, &offset, &reserved)) {
617 g_message ("couldn't read acl reserved string");
618 goto bail;
619 }
620 g_free (reserved);
621
622 if (!buffer_get_uint32 (buffer, offset, &offset, &y)) {
623 g_message ("couldn't read acl reserved integer");
624 goto bail;
625 }
626 }
627
628 *offset_out = offset;
629 res = TRUE;
630
631 bail:
632 g_free (group);
633 return res;
634 }
635
636 static gboolean
read_hashed_item_info(Buffer * buffer,gsize * offset,guint n_items,GKeyFile * file,GPtrArray * items)637 read_hashed_item_info (Buffer *buffer,
638 gsize *offset,
639 guint n_items,
640 GKeyFile *file,
641 GPtrArray *items)
642 {
643 gchar *identifier;
644 guint type;
645 guint id;
646 gint i;
647
648 g_assert (buffer);
649 g_assert (offset);
650 g_assert (items);
651
652 for (i = 0; i < n_items; i++) {
653 if (!buffer_get_uint32 (buffer, *offset, offset, &id)) {
654 g_message ("couldn't read item id");
655 return FALSE;
656 }
657 identifier = g_strdup_printf ("%u", id);
658 g_ptr_array_add (items, identifier);
659
660 if (!buffer_get_uint32 (buffer, *offset, offset, &type)) {
661 g_message ("couldn't read item type");
662 return FALSE;
663 }
664 g_key_file_set_integer (file, identifier, "item-type", type);
665
666 /* NULL passed as file, so nothing gets written */
667 if (!read_attributes (buffer, *offset, offset, identifier, NULL)) {
668 g_message ("couldn't read hashed attributes");
669 return FALSE;
670 }
671 }
672
673 return TRUE;
674 }
675
676 static gboolean
read_full_item_info(Buffer * buffer,gsize * offset,guint n_items,GKeyFile * file,GPtrArray * items)677 read_full_item_info (Buffer *buffer,
678 gsize *offset,
679 guint n_items,
680 GKeyFile *file,
681 GPtrArray *items)
682 {
683 const gchar *identifier;
684 const unsigned char *ptr_secret;
685 gsize n_secret;
686 gchar *value;
687 guint32 tmp;
688 time_t ctime, mtime;
689 gint i, j;
690
691 g_assert (buffer);
692 g_assert (offset);
693 g_assert (items->len == n_items);
694
695 for (i = 0; i < n_items; i++) {
696 identifier = items->pdata[i];
697
698 /* The display name */
699 if (!buffer_get_utf8_string (buffer, *offset, offset, &value)) {
700 g_message ("couldn't read item display name");
701 return FALSE;
702 }
703 g_key_file_set_string (file, identifier, "display-name", value);
704 g_free (value);
705
706 /* The secret */
707 if (!buffer_get_byte_array (buffer, *offset, offset, &ptr_secret, &n_secret)) {
708 g_message ("couldn't read item secret");
709 return FALSE;
710 }
711 if (g_utf8_validate ((gchar *)ptr_secret, n_secret, NULL))
712 value = g_strndup ((gchar *)ptr_secret, n_secret);
713 else
714 value = g_base64_encode (ptr_secret, n_secret);
715 g_key_file_set_string (file, identifier, "secret", value);
716 g_free (value);
717
718 /* The item times */
719 if (!buffer_get_time (buffer, *offset, offset, &ctime)) {
720 g_message ("couldn't read item creation time");
721 return FALSE;
722 }
723 g_key_file_set_int64 (file, identifier, "ctime", ctime);
724
725 if (!buffer_get_time (buffer, *offset, offset, &mtime)) {
726 g_message ("couldn't read item modification time");
727 return FALSE;
728 }
729 g_key_file_set_int64 (file, identifier, "mtime", mtime);
730
731 /* Reserved data */
732 if (!buffer_get_utf8_string (buffer, *offset, offset, &value)) {
733 g_message ("couldn't read item reserved string");
734 return FALSE;
735 }
736 g_free (value);
737 for (j = 0; j < 4; j++) {
738 if (!buffer_get_uint32 (buffer, *offset, offset, &tmp)) {
739 g_message ("couldn't read item reserved integer");
740 return FALSE;
741 }
742 }
743
744 if (!read_attributes (buffer, *offset, offset, identifier, file))
745 return FALSE;
746
747 /* The ACLs */
748 if (!read_acl (buffer, *offset, offset, identifier, file))
749 return FALSE;
750 }
751
752 return TRUE;
753 }
754
755 static gboolean
transform_keyring_binary_to_text(gconstpointer data,gsize n_data,const gchar * password,GKeyFile * file)756 transform_keyring_binary_to_text (gconstpointer data,
757 gsize n_data,
758 const gchar *password,
759 GKeyFile *file)
760 {
761 Buffer to_decrypt = BUFFER_EMPTY;
762 guchar major, minor, crypto, hash;
763 guint32 flags;
764 guint32 lock_timeout;
765 time_t mtime, ctime;
766 guint32 tmp;
767 guint32 num_items;
768 guint32 crypto_size;
769 guint32 hash_iterations;
770 guchar salt[8];
771 Buffer buffer;
772 GPtrArray *items = NULL;
773 gboolean res = FALSE;
774 gsize offset;
775 gchar *value;
776 int i;
777
778 /* The buffer we read from */
779 buffer_init_static (&buffer, data, n_data);
780
781 if (buffer.len < KEYRING_FILE_HEADER_LEN ||
782 memcmp (buffer.buf, KEYRING_FILE_HEADER, KEYRING_FILE_HEADER_LEN) != 0) {
783 buffer_uninit (&buffer);
784 return FALSE;
785 }
786
787 items = g_ptr_array_new_with_free_func (g_free);
788 offset = KEYRING_FILE_HEADER_LEN;
789 major = buffer.buf[offset++];
790 minor = buffer.buf[offset++];
791 crypto = buffer.buf[offset++];
792 hash = buffer.buf[offset++];
793
794 value = g_strdup_printf ("version: %d.%d / crypto: %d / hash: %d",
795 (gint)major, (gint)minor, (gint)crypto, (gint)hash);
796 if (!g_key_file_set_comment (file, NULL, NULL, value, NULL))
797 g_warn_if_reached ();
798 g_free (value);
799
800 if (major != 0 || minor != 0) {
801 g_message ("unknown version: %d.%d", (gint)major, (gint)minor);
802 buffer_uninit (&buffer);
803 return FALSE;
804 }
805
806 if (!buffer_get_utf8_string (&buffer, offset, &offset, &value)) {
807 g_message ("couldn't read keyring display name");
808 goto bail;
809 }
810 g_key_file_set_string (file, "keyring", "display-name", value);
811 g_free (value);
812
813 if (!buffer_get_time (&buffer, offset, &offset, &ctime)) {
814 g_message ("couldn't read keyring creation time");
815 goto bail;
816 }
817 g_key_file_set_int64 (file, "keyring", "ctime", ctime);
818
819 if (!buffer_get_time (&buffer, offset, &offset, &mtime)) {
820 g_message ("couldn't read keyring modification time");
821 goto bail;
822 }
823 g_key_file_set_int64 (file, "keyring", "mtime", mtime);
824
825 if (!buffer_get_uint32 (&buffer, offset, &offset, &flags)) {
826 g_message ("couldn't read keyring flags");
827 goto bail;
828 }
829 g_key_file_set_boolean (file, "keyring", "lock-on-idle", flags & LOCK_ON_IDLE_FLAG);
830 g_key_file_set_boolean (file, "keyring", "lock-after", flags & LOCK_AFTER_FLAG);
831
832 if (!buffer_get_uint32 (&buffer, offset, &offset, &lock_timeout)) {
833 g_message ("couldn't read lock timeout");
834 goto bail;
835 }
836 g_key_file_set_integer (file, "keyring", "lock-timeout", lock_timeout);
837
838 if (!buffer_get_uint32 (&buffer, offset, &offset, &hash_iterations)) {
839 g_message ("couldn't read hash iterations");
840 goto bail;
841 }
842 g_key_file_set_integer (file, "keyring", "x-hash-iterations", hash_iterations);
843
844 if (!buffer_get_bytes (&buffer, offset, &offset, salt, 8)) {
845 g_message ("couldn't read salt");
846 goto bail;
847 }
848 value = g_base64_encode (salt, 8);
849 g_key_file_set_string (file, "keyring", "x-salt", value);
850 g_free (value);
851
852 for (i = 0; i < 4; i++) {
853 if (!buffer_get_uint32 (&buffer, offset, &offset, &tmp))
854 goto bail;
855 }
856
857 if (!buffer_get_uint32 (&buffer, offset, &offset, &num_items)) {
858 g_message ("couldn't read number of items");
859 goto bail;
860 }
861 g_key_file_set_integer (file, "keyring", "x-num-items", num_items);
862
863 /* Hashed data, without secrets */
864 if (!read_hashed_item_info (&buffer, &offset, num_items, file, items)) {
865 g_message ("couldn't read hashed items");
866 goto bail;
867 }
868
869 if (!buffer_get_uint32 (&buffer, offset, &offset, &crypto_size)) {
870 g_message ("couldn't read size of encrypted data");
871 goto bail;
872 }
873 g_key_file_set_integer (file, "keyring", "x-crypto-size", crypto_size);
874
875 if (crypto_size > buffer.len - offset) {
876 g_message ("encrypted data size is greater than file size, possibly truncated");
877 crypto_size = buffer.len - offset;
878 }
879
880 /* Make the crypted part is the right size */
881 if (crypto_size % 16 != 0) {
882 g_message ("encrypted data size is not a multiple of the encryption block size, possibly truncated");
883 crypto_size = (crypto_size / 16) * 16;
884 }
885
886 /* Copy the data into to_decrypt into non-pageable memory */
887 buffer_init (&to_decrypt, crypto_size);
888 memcpy (to_decrypt.buf, buffer.buf + offset, crypto_size);
889 to_decrypt.len = crypto_size;
890
891 if (!decrypt_buffer (&to_decrypt, password, salt, hash_iterations))
892 goto bail;
893 if (!verify_decrypted_buffer (&to_decrypt))
894 g_message ("encrypted data failed to verify, password wrong, or file corrupted");
895 offset = 16; /* Skip hash */
896 if (!read_full_item_info (&to_decrypt, &offset, num_items, file, items))
897 goto bail;
898
899 res = TRUE;
900
901 bail:
902 g_ptr_array_free (items, TRUE);
903 buffer_uninit (&to_decrypt);
904 return res;
905 }
906
907
908
909 int
main(int argc,char * argv[])910 main (int argc,
911 char *argv[])
912 {
913 GError *error = NULL;
914 const gchar *password;
915 GKeyFile *file;
916 gboolean ret;
917 gchar *contents;
918 gsize length;
919
920 g_set_prgname ("dump-keyring0-format");
921 gcry_check_version (GCRYPT_VERSION);
922
923 if (argc < 2 || argc > 3) {
924 g_printerr ("usage: %s file.keyring [output]\n", g_get_prgname ());
925 return 2;
926 }
927
928 if (!g_file_get_contents (argv[1], &contents, &length, &error)) {
929 g_printerr ("%s: %s\n", g_get_prgname (), error->message);
930 g_error_free (error);
931 return 1;
932 }
933
934 file = g_key_file_new ();
935 password = getpass ("Password: ");
936
937 transform_keyring_binary_to_text (contents, length, password, file);
938 g_free (contents);
939
940 contents = g_key_file_to_data (file, &length, &error);
941 g_key_file_free (file);
942
943 if (contents == NULL) {
944 g_printerr ("%s: couldn't encode: %s", g_get_prgname (), error->message);
945 g_error_free (error);
946 return 1;
947 }
948
949 ret = TRUE;
950 if (argc == 3)
951 ret = g_file_set_contents (argv[2], contents, length, &error);
952 else
953 g_print ("%s", contents);
954 g_free (contents);
955
956 if (!ret) {
957 g_printerr ("%s: %s", g_get_prgname (), error->message);
958 g_error_free (error);
959 return 1;
960 }
961
962 return 0;
963 }
964