summaryrefslogtreecommitdiffabout
path: root/pwmanager/pwmanager/gpasmanfile.cpp
authorulf69 <ulf69>2004-09-15 17:53:22 (UTC)
committer ulf69 <ulf69>2004-09-15 17:53:22 (UTC)
commitd3925ba5bd25224bc4a60d3d6a107c464994a1ea (patch) (side-by-side diff)
tree60f69da1d2b79ee3081e7ef5c09a46470ca6eda0 /pwmanager/pwmanager/gpasmanfile.cpp
parentce83a3479d23b9e8a59c745ccd0a0b14f64ef4e8 (diff)
downloadkdepimpi-d3925ba5bd25224bc4a60d3d6a107c464994a1ea.zip
kdepimpi-d3925ba5bd25224bc4a60d3d6a107c464994a1ea.tar.gz
kdepimpi-d3925ba5bd25224bc4a60d3d6a107c464994a1ea.tar.bz2
initial revision
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 @@
+/* Gpasman, a password manager
+ Copyright (C) 1998-1999 Olivier Sessink, olivier@lx.student.wau.nl
+
+ file.c, handles file opening and closing
+
+ Other code contributors:
+ Dave Rudder
+ Chris Halverson
+ Matthew Palmer
+ Guide Berning
+ Jimmy Mason
+ website at http://www.student.wau.nl/~olivier/gpasman/
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/* 2003/06/10:
+ * modified by Michael Buesch to work together
+ * with PwM as import/export module.
+ */
+
+/***************************************************************************
+ * copyright (C) 2004 by Ulf Schenk
+ * This file is originaly based on version 1.0.1 of pwmanager
+ * and was modified to run on embedded devices that run microkde
+ *
+ * $Id$
+ **************************************************************************/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "gpasmanfile.h"
+#include "globalstuff.h"
+
+#define SAVE_BUFFER_LENGTH 1024
+#define LOAD_BUFFER_LENGTH 2048
+
+#ifndef S_IAMB
+#define S_IAMB 00777
+#endif
+
+// enable/disable debug output
+//#define GPASMANFILE_DEBUG
+#undef GPASMANFILE_DEBUG
+
+
+#if defined(PWM_DEBUG) && defined(GPASMANFILE_DEBUG)
+# define DBG(msg,x...) do { fprintf(stderr, msg "\n" , ##x); } while (0)
+#else
+# define DBG(msg,x...) do { } while (0)
+#endif
+
+#ifdef BIG_ENDIAN_HOST
+# define WORDS_BIGENDIAN
+#else
+# undef WORDS_BIGENDIAN
+#endif
+
+
+GpasmanFile::GpasmanFile()
+{
+}
+
+GpasmanFile::~GpasmanFile()
+{
+}
+
+int GpasmanFile::save_init(const char *filename, const char *password)
+{
+
+/*
+ * returncodes:
+ * 1 = success
+ * 0 = can't open filedescriptor / can't create file
+ * -1 = permissions are bad
+ * -2 = is a symlink
+ * -3 = can't get file status
+ */
+
+ unsigned char key[128];
+ unsigned int j = 0;
+ unsigned int keylength;
+ int val, count2;
+
+ /* first we should check the permissions of the filename */
+
+ if (file_exists(filename)) {
+ val = check_file(filename);
+ if (val != 1) {
+ DBG("save_init, return %d", val);
+ return val;
+ }
+ } else {
+ val = creat(filename, (S_IRUSR | S_IWUSR));
+ if (val == -1) {
+ DBG("%s", "save_init, return 0");
+ return 0;
+ } else {
+ close(val);
+ }
+ }
+
+ fd = fopen(filename, "wb");
+ if (fd == NULL) {
+ return 0;
+ }
+ buffer = (char*)malloc(SAVE_BUFFER_LENGTH);
+
+ /* make the key ready */
+ DBG("save_init, password=%s", password);
+ for (j = 0; password[j] != '\0'; j++) {
+ key[j] = password[j];
+ }
+ keylength = j;
+ rc2.rc2_expandkey((char*)key, (int)keylength, 128);
+
+ /* First, we make the IV */
+ for (count2 = 0; count2 < 4; count2++) {
+ iv[count2] = rand();
+ putc((unsigned char) (iv[count2] >> 8), fd);
+ putc((unsigned char) (iv[count2] & 0xff), fd);
+ }
+
+ bufferIndex = 0;
+ return 1;
+}
+
+int GpasmanFile::save_entry(char *entry[4])
+{
+
+ char *text1;
+ int count2, count3;
+ unsigned short ciphertext[4];
+
+ buffer = (char*)memset(buffer, '\0', SAVE_BUFFER_LENGTH);
+
+ for (count2 = 0; count2 < 4; count2++) {
+ text1 = entry[count2];
+ if (strlen(text1) == 0) {
+ strncpy(text1, " ", strlen(" "));
+ }
+ strncat(buffer, text1, strlen(text1));
+ /* Use 255 as the marker. \n is too tough to test for */
+ buffer[strlen(buffer)] = 255;
+
+ } /*for (count2 = 0; count2 < 4; count2++) */
+ DBG("save_entry, buffer contains %s", buffer);
+ count2 = 0;
+ /* I'm using CBC mode and encrypting the data straight from top down.
+ * At the bottom, encrypted, I will append an MD5 hash of the file, eventually.
+ * PKCS 5 padding (explained at the code section
+ */
+ while (count2 < (int)strlen(buffer)) {
+#ifndef WORDS_BIGENDIAN
+ plaintext[bufferIndex] = buffer[count2 + 1] << 8;
+ plaintext[bufferIndex] += buffer[count2] & 0xff;
+#else
+ plaintext[bufferIndex] = buffer[count2] << 8;
+ plaintext[bufferIndex] += buffer[count2 + 1] & 0xff;
+#endif
+ bufferIndex++;
+ if (bufferIndex == 4) {
+ rc2.rc2_encrypt(plaintext);
+
+ for (count3 = 0; count3 < 4; count3++) {
+ ciphertext[count3] =
+ iv[count3] ^ plaintext[count3];
+
+ /* Now store the ciphertext as the iv */
+ iv[count3] = plaintext[count3];
+
+ /* reset the buffer index */
+ bufferIndex = 0;
+ if (putc
+ ((unsigned char) (ciphertext[count3] >> 8),
+ fd) == EOF)
+ return -1;
+ if (putc
+ ((unsigned char) (ciphertext[count3] &
+ 0xff), fd) == EOF)
+ return -1;
+ } /*for (count3 = 0; count3 < 4; count3++) */
+ }
+ /*if (bufferIndex == 4) */
+ /* increment a short, not a byte */
+ count2 += 2;
+ } /*while (count2 < strlen (buffer)) */
+ return 1;
+}
+
+int GpasmanFile::save_finalize(void)
+{
+
+ int count1, retval = 1;
+ unsigned short ciphertext[4];
+
+ /* Tack on the PKCS 5 padding
+ How it works is we fill up the last n bytes with the value n
+
+ So, if we have, say, 13 bytes, 8 of which are used, we have 5 left
+ over, leaving us 3 short, so we fill it in with 3's.
+
+ If we come out even, we fill it with 8 8s
+
+ um, except that in this instance we are using 4 shorts instead of 8 bytes.
+ so, half everything
+ */
+ for (count1 = bufferIndex; count1 < 4; count1++) {
+ plaintext[count1] = (4 - bufferIndex);
+ }
+ DBG("save_finalize, 4 - bufferIndex = %d",
+ 4 - bufferIndex);
+ DBG("save_finalize, plaintext[3]=%c", plaintext[3]);
+ rc2.rc2_encrypt(plaintext);
+ for (count1 = 0; count1 < 4; count1++) {
+ ciphertext[count1] = iv[count1] ^ plaintext[count1];
+ if (putc((unsigned char) (ciphertext[count1] >> 8), fd) == EOF)
+ retval = -1;
+ if (putc((unsigned char) (ciphertext[count1] & 0xff), fd) ==
+ EOF)
+ retval = -1;
+ }
+
+ fclose(fd);
+ DBG("%s", "save_finalize, fd is closed");
+ free(buffer);
+ return retval;
+
+}
+
+int GpasmanFile::load_init(const char *filename, const char *password)
+{
+/*
+ * returncodes:
+ * 1 = success
+ * 0 = can't open filedescriptor / can't create file
+ * -1 = permissions are bad
+ * -2 = is a symlink
+ * -3 = can't get file status
+ */
+ unsigned int j = 0;
+ unsigned int keylength = 0;
+ int count = 0, count2 = 0, count3 = 0;
+ unsigned char charbuf[8];
+ unsigned short ciphertext[4];
+ int val = 0;
+ unsigned char key[128];
+
+ /* first we should check the file permissions */
+ if (file_exists(filename)) {
+ val = check_file(filename);
+ if (val != 1) {
+ return val;
+ }
+ } else {
+ return 0;
+ }
+
+ fd = fopen(filename, "rb");
+ if (fd == NULL) {
+ return 0;
+ }
+
+ buffer = (char*)malloc(LOAD_BUFFER_LENGTH);
+ DBG("load_init, password=\"%s\"", password);
+ for (j = 0; password[j] != '\0'; j++) {
+ key[j] = password[j];
+ }
+ keylength = j;
+ rc2.rc2_expandkey((char*)key, (int)keylength, 128);
+
+ size = read(fileno(fd), (unsigned char *) (charbuf + count), 8);
+ DBG("load_init, size=%d, keylength=%d", size, keylength);
+
+ if (size < 8) {
+ fclose(fd);
+ free(buffer);
+ return -1;
+ }
+
+ for (count = 0; count < 4; count++) {
+ count2 = count << 1;
+ iv[count] = charbuf[count2] << 8;
+ iv[count] += charbuf[count2 + 1];
+ DBG("load_init iv[%d]=%d", count, iv[count]);
+ }
+
+ size = 0;
+ bufferIndex = 0;
+ while ((count = read(fileno(fd), (unsigned char *) charbuf, 8)) > 0) {
+ DBG("load_init A, count=%d, count2=%d", count, count2);
+ while (count < 8) {
+ count2 = read(fileno(fd), (unsigned char *) (charbuf +
+ count), 8);
+ DBG("load_init B, count=%d, count2=%d",
+ count, count2);
+ if (count2 == 0) {
+ printf("bad EOF\n");
+ fclose(fd);
+ free(buffer);
+ return -1;
+ }
+ count += count2;
+ } /* while (count < 8) */
+
+ size += 8;
+ DBG("load_init charbuf[1]=%c", charbuf[1]);
+ for (count2 = 0; count2 < 8; count2 += 2) {
+ count3 = count2 >> 1;
+ ciphertext[count3] = charbuf[count2] << 8;
+ ciphertext[count3] += charbuf[count2 + 1];
+
+ plaintext[count3] = ciphertext[count3] ^ iv[count3];
+ iv[count3] = plaintext[count3];
+ }
+
+ rc2.rc2_decrypt(plaintext);
+ memcpy((unsigned char *) (buffer + bufferIndex), plaintext, 8);
+ bufferIndex += 8;
+ buffer[bufferIndex + 1] = '\0';
+ DBG("bufferIndex=%d, buffer=%s", bufferIndex,
+ buffer);
+ } /* while ((count = read (fileno (fd), (unsigned char *) charbuf, 8)) > 0) */
+ DBG("load_init, size=%d, buffer[size-1]=%d,", size,
+ buffer[size - 1]);
+ size -= buffer[size - 1];
+ DBG("size=%d", size);
+ lastcount = 0;
+
+ /* This will point to the starting index */
+ bufferIndex = 0;
+ return 1;
+}
+
+int GpasmanFile::load_entry(char *entry[4])
+{
+/* Strip off PKCS 5 padding
+ Should check to make sure it's good here
+ */
+ int count, count1 = 0;
+ DBG("load_entry, lastcount=%d, size=%d, entry=%p",
+ lastcount, size, entry);
+
+ for (count = lastcount; count < size; count++) {
+ if ((unsigned char) (buffer[count]) == 255) {
+ if (buffer[bufferIndex] == '\0') {
+ bufferIndex++;
+ }
+ entry[count1] =
+ (char *) malloc(count - bufferIndex + 1);
+ DBG("load_entry, entry[%d]=%p", count1,
+ entry[count1]);
+ memcpy(entry[count1],
+ (unsigned char *) (buffer + bufferIndex),
+ count - bufferIndex);
+ entry[count1][count - bufferIndex] = '\0';
+ DBG("load_entry, entry[%d]=%s", count1,
+ entry[count1]);
+ count++;
+ bufferIndex = count;
+ count1++;
+ if (count1 == 4) {
+ lastcount = count;
+ DBG("%s", "load_entry, return 1, entry ready");
+ return 1;
+ }
+ } /* if ((unsigned char) (buffer[count]) == 255) */
+ } /* for (count = 0; count < size; count++) */
+
+ DBG("%s", "load_entry, ended no entry anymore");
+ return 2;
+}
+
+void GpasmanFile::load_finalize(void)
+{
+ fclose(fd);
+ free(buffer);
+}
+
+int GpasmanFile::check_file(const char *filename)
+{
+ struct stat naamstat;
+
+ if (stat(filename, &naamstat) == -1) {
+ return (-3);
+ }
+
+ if (((naamstat.st_mode & S_IAMB) | (S_IRUSR | S_IWUSR)) != (S_IRUSR |
+ S_IWUSR)) {
+ DBG("%s perms are bad, they are: %ld, should be -rw------",
+ filename, (naamstat.st_mode & (S_IREAD | S_IWRITE)));
+ return (-1);
+ }
+
+ if (!S_ISREG(naamstat.st_mode)) {
+ lstat(filename, &naamstat);
+ if (S_ISLNK(naamstat.st_mode)) {
+ DBG("%s is a symlink", filename);
+ return (-2);
+ }
+ }
+
+ return (1);
+}
+
+int GpasmanFile::file_exists(const char *tfile)
+{
+ struct stat naamstat;
+
+ if ((stat(tfile, &naamstat) == -1) && (errno == ENOENT)) {
+ DBG("file_exists, %s does NOT exist", tfile);
+ return (0);
+ } else {
+ DBG("file_exists, %s DOES exist", tfile);
+ return (1);
+ }
+}
+