diff options
author | Nils Wallménius <nils@rockbox.org> | 2008-07-07 14:04:18 +0000 |
---|---|---|
committer | Nils Wallménius <nils@rockbox.org> | 2008-07-07 14:04:18 +0000 |
commit | bd12def3938b4eb2821675ef2e86bca271176cbc (patch) | |
tree | 14286e76c8783dab4b6712b0a52dcd7604636f66 /apps/plugins | |
parent | 6d7adb608a04e937595ca7f29b0fbdc251f13184 (diff) | |
download | rockbox-bd12def3938b4eb2821675ef2e86bca271176cbc.tar.gz rockbox-bd12def3938b4eb2821675ef2e86bca271176cbc.zip |
Keybox, encrypted password storage. Manual page comming soon
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17979 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins')
-rw-r--r-- | apps/plugins/CATEGORIES | 1 | ||||
-rw-r--r-- | apps/plugins/SOURCES | 1 | ||||
-rw-r--r-- | apps/plugins/keybox.c | 666 |
3 files changed, 668 insertions, 0 deletions
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES index 029bcfd164..a8110593f0 100644 --- a/apps/plugins/CATEGORIES +++ b/apps/plugins/CATEGORIES | |||
@@ -32,6 +32,7 @@ iriverify,viewers | |||
32 | jackpot,games | 32 | jackpot,games |
33 | jewels,games | 33 | jewels,games |
34 | jpeg,viewers | 34 | jpeg,viewers |
35 | keybox,apps | ||
35 | lamp,apps | 36 | lamp,apps |
36 | logo,demos | 37 | logo,demos |
37 | mandelbrot,demos | 38 | mandelbrot,demos |
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index 8b491f4c1c..4b0efa9ea4 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES | |||
@@ -6,6 +6,7 @@ cube.c | |||
6 | dict.c | 6 | dict.c |
7 | firmware_flash.c | 7 | firmware_flash.c |
8 | jackpot.c | 8 | jackpot.c |
9 | keybox.c | ||
9 | logo.c | 10 | logo.c |
10 | mosaique.c | 11 | mosaique.c |
11 | properties.c | 12 | properties.c |
diff --git a/apps/plugins/keybox.c b/apps/plugins/keybox.c new file mode 100644 index 0000000000..d3b03f28a7 --- /dev/null +++ b/apps/plugins/keybox.c | |||
@@ -0,0 +1,666 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id:$ | ||
9 | * | ||
10 | * Copyright (C) 2008 Nils Wallménius | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "plugin.h" | ||
22 | #include "md5.h" | ||
23 | PLUGIN_HEADER | ||
24 | |||
25 | #define KEYBOX_FILE PLUGIN_DIR "/apps/keybox.dat" | ||
26 | #define BLOCK_SIZE 8 | ||
27 | #define MAX_ENTRIES 12*BLOCK_SIZE /* keep this a multiple of BLOCK_SIZE */ | ||
28 | #define FIELD_LEN 32 /* should be enough for anyone ;) */ | ||
29 | |||
30 | /* salt 4 bytes (needed for decryption) not encrypted padded with 4 bytes of zeroes | ||
31 | pwhash 16 bytes (to check for the right password) encrypted | ||
32 | encrypted data. */ | ||
33 | |||
34 | #define HEADER_LEN 24 | ||
35 | |||
36 | enum | ||
37 | { | ||
38 | FILE_OPEN_ERROR = -1 | ||
39 | }; | ||
40 | |||
41 | struct pw_entry | ||
42 | { | ||
43 | bool used; | ||
44 | char title[FIELD_LEN]; | ||
45 | char name[FIELD_LEN]; | ||
46 | char password[FIELD_LEN]; | ||
47 | struct pw_entry *next; | ||
48 | }; | ||
49 | |||
50 | struct pw_list | ||
51 | { | ||
52 | struct pw_entry first; /* always points to the first element in the list */ | ||
53 | struct pw_entry entries[MAX_ENTRIES]; | ||
54 | int num_entries; | ||
55 | } pw_list; | ||
56 | |||
57 | /* use this to access hashes in different ways, not byte order | ||
58 | independent but does it matter? */ | ||
59 | union hash | ||
60 | { | ||
61 | uint8_t bytes[16]; | ||
62 | uint32_t words[4]; | ||
63 | }; | ||
64 | |||
65 | static const struct plugin_api* rb; | ||
66 | MEM_FUNCTION_WRAPPERS(rb); | ||
67 | static char buffer[sizeof(struct pw_entry)*MAX_ENTRIES]; | ||
68 | static int bytes_read = 0; /* bytes read into the buffer */ | ||
69 | static struct gui_synclist kb_list; | ||
70 | static union hash key; | ||
71 | static char master_pw[FIELD_LEN]; | ||
72 | static uint32_t salt; | ||
73 | static union hash pwhash; | ||
74 | static bool data_changed = false; | ||
75 | |||
76 | static int context_item_cb(int action, const struct menu_item_ex *this_item); | ||
77 | static void encrypt_buffer(char *buf, size_t size, uint32_t *key); | ||
78 | static void decrypt_buffer(char *buf, size_t size, uint32_t *key); | ||
79 | |||
80 | /* the following two functions are the reference TEA implementation by | ||
81 | David Wheeler and Roger Needham taken from | ||
82 | http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm */ | ||
83 | |||
84 | static void encrypt(uint32_t* v, uint32_t* k) | ||
85 | { | ||
86 | uint32_t v0=v[0], v1=v[1], sum=0, i; /* set up */ | ||
87 | static const uint32_t delta=0x9e3779b9; /* a key schedule constant */ | ||
88 | uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */ | ||
89 | for (i=0; i < 32; i++) { /* basic cycle start */ | ||
90 | sum += delta; | ||
91 | v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1); | ||
92 | v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3); /* end cycle */ | ||
93 | } | ||
94 | v[0]=v0; v[1]=v1; | ||
95 | } | ||
96 | |||
97 | static void decrypt(uint32_t* v, uint32_t* k) | ||
98 | { | ||
99 | uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i; /* set up */ | ||
100 | static const uint32_t delta=0x9e3779b9; /* a key schedule constant */ | ||
101 | uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */ | ||
102 | for (i=0; i<32; i++) { /* basic cycle start */ | ||
103 | v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3); | ||
104 | v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1); | ||
105 | sum -= delta; /* end cycle */ | ||
106 | } | ||
107 | v[0]=v0; v[1]=v1; | ||
108 | } | ||
109 | |||
110 | MENUITEM_RETURNVALUE(context_add_entry, "Add entry", 0, | ||
111 | NULL, Icon_NOICON); | ||
112 | MENUITEM_RETURNVALUE(context_edit_title, "Edit title", 1, | ||
113 | &context_item_cb, Icon_NOICON); | ||
114 | MENUITEM_RETURNVALUE(context_edit_name, "Edit user name", 1, | ||
115 | &context_item_cb, Icon_NOICON); | ||
116 | MENUITEM_RETURNVALUE(context_edit_password, "Edit password", 2, | ||
117 | &context_item_cb, Icon_NOICON); | ||
118 | MENUITEM_RETURNVALUE(context_delete_entry, "Delete entry", 3, | ||
119 | &context_item_cb, Icon_NOICON); | ||
120 | MENUITEM_RETURNVALUE(context_debug, "debug", 4, | ||
121 | &context_item_cb, Icon_NOICON); | ||
122 | |||
123 | MAKE_MENU(context_m, "Context menu", | ||
124 | context_item_cb, Icon_NOICON, | ||
125 | &context_add_entry, &context_edit_title, &context_edit_name, | ||
126 | &context_edit_password, &context_delete_entry); | ||
127 | |||
128 | static int context_item_cb(int action, const struct menu_item_ex *this_item) | ||
129 | { | ||
130 | if (action == ACTION_REQUEST_MENUITEM | ||
131 | && pw_list.num_entries == 0 | ||
132 | && this_item != &context_add_entry) | ||
133 | { | ||
134 | return ACTION_EXIT_MENUITEM; | ||
135 | } | ||
136 | return action; | ||
137 | } | ||
138 | |||
139 | static char * kb_list_cb(int selected_item, void *data, | ||
140 | char *buffer, size_t buffer_len) | ||
141 | { | ||
142 | (void)data; | ||
143 | int i; | ||
144 | struct pw_entry *entry = pw_list.first.next; | ||
145 | for (i = 0; i < selected_item; i++) | ||
146 | { | ||
147 | if (entry->next) | ||
148 | entry = entry->next; | ||
149 | } | ||
150 | rb->snprintf(buffer, buffer_len, "%s", entry->title); | ||
151 | |||
152 | return buffer; | ||
153 | } | ||
154 | |||
155 | static void init_ll(void) | ||
156 | { | ||
157 | pw_list.first.next = &pw_list.entries[0]; | ||
158 | pw_list.entries[0].next = NULL; | ||
159 | pw_list.num_entries = 0; | ||
160 | } | ||
161 | |||
162 | static void delete_entry(int selected_item) | ||
163 | { | ||
164 | int i; | ||
165 | struct pw_entry *entry = pw_list.first.next; | ||
166 | struct pw_entry *entry2; | ||
167 | |||
168 | /* find the entry before the one to delete */ | ||
169 | for (i = 0; i < selected_item - 1; i++) | ||
170 | { | ||
171 | if (entry->next) | ||
172 | entry = entry->next; | ||
173 | } | ||
174 | if (entry->next) | ||
175 | entry2 = entry->next; | ||
176 | else | ||
177 | return; | ||
178 | if (entry2->next) | ||
179 | entry->next = entry2->next; | ||
180 | |||
181 | entry2->used = false; | ||
182 | entry2->name[0] = '\0'; | ||
183 | entry2->password[0] = '\0'; | ||
184 | entry2->next = NULL; | ||
185 | |||
186 | rb->gui_synclist_set_nb_items(&kb_list, --pw_list.num_entries); | ||
187 | data_changed = true; | ||
188 | } | ||
189 | |||
190 | static void add_entry(int selected_item) | ||
191 | { | ||
192 | int i, j; | ||
193 | struct pw_entry *entry = pw_list.first.next; | ||
194 | for (i = 0; i < MAX_ENTRIES && pw_list.entries[i].used; i++) | ||
195 | ; | ||
196 | |||
197 | if (pw_list.entries[i].used) | ||
198 | { | ||
199 | rb->splash(HZ, "Password list full"); | ||
200 | return; | ||
201 | } | ||
202 | |||
203 | rb->splash(HZ, "Enter title"); | ||
204 | rb->kbd_input(pw_list.entries[i].title, FIELD_LEN); | ||
205 | rb->splash(HZ, "Enter name"); | ||
206 | rb->kbd_input(pw_list.entries[i].name, FIELD_LEN); | ||
207 | rb->splash(HZ, "Enter password"); | ||
208 | rb->kbd_input(pw_list.entries[i].password, FIELD_LEN); | ||
209 | |||
210 | for (j = 0; j < selected_item; j++) | ||
211 | { | ||
212 | if (entry->next) | ||
213 | entry = entry->next; | ||
214 | } | ||
215 | |||
216 | rb->gui_synclist_set_nb_items(&kb_list, ++pw_list.num_entries); | ||
217 | |||
218 | pw_list.entries[i].used = true; | ||
219 | pw_list.entries[i].next = entry->next; | ||
220 | |||
221 | entry->next = &pw_list.entries[i]; | ||
222 | |||
223 | if (entry->next == entry) | ||
224 | entry->next = NULL; | ||
225 | |||
226 | data_changed = true; | ||
227 | } | ||
228 | |||
229 | static void edit_title(int selected_item) | ||
230 | { | ||
231 | int i; | ||
232 | struct pw_entry *entry = pw_list.first.next; | ||
233 | for (i = 0; i < selected_item; i++) | ||
234 | { | ||
235 | if (entry->next) | ||
236 | entry = entry->next; | ||
237 | } | ||
238 | if (rb->kbd_input(entry->title, FIELD_LEN) == 0) | ||
239 | data_changed = true; | ||
240 | } | ||
241 | |||
242 | static void edit_name(int selected_item) | ||
243 | { | ||
244 | int i; | ||
245 | struct pw_entry *entry = pw_list.first.next; | ||
246 | for (i = 0; i < selected_item; i++) | ||
247 | { | ||
248 | if (entry->next) | ||
249 | entry = entry->next; | ||
250 | } | ||
251 | if (rb->kbd_input(entry->name, FIELD_LEN) == 0) | ||
252 | data_changed = true; | ||
253 | } | ||
254 | |||
255 | static void edit_pw(int selected_item) | ||
256 | { | ||
257 | int i; | ||
258 | struct pw_entry *entry = pw_list.first.next; | ||
259 | for (i = 0; i < selected_item; i++) | ||
260 | { | ||
261 | if (entry->next) | ||
262 | entry = entry->next; | ||
263 | } | ||
264 | if (rb->kbd_input(entry->password, FIELD_LEN) == 0) | ||
265 | data_changed = true; | ||
266 | } | ||
267 | |||
268 | static void context_menu(int selected_item) | ||
269 | { | ||
270 | int selection, result; | ||
271 | bool exit = false; | ||
272 | |||
273 | do { | ||
274 | result = rb->do_menu(&context_m, &selection, NULL, false); | ||
275 | switch (result) { | ||
276 | case 0: | ||
277 | add_entry(selected_item); | ||
278 | return; | ||
279 | case 1: | ||
280 | edit_title(selected_item); | ||
281 | return; | ||
282 | case 2: | ||
283 | edit_name(selected_item); | ||
284 | return; | ||
285 | case 3: | ||
286 | edit_pw(selected_item); | ||
287 | return; | ||
288 | case 4: | ||
289 | delete_entry(selected_item); | ||
290 | return; | ||
291 | default: | ||
292 | exit = true; | ||
293 | break; | ||
294 | } | ||
295 | rb->yield(); | ||
296 | } while (!exit); | ||
297 | } | ||
298 | |||
299 | static void splash_pw(int selected_item) | ||
300 | { | ||
301 | int i; | ||
302 | struct pw_entry *entry = pw_list.first.next; | ||
303 | |||
304 | for (i = 0; i < selected_item; i++) | ||
305 | { | ||
306 | if (entry->next) | ||
307 | entry = entry->next; | ||
308 | } | ||
309 | if (entry->name != '\0') | ||
310 | rb->splash(0, "%s %s", entry->name, entry->password); | ||
311 | else | ||
312 | rb->splash(0, "%s", entry->password); | ||
313 | rb->get_action(CONTEXT_STD, TIMEOUT_BLOCK); | ||
314 | } | ||
315 | |||
316 | static void hash_pw(union hash *out) | ||
317 | { | ||
318 | int i; | ||
319 | struct md5_s pw_md5; | ||
320 | |||
321 | InitMD5(&pw_md5); | ||
322 | AddMD5(&pw_md5, master_pw, rb->strlen(master_pw)); | ||
323 | EndMD5(&pw_md5); | ||
324 | |||
325 | for (i = 0; i < 4; i++) | ||
326 | out->words[i] = htole32(pw_md5.p_digest[i]); | ||
327 | } | ||
328 | |||
329 | static void make_key(void) | ||
330 | { | ||
331 | int i; | ||
332 | char buf[sizeof(master_pw) + sizeof(salt) + 1]; | ||
333 | struct md5_s key_md5; | ||
334 | size_t len = rb->strlen(master_pw); | ||
335 | |||
336 | rb->strncpy(buf, master_pw, sizeof(buf)); | ||
337 | |||
338 | rb->memcpy(&buf[len], &salt, sizeof(salt)); | ||
339 | |||
340 | InitMD5(&key_md5); | ||
341 | AddMD5(&key_md5, buf, rb->strlen(buf)); | ||
342 | EndMD5(&key_md5); | ||
343 | |||
344 | for (i = 0; i < 4; i++) | ||
345 | key.words[i] = key_md5.p_digest[i]; | ||
346 | } | ||
347 | |||
348 | static void decrypt_buffer(char *buf, size_t size, uint32_t *key) | ||
349 | { | ||
350 | unsigned int i; | ||
351 | uint32_t block[2]; | ||
352 | |||
353 | for (i = 0; i < size/BLOCK_SIZE; i++) | ||
354 | { | ||
355 | rb->memcpy(&block[0], &buf[i*BLOCK_SIZE], sizeof(block)); | ||
356 | |||
357 | block[0] = letoh32(block[0]); | ||
358 | block[1] = letoh32(block[1]); | ||
359 | |||
360 | decrypt(&block[0], key); | ||
361 | |||
362 | /* byte swap one block */ | ||
363 | block[0] = letoh32(block[0]); | ||
364 | block[1] = letoh32(block[1]); | ||
365 | |||
366 | rb->memcpy(&buf[i*BLOCK_SIZE], &block[0], sizeof(block)); | ||
367 | } | ||
368 | } | ||
369 | |||
370 | static void encrypt_buffer(char *buf, size_t size, uint32_t *key) | ||
371 | { | ||
372 | unsigned int i; | ||
373 | uint32_t block[2]; | ||
374 | |||
375 | for (i = 0; i < size/BLOCK_SIZE; i++) | ||
376 | { | ||
377 | rb->memcpy(&block[0], &buf[i*BLOCK_SIZE], sizeof(block)); | ||
378 | |||
379 | /* byte swap one block */ | ||
380 | block[0] = htole32(block[0]); | ||
381 | block[1] = htole32(block[1]); | ||
382 | |||
383 | encrypt(&block[0], key); | ||
384 | |||
385 | block[0] = htole32(block[0]); | ||
386 | block[1] = htole32(block[1]); | ||
387 | |||
388 | rb->memcpy(&buf[i*BLOCK_SIZE], &block[0], sizeof(block)); | ||
389 | } | ||
390 | } | ||
391 | |||
392 | static int parse_buffer(void) | ||
393 | { | ||
394 | int i; | ||
395 | intptr_t len; | ||
396 | struct pw_entry *entry = pw_list.first.next; | ||
397 | char *start, *end; | ||
398 | start = &buffer[HEADER_LEN]; | ||
399 | |||
400 | rb->memcpy(&salt, &buffer[0], sizeof(salt)); | ||
401 | make_key(); | ||
402 | |||
403 | decrypt_buffer(&buffer[8], bytes_read - 8, &key.words[0]); | ||
404 | |||
405 | if (rb->memcmp(&buffer[8], &pwhash, sizeof(union hash))) | ||
406 | { | ||
407 | rb->splash(HZ*2, "Wrong password"); | ||
408 | return -1; | ||
409 | } | ||
410 | |||
411 | for (i=0; i < MAX_ENTRIES; i++) | ||
412 | { | ||
413 | end = rb->strchr(start, '\0'); /* find eol */ | ||
414 | len = (intptr_t)end - (intptr_t)&buffer[HEADER_LEN]; | ||
415 | if ((len > bytes_read + HEADER_LEN) | ||
416 | || (intptr_t)start == (intptr_t)end) | ||
417 | { | ||
418 | break; | ||
419 | } | ||
420 | |||
421 | rb->strncpy(entry->title, start, | ||
422 | MIN((intptr_t)end - (intptr_t)start, FIELD_LEN)); | ||
423 | start = end +1; | ||
424 | |||
425 | end = rb->strchr(start, '\0'); /* find eol */ | ||
426 | len = (intptr_t)end - (intptr_t)&buffer[HEADER_LEN]; | ||
427 | if (len > bytes_read + HEADER_LEN) | ||
428 | { | ||
429 | break; | ||
430 | } | ||
431 | |||
432 | rb->strncpy(entry->name, start, | ||
433 | MIN((intptr_t)end - (intptr_t)start, FIELD_LEN)); | ||
434 | start = end +1; | ||
435 | |||
436 | end = rb->strchr(start, '\0'); /* find eol */ | ||
437 | len = (intptr_t)end - (intptr_t)&buffer[HEADER_LEN]; | ||
438 | if (len > bytes_read + HEADER_LEN) | ||
439 | { | ||
440 | break; | ||
441 | } | ||
442 | rb->strncpy(entry->password, start, | ||
443 | MIN((intptr_t)end - (intptr_t)start, FIELD_LEN)); | ||
444 | start = end +1; | ||
445 | entry->used = true; | ||
446 | if (i + 1 < MAX_ENTRIES - 1) | ||
447 | { | ||
448 | entry->next = &pw_list.entries[i+1]; | ||
449 | entry = entry->next; | ||
450 | } | ||
451 | else | ||
452 | { | ||
453 | break; | ||
454 | } | ||
455 | } | ||
456 | entry->next = NULL; | ||
457 | pw_list.num_entries = i; | ||
458 | rb->gui_synclist_set_nb_items(&kb_list, pw_list.num_entries); | ||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static void write_output(int fd) | ||
463 | { | ||
464 | size_t bytes_written; | ||
465 | int i; | ||
466 | size_t len, size; | ||
467 | char *p = &buffer[HEADER_LEN]; /* reserve space for salt + hash */ | ||
468 | |||
469 | rb->memcpy(&buffer[8], &pwhash, sizeof(union hash)); | ||
470 | struct pw_entry *entry = pw_list.first.next; | ||
471 | |||
472 | for (i = 0; i < pw_list.num_entries; i++) | ||
473 | { | ||
474 | len = rb->strlen(entry->title); | ||
475 | rb->strncpy(p, entry->title, len+1); | ||
476 | p += len+1; | ||
477 | len = rb->strlen(entry->name); | ||
478 | rb->strncpy(p, entry->name, len+1); | ||
479 | p += len+1; | ||
480 | len = rb->strlen(entry->password); | ||
481 | rb->strncpy(p, entry->password, len+1); | ||
482 | p += len+1; | ||
483 | if (entry->next) | ||
484 | entry = entry->next; | ||
485 | } | ||
486 | |||
487 | /* round up to a number divisible by BLOCK_SIZE */ | ||
488 | size = (((intptr_t)p - (intptr_t)&buffer) / BLOCK_SIZE + 1) * BLOCK_SIZE; | ||
489 | |||
490 | salt = rb->rand(); | ||
491 | make_key(); | ||
492 | |||
493 | encrypt_buffer(&buffer[8], size, &key.words[0]); | ||
494 | rb->memcpy(&buffer[0], &salt, sizeof(salt)); | ||
495 | |||
496 | bytes_written = rb->write(fd, &buffer, size); | ||
497 | } | ||
498 | |||
499 | static int enter_pw(char *pw_buf, size_t buflen, bool new_pw) | ||
500 | { | ||
501 | char buf[2][sizeof(master_pw)]; | ||
502 | rb->memset(buf, 0, sizeof(buf)); | ||
503 | rb->memset(master_pw, 0, sizeof(master_pw)); | ||
504 | |||
505 | if (new_pw) | ||
506 | { | ||
507 | rb->splash(HZ, "Enter new master password"); | ||
508 | rb->kbd_input(buf[0], sizeof(buf[0])); | ||
509 | rb->splash(HZ, "Confirm master password"); | ||
510 | rb->kbd_input(buf[1], sizeof(buf[1])); | ||
511 | |||
512 | if (rb->strcmp(buf[0], buf[1])) | ||
513 | { | ||
514 | rb->splash(HZ, "Password mismatch"); | ||
515 | return -1; | ||
516 | } | ||
517 | else | ||
518 | { | ||
519 | rb->strncpy(pw_buf, buf[0], buflen); | ||
520 | hash_pw(&pwhash); | ||
521 | return 0; | ||
522 | } | ||
523 | } | ||
524 | |||
525 | rb->splash(HZ, "Enter master password"); | ||
526 | if (rb->kbd_input(pw_buf, buflen)) | ||
527 | return -1; | ||
528 | hash_pw(&pwhash); | ||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | static int keybox(void) | ||
533 | { | ||
534 | int button, fd; | ||
535 | bool new_file = !rb->file_exists(KEYBOX_FILE); | ||
536 | bool done = false; | ||
537 | |||
538 | if (enter_pw(master_pw, sizeof (master_pw), new_file)) | ||
539 | return 0; | ||
540 | |||
541 | /* Read the existing file */ | ||
542 | if (!new_file) | ||
543 | { | ||
544 | fd = rb->open(KEYBOX_FILE, O_RDONLY); | ||
545 | if (fd < 0) | ||
546 | return FILE_OPEN_ERROR; | ||
547 | bytes_read = rb->read(fd, &buffer, sizeof(buffer)); | ||
548 | |||
549 | if (parse_buffer()) | ||
550 | return 0; | ||
551 | |||
552 | rb->close(fd); | ||
553 | } | ||
554 | |||
555 | while (!done) | ||
556 | { | ||
557 | rb->gui_syncstatusbar_draw(rb->statusbars, true); | ||
558 | rb->gui_synclist_draw(&kb_list); | ||
559 | button = rb->get_action(CONTEXT_LIST, TIMEOUT_BLOCK); | ||
560 | if (rb->gui_synclist_do_button(&kb_list, &button, LIST_WRAP_ON)) | ||
561 | continue; | ||
562 | |||
563 | switch (button) | ||
564 | { | ||
565 | case ACTION_STD_OK: | ||
566 | splash_pw(rb->gui_synclist_get_sel_pos(&kb_list)); | ||
567 | break; | ||
568 | case ACTION_STD_CONTEXT: | ||
569 | context_menu(rb->gui_synclist_get_sel_pos(&kb_list)); | ||
570 | break; | ||
571 | case ACTION_STD_CANCEL: | ||
572 | done = true; | ||
573 | break; | ||
574 | } | ||
575 | rb->yield(); | ||
576 | } | ||
577 | |||
578 | if (data_changed) | ||
579 | { | ||
580 | fd = rb->open(KEYBOX_FILE, O_WRONLY | O_CREAT | O_TRUNC); | ||
581 | if (fd < 0) | ||
582 | return FILE_OPEN_ERROR; | ||
583 | write_output(fd); | ||
584 | rb->close(fd); | ||
585 | } | ||
586 | |||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | static void reset(void) | ||
591 | { | ||
592 | static const char *message_lines[]= | ||
593 | {"Do you really want", "to reset keybox?"}; | ||
594 | static const char *yes_lines[]= | ||
595 | {"Keybox reset."}; | ||
596 | static const struct text_message message={message_lines, 2}; | ||
597 | static const struct text_message yes_message={yes_lines, 1}; | ||
598 | |||
599 | if(rb->gui_syncyesno_run(&message, &yes_message, NULL) == YESNO_YES) | ||
600 | { | ||
601 | rb->remove(KEYBOX_FILE); | ||
602 | rb->memset(&buffer, 0, sizeof(buffer)); | ||
603 | rb->memset(&pw_list, 0, sizeof(pw_list)); | ||
604 | init_ll(); | ||
605 | } | ||
606 | } | ||
607 | |||
608 | static int main_menu(void) | ||
609 | { | ||
610 | int selection, result, ret; | ||
611 | bool exit = false; | ||
612 | |||
613 | MENUITEM_STRINGLIST(menu,"Keybox", NULL, "Enter Keybox", | ||
614 | "Reset Keybox", "Exit"); | ||
615 | |||
616 | do { | ||
617 | result = rb->do_menu(&menu, &selection, NULL, false); | ||
618 | switch (result) { | ||
619 | case 0: | ||
620 | ret = keybox(); | ||
621 | if (ret) | ||
622 | return ret; | ||
623 | break; | ||
624 | case 1: | ||
625 | reset(); | ||
626 | break; | ||
627 | case 2: | ||
628 | exit = true; | ||
629 | break; | ||
630 | } | ||
631 | rb->yield(); | ||
632 | } while (!exit); | ||
633 | |||
634 | return 0; | ||
635 | } | ||
636 | |||
637 | enum plugin_status plugin_start(const struct plugin_api *api, | ||
638 | const void *parameter) | ||
639 | { | ||
640 | (void)parameter; | ||
641 | rb = api; | ||
642 | int ret; | ||
643 | |||
644 | rb->gui_synclist_init(&kb_list, &kb_list_cb, NULL, false, 1, NULL); | ||
645 | |||
646 | rb->gui_synclist_set_title(&kb_list, "Keybox", NOICON); | ||
647 | rb->gui_synclist_set_icon_callback(&kb_list, NULL); | ||
648 | rb->gui_synclist_set_nb_items(&kb_list, 0); | ||
649 | rb->gui_synclist_limit_scroll(&kb_list, false); | ||
650 | rb->gui_synclist_select_item(&kb_list, 0); | ||
651 | |||
652 | md5_init(api); | ||
653 | |||
654 | init_ll(); | ||
655 | ret = main_menu(); | ||
656 | |||
657 | switch (ret) | ||
658 | { | ||
659 | case FILE_OPEN_ERROR: | ||
660 | rb->splash(HZ*2, "Error opening file"); | ||
661 | return PLUGIN_ERROR; | ||
662 | } | ||
663 | |||
664 | return PLUGIN_OK; | ||
665 | } | ||
666 | |||