summaryrefslogtreecommitdiffabout
path: root/pwmanager/pwmanager/gpasmanfile.cpp
Unidiff
Diffstat (limited to 'pwmanager/pwmanager/gpasmanfile.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--pwmanager/pwmanager/gpasmanfile.cpp437
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
79GpasmanFile::GpasmanFile()
80{
81}
82
83GpasmanFile::~GpasmanFile()
84{
85}
86
87int 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
147int 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
210int 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
250int 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
354int 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
393void GpasmanFile::load_finalize(void)
394{
395 fclose(fd);
396 free(buffer);
397}
398
399int 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
425int 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