Diffstat (limited to 'pwmanager/pwmanager/gpasmanfile.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | pwmanager/pwmanager/gpasmanfile.cpp | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/pwmanager/pwmanager/gpasmanfile.cpp b/pwmanager/pwmanager/gpasmanfile.cpp new file mode 100644 index 0000000..f80bc13 --- a/dev/null +++ b/pwmanager/pwmanager/gpasmanfile.cpp | |||
@@ -0,0 +1,437 @@ | |||
1 | /* Gpasman, a password manager | ||
2 | Copyright (C) 1998-1999 Olivier Sessink, olivier@lx.student.wau.nl | ||
3 | |||
4 | file.c, handles file opening and closing | ||
5 | |||
6 | Other code contributors: | ||
7 | Dave Rudder | ||
8 | Chris Halverson | ||
9 | Matthew Palmer | ||
10 | Guide Berning | ||
11 | Jimmy Mason | ||
12 | website at http://www.student.wau.nl/~olivier/gpasman/ | ||
13 | |||
14 | This program is free software; you can redistribute it and/or modify | ||
15 | it under the terms of the GNU General Public License as published by | ||
16 | the Free Software Foundation; either version 2 of the License, or | ||
17 | (at your option) any later version. | ||
18 | |||
19 | This program is distributed in the hope that it will be useful, | ||
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | GNU General Public License for more details. | ||
23 | |||
24 | You should have received a copy of the GNU General Public License | ||
25 | along with this program; if not, write to the Free Software | ||
26 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
27 | */ | ||
28 | |||
29 | /* 2003/06/10: | ||
30 | * modified by Michael Buesch to work together | ||
31 | * with PwM as import/export module. | ||
32 | */ | ||
33 | |||
34 | /*************************************************************************** | ||
35 | * copyright (C) 2004 by Ulf Schenk | ||
36 | * This file is originaly based on version 1.0.1 of pwmanager | ||
37 | * and was modified to run on embedded devices that run microkde | ||
38 | * | ||
39 | * $Id$ | ||
40 | **************************************************************************/ | ||
41 | |||
42 | #include <sys/types.h> | ||
43 | #include <sys/stat.h> | ||
44 | #include <stdio.h> | ||
45 | #include <fcntl.h> | ||
46 | #include <stdlib.h> | ||
47 | #include <unistd.h> | ||
48 | #include <string.h> | ||
49 | #include <errno.h> | ||
50 | |||
51 | #include "gpasmanfile.h" | ||
52 | #include "globalstuff.h" | ||
53 | |||
54 | #define SAVE_BUFFER_LENGTH 1024 | ||
55 | #define LOAD_BUFFER_LENGTH 2048 | ||
56 | |||
57 | #ifndef S_IAMB | ||
58 | #define S_IAMB 00777 | ||
59 | #endif | ||
60 | |||
61 | // enable/disable debug output | ||
62 | //#define GPASMANFILE_DEBUG | ||
63 | #undef GPASMANFILE_DEBUG | ||
64 | |||
65 | |||
66 | #if defined(PWM_DEBUG) && defined(GPASMANFILE_DEBUG) | ||
67 | # define DBG(msg,x...)do { fprintf(stderr, msg "\n" , ##x); } while (0) | ||
68 | #else | ||
69 | # define DBG(msg,x...)do { } while (0) | ||
70 | #endif | ||
71 | |||
72 | #ifdef BIG_ENDIAN_HOST | ||
73 | # define WORDS_BIGENDIAN | ||
74 | #else | ||
75 | # undef WORDS_BIGENDIAN | ||
76 | #endif | ||
77 | |||
78 | |||
79 | GpasmanFile::GpasmanFile() | ||
80 | { | ||
81 | } | ||
82 | |||
83 | GpasmanFile::~GpasmanFile() | ||
84 | { | ||
85 | } | ||
86 | |||
87 | int GpasmanFile::save_init(const char *filename, const char *password) | ||
88 | { | ||
89 | |||
90 | /* | ||
91 | * returncodes: | ||
92 | * 1 = success | ||
93 | * 0 = can't open filedescriptor / can't create file | ||
94 | * -1 = permissions are bad | ||
95 | * -2 = is a symlink | ||
96 | * -3 = can't get file status | ||
97 | */ | ||
98 | |||
99 | unsigned char key[128]; | ||
100 | unsigned int j = 0; | ||
101 | unsigned int keylength; | ||
102 | int val, count2; | ||
103 | |||
104 | /* first we should check the permissions of the filename */ | ||
105 | |||
106 | if (file_exists(filename)) { | ||
107 | val = check_file(filename); | ||
108 | if (val != 1) { | ||
109 | DBG("save_init, return %d", val); | ||
110 | return val; | ||
111 | } | ||
112 | } else { | ||
113 | val = creat(filename, (S_IRUSR | S_IWUSR)); | ||
114 | if (val == -1) { | ||
115 | DBG("%s", "save_init, return 0"); | ||
116 | return 0; | ||
117 | } else { | ||
118 | close(val); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | fd = fopen(filename, "wb"); | ||
123 | if (fd == NULL) { | ||
124 | return 0; | ||
125 | } | ||
126 | buffer = (char*)malloc(SAVE_BUFFER_LENGTH); | ||
127 | |||
128 | /* make the key ready */ | ||
129 | DBG("save_init, password=%s", password); | ||
130 | for (j = 0; password[j] != '\0'; j++) { | ||
131 | key[j] = password[j]; | ||
132 | } | ||
133 | keylength = j; | ||
134 | rc2.rc2_expandkey((char*)key, (int)keylength, 128); | ||
135 | |||
136 | /* First, we make the IV */ | ||
137 | for (count2 = 0; count2 < 4; count2++) { | ||
138 | iv[count2] = rand(); | ||
139 | putc((unsigned char) (iv[count2] >> 8), fd); | ||
140 | putc((unsigned char) (iv[count2] & 0xff), fd); | ||
141 | } | ||
142 | |||
143 | bufferIndex = 0; | ||
144 | return 1; | ||
145 | } | ||
146 | |||
147 | int GpasmanFile::save_entry(char *entry[4]) | ||
148 | { | ||
149 | |||
150 | char *text1; | ||
151 | int count2, count3; | ||
152 | unsigned short ciphertext[4]; | ||
153 | |||
154 | buffer = (char*)memset(buffer, '\0', SAVE_BUFFER_LENGTH); | ||
155 | |||
156 | for (count2 = 0; count2 < 4; count2++) { | ||
157 | text1 = entry[count2]; | ||
158 | if (strlen(text1) == 0) { | ||
159 | strncpy(text1, " ", strlen(" ")); | ||
160 | } | ||
161 | strncat(buffer, text1, strlen(text1)); | ||
162 | /* Use 255 as the marker. \n is too tough to test for */ | ||
163 | buffer[strlen(buffer)] = 255; | ||
164 | |||
165 | } /*for (count2 = 0; count2 < 4; count2++) */ | ||
166 | DBG("save_entry, buffer contains %s", buffer); | ||
167 | count2 = 0; | ||
168 | /* I'm using CBC mode and encrypting the data straight from top down. | ||
169 | * At the bottom, encrypted, I will append an MD5 hash of the file, eventually. | ||
170 | * PKCS 5 padding (explained at the code section | ||
171 | */ | ||
172 | while (count2 < (int)strlen(buffer)) { | ||
173 | #ifndef WORDS_BIGENDIAN | ||
174 | plaintext[bufferIndex] = buffer[count2 + 1] << 8; | ||
175 | plaintext[bufferIndex] += buffer[count2] & 0xff; | ||
176 | #else | ||
177 | plaintext[bufferIndex] = buffer[count2] << 8; | ||
178 | plaintext[bufferIndex] += buffer[count2 + 1] & 0xff; | ||
179 | #endif | ||
180 | bufferIndex++; | ||
181 | if (bufferIndex == 4) { | ||
182 | rc2.rc2_encrypt(plaintext); | ||
183 | |||
184 | for (count3 = 0; count3 < 4; count3++) { | ||
185 | ciphertext[count3] = | ||
186 | iv[count3] ^ plaintext[count3]; | ||
187 | |||
188 | /* Now store the ciphertext as the iv */ | ||
189 | iv[count3] = plaintext[count3]; | ||
190 | |||
191 | /* reset the buffer index */ | ||
192 | bufferIndex = 0; | ||
193 | if (putc | ||
194 | ((unsigned char) (ciphertext[count3] >> 8), | ||
195 | fd) == EOF) | ||
196 | return -1; | ||
197 | if (putc | ||
198 | ((unsigned char) (ciphertext[count3] & | ||
199 | 0xff), fd) == EOF) | ||
200 | return -1; | ||
201 | }/*for (count3 = 0; count3 < 4; count3++) */ | ||
202 | } | ||
203 | /*if (bufferIndex == 4) */ | ||
204 | /* increment a short, not a byte */ | ||
205 | count2 += 2; | ||
206 | } /*while (count2 < strlen (buffer)) */ | ||
207 | return 1; | ||
208 | } | ||
209 | |||
210 | int GpasmanFile::save_finalize(void) | ||
211 | { | ||
212 | |||
213 | int count1, retval = 1; | ||
214 | unsigned short ciphertext[4]; | ||
215 | |||
216 | /* Tack on the PKCS 5 padding | ||
217 | How it works is we fill up the last n bytes with the value n | ||
218 | |||
219 | So, if we have, say, 13 bytes, 8 of which are used, we have 5 left | ||
220 | over, leaving us 3 short, so we fill it in with 3's. | ||
221 | |||
222 | If we come out even, we fill it with 8 8s | ||
223 | |||
224 | um, except that in this instance we are using 4 shorts instead of 8 bytes. | ||
225 | so, half everything | ||
226 | */ | ||
227 | for (count1 = bufferIndex; count1 < 4; count1++) { | ||
228 | plaintext[count1] = (4 - bufferIndex); | ||
229 | } | ||
230 | DBG("save_finalize, 4 - bufferIndex = %d", | ||
231 | 4 - bufferIndex); | ||
232 | DBG("save_finalize, plaintext[3]=%c", plaintext[3]); | ||
233 | rc2.rc2_encrypt(plaintext); | ||
234 | for (count1 = 0; count1 < 4; count1++) { | ||
235 | ciphertext[count1] = iv[count1] ^ plaintext[count1]; | ||
236 | if (putc((unsigned char) (ciphertext[count1] >> 8), fd) == EOF) | ||
237 | retval = -1; | ||
238 | if (putc((unsigned char) (ciphertext[count1] & 0xff), fd) == | ||
239 | EOF) | ||
240 | retval = -1; | ||
241 | } | ||
242 | |||
243 | fclose(fd); | ||
244 | DBG("%s", "save_finalize, fd is closed"); | ||
245 | free(buffer); | ||
246 | return retval; | ||
247 | |||
248 | } | ||
249 | |||
250 | int GpasmanFile::load_init(const char *filename, const char *password) | ||
251 | { | ||
252 | /* | ||
253 | * returncodes: | ||
254 | * 1 = success | ||
255 | * 0 = can't open filedescriptor / can't create file | ||
256 | * -1 = permissions are bad | ||
257 | * -2 = is a symlink | ||
258 | * -3 = can't get file status | ||
259 | */ | ||
260 | unsigned int j = 0; | ||
261 | unsigned int keylength = 0; | ||
262 | int count = 0, count2 = 0, count3 = 0; | ||
263 | unsigned char charbuf[8]; | ||
264 | unsigned short ciphertext[4]; | ||
265 | int val = 0; | ||
266 | unsigned char key[128]; | ||
267 | |||
268 | /* first we should check the file permissions */ | ||
269 | if (file_exists(filename)) { | ||
270 | val = check_file(filename); | ||
271 | if (val != 1) { | ||
272 | return val; | ||
273 | } | ||
274 | } else { | ||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | fd = fopen(filename, "rb"); | ||
279 | if (fd == NULL) { | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | buffer = (char*)malloc(LOAD_BUFFER_LENGTH); | ||
284 | DBG("load_init, password=\"%s\"", password); | ||
285 | for (j = 0; password[j] != '\0'; j++) { | ||
286 | key[j] = password[j]; | ||
287 | } | ||
288 | keylength = j; | ||
289 | rc2.rc2_expandkey((char*)key, (int)keylength, 128); | ||
290 | |||
291 | size = read(fileno(fd), (unsigned char *) (charbuf + count), 8); | ||
292 | DBG("load_init, size=%d, keylength=%d", size, keylength); | ||
293 | |||
294 | if (size < 8) { | ||
295 | fclose(fd); | ||
296 | free(buffer); | ||
297 | return -1; | ||
298 | } | ||
299 | |||
300 | for (count = 0; count < 4; count++) { | ||
301 | count2 = count << 1; | ||
302 | iv[count] = charbuf[count2] << 8; | ||
303 | iv[count] += charbuf[count2 + 1]; | ||
304 | DBG("load_init iv[%d]=%d", count, iv[count]); | ||
305 | } | ||
306 | |||
307 | size = 0; | ||
308 | bufferIndex = 0; | ||
309 | while ((count = read(fileno(fd), (unsigned char *) charbuf, 8)) > 0) { | ||
310 | DBG("load_init A, count=%d, count2=%d", count, count2); | ||
311 | while (count < 8) { | ||
312 | count2 = read(fileno(fd), (unsigned char *) (charbuf + | ||
313 | count), 8); | ||
314 | DBG("load_init B, count=%d, count2=%d", | ||
315 | count, count2); | ||
316 | if (count2 == 0) { | ||
317 | printf("bad EOF\n"); | ||
318 | fclose(fd); | ||
319 | free(buffer); | ||
320 | return -1; | ||
321 | } | ||
322 | count += count2; | ||
323 | } /* while (count < 8) */ | ||
324 | |||
325 | size += 8; | ||
326 | DBG("load_init charbuf[1]=%c", charbuf[1]); | ||
327 | for (count2 = 0; count2 < 8; count2 += 2) { | ||
328 | count3 = count2 >> 1; | ||
329 | ciphertext[count3] = charbuf[count2] << 8; | ||
330 | ciphertext[count3] += charbuf[count2 + 1]; | ||
331 | |||
332 | plaintext[count3] = ciphertext[count3] ^ iv[count3]; | ||
333 | iv[count3] = plaintext[count3]; | ||
334 | } | ||
335 | |||
336 | rc2.rc2_decrypt(plaintext); | ||
337 | memcpy((unsigned char *) (buffer + bufferIndex), plaintext, 8); | ||
338 | bufferIndex += 8; | ||
339 | buffer[bufferIndex + 1] = '\0'; | ||
340 | DBG("bufferIndex=%d, buffer=%s", bufferIndex, | ||
341 | buffer); | ||
342 | } /* while ((count = read (fileno (fd), (unsigned char *) charbuf, 8)) > 0) */ | ||
343 | DBG("load_init, size=%d, buffer[size-1]=%d,", size, | ||
344 | buffer[size - 1]); | ||
345 | size -= buffer[size - 1]; | ||
346 | DBG("size=%d", size); | ||
347 | lastcount = 0; | ||
348 | |||
349 | /* This will point to the starting index */ | ||
350 | bufferIndex = 0; | ||
351 | return 1; | ||
352 | } | ||
353 | |||
354 | int GpasmanFile::load_entry(char *entry[4]) | ||
355 | { | ||
356 | /* Strip off PKCS 5 padding | ||
357 | Should check to make sure it's good here | ||
358 | */ | ||
359 | int count, count1 = 0; | ||
360 | DBG("load_entry, lastcount=%d, size=%d, entry=%p", | ||
361 | lastcount, size, entry); | ||
362 | |||
363 | for (count = lastcount; count < size; count++) { | ||
364 | if ((unsigned char) (buffer[count]) == 255) { | ||
365 | if (buffer[bufferIndex] == '\0') { | ||
366 | bufferIndex++; | ||
367 | } | ||
368 | entry[count1] = | ||
369 | (char *) malloc(count - bufferIndex + 1); | ||
370 | DBG("load_entry, entry[%d]=%p", count1, | ||
371 | entry[count1]); | ||
372 | memcpy(entry[count1], | ||
373 | (unsigned char *) (buffer + bufferIndex), | ||
374 | count - bufferIndex); | ||
375 | entry[count1][count - bufferIndex] = '\0'; | ||
376 | DBG("load_entry, entry[%d]=%s", count1, | ||
377 | entry[count1]); | ||
378 | count++; | ||
379 | bufferIndex = count; | ||
380 | count1++; | ||
381 | if (count1 == 4) { | ||
382 | lastcount = count; | ||
383 | DBG("%s", "load_entry, return 1, entry ready"); | ||
384 | return 1; | ||
385 | } | ||
386 | } /* if ((unsigned char) (buffer[count]) == 255) */ | ||
387 | } /* for (count = 0; count < size; count++) */ | ||
388 | |||
389 | DBG("%s", "load_entry, ended no entry anymore"); | ||
390 | return 2; | ||
391 | } | ||
392 | |||
393 | void GpasmanFile::load_finalize(void) | ||
394 | { | ||
395 | fclose(fd); | ||
396 | free(buffer); | ||
397 | } | ||
398 | |||
399 | int GpasmanFile::check_file(const char *filename) | ||
400 | { | ||
401 | struct stat naamstat; | ||
402 | |||
403 | if (stat(filename, &naamstat) == -1) { | ||
404 | return (-3); | ||
405 | } | ||
406 | |||
407 | if (((naamstat.st_mode & S_IAMB) | (S_IRUSR | S_IWUSR)) != (S_IRUSR | | ||
408 | S_IWUSR)) { | ||
409 | DBG("%s perms are bad, they are: %ld, should be -rw------", | ||
410 | filename, (naamstat.st_mode & (S_IREAD | S_IWRITE))); | ||
411 | return (-1); | ||
412 | } | ||
413 | |||
414 | if (!S_ISREG(naamstat.st_mode)) { | ||
415 | lstat(filename, &naamstat); | ||
416 | if (S_ISLNK(naamstat.st_mode)) { | ||
417 | DBG("%s is a symlink", filename); | ||
418 | return (-2); | ||
419 | } | ||
420 | } | ||
421 | |||
422 | return (1); | ||
423 | } | ||
424 | |||
425 | int GpasmanFile::file_exists(const char *tfile) | ||
426 | { | ||
427 | struct stat naamstat; | ||
428 | |||
429 | if ((stat(tfile, &naamstat) == -1) && (errno == ENOENT)) { | ||
430 | DBG("file_exists, %s does NOT exist", tfile); | ||
431 | return (0); | ||
432 | } else { | ||
433 | DBG("file_exists, %s DOES exist", tfile); | ||
434 | return (1); | ||
435 | } | ||
436 | } | ||
437 | |||